summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2021-05-17 23:57:45 +1000
committerDamien George <damien@micropython.org>2021-05-21 00:46:01 +1000
commitea81bcf1c0ddeb8be34192cbededecfa425c039b (patch)
treec8debef5d356eb0290749c531a5d2b75b46d6e41
parent748339b28126e69fd2dc2778b2a182901d0a4693 (diff)
stm32/mboot: Leave bootloader from thread mode, not from IRQ.
Leaving the bootloader from an IRQ (eg USB or I2C IRQ) will not work if MBOOT_LEAVE_BOOTLOADER_VIA_RESET is disabled, ie if mboot jumps directly to the application. This is because the CPU will still be in IRQ state when the application starts and IRQs of lower priority will be blocked. Fix this by setting a flag when the bootloader should finish, and exit the bootloader always from the main (top level) thread. This also improves the USB behaviour of mboot: it no longer abruptly disconnects when the manifest command is sent. Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--ports/stm32/mboot/dfu.h2
-rw-r--r--ports/stm32/mboot/main.c33
2 files changed, 18 insertions, 17 deletions
diff --git a/ports/stm32/mboot/dfu.h b/ports/stm32/mboot/dfu.h
index 73db3545d..e867a3e22 100644
--- a/ports/stm32/mboot/dfu.h
+++ b/ports/stm32/mboot/dfu.h
@@ -26,6 +26,7 @@
#ifndef MICROPY_INCLUDED_STM32_MBOOT_DFU_H
#define MICROPY_INCLUDED_STM32_MBOOT_DFU_H
+#include <stdbool.h>
#include <stdint.h>
// DFU spec: https://www.usb.org/sites/default/files/DFU_1.1.pdf
@@ -106,6 +107,7 @@ typedef struct _dfu_state_t {
dfu_cmd_t cmd;
dfu_status_t status;
uint8_t error;
+ bool leave_dfu;
uint16_t wBlockNum;
uint16_t wLength;
uint32_t addr;
diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c
index 3a0242a8d..c1e1d59d2 100644
--- a/ports/stm32/mboot/main.c
+++ b/ports/stm32/mboot/main.c
@@ -106,8 +106,6 @@ static volatile uint32_t systick_ms;
// Global dfu state
dfu_context_t dfu_context SECTION_NOZERO_BSS;
-static void do_reset(void);
-
uint32_t get_le32(const uint8_t *b) {
return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;
}
@@ -771,7 +769,7 @@ void i2c_slave_process_rx_end(i2c_slave_t *i2c) {
memcpy(buf + 12 + sizeof(MICROPY_HW_MCU_NAME), MICROPY_HW_BOARD_NAME, sizeof(MICROPY_HW_BOARD_NAME) - 1);
len = 12 + sizeof(MICROPY_HW_MCU_NAME) + sizeof(MICROPY_HW_BOARD_NAME) - 1;
} else if (buf[0] == I2C_CMD_RESET && len == 0) {
- do_reset();
+ dfu_context.leave_dfu = true;
} else if (buf[0] == I2C_CMD_GETLAYOUT && len == 0) {
len = strlen(FLASH_LAYOUT_STR);
memcpy(buf, FLASH_LAYOUT_STR, len);
@@ -864,6 +862,7 @@ static void dfu_init(void) {
dfu_context.cmd = DFU_CMD_NONE;
dfu_context.status = DFU_STATUS_OK;
dfu_context.error = 0;
+ dfu_context.leave_dfu = false;
dfu_context.addr = 0x08000000;
}
@@ -931,7 +930,8 @@ static void dfu_handle_rx(int cmd, int arg, int len, const void *buf) {
static void dfu_process(void) {
if (dfu_context.state == DFU_STATE_MANIFEST) {
- do_reset();
+ // Set a flag to leave DFU mode from the main thread (here we are in an IRQ handler).
+ dfu_context.leave_dfu = true;
}
if (dfu_context.state == DFU_STATE_BUSY) {
@@ -1412,17 +1412,6 @@ static void leave_bootloader(void) {
NVIC_SystemReset();
}
-static void do_reset(void) {
- led_state_all(0);
- mp_hal_delay_ms(50);
- pyb_usbdd_shutdown();
- #if defined(MBOOT_I2C_SCL)
- i2c_slave_shutdown(MBOOT_I2Cx, I2Cx_EV_IRQn);
- #endif
- mp_hal_delay_ms(50);
- leave_bootloader();
-}
-
extern PCD_HandleTypeDef pcd_fs_handle;
extern PCD_HandleTypeDef pcd_hs_handle;
@@ -1561,7 +1550,7 @@ enter_bootloader:
#if MBOOT_USB_RESET_ON_DISCONNECT
bool has_connected = false;
#endif
- for (;;) {
+ while (!dfu_context.leave_dfu) {
#if USE_USB_POLLING
#if MBOOT_USB_AUTODETECT_PORT || MICROPY_HW_USB_MAIN_DEV == USB_PHY_FS_ID
if (USB_OTG_FS->GINTSTS & USB_OTG_FS->GINTMSK) {
@@ -1585,10 +1574,20 @@ enter_bootloader:
has_connected = true;
}
if (has_connected && pyb_usbdd.hUSBDDevice.dev_state == USBD_STATE_SUSPENDED) {
- do_reset();
+ break;
}
#endif
}
+
+ // Shutdown and leave the bootloader.
+ led_state_all(0);
+ mp_hal_delay_ms(50);
+ pyb_usbdd_shutdown();
+ #if defined(MBOOT_I2C_SCL)
+ i2c_slave_shutdown(MBOOT_I2Cx, I2Cx_EV_IRQn);
+ #endif
+ mp_hal_delay_ms(50);
+ leave_bootloader();
}
void NMI_Handler(void) {