Browse Source

stm32/powerctrl: Add MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET option.

When disabled the bootloader is entered via a direct jump.  When enabled
the bootloader is entered via a system reset then a jump.  It's enabled by
default to retain the existing behaviour, which is the recommended way.

Signed-off-by: Damien George <damien@micropython.org>
pull/7257/head
Damien George 4 years ago
parent
commit
ee4ffc1804
  1. 5
      ports/stm32/mpconfigboard_common.h
  2. 34
      ports/stm32/powerctrl.c

5
ports/stm32/mpconfigboard_common.h

@ -47,6 +47,11 @@
#define MICROPY_PY_PYB_LEGACY (1) #define MICROPY_PY_PYB_LEGACY (1)
#endif #endif
// Whether machine.bootloader() will enter the bootloader via reset, or direct jump.
#ifndef MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
#define MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET (1)
#endif
// Whether to enable storage on the internal flash of the MCU // Whether to enable storage on the internal flash of the MCU
#ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE #ifndef MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE
#define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1) #define MICROPY_HW_ENABLE_INTERNAL_FLASH_STORAGE (1)

34
ports/stm32/powerctrl.c

@ -66,9 +66,11 @@
#define HAVE_PLL48 0 #define HAVE_PLL48 0
#endif #endif
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
// Location in RAM of bootloader state (just after the top of the stack) // Location in RAM of bootloader state (just after the top of the stack)
extern uint32_t _estack[]; extern uint32_t _estack[];
#define BL_STATE ((uint32_t *)&_estack) #define BL_STATE ((uint32_t *)&_estack)
#endif
static inline void powerctrl_disable_hsi_if_unused(void) { static inline void powerctrl_disable_hsi_if_unused(void) {
#if !MICROPY_HW_CLK_USE_HSI && (defined(STM32F4) || defined(STM32F7) || defined(STM32H7)) #if !MICROPY_HW_CLK_USE_HSI && (defined(STM32F4) || defined(STM32F7) || defined(STM32H7))
@ -78,32 +80,47 @@ static inline void powerctrl_disable_hsi_if_unused(void) {
} }
NORETURN void powerctrl_mcu_reset(void) { NORETURN void powerctrl_mcu_reset(void) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
BL_STATE[1] = 1; // invalidate bootloader address BL_STATE[1] = 1; // invalidate bootloader address
#if __DCACHE_PRESENT == 1 #if __DCACHE_PRESENT == 1
SCB_CleanDCache(); SCB_CleanDCache();
#endif #endif
#endif
NVIC_SystemReset(); NVIC_SystemReset();
} }
NORETURN static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t bl_addr) {
__asm volatile (
"ldr r2, [r1, #0]\n" // get address of stack pointer
"msr msp, r2\n" // get stack pointer
"ldr r2, [r1, #4]\n" // get address of destination
"bx r2\n" // branch to bootloader
);
MP_UNREACHABLE;
}
NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) { NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
// Enter the bootloader via a reset, so everything is reset (including WDT).
// Upon reset powerctrl_check_enter_bootloader() will jump to the bootloader.
BL_STATE[0] = r0; BL_STATE[0] = r0;
BL_STATE[1] = bl_addr; BL_STATE[1] = bl_addr;
#if __DCACHE_PRESENT == 1 #if __DCACHE_PRESENT == 1
SCB_CleanDCache(); SCB_CleanDCache();
#endif #endif
NVIC_SystemReset(); NVIC_SystemReset();
}
static __attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t bl_addr) { #else
__asm volatile (
"ldr r2, [r1, #0]\n" // get address of stack pointer // Enter the bootloader via a direct jump.
"msr msp, r2\n" // get stack pointer branch_to_bootloader(r0, bl_addr);
"ldr r2, [r1, #4]\n" // get address of destination
"bx r2\n" // branch to bootloader #endif
);
} }
void powerctrl_check_enter_bootloader(void) { void powerctrl_check_enter_bootloader(void) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
uint32_t bl_addr = BL_STATE[1]; uint32_t bl_addr = BL_STATE[1];
BL_STATE[1] = 1; // invalidate bootloader address BL_STATE[1] = 1; // invalidate bootloader address
if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) { if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) {
@ -115,6 +132,7 @@ void powerctrl_check_enter_bootloader(void) {
uint32_t r0 = BL_STATE[0]; uint32_t r0 = BL_STATE[0];
branch_to_bootloader(r0, bl_addr); branch_to_bootloader(r0, bl_addr);
} }
#endif
} }
#if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB) #if !defined(STM32F0) && !defined(STM32L0) && !defined(STM32WB)

Loading…
Cancel
Save