Step 26 of 56
RTC, pad hold and deep sleep
Deep sleep is not a pause — the chip resets and re-runs from the start. What survives is RTC memory, and the pads you explicitly told to hold their level.
The mental model that matters
Waking from deep sleep is a reset, not a resume.
The digital core — CPU and main RAM — is powered down; only the RTC
domain stays alive. On wake the chip restarts from the beginning: your
Main runs again from the top, every variable re-elaborated. Nothing
in ordinary RAM survives. Code written as though sleep were a blocking delay will
be wrong in a way that looks like a spontaneous reboot.
Two things do survive: data you deliberately put in RTC memory, and RTC pads you told to hold.
Retained memory
subtype Word_Index is Natural range 0 .. Slow_Memory_Size / 4 - 1;
function Read (Index : Word_Index) return Interfaces.Unsigned_32;
procedure Write (Index : Word_Index; Value : Interfaces.Unsigned_32);
There is also a generic typed retained object: instantiate it once per stored item and it gives you a distinct slot with a real type, rather than making you hand-manage word indices and remember which one held what. Prefer that for anything beyond a single counter.
Knowing why you are running
type Wake_Cause is ...; -- power-on, timer, RTC-GPIO, ...
function Last_Wake return Wake_Cause;
function Raw_Reset_Cause return Natural; -- 5 = deep-sleep wake
function Raw_Wake_Cause return Natural;
Because every wake re-runs your program, the first thing it usually has to do is ask why: a cold power-on initialises state, a timer wake continues a duty cycle, a pin wake handles an event. That branch is the shape of nearly every low-power application.
Entering sleep
procedure Deep_Sleep_For (Wake_After : Duration); -- timer wake
-- plus a variant that sleeps until an RTC-capable pin reaches a level (EXT1)
These do not return. If one does, the sleep FSM
rejected the request — and Raw_Reject_Cause tells you why.
Treat a return as an error path, not as normal control flow, because that is
exactly what it is.
Pad hold: keeping a line asserted through the reset
GPIO0 .. GPIO21 are RTC-capable. The headline feature of
ESP32S3.RTC_IO is hold: latch a pad at its current
output level so it keeps driving while the rest of the chip changes —
including through deep sleep and across the reset that waking causes.
subtype RTC_Pin is ESP32S3.GPIO.Pin_Id range 0 .. 21;
procedure Hold (Pin : RTC_Pin);
procedure Release (Pin : RTC_Pin);
function Is_Held (Pin : RTC_Pin) return Boolean;
procedure Set_Pull (Pin : RTC_Pin; Mode : Pull_Mode); -- No_Pull | Up | Down
This is how you keep a load enabled or a peripheral's reset line asserted while you sleep — without it, every pad returns to a default input at the moment of sleep and your board resets its own sensors.
A held pad ignores ordinary GPIO writes until you
Release it. On the run after a wake, a pin that refuses to
change is almost always one you held before sleeping and have not released.
Neither package needs a tasking runtime — both are register pokes — and RTC-IO works under every runtime profile.