Why Does My STM32 Keep Resetting Unexpectedly?
Last updated 12 June 2026 · 3 min read
Direct Answer
An STM32 that resets unexpectedly is almost always triggered by one of four causes — an unserviced watchdog timeout, a brown-out from inadequate power decoupling, an unhandled hard fault, or an external reset glitch — and the RCC/RCC_CSR reset-flag register on the chip tells you exactly which one occurred on the last reset.
Detailed Explanation
STM32 parts expose a reset-cause register (RCC_CSR on F4/F1-class parts, RCC_RSR on newer G0/G4/H5 families) that latches a flag for each possible reset source and persists across the reset itself. The four most common causes in the field are:
- Independent or window watchdog (IWDG/WWDG) timeout — firmware stalled (deadlock, infinite loop, blocking on a peripheral that never responds) and missed its watchdog refresh window.
- Brown-out / power-on reset (BOR/POR) — the supply rail dropped below the brown-out threshold, often momentarily under load.
- Hard fault escalating to a system reset — an unhandled fault (bad pointer, stack overflow, unaligned access, or NVIC priority misconfiguration when using FreeRTOS) that the fault handler resolves by forcing a reset rather than halting. See STM32 NVIC interrupt priority configuration for the FreeRTOS-specific priority constraints that cause hard faults when violated.
- External NRST glitch — noise or a marginal reset-line design pulling NRST low transiently.
Reading the flag register first thing in main() (or even earlier, in SystemInit) and logging or storing it before anything else touches the register turns "it just resets sometimes" into a specific, addressable bug.
Practical Examples
A board that resets only when a Wi-Fi or BLE radio transmits is a textbook brown-out symptom: the transmit current spike sags the 3.3V rail just enough to trip BOR, especially if decoupling capacitance near the radio is thin. Reading RCC_CSR after such a reset and seeing the BOR flag set (rather than the watchdog flag) immediately rules out a firmware logic bug and points straight at power design.
Conversely, a reset that only happens after the device has been running for hours under heavy peripheral load, with the IWDG flag set, points at a deadlock or missed refresh under specific timing conditions — a firmware bug, not a hardware one.
Design Considerations
- Always enable and service a watchdog timer in production firmware — it converts an unrecoverable hang into a clean, identifiable reset rather than a frozen device.
- Verify clock configuration before assuming a firmware bug: a PLL configured with insufficient flash wait states, or an HSE that never reaches its ready flag, can cause crashes at startup that look like firmware faults. See how the STM32 clock tree works for the correct initialisation sequence.
- Decouple aggressively near high-transient loads (radios, motor drivers, relays) and verify rail droop with a scope under real load, not just a multimeter average.
- Log the reset cause to non-volatile storage (or send it over the debug/telemetry channel) on every boot in deployed products — without this, field-reported "random resets" are nearly impossible to diagnose remotely.
- Clear the reset flags explicitly (
RCC_CSR |= RCC_CSR_RMVFor equivalent) after reading them, since they otherwise persist and can be misread after a subsequent unrelated reset. - Production firmware reliability: Shipping firmware that handles watchdog timeouts, hard faults, and power-supply variations gracefully requires production-hardened patterns — Zeus Design's embedded software team builds this robustness in as a standard part of the firmware development process.
Common Mistakes
- Disabling the watchdog "temporarily" during development and forgetting to re-enable it before shipping.
- Assuming every reset is a firmware bug without first checking whether it's actually a brown-out from inadequate decoupling.
- Refreshing the watchdog from a low-priority task or interrupt that can itself be starved, which defeats the watchdog's purpose.
- Never reading the reset-cause register at all, leaving the team debugging blind on every field report.
Frequently Asked Questions
- How do I find out what caused the last STM32 reset?
- Read the reset flag bits in the RCC_CSR (or RCC_RSR on newer families) register immediately after startup, before anything else clears them. The flags distinguish watchdog, brown-out, software, pin, and low-power resets.
- Can a brown-out reset look like a random crash?
- Yes — a marginal 3.3V rail that dips under load (e.g. when a radio or motor driver switches on) will trigger the brown-out detector, which looks identical to a 'random' reset unless you check the reset cause register.
References
Related Questions
How Does the STM32 Clock Tree Work?
The STM32 clock tree routes HSE or HSI through a PLL to generate SYSCLK, then divides it across AHB and APB buses. Learn how it works and how to configure it.
How Do You Configure STM32 NVIC Interrupt Priorities?
Learn how to configure STM32 NVIC interrupt priorities using HAL, priority grouping, and the FreeRTOS configMAX_SYSCALL_INTERRUPT_PRIORITY constraint.
How Do You Configure STM32 Peripherals with HAL and CubeMX?
STM32CubeMX generates HAL initialisation code for UART, SPI, and I2C from a GUI. This guide explains key settings and how generated code maps to the hardware.
How Do You Use the STM32 DFU Bootloader to Flash Firmware?
The STM32 DFU bootloader lets you flash firmware over USB without a debug probe. Learn how to enter DFU mode, use dfu-util, and fix common detection issues.
What Is a Watchdog Timer and How Do You Use It?
A watchdog timer resets an MCU when firmware hangs. Covers IWDG vs WWDG on STM32, prescaler setup, kick strategy, and window mode for fault detection.
How Should You Place Decoupling Capacitors on a PCB?
Decoupling capacitors need to sit close to the power pin they protect with a short, low-inductance path to ground. Here's how placement affects performance.
Related Forum Discussions
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_R
Scope showing 200+ mV spikes on my 3.3V rail — is this real or a probe problem?
Probing the 3.3V output of a switching regulator on a new board and I'm seeing large spikes on the scope that don't make sense to me. The wa
STM32 GPIO interrupt configured but ISR never fires — what am I missing?
Trying to use a button on PA0 to trigger an interrupt on an STM32F411 Nucleo board. Using HAL, generated the init code with CubeMX. The GPIO