ports/stm: bootloader entry on STM32F4 - #11270
Conversation
243c173 to
78db9aa
Compare
78db9aa to
1e0e328
Compare
The ROM clocks USB from the HSE but does not know which crystal is fitted, so it measures one against the HSI. On a miss it resets the part instead of starting DFU: AN2606 Figure 32/33, "HSE detected" -> no -> "Generate System reset". On a Feather STM32F405 Express and its 12 MHz crystal a single jump reached DFU 5 times in 12. Record the request in a backup register and take a real reset, then jump from the top of port_init() and retry when the ROM bounces us. That reaches DFU 12 times in 12. Also drops the HAL_RCC_DeInit()/HAL_DeInit()/NVIC teardown, which a system reset supersedes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TehTMf9ApHxxU5UNHosXKj
1e0e328 to
7717926
Compare
|
The |
tannewt
left a comment
There was a problem hiding this comment.
One question. Thanks for looking into this.
| #define BOOTLOADER_MAGIC 0xf05a0000 | ||
| #define BOOTLOADER_MAGIC_MASK 0xffff0000 | ||
| #define BOOTLOADER_SECONDS_SHIFT 8 | ||
| #define BOOTLOADER_SECONDS_MASK 0xff |
There was a problem hiding this comment.
Can you use port_set_saved_word instead? It is just memory that doesn't get cleared. It'd simplify this a bit.
There was a problem hiding this comment.
Done in 8dacf73. Kept the RTC staleness window, hardware shows it is load-bearing.
| Test | Result |
|---|---|
| Bootloader entry | 6 / 6 reached DFU |
dfu-util --leave |
back to app, stayed |
| Power cycle out of DFU | back to app, stayed |
| Software reset in DFU, window expired | back to app |
| Software reset in DFU, within window | retries, by design |
Plain microcontroller.reset() |
no DFU |
AI assistance: Claude wrote the patch, numbers measured on hardware.
Move the pending ST system bootloader request from RTC->BKP1R to port_set_saved_word(), which is RAM that startup does not clear. This drops the backup domain clock enable and access unlock at both call sites, and removes the ordering constraint against the __HAL_RCC_BACKUPRESET_FORCE() further down port_init(). The RTC staleness window stays. It only needs a read of RTC->TR, which does not require unlocking the backup domain for write. safe_mode.c shares the saved word. Its guard is 0xad0000af under mask 0xff0000ff and the bootloader magic is 0xf05a0000 under mask 0xffff0000, so neither can be read as the other, and the word is only zeroed when the magic is ours. Co-Authored-By: Claude <noreply@anthropic.com>
What
RunMode.BOOTLOADERand 1200 baud touch reach the bootloader 40% of the time on STM32F405. Retrying gives 12/12.Why
ROM HSE detection is marginal at 12 MHz (AN2606) and resets on a miss. Firmware cannot fix it, only retry.
History
#3444 requested, #6919 implemented, #6961 fixed. Verified only on NUCLEO-F446RE, whose HSE is 8 MHz.
How
reset_to_bootloader()sets a backup register and resets.check_enter_bootloader()inport_init()jumps, retrying when the ROM resets us.Notes
BKP1R matches other ports' double-tap state; BKP0R already used. Requests older than 5 seconds are dropped as stale.
Evidence
Feather STM32F405, 12 MHz crystal, 10.3.0-rc.0, Linux host. Each trial power cycles USB, triggers over REPL, reads idProduct.
maindfu-util -s 0x08000000:leave -D firmware.bindfu-util --leaveDecisions
AI assistance
Claude Code was used. All hardware trials run on real boards and reviewed by hand.