The first question after any unexpected reset is which source fired, and the chip answers it exactly once, in a register that the next reset may clear. An integrator who cannot list the sources with their scopes reads that register as trivia instead of evidence. This lesson makes each source precise: what fires it, what it resets, and which cause bit survives it. Its one job is the sources; how they fan out is next.
Power-on reset comes from the analog POR cell in the always-on domain when the supply crosses its threshold. It resets everything including the cause register, and sets the POR bit so software knows no earlier cause survived. The pad reset comes from the RESET_N pin, debounced: it must be held low for more than 16 clk_per cycles (16 x 41.667 ns = 666.7 ns), so a glitch shorter than that never resets the chip. It resets everything except the cause register and the SRAM0 contents: arrays are never reset, only logic. The software reset comes from a write to RSTPWR SWRST with the 0xA5 key in bits 15 down to 8; it resets the system and CPU domains for 16 clk_sys cycles and leaves the peripheral domain, and the controller that issued it, running (the one exception inside the peripheral domain is the clk_per half of the APB bridge, which the tree lesson explains). The wake reset comes from power-up of the switchable domain when SW_ON rises; it resets the system and CPU domains like a software reset and sets the WAKE bit.
T_PER_NS, T_SYS_NS = 1e9 / 24e6, 1e9 / 96e6
# Pad debounce: 16 slow clocks must see the pin low.
debounce_ns = 16 * T_PER_NS
assert abs(debounce_ns - 666.667) < 0.01, debounce_ns
# Software reset scope: 16 system clocks on sys and cpu domains only.
sw_ns = 16 * T_SYS_NS
assert abs(sw_ns - 166.667) < 0.01, sw_ns
# Minimum assertion everywhere: 16 cycles of the domain's own clock. The
# FASTEST clock gives the shortest absolute width (83.3 ns), the slowest the
# longest (666.7 ns); a 4-cycle reset in clk_cpu (20.8 ns) would be too short.
WIDTHS = {name: 16 * period for name, period in
[("cpu", 1e9 / 192e6), ("sys", T_SYS_NS), ("per", T_PER_NS)]}
assert min(WIDTHS.values()) >= 80.0, WIDTHS
assert abs(WIDTHS["cpu"] - 83.333) < 0.01
assert not (4 * 1e9 / 192e6 >= 80.0)
# Debounce rule: a pulse of exactly 16 cycles is NOT enough, more than 16 is.
def pad_resets(low_cycles):
return low_cycles > 16
assert not pad_resets(16) and pad_resets(17) and not pad_resets(3)
print("PASS: debounce 666.7 ns; sw reset 166.7 ns sys+cpu; 16-cycle floor ok")Each source states its condition, its scope and its cause bit in one row; no source resets by implication.
The debounce and the software-reset width are quoted in domain cycles with the nanosecond conversion beside them.
SRAM0 survival is stated per source: everything except supply loss preserves the arrays.
Fire each source in simulation and read back the cause register plus a retained SRAM0 word: POR sets POR with cause otherwise clear, pad sets PAD with memory intact, software sets SW with the peripheral domain undisturbed, wake sets WAKE with the image resumable. A cause register that reads zero after a reset points at a POR-scoped clear applied to the wrong source.
The peripheral domain, the cause bit and SRAM0 survive. The DMA, bridge, fabric and CPU reset, so software must reprogram the DMA and SBR from scratch and cannot assume any transfer completed.