diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 9a52a9aff..05bc0aa5d 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -480,7 +480,7 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta #if HAS_SCREEN IF_SCREEN(screen->showSimpleBanner("Device is rebooting\ninto DFU mode.", 0)); #endif -#if defined(ARCH_NRF52) || defined(ARCH_RP2040) +#if defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_STM32WL) enterDfuMode(); #endif break; diff --git a/src/platform/stm32wl/main-stm32wl.cpp b/src/platform/stm32wl/main-stm32wl.cpp index 93080f840..241020126 100644 --- a/src/platform/stm32wl/main-stm32wl.cpp +++ b/src/platform/stm32wl/main-stm32wl.cpp @@ -4,6 +4,57 @@ #include #include +// ─── Bootloader redirect ────────────────────────────────────────────────────── +// +// Why .noinit + constructor instead of TAMP backup registers: +// +// The STM32duino startup sequence initialises clocks which may call +// __HAL_RCC_BACKUPRESET_FORCE/RELEASE when configuring the LSE oscillator, +// wiping the entire backup domain (including TAMP->BKP0R) before setup() +// ever runs. The backup-register approach therefore cannot reliably survive +// a soft reset in this toolchain. +// +// Solution: store the magic in a .noinit SRAM variable. +// - NVIC_SystemReset() does NOT clear SRAM. +// - The linker script skips zero-init for .noinit sections. +// - __attribute__((constructor)) fires before main()/HAL_Init(), so we can +// intercept and jump before anything disturbs peripheral state. + +#define BOOTLOADER_MAGIC 0xD00DB007UL +#define SYS_MEM_BASE 0x1FFF0000UL + +// Placed in .noinit — not zeroed at startup, survives NVIC_SystemReset(). +__attribute__((section(".noinit"), used)) volatile uint32_t g_bootloaderMagic; + +// Fires before main() / HAL_Init(). Must use only core Cortex-M registers. +__attribute__((constructor(101), used)) static void earlyBootCheck(void) +{ + if (g_bootloaderMagic != BOOTLOADER_MAGIC) + return; + g_bootloaderMagic = 0; + + SysTick->CTRL = 0; + SysTick->LOAD = 0; + SysTick->VAL = 0; + for (int i = 0; i < 8; i++) { + NVIC->ICER[i] = 0xFFFFFFFF; + NVIC->ICPR[i] = 0xFFFFFFFF; + } + __DSB(); + __ISB(); + SCB->VTOR = SYS_MEM_BASE; + __set_MSP(*(volatile uint32_t *)SYS_MEM_BASE); + ((void (*)(void))(*(volatile uint32_t *)(SYS_MEM_BASE + 4)))(); + while (1) + ; +} + +void enterDfuMode() +{ + g_bootloaderMagic = BOOTLOADER_MAGIC; + HAL_NVIC_SystemReset(); +} + void setBluetoothEnable(bool enable) {} void playStartMelody() {}