diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile index 31597e88a5..153ea44626 100644 --- a/ports/stm32/Makefile +++ b/ports/stm32/Makefile @@ -92,6 +92,7 @@ CFLAGS += -fsingle-precision-constant -Wdouble-promotion endif LDFLAGS = -nostdlib -L $(LD_DIR) $(addprefix -T,$(LD_FILES)) -Map=$(@:.elf=.map) --cref +LDFLAGS += --defsym=_estack_reserve=8 LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) # Remove uncalled code from the final image. diff --git a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld index e9d6fa3c39..b6d3e08e30 100644 --- a/ports/stm32/boards/PYBD_SF2/f722_qspi.ld +++ b/ports/stm32/boards/PYBD_SF2/f722_qspi.ld @@ -31,7 +31,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/PYBD_SF6/f767.ld b/ports/stm32/boards/PYBD_SF6/f767.ld index 2a474fba07..1dd4c11ed9 100644 --- a/ports/stm32/boards/PYBD_SF6/f767.ld +++ b/ports/stm32/boards/PYBD_SF6/f767.ld @@ -30,7 +30,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 24K; /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld index 362fab3305..9a0bd56fb3 100644 --- a/ports/stm32/boards/STM32F769DISC/f769_qspi.ld +++ b/ports/stm32/boards/STM32F769DISC/f769_qspi.ld @@ -29,7 +29,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f091xc.ld b/ports/stm32/boards/stm32f091xc.ld index 5e1e9e7bd3..5bcc4c7275 100644 --- a/ports/stm32/boards/stm32f091xc.ld +++ b/ports/stm32/boards/stm32f091xc.ld @@ -16,7 +16,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 6K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f401xd.ld b/ports/stm32/boards/stm32f401xd.ld index 50cb3c571b..f4146abc6d 100644 --- a/ports/stm32/boards/stm32f401xd.ld +++ b/ports/stm32/boards/stm32f401xd.ld @@ -18,7 +18,7 @@ _minimum_heap_size = 16K; /* tunable */ /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f401xe.ld b/ports/stm32/boards/stm32f401xe.ld index 78e0dc1cba..e7bd8edfed 100644 --- a/ports/stm32/boards/stm32f401xe.ld +++ b/ports/stm32/boards/stm32f401xe.ld @@ -18,7 +18,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f405.ld b/ports/stm32/boards/stm32f405.ld index 13133e8c6d..b6f5d30578 100644 --- a/ports/stm32/boards/stm32f405.ld +++ b/ports/stm32/boards/stm32f405.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f411.ld b/ports/stm32/boards/stm32f411.ld index 8ae5f6929c..50633118eb 100644 --- a/ports/stm32/boards/stm32f411.ld +++ b/ports/stm32/boards/stm32f411.ld @@ -18,7 +18,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f413xg.ld b/ports/stm32/boards/stm32f413xg.ld index c2719b834f..96d6dc5fb0 100644 --- a/ports/stm32/boards/stm32f413xg.ld +++ b/ports/stm32/boards/stm32f413xg.ld @@ -21,7 +21,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f413xh.ld b/ports/stm32/boards/stm32f413xh.ld index 017dbbac17..0b28730de5 100644 --- a/ports/stm32/boards/stm32f413xh.ld +++ b/ports/stm32/boards/stm32f413xh.ld @@ -21,7 +21,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f429.ld b/ports/stm32/boards/stm32f429.ld index 35d0736eef..beeaa4df21 100644 --- a/ports/stm32/boards/stm32f429.ld +++ b/ports/stm32/boards/stm32f429.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f439.ld b/ports/stm32/boards/stm32f439.ld index 2b51c3a371..e847646b35 100644 --- a/ports/stm32/boards/stm32f439.ld +++ b/ports/stm32/boards/stm32f439.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f722.ld b/ports/stm32/boards/stm32f722.ld index 8986c68d52..ab41f0ea90 100644 --- a/ports/stm32/boards/stm32f722.ld +++ b/ports/stm32/boards/stm32f722.ld @@ -17,7 +17,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f746.ld b/ports/stm32/boards/stm32f746.ld index 330dd97141..0f1de26964 100644 --- a/ports/stm32/boards/stm32f746.ld +++ b/ports/stm32/boards/stm32f746.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f767.ld b/ports/stm32/boards/stm32f767.ld index 47e992c2dd..9410b9fa6b 100644 --- a/ports/stm32/boards/stm32f767.ld +++ b/ports/stm32/boards/stm32f767.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32f769.ld b/ports/stm32/boards/stm32f769.ld index 41bb321a37..ebc6d033d9 100644 --- a/ports/stm32/boards/stm32f769.ld +++ b/ports/stm32/boards/stm32f769.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 32K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32h743.ld b/ports/stm32/boards/stm32h743.ld index 0f1c2b777e..69738ab8b9 100644 --- a/ports/stm32/boards/stm32h743.ld +++ b/ports/stm32/boards/stm32h743.ld @@ -19,7 +19,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l432.ld b/ports/stm32/boards/stm32l432.ld index 40515e75b3..5558b13c89 100644 --- a/ports/stm32/boards/stm32l432.ld +++ b/ports/stm32/boards/stm32l432.ld @@ -17,7 +17,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 6K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l476xe.ld b/ports/stm32/boards/stm32l476xe.ld index 330ec96e67..e4bcda1f16 100644 --- a/ports/stm32/boards/stm32l476xe.ld +++ b/ports/stm32/boards/stm32l476xe.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l476xg.ld b/ports/stm32/boards/stm32l476xg.ld index 7983fb39a1..9fe83c74a4 100644 --- a/ports/stm32/boards/stm32l476xg.ld +++ b/ports/stm32/boards/stm32l476xg.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM); +_estack = ORIGIN(RAM) + LENGTH(RAM) - _estack_reserve; _sstack = _estack - 16K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/boards/stm32l496xg.ld b/ports/stm32/boards/stm32l496xg.ld index e1ceb50707..c339903422 100644 --- a/ports/stm32/boards/stm32l496xg.ld +++ b/ports/stm32/boards/stm32l496xg.ld @@ -20,7 +20,7 @@ _minimum_heap_size = 16K; /* Define the stack. The stack is full descending so begins just above last byte of RAM. Note that EABI requires the stack to be 8-byte aligned for a call. */ -_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2); +_estack = ORIGIN(RAM) + LENGTH(RAM) + LENGTH(SRAM2) - _estack_reserve; _sstack = _estack - 206K; /* tunable */ /* RAM extents for the garbage collector */ diff --git a/ports/stm32/main.c b/ports/stm32/main.c index 523034e097..2dcc09ae7a 100644 --- a/ports/stm32/main.c +++ b/ports/stm32/main.c @@ -45,6 +45,7 @@ #include "systick.h" #include "pendsv.h" +#include "powerctrl.h" #include "pybthread.h" #include "gccollect.h" #include "factoryreset.h" @@ -368,6 +369,9 @@ STATIC uint update_reset_mode(uint reset_mode) { #endif void stm32_main(uint32_t reset_mode) { + // Check if bootloader should be entered instead of main application + powerctrl_check_enter_bootloader(); + // Enable caches and prefetch buffers #if defined(STM32F4) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index cf615ea6aa..a4ee47470b 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -237,7 +237,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(machine_unique_id_obj, machine_unique_id); // Resets the pyboard in a manner similar to pushing the external RESET button. STATIC mp_obj_t machine_reset(void) { - NVIC_SystemReset(); + powerctrl_mcu_reset(); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset); @@ -248,15 +248,6 @@ STATIC mp_obj_t machine_soft_reset(void) { } MP_DEFINE_CONST_FUN_OBJ_0(machine_soft_reset_obj, machine_soft_reset); -__attribute__((naked)) void branch_to_bootloader(uint32_t r0, uint32_t 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 - ); -} - // Activate the bootloader without BOOT* pins. STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) { #if MICROPY_HW_ENABLE_USB @@ -266,24 +257,10 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) storage_flush(); #endif - #if __DCACHE_PRESENT == 1 - // Flush and disable caches before turning off peripherals (eg SDRAM) - SCB_DisableICache(); - SCB_DisableDCache(); - #endif - - HAL_RCC_DeInit(); - HAL_DeInit(); - - #if (__MPU_PRESENT == 1) - // MPU must be disabled for bootloader to function correctly - HAL_MPU_Disable(); - #endif - #if MICROPY_HW_USES_BOOTLOADER if (n_args == 0 || !mp_obj_is_true(args[0])) { // By default, with no args given, we enter the custom bootloader (mboot) - branch_to_bootloader(0x70ad0000, 0x08000000); + powerctrl_enter_bootloader(0x70ad0000, 0x08000000); } if (n_args == 1 && mp_obj_is_str_or_bytes(args[0])) { @@ -292,15 +269,14 @@ STATIC NORETURN mp_obj_t machine_bootloader(size_t n_args, const mp_obj_t *args) const char *data = mp_obj_str_get_data(args[0], &len); void *mboot_region = (void*)*((volatile uint32_t*)0x08000000); memmove(mboot_region, data, len); - branch_to_bootloader(0x70ad0080, 0x08000000); + powerctrl_enter_bootloader(0x70ad0080, 0x08000000); } #endif #if defined(STM32F7) || defined(STM32H7) - branch_to_bootloader(0, 0x1ff00000); + powerctrl_enter_bootloader(0, 0x1ff00000); #else - __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); - branch_to_bootloader(0, 0x00000000); + powerctrl_enter_bootloader(0, 0x00000000); #endif while (1); diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index c3792be3ed..2ad2426005 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -30,6 +30,60 @@ #include "rtc.h" #include "genhdr/pllfreqtable.h" +#if defined(STM32H7) +#define RCC_SR RSR +#define RCC_SR_SFTRSTF RCC_RSR_SFTRSTF +#define RCC_SR_RMVF RCC_RSR_RMVF +#else +#define RCC_SR CSR +#define RCC_SR_SFTRSTF RCC_CSR_SFTRSTF +#define RCC_SR_RMVF RCC_CSR_RMVF +#endif + +// Location in RAM of bootloader state (just after the top of the stack) +extern uint32_t _estack[]; +#define BL_STATE ((uint32_t*)&_estack) + +NORETURN void powerctrl_mcu_reset(void) { + BL_STATE[1] = 1; // invalidate bootloader address + #if __DCACHE_PRESENT == 1 + SCB_CleanDCache(); + #endif + NVIC_SystemReset(); +} + +NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) { + BL_STATE[0] = r0; + BL_STATE[1] = bl_addr; + #if __DCACHE_PRESENT == 1 + SCB_CleanDCache(); + #endif + NVIC_SystemReset(); +} + +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 + ); +} + +void powerctrl_check_enter_bootloader(void) { + uint32_t bl_addr = BL_STATE[1]; + BL_STATE[1] = 1; // invalidate bootloader address + if ((bl_addr & 0xfff) == 0 && (RCC->RCC_SR & RCC_SR_SFTRSTF)) { + // Reset by NVIC_SystemReset with bootloader data set -> branch to bootloader + RCC->RCC_SR = RCC_SR_RMVF; + #if defined(STM32F0) || defined(STM32F4) || defined(STM32L4) + __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH(); + #endif + uint32_t r0 = BL_STATE[0]; + branch_to_bootloader(r0, bl_addr); + } +} + #if !defined(STM32F0) // Assumes that PLL is used as the SYSCLK source diff --git a/ports/stm32/powerctrl.h b/ports/stm32/powerctrl.h index b26cab391c..6eb0342287 100644 --- a/ports/stm32/powerctrl.h +++ b/ports/stm32/powerctrl.h @@ -28,6 +28,10 @@ #include +NORETURN void powerctrl_mcu_reset(void); +NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr); +void powerctrl_check_enter_bootloader(void); + int powerctrl_rcc_clock_config_pll(RCC_ClkInitTypeDef *rcc_init, uint32_t sysclk_mhz, bool need_pllsai); int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t apb2); void powerctrl_enter_stop_mode(void); diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c index 0c5263e053..a3740d59cd 100644 --- a/ports/stm32/stm32_it.c +++ b/ports/stm32/stm32_it.c @@ -72,6 +72,7 @@ #include "stm32_it.h" #include "pendsv.h" #include "irq.h" +#include "powerctrl.h" #include "pybthread.h" #include "gccollect.h" #include "extint.h" @@ -144,7 +145,7 @@ int pyb_hard_fault_debug = 0; void HardFault_C_Handler(ExceptionRegisters_t *regs) { if (!pyb_hard_fault_debug) { - NVIC_SystemReset(); + powerctrl_mcu_reset(); } #if MICROPY_HW_ENABLE_USB