Bring-up software turns on the DMA, the SPI flash and the PLL in the same millisecond, the core rail sags 12 percent, and the chip takes a brown-out reset in the middle of the image load. Without a specified response that event is a mystery hang; with one it is a diagnosed reset with a cause bit. This lesson specifies the handshake that orders the load steps and the response when the rail sags anyway.
The PMIC handshake is enable-request, ramp, power-good, then load: the sequencer or board controller enables one rail at a time, waits for its debounced power-good, and only then enables the next rail or the load it feeds. Staggering the board-level rail enables keeps one rail's start-up from sagging another. Brown-out is the sag case: a monitor watches the core rail against an illustrative threshold of 0.81 V, 10 percent below the 0.9 V nominal, and on a sustained dip asserts a reset that is recorded like a POR for the affected domains, never a silent continuation. The monitor is an always-on analogue block with a filter; the 3-sample depth in the script below is an illustrative digital stand-in for that filter. Recovery is a full re-sequence through power-good, not a resume, because retained state may have been corrupted below the retention voltage.
# Brown-out monitor model: sustained dip resets, glitches do not.
# Threshold 0.81 V illustrative; NanoSoC rail 0.9 V is the NanoSoC value.
THRESH, NEED = 0.81, 3 # volts, consecutive samples (illustrative depth)
def brown_out(samples):
run = 0
for v in samples:
run = run + 1 if v < THRESH else 0
if run >= NEED:
return True
return False
assert not brown_out([0.90, 0.80, 0.90, 0.90]) # single-sample glitch rides through
assert brown_out([0.90, 0.80, 0.79, 0.78, 0.90]) # sustained dip resets
assert not brown_out([0.85, 0.86, 0.87]) # margin sag, no reset
# Inrush staggering: three enables at least 10 us apart (illustrative spacing).
enables_us = [0.0, 12.0, 25.0]
assert all(b - a >= 10.0 for a, b in zip(enables_us, enables_us[1:]))
print("PASS: glitch rides through, sustained dip resets, enables staggered >=10 us")Each rail enable names what it waits for: the previous rail's debounced power-good, with the stagger interval written down.
The brown-out threshold, depth and response are specified together: threshold 0.81 V illustrative, 3-sample depth illustrative, full re-sequence on trip.
No software path continues after a brown-out without re-initialising state that retention voltage may not have protected.
Test the handshake by delaying each power-good past its nominal and by sagging the rail model through the threshold for one, two and three samples: only the three-sample sag may reset. If brown-outs strike in normal operation, measure the rail at the balls during the load step, not at the regulator: board inductance between the two is usually the sag. The fix is sequencing the load, more decap, or a higher current limit, in that order of cheapness.
The monitor path, not the rail: wrong threshold trim, the monitor muxed to the wrong rail, or the filter output masked by a stale mask bit. Stimulate the monitor directly with a forced sag in simulation and confirm the trip.