STM32 USB not detected by Windows after jumping to bootloader mode
Asked by stale_biscuit_03 ·
Working on a custom STM32F411 board, trying to jump into the built-in USB DFU bootloader
from application code instead of holding BOOT0 on power-up. I'm doing the usual: disable
interrupts, deinit any peripherals I've touched, set the stack pointer to the value at
0x1FFF0000, then jump to the reset vector at 0x1FFF0004.
It resets fine, no crash, no hang, but Windows Device Manager never shows a new DFU device. Same board works perfectly if I hold BOOT0 high and power-cycle manually, DfuSe sees it instantly. So the bootloader itself is clearly fine, it's something about the jump from application code specifically.
Tried a different USB cable and a different PC already, same result both times.
2 Replies
Classic symptom, and it's almost never the jump code itself. It's leftover peripheral state. The system bootloader assumes it's starting from a clean reset, but a software jump doesn't reset peripheral registers, NVIC state, or clock configuration the way a real power-on or NRST reset does.
Two things to check, in order:
- Clock configuration. If you'd already cranked the PLL up for your application
(anything other than the default HSI), the bootloader's USB stack may be running off
a clock configuration it never expects. Reset
RCCback to its default state before jumping (RCC->CR,RCC->CFGR, etc.), not just disabling peripherals. - SysTick and any active interrupts. Make sure SysTick is disabled and all NVIC interrupt enables are cleared before the jump. A leftover SysTick interrupt firing into a vector table that hasn't been remapped yet will silently wedge the USB stack before it ever enumerates.
ST's AN2606 covers the exact boot mode entry conditions if you want the reference, but in practice "reset RCC to defaults, disable SysTick, clear NVIC, then jump" fixes this 90% of the time. If it's still not enumerating after that, scope D+/D- right after the jump. If you don't see anything at all, the jump itself isn't reaching the bootloader's USB init. For a broader explanation of how embedded bootloaders work and how they decide whether to enter update mode, our bootloader overview is a useful starting point.
Same reset discipline applies in reverse, by the way. If your own application brings up its own USBD_CDC virtual COM port after the bootloader hands control back, a stale peripheral or clock state left over from the bootloader's own USB stack can cause the same kind of enumeration failure on your side. How to implement a USB CDC virtual COM port on STM32 covers the class setup and the ring-buffer RX/TX handling once it's actually enumerating.
Separate but related: if you ever see this same board reset on its own with no jump involved, don't assume it's the same bug. Go read the reset-cause flag first: our breakdown of why STM32 boards reset unexpectedly covers exactly which register to check.
Adding a verification step since "it resets fine" can be misleading here. A clean reset and a bootloader that's actually alive are two different things to confirm separately:
- After the jump, check the reset cause register is what you expect (it won't show a
real reset cause if you jumped without using
NVIC_SystemReset(), which is itself useful information). - Confirm with a logic analyzer or scope that D+ goes high within the expected window. That's the bootloader signalling device-present, independent of whether Windows ever shows it.
- Only after both of those check out should you treat a missing Device Manager entry as a USB enumeration problem rather than a "did we actually reach the bootloader" problem.
In my experience this kind of bug report is usually two bugs stacked: the jump partially works, then enumeration fails for the separate reason already covered above. Worth ruling each one out independently rather than assuming it's a single root cause.
Related Discussions
I2C bus completely dead after unplugging a sensor live — SDA stuck low, no NACK, nothing
We've got a shared I2C bus with four sensors on it (temperature, humidity, an IMU, and a current sense IC), all on the same bus off one MCU.
STM32L4 never wakes from Stop mode — button EXTI interrupt just doesn't fire
Working on a battery-powered sensor node, STM32L476RG (Nucleo board for now). Idea is: device sits in Stop 2 mode most of the time, wakes wh
STM32F401 UART printing garbage after switching to 84 MHz PLL — same 115200 baud in CubeMX and PuTTY
Got a WeAct Black Pill (STM32F401CCU6) project that's been running happily on the default HSI clock at 16 MHz. Using USART1 on PA9/PA10 thro
STM32H743 HAL_UART_Receive_DMA fires error callback immediately — TEIF1 set, RxCplt never fires
Upgrading a project from STM32F4 to STM32H743. UART DMA receive worked on the F4 without any issues: standard CubeMX setup, call HAL_UART_Re