ports/stm: bootloader entry on STM32F4 - #11270
Open
mikeysklar wants to merge 1 commit into
Open
Conversation
mikeysklar
force-pushed
the
stm32f4-dfu-retry
branch
2 times, most recently
from
August 29, 2026 03:06
243c173 to
78db9aa
Compare
mikeysklar
force-pushed
the
stm32f4-dfu-retry
branch
from
August 29, 2026 03:37
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
mikeysklar
force-pushed
the
stm32f4-dfu-retry
branch
from
August 29, 2026 05:24
1e0e328 to
7717926
Compare
Collaborator
Author
|
The |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
microcontroller.on_next_reset(RunMode.BOOTLOADER)and the 1200-baud touch reach the ST system bootloader about 40% of the time on an STM32F405. This retries, taking it to 12 of 12.Why
The ROM clocks USB from the HSE but does not know which crystal is fitted, so it measures one against the HSI with TIM11. On a miss it resets the part instead of starting DFU: AN2606 Rev 61 Figure 32/33,
HSE detected-> no -> "Generate System reset". Section 28.2.1 says the measurement is marginal, and that lower frequencies detect better, "better to use 8 MHz instead of 25 MHz". The Feather has 12 MHz.Nothing in firmware can change the outcome of that measurement, so the only response is to ask again.
Not a new feature: #3444 asked for it, #6919 implemented it, #6961 fixed it, #3444 was closed as fixed. #6919 was verified only on a NUCLEO-F446RE, whose HSE is 8 MHz from the ST-LINK MCO.
How
reset_to_bootloader()sets a backup register and takes a real reset instead of jumping from the running application.check_enter_bootloader()runs at the top ofport_init()and jumps, retrying when the ROM resets us. Gated onRCC_CSR.SFTRSTF, so a power cycle always exits.BKP1R matches how the other ports hold this state (
_bootloader_dbl_tap,NRF_POWER->GPREGRET,SNVS->LPGPR[3]). BKP0R is alreadySTM_ALARM_FLAG.Evidence
Adafruit Feather STM32F405 Express, 12 MHz crystal, CircuitPython 10.3.0-rc.0, Linux host, arm-none-eabi-gcc 14.2.1.
Each trial power cycles the USB port, waits for boot, then over the REPL:
Result read from
/sys/bus/usb/devices/3-3.3.4.4/idProduct(df11= DFU,805a= CircuitPython). The harness asserts the REPL accepted both statements, so a failed trigger is not counted as a firmware result.mainTypically under 1 s. Attempt counts, read out of the backup register over SWD on an earlier build of this change, were 1 to 4.
Also verified on hardware:
dfu-util -a 0 -s 0x08000000:leave -D firmware.binflashes and returns to CircuitPython.A retry only counts if it follows the previous attempt within 5 seconds, read from the RTC. The ROM fails and resets in well under a second, so anything slower is the part being reset by something else while the bootloader was running, and the request is dropped as stale. Exit paths, each verified:
dfu-util --leaveThe last row is inherent: inside the window the ROM's own reset and an external one are indistinguishable. A flashing session takes longer than that.
Decisions
0x1FFF0000.HSEONand spinning onHSERDYbefore the branch, so the ROM gets a settled crystal, still needed 1 to 4 attempts over 12 trials. The ROM appears to re-initialise RCC and re-measure regardless, so the retry is not covering for a startup race.HAL_RCC_DeInit()/HAL_DeInit()/NVIC teardown. A system reset supersedes it.#if UF2handling to prefer a UF2 bootloader; still not implemented, and this does not change that behaviour.Claude Code was used.