summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/powerctrl.c30
1 files changed, 19 insertions, 11 deletions
diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c
index 406325581..a3f8207e9 100644
--- a/ports/stm32/powerctrl.c
+++ b/ports/stm32/powerctrl.c
@@ -75,9 +75,19 @@
#endif
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
-// Location in RAM of bootloader state (just after the top of the stack)
-extern uint32_t _estack[];
-#define BL_STATE ((uint32_t *)&_estack)
+// Location in RAM of bootloader state (just after the top of the stack).
+// STM32H7 has ECC and writes to RAM must be 64-bit so they are fully committed
+// to actual SRAM before a system reset occurs.
+#define BL_STATE_PTR ((uint64_t *)&_estack)
+#define BL_STATE_KEY (0x5a5)
+#define BL_STATE_KEY_MASK (0xfff)
+#define BL_STATE_KEY_SHIFT (32)
+#define BL_STATE_INVALID (0)
+#define BL_STATE_VALID(reg, addr) ((uint64_t)(reg) | ((uint64_t)((addr) | BL_STATE_KEY)) << BL_STATE_KEY_SHIFT)
+#define BL_STATE_GET_REG(s) ((s) & 0xffffffff)
+#define BL_STATE_GET_KEY(s) (((s) >> BL_STATE_KEY_SHIFT) & BL_STATE_KEY_MASK)
+#define BL_STATE_GET_ADDR(s) (((s) >> BL_STATE_KEY_SHIFT) & ~BL_STATE_KEY_MASK)
+extern uint64_t _estack[];
#endif
static inline void powerctrl_disable_hsi_if_unused(void) {
@@ -89,7 +99,7 @@ static inline void powerctrl_disable_hsi_if_unused(void) {
NORETURN void powerctrl_mcu_reset(void) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
- BL_STATE[1] = 1; // invalidate bootloader address
+ *BL_STATE_PTR = BL_STATE_INVALID;
#if __DCACHE_PRESENT == 1
SCB_CleanDCache();
#endif
@@ -112,8 +122,7 @@ NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
// 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[1] = bl_addr;
+ *BL_STATE_PTR = BL_STATE_VALID(r0, bl_addr);
#if __DCACHE_PRESENT == 1
SCB_CleanDCache();
#endif
@@ -129,16 +138,15 @@ NORETURN void powerctrl_enter_bootloader(uint32_t r0, uint32_t bl_addr) {
void powerctrl_check_enter_bootloader(void) {
#if MICROPY_HW_ENTER_BOOTLOADER_VIA_RESET
- 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)) {
+ uint64_t bl_state = *BL_STATE_PTR;
+ *BL_STATE_PTR = BL_STATE_INVALID;
+ if (BL_STATE_GET_KEY(bl_state) == BL_STATE_KEY && (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(STM32L0) || defined(STM32L4) || defined(STM32WB)
__HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
#endif
- uint32_t r0 = BL_STATE[0];
- branch_to_bootloader(r0, bl_addr);
+ branch_to_bootloader(BL_STATE_GET_REG(bl_state), BL_STATE_GET_ADDR(bl_state));
}
#endif
}