Low-Power MCU Design Guide
Sleep Modes, Clock Gating & Power Budgeting
1. Introduction — Power Is a Design Constraint
For battery-powered IoT nodes, wearables, and industrial sensors, the microcontroller is often the single largest controllable power consumer. The difference between a poorly configured MCU (hundreds of microamps average) and a well-optimized one (single-digit microamps) is not a silicon difference — it is a design difference: which sleep mode, what clock tree, how the peripherals are gated, and how leakage paths through GPIO are closed. This guide gives a complete, practical methodology: understand where the power goes, pick the right sleep mode, gate clocks and peripherals, compute a battery lifetime with a worked example, and apply RTOS tickless idle so the power plan actually holds in software.
2. Where MCU Power Goes
2.1 The Three Components
Ptotal = Pdynamic + Pstatic + PIO
Pdynamic = α · Cload · VDD² · f (switching — scales with frequency and activity factor α)
Pstatic = Ileak · VDD (sub-threshold + gate leakage — dominates in deep sleep)
PIO = Σ(switching pin power + static sink/source + pull-up/pull-down resistor power)
The ratio changes with operating point: at 48 MHz active, dynamic dominates; in standby, static leakage dominates. This is why a single “current at 3.3 V” datasheet number is useless — you must build a per-state current model (active, sleep, stop, standby, shutdown) and a time-weighted average.
2.2 Power State Model
| State | CPU | Clocks | RAM/Regs | Typical I (3.3 V) | Wake source |
|---|---|---|---|---|---|
| Run | On | Full | Retained | 1–30 mA (f-dependent) | — |
| Sleep | Off | Core stopped, periph on | Retained | 100–1000 µA | IRQ, event |
| Stop | Off | HSI off, LSI on | Retained | 1–20 µA | EXTI, RTC, LPTIM |
| Standby | Off | Almost all off | Retained (w/ backup) | 0.3–3 µA | Wakeup pin, RTC, NRST |
| Shutdown | Off | All off | Lost (context lost) | 20–100 nA | Wakeup pin only |
3. Sleep Modes — Choosing the Right One
3.1 Comparison Criteria
Pick the deepest sleep mode that still: (a) retains what you need (RAM? RTC? GPIO state?), (b) can be woken by the events you have (timer, external interrupt, comparator), and (c) has acceptable wake latency — deep modes take tens to hundreds of microseconds to restart the oscillator, which matters if you must react to a fast event.
| Criterion | Sleep | Stop | Standby |
|---|---|---|---|
| Wake latency | ~1–5 µs | ~5–30 µs | ~50–300 µs |
| RAM retention | Yes | Yes | Partial / backup only |
| RTC keeps running | Yes | Yes (on LSI) | Yes (on LSI) |
| Peripheral wake | Any IRQ | EXTI, RTC, LPTIM, comparator | Wakeup pin, RTC |
| Best for | Frequent, fast wakeups | Periodic sensor reads | Rare, long sleeps |
3.2 Rule of Thumb
Iavg = (Irun·trun + Isleep·tsleep) / (trun + tsleep) + Ileak
Optimization loop: if tsleep dominates and Isleep is the lever, the cheapest win is deeper sleep, not faster clock. Conversely if trun dominates, reduce active current by lowering VDD (if the rail allows) or frequency (P ∝ f, V²).
4. Clock Gating and Frequency Scaling
4.1 Dynamic Power vs Frequency
Idyn = Ceff·VDD·f
Worked: Ceff ≈ 6.6 pF·MHz⁻¹·(typ MCU). At 3.3 V, 48 MHz: Idyn ≈ 6.6e-12·3.3·48e6 ≈ 1.05 mA. Drop to 8 MHz: ≈ 0.17 mA — a 6× active-current cut for the same code executed over 6× longer wall time. Net energy per task is roughly constant (energy = P·t), so only reduce f when the deadline allows; the real saving is avoiding running between tasks.
4.2 Clock Gating Best Practices
- Gate unused peripheral clocks — an enabled-but-unused SPI/UART clock keeps switching internal dividers and can cost 10–100 µA. Disable the clock, not just the peripheral.
- Use the low-speed oscillator (32 kHz) for the RTC/watchdog in sleep — running the HSI just to keep time wastes microamps.
- Prescalers over PLL: when a slow clock suffices (e.g., a sensor polling loop), select the HSI/prescaler path and power down the PLL — PLLs burn tens of microamps continuously.
- Voltage scaling (core LDO/regulator in low-power mode): many MCUs expose a “low-power run” range; entering it halves core current for the same frequency at the cost of a max clock cap.
5. Peripheral Power Management
| Peripheral | Sleep cost | Leakage trap | Management |
|---|---|---|---|
| ADC | ~0 (clock-gated) | Analog block left enabled | Disable ADCEN after conversion; power down voltage ref |
| UART/SPI/I2C | Clock only | TX/RX pull resistors on pins | Gate clocks; assert RX line high before sleep |
| Timer | Low (LP timer ideal) | Full timer on HSI in sleep | Use LPTIM on LSI for wake scheduling |
| Comparator / op-amp | µA-level analog | Left powered in stop | Enable only when needed for wake-on-threshold |
| DMA | ~0 | — | No special handling |
6. GPIO Leakage — The Hidden Currents
GPIO pins left floating, driven into an undefined state, or driving LEDs that stay on are classic multi-hundred-microamp leaks. Key rules:
- Never leave a pin floating — floating inputs oscillate and draw switching current through the input buffer; tie unused pins to GND via the internal pull-down (or pull-up per logic) in low-power state.
- Drive outputs to a defined rail — a pin left as high-impedance input with an internal pull-up can sink current through an external load; set unused pins to analog/input-pulldown and disable them.
- LED drive via active-low with series R — a 2 V LED at 1 mA costs 2 mW; if it must remain on during sleep, budget it explicitly; better: PWM or switch it off in sleep and light only on demand.
- Pull-up/pull-down values: a 10 kΩ pull-up at 3.3 V sinks 330 µA when the line is low — for idle-high lines prefer 100 kΩ–1 MΩ or disable the resistor.
- Wakeup pin polarization: choose a wake source whose resting level aligns with the disabled state to avoid resistor current during the long sleep window.
7. Wake-Up Source Design
| Wake source | Sleep mode | Latency | Typical use |
|---|---|---|---|
| RTC alarm | Stop/Standby | µs–ms | Periodic sensor sample, time sync |
| EXTI (pin) | Stop/Standby | µs | Button, door sensor, IRQ |
| LPTIM | Stop | µs | Low-power periodic timer |
| Comparator | Stop | µs | Threshold crossing (light, voltage) |
| Wakeup pin (WKUP) | Standby/Shutdown | µs–ms | Deepest sleep wake |
8. Worked Example — Battery Lifetime Budget
State currents (measured):
Irun = 6 mA (48 MHz active, sensor on), trun = 10 ms
Itx = 15 mA, ttx = 5 ms
Isleep = 1.2 µA (standby with RTC on LSI, GPIO configured off)
Time-weighted average per 60 s cycle:
Charge per cycle = Irun·trun + Itx·ttx + Isleep·(60−0.015)
= 6 mA·10 ms + 15 mA·5 ms + 1.2 µA·59.985 s
= 0.06 mAh + 0.0208 mAh + 0.01999 µAh ≈ 0.0209 mAh… recompute in consistent units:
6e-3·10e-3 = 60 µAs; 15e-3·5e-3 = 75 µAs; 1.2e-6·60 = 72 µAs → total ≈ 207 µAs/cycle.
Cycles per day = 1440; charge/day = 207 µAs·1440 = 0.298 C·(convert) = 0.298 A·s = 0.0828 mAh/day.
Lifetime ≈ 225 mAh / 0.0828 mAh/day ≈ 2717 days ≈ 7.4 years (battery self-discharge reduces to ~5–6 years practical).
Levers: switching sleep 1.2→0.3 µA barely moves the number because the sleep window’s contribution is tiny relative to the 10 ms burst; the big lever is reducing trun/Irun (faster wake, lower clock, or fewer BLE retries). Always budget with the burst terms, not the sleep term.
9. RTOS Tickless Idle
A classic RTOS keeps a periodic tick (e.g., 1 ms SysTick) that wakes the CPU even with nothing to do — destroying deep-sleep. Tickless idle (dynamic tick) stops the periodic tick and arms a one-shot timer for the next scheduled deadline, letting the scheduler put the CPU into Stop/Standby between deadlines.
- Implementation: before entering idle, compute the next timeout across all timers (and the OS tickless hook); enter the deepest sleep that still allows that one-shot to fire.
- FreeRTOS: enable
configUSE_TICKLESS_IDLEand providevPortSuppressTicksAndSleep; keep tick correction math (ticks skipped must be accounted when waking). - Watchdog: a hardware IWDG on the low-speed clock still runs in sleep — good; a software tick-based watchdog must be suspended or its deadline extended during long sleeps.
- Wake latency bookkeeping: the tickless code must add the oscillator start-up time so the scheduler deadline is not violated.
// Pseudocode: tickless idle decision in a FreeRTOS-style scheduler
void portSUPPRESS_TICKS_AND_SLEEP(TickType_t xExpectedIdleTime) {
uint32_t sleep_us = xExpectedIdleTime * TICK_US; // next deadline
// gate peripheral clocks off, configure EXTI/RTC wake
__disable_irq();
if (sleep_us > DEEP_SLEEP_THRESHOLD_US) {
enter_stop_with_rtc_wake(sleep_us); // deepest legal mode
} else {
enter_sleep(); // light sleep, fast wake
}
__enable_irq();
// add oscillator startup latency back to the tick count
vTaskStepTick(ticks_elapsed + WAKE_LATENCY_TICKS);
}
10. Common Mistakes
- Leaving unused peripheral clocks on — the single most common 10–100 µA leak; gate every unused peripheral clock.
- Floating GPIO in sleep — oscillation draws µA–tens of µA through input buffers; tie pins to a defined level.
- Forgetting the LED/load current — a visible LED costs more than the entire sleep budget.
- Using Stop when a single periodic wake would allow Standby — the deeper mode costs nothing in latency for a 60 s period and saves 10–50× current.
- RTOS periodic tick defeating sleep — without tickless idle, a 1 ms tick wakes the CPU 60,000×/min even when idle.
- Ignoring the brown-out detector (BOD) current — some BOD/LVD blocks add µA; use the lowest usable threshold or disable in standby if the rail is clean.
- Not verifying with a power analyzer — datasheet numbers are per-configuration; measure actual Iavg with a µA-range shunt (e.g., a Nordic Power Profiler or a 10 kΩ sense with scope averaging).
11. Frequently Asked Questions
Q1. Which sleep mode should I use for a sensor that wakes every 5 minutes?
If 5-minute latency is acceptable, use Standby (with RTC alarm) — it saves the most. Keep the RTC on the low-speed oscillator and configure a wakeup pin for a “service now” path. If you need <5 ms response, move to Stop.
Q2. Does lowering the clock frequency always save power?
No — energy per task is roughly constant (P ∝ f, but t ∝ 1/f). Frequency scaling helps when you finish early and sleep longer; it does not help a task that runs the full duty window. Lowering VDD is a true energy win (P ∝ V²) when the MCU supports it.
Q3. Why does my board measure 200 µA in standby instead of 1 µA?
Almost always a peripheral clock, a floating GPIO, an enabled pull-up, a BOD block, or an unconfigured debug interface (SWD pins left active). Systematically gate clocks, configure every unused pin, and re-measure after each change to isolate the leaker.
Q4. Is tickless idle worth it on a bare-metal design?
Bare-metal with a single periodic wake often doesn’t need it — just sleep until the next scheduled event. Tickless idle pays off with an RTOS where multiple timers and tasks make the “next deadline” dynamic.
Q5. How do I keep the watchdog alive in deep sleep?
Use the independent watchdog (IWDG) clocked by the low-speed RC/LSI, which keeps counting in Standby; configure its timeout to exceed the longest sleep, and refresh before entering sleep or via a hardware refresh trigger.
Q6. What is a realistic “good” standby current target?
For a mainstream Cortex-M MCU at 3.3 V: 1–5 µA standby with RTC is excellent; 0.3–1 µA with just a wakeup pin is typical of the best-in-class parts; below 0.1 µA requires shutdown modes and external circuitry. Target per your battery math, not per datasheet headlines.