Embedded Systems · Power Management

Retention Versus Reinitialisation in Deep Sleep

The trade between keeping state alive across a sleep and rebuilding it on wake, expressed as a sleep-current penalty against a per-wake energy cost.

Every deep sleep state forces a choice about memory. Keeping SRAM powered preserves the program’s variables, so the wake path can skip memory initialisation and rebuild far less state. Removing the power saves the retention current but destroys the contents, and the wake must rebuild them from something durable. The two options differ in where the energy is spent, and the decision is a rate calculation rather than a matter of preference.

What retention costs per byte

A retained SRAM cell is a cell held at a voltage high enough to keep its bistable state, with its bit lines unpowered and its periphery clocked off. The current it draws is the cell’s leakage plus the bias needed to hold the state, and it scales with the number of bits retained.

Vendors quote retention in microamps per unit of retained memory, and the figure is small enough to sound free. It is not free, because the sleep may last months. A retained region drawing 1 µA costs 1 µA for the entire sleep, while a reinitialisation path that costs 50 µJ per wake costs the same energy as 1 µA for about fourteen seconds at 3.6 V. If the device wakes every ten seconds, retention is cheaper; if it wakes once an hour, reinitialisation is cheaper by a wide margin, because the retained region would have been paid for 3600 times over. The crossover is the whole question, and it is computable from three numbers: retention current, wake energy, and wake period.

The comparison has a second axis, which is state complexity. The energy of reinitialisation is not only the code that runs; it is the work needed to reconstruct every piece of state the program needs, including the peripheral configuration, the calibration values, the radio’s channel and address, and the protocol’s sequence numbers. A firmware that keeps a large amount of derived state in RAM pays a correspondingly large cost to rebuild it, and a firmware that keeps almost nothing pays almost nothing. The retention decision is therefore also an architectural decision about how much state the program holds.

The three ways to preserve state

The first is retained SRAM, as above. It preserves everything in the retained region exactly, needs no code on wake, and costs current proportional to size.

The second is a durable store outside the microcontroller: an EEPROM, a flash region, or an external FRAM. It costs nothing while asleep, and it costs a write on the way down and a read on the way up. The write’s energy is per byte and the read’s is per byte, and both are paid per sleep cycle. Flash has a further constraint: its write endurance is finite, typically quoted in tens of thousands of cycles per sector, so a device that checkpoints on every sleep can exhaust a sector within the product’s life. Wear levelling across sectors extends it, and the bookkeeping for that is itself state that must be preserved.

The third is to keep nothing and rebuild. This works when the state is small and derivable: a device whose only state is the current time and a sensor offset can rebuild both from a real-time clock and a stored calibration constant. It fails when the state includes anything that cannot be recovered, such as a sequence number that must not repeat or a running average.

A hybrid is common: a small retained region holds the few bytes that cannot be rebuilt, and everything else is rebuilt from flash constants. The retained region is sized to the irreducible state, which keeps its current small, and the rebuild path is written to tolerate a cold start.

/* The irreducible state across a power-off sleep. Everything not in
   this struct is rebuilt by init_from_constants() on wake. */
struct persistent {
    uint32_t magic;
    uint32_t sequence;          /* must never repeat after a reset  */
    int16_t  sensor_offset;
    uint16_t crc;
};

static bool restore(struct persistent *p)
{
    if (p->magic != PERSIST_MAGIC)
        return false;
    if (crc16(p, offsetof(struct persistent, crc)) != p->crc)
        return false;           /* a torn write: treat as absent     */
    return true;
}

The checksum is not defensive coding. A write that is interrupted by a power failure leaves a record whose fields are individually plausible and collectively wrong, and the only reliable way to distinguish it from a good record is a check over the whole thing with the check value written last.

The wake path is the cost

The reinitialisation cost is the integral of current over the wake path, and the wake path includes phases that are easy to forget. The regulator ramp, the oscillator start, the clock tree configuration, the peripheral reconfiguration, the self-test of any safety-critical subsystem, and the reconstruction of the application state all run at the active current. On a part with a slow crystal, the oscillator start alone can dominate.

The measurement is the only way to know. Recording the current at each step of the wake, with timestamps, produces a profile from which the energy is the area under the curve. Comparing that area against the retention current times the sleep duration gives the decision directly, and it also shows which step to attack if reinitialisation turns out to be the wrong choice.

The largest step is often not the code but the analog settling. An ADC’s reference and input network, a radio’s frequency synthesizer, and a comparator’s bias all need time, and that time is not reduced by optimising the firmware. Where it dominates, retention is the only way to avoid paying it, because the analog blocks can be left biased in a retention state that costs a fraction of their active current.

Latency is a separate constraint

Energy is not the only cost. Retention shortens the wake to the reset path plus the restore of the retained region: the regulator ramp, the oscillator start, and boot code that skips memory initialisation. Reinitialisation adds the full boot, the self-tests, and the peripheral reconfiguration on top, which can run into milliseconds. A device with a 10 ms response requirement cannot afford a full boot on every wake, regardless of the energy arithmetic, and the decision is made by the deadline rather than by the joule count.

The asymmetry means the two options are not interchangeable even when their energies match. Retention buys latency with current; reinitialisation buys current with latency. A design with a tight deadline and a generous energy budget chooses retention, and a design with a loose deadline and a tight budget chooses reinitialisation.

Degenerate cases

The first is a sleep so short that neither option matters: if the device sleeps for a microsecond, the retention current and the wake cost are both irrelevant, and the decision is dominated by the transition’s fixed overhead. The second is a sleep so long that retention dominates everything: a device that sleeps for a month and wakes once is paying retention current for a month to avoid a millisecond of work, and the arithmetic is unambiguous.

The third is the case where the retained region cannot hold the state. A program with a large buffer (a frame buffer, an audio buffer, a table of samples) cannot retain it without a proportional current, and the alternative is to move it to external memory or to discard it. Discarding it changes the algorithm: a device that must average 1000 samples cannot keep them across a sleep, so it must accumulate a running sum and keep only that. The retention decision therefore reaches back into the data structures, and a design that ignores it ends up with a retained region that grows until the sleep current is no longer acceptable.

A fourth case is the partially retained part, where only some SRAM blocks can be retained and the rest lose power. The firmware must know which variables live in which block, which is a linker-script decision, and a variable that is accidentally placed in a non-retained block is silently corrupted across the sleep. The failure appears as a value that is occasionally wrong after a wake, and it is one of the harder classes of bug to find because the corruption is data-dependent.

Relating the choice to the sleep state

The retention decision is not independent of the sleep state, because the state determines what the hardware offers. A state that removes power from the core but keeps an always-on domain can retain a small region cheaply; a state that removes power from everything retains nothing, and the choice becomes whether to write to flash before entering it. The interaction is why the sleep-state selection described in what a sleep mode actually turns off and the retention decision are usually made together, with the wake latency from the transition-cost analysis as the third input.

The practical outcome is a small table: for each candidate state, the retention current, the wake latency, and the wake energy. The design picks the row that minimises total energy subject to the latency constraint, and the table is per part and per configuration. It is the kind of artefact that should be measured once and kept with the firmware, because it is the input to a decision that is otherwise made by intuition.

References

  1. ARMv7-M Architecture Reference Manual — ARM Limited
  2. ARM Cortex-M4 Processor Technical Reference Manual — ARM Limited