Low-Power Design: RTC Wake, Interrupt-Driven, Tickless

Learn RTC wake, interrupt-driven design, and tickless kernels to build battery-powered IoT devices that run for months on a coin cell.

12 min readAhmet Zahid ArıcanUpdated 30 Oct 2026
Low-Power Design: RTC Wake, Interrupt-Driven, Tickless
Contents & prerequisites

Why Low-Power Architecture Matters for Constrained IoT Devices

Battery life as a system constraint

A coin-cell-powered sensor node with a CR2032 has roughly 220–240 mAh of usable capacity at moderate discharge rates. If the firmware draws even 1 mA continuously, that battery is dead in under ten days. To hit a multi-year deployment target, average current draw typically has to stay in the 5–20 µA range, which means the processor and radio must spend more than 99.9% of their time asleep. That number isn't a nice-to-have efficiency goal — it's a hard system constraint that shapes every architectural decision downstream, from which timer peripheral wakes the chip to how interrupts are prioritized.

Power budgets in RFC 7228 Class 0 and 1 devices

The IETF's classification in Constrained Devices: RFC 7228 Class 0, 1, 2 Definitions ties directly into power budgeting. Class 0 devices (typically under 10 KiB RAM, under 100 KiB flash) usually can't run a full IP stack and rely on proxies or gateways for protocol translation, which also reduces on-device radio time. Class 1 devices have enough headroom to speak CoAP or similar directly but still can't afford a traditional RTOS with a high-frequency tick. In both classes, the energy budget is dominated not by instruction execution but by how long and how often the radio and processor are not asleep — which is why wake architecture, not clock speed, is the primary lever available to the firmware engineer.

Trade-offs between responsiveness and energy consumption

Every microsecond the processor stays awake costs charge, and every microsecond it stays asleep risks missing something. A door sensor that must report within 200 ms of a contact change has a different sleep budget than a soil-moisture logger reporting hourly. The architecture has to make this trade explicit rather than accidental — a generic "sleep when idle" loop makes no such decision, and generic power tips (lower the clock, disable unused peripherals) only get a design to the 1 mA range, not the 10 µA range. Getting there requires the RTC-wake, interrupt-driven, tickless trio working together.

Real-Time Clock (RTC) as a Wake Source

RTC module architecture and ultra-low quiescent current

An RTC peripheral typically runs from a separate 32.768 kHz crystal oscillator and its own low-voltage domain, independent of the main system clock tree. Because it only needs to increment a counter, its quiescent current is often two to three orders of magnitude lower than the core running at full speed — check the specific MCU's datasheet for the RTC domain current, but values in the 300 nA–1 µA range are common for modern low-power microcontrollers. This domain usually survives every sleep mode except full power-off, which is precisely what makes it the anchor for long-duration timing: the rest of the chip can lose state, but the RTC keeps counting.

Configuring periodic and alarm-based wake events

Two wake patterns cover most use cases. A periodic wake (e.g., every 60 s) is configured via a counter-compare or prescaler-driven tick that fires an interrupt and resets automatically — good for regular sampling. An alarm-based wake sets a specific target time (date/hour/minute/second match) and is better suited to calendar-aligned events, such as "wake at the top of every hour" regardless of drift. Most RTC peripherals support both modes from the same counter, so the choice is a configuration decision, not a hardware one.

RTC vs. systemic timers: when to use each

A general-purpose or systick timer derived from the main oscillator is higher resolution but dies the moment the core clock is gated in deep sleep. The RTC is lower resolution (typically 1 Hz to a few hundred Hz effective) but survives the deepest sleep states. The rule of thumb: use the RTC for anything that must wake the device from its lowest-power state, and use system timers only for short, sub-second timing needed while the core is already awake.

Integration with main processor sleep states

The RTC's wake interrupt must be routed to whichever interrupt controller remains powered in the target sleep mode. This is a common integration bug: a design selects a very deep sleep mode, then discovers the RTC interrupt line isn't wired to the always-on interrupt controller in that mode, so the device never wakes. Always verify the wake-source-to-sleep-mode matrix in the reference manual before committing to a sleep state.

Interrupt-Driven Execution Model

Event-based task scheduling vs. polling loops

A polling loop that checks if (sensor_ready()) every iteration keeps the core awake and the clock running regardless of whether there's work to do — it burns milliamps to detect microamp-scale events. An interrupt-driven model inverts this: the core sleeps until a peripheral (RTC, GPIO, UART RX, ADC watermark) asserts an interrupt, runs a short handler, and returns to sleep. This is the single biggest lever in the entire architecture, because idle current in sleep can be 100–1000x lower than idle current while spinning in a loop at full clock speed.

Prioritizing interrupts for low-power firmware

Not all wake sources are equal. A battery-critical alarm should preempt a routine sensor-read interrupt; a radio RX-ready event should preempt a periodic housekeeping wake. Assign interrupt priorities so that time-critical, short handlers can interrupt longer ones, and keep every ISR itself short — defer real work to the main loop (see deferred interrupt handling below) so the core can decide, with full context, whether it's worth staying awake at all.

Minimizing interrupt latency while preserving sleep duration

Deep sleep modes often have non-trivial wake latency — the oscillator needs to stabilize, voltage regulators need to settle. A mode with 100 µs wake latency is fine for a sensor poll but may violate a 50 µs response requirement for a safety interlock. The firmware must match sleep depth to the tightest latency requirement among all enabled wake sources, not just the average one.

Debouncing and spurious wake prevention

GPIO-triggered wakes are notorious for firing multiple times on a single mechanical event. Hardware debounce (RC filter, Schmitt trigger) is preferable because it prevents the wake entirely; software debounce still requires the core to wake, check a timestamp against a minimum interval, and go back to sleep — correct, but costs energy per spurious edge. For high-bounce inputs (mechanical switches), budget for this in the energy model explicitly.

Tickless Kernel Design Patterns

Eliminating the periodic system tick

A traditional RTOS wakes the core every tick period (often 1–10 ms) to update timers and check the scheduler, even when no task is runnable. At a 1 ms tick, that's 1000 unnecessary wake cycles per second — each with its own wake latency and dynamic power cost. A tickless kernel removes this fixed heartbeat entirely, relying instead on hardware timers configured for the next actual event.

Dynamic scheduling and timer wheel implementations

Instead of a fixed tick, the kernel maintains a sorted list (often a timer wheel or min-heap) of pending timeouts. Before entering sleep, the scheduler computes the delta to the nearest deadline — the next software timer, the next RTC alarm, or an application-level deferred task — and programs that single value into hardware.

// Simplified tickless sleep decision
uint32_t next_deadline = timer_queue_peek_min();   // ticks until next event
if (next_deadline == TIMER_QUEUE_EMPTY) {
    rtc_set_alarm(DEFAULT_MAX_SLEEP);              // fallback wake, e.g. 1 hour
} else {
    rtc_set_alarm(next_deadline);
}
enter_sleep_mode(SLEEP_DEEPEST_SAFE);

One-shot interrupt configuration for next event

Each time the core wakes, it processes whatever fired, re-evaluates the timer queue, and reprograms a fresh one-shot interrupt for the new nearest deadline. This is the mechanical difference between interrupt-driven and tickless execution: interrupt-driven just means "sleep until something happens"; tickless additionally means the kernel itself never imposes its own periodic wake, so the only wake sources left are genuine application or communication events.

Implications for real-time constraints

Tickless designs trade a small amount of scheduling jitter (the time to recompute and reprogram the next deadline) for large power savings. For soft real-time IoT workloads — sensor sampling, telemetry upload — this is almost always a good trade. For hard real-time control loops with sub-millisecond deadlines, a hybrid approach (tickless in idle periods, ticked during active bursts) is more appropriate.

Sleep States and Power Mode Selection

Processor sleep modes (idle, light sleep, deep sleep, hibernation)

Most modern MCUs expose a ladder of modes: idle (core clock gated, peripherals and RAM retained, wake in microseconds), light/stop sleep (most clocks gated, RAM retained, wake in tens of microseconds), deep sleep/standby (core powered down, limited RAM retention, wake in hundreds of microseconds to milliseconds), and hibernation/shutdown (only the RTC domain and a handful of registers retained, wake requires a near-full reboot). The deeper the mode, the lower the current — often by one to two orders of magnitude between each step — but the higher the wake latency and the less context survives.

Peripheral shutdown and wake-capable I/O configuration

Before entering a deep sleep mode, every peripheral not needed for wake must be explicitly disabled — ADCs, unused clock domains, pull-up/pull-down networks left floating. Leaving a peripheral clocked "because it was easier" is one of the most common sources of a design hitting 200 µA instead of its 10 µA target. Conversely, whichever GPIOs are meant to wake the device must be configured in the sleep-mode-specific wake-enable register, since many MCUs disable GPIO interrupts by default in their deepest modes.

Context preservation and state machine design

In modes where RAM isn't retained, application state must be explicitly saved to retained registers or non-volatile memory before sleep and restored on wake. This pushes the firmware toward an explicit state machine design — rather than relying on the call stack and local variables to persist across sleep, state transitions are modeled as data (current state enum, relevant counters) that's cheap to checkpoint.

Entry and exit latency trade-offs

Entering and exiting sleep isn't free — oscillator startup, regulator ramp, cache or RAM retraining all cost time and energy. If a device wakes every 100 ms but spends 2 ms on entry/exit overhead, that overhead alone is 2% of the duty cycle — a significant tax. For very short sleep intervals, a shallower mode with lower transition cost sometimes wins on average power even though its sleep current is higher, because the deep mode's transition overhead dominates.

Firmware Implementation Patterns

Main event loop with RTC-driven state transitions

A robust pattern is a superloop that sleeps by default and is driven entirely by interrupt flags:

while (1) {
    disable_interrupts();
    if (!work_pending()) {
        enter_sleep_mode(select_sleep_depth());
    }
    enable_interrupts();

    if (flag_rtc_wake)   { handle_scheduled_task();  flag_rtc_wake = 0; }
    if (flag_gpio_event) { handle_external_event();  flag_gpio_event = 0; }
    if (flag_radio_rx)   { handle_radio_data();      flag_radio_rx = 0; }
}

The disable_interrupts()/check/sleep sequence closes a classic race: without it, an interrupt can arrive between the work_pending() check and the sleep instruction, setting a flag that's then missed for an entire sleep period.

Deferrable work and deferred interrupt handling

ISRs should do the minimum — clear the interrupt source, set a flag or push to a queue, return. Heavier processing (parsing a packet, computing an average) happens in the main loop afterward, with interrupts re-enabled, so a second time-critical interrupt isn't blocked. This also lets the main loop batch deferred work and decide, holistically, how deep to sleep next.

Measuring power consumption during development

A power profiler (many vendor dev boards have one built in) that samples current at microsecond resolution is not optional for this work — print statements and oscilloscope probes on GPIO toggles give timing but not the current levels, and current levels are the metric that matters. Capture a current-vs-time trace across a full wake-sleep cycle and verify that the sleep floor matches the datasheet figure for the selected mode; a floor 5–10x higher than expected almost always indicates a peripheral or pull-up left enabled.

Common pitfalls: preventing unintended wake paths

Floating input pins, enabled-but-unused analog comparators, a debug/JTAG port left powered, or a watchdog configured with too short a timeout relative to the sleep interval are the usual suspects behind a device that never reaches its target sleep current, or that wakes far more often than its scheduling logic intends. A checklist pass over every pin and clock domain before each sleep-mode entry, ideally automated in a self-test routine, catches most of these early.

System Integration for IoT Applications

Low-power wireless wake (BLE beacon polling, LoRaWAN class B)

Radios have their own wake economics layered on top of the processor's. BLE devices extend battery life by widening advertising/scan intervals and using directed or periodic beacon polling rather than continuous scanning. LoRaWAN Class B devices synchronize to network beacons to open short receive windows at predictable times, giving downlink capability without the continuous-listen cost of Class C. These choices interact directly with the trade-offs covered in IoT Connectivity Trade-Offs: Range, Bandwidth, Power, Cost, where duty cycle is one of several dimensions being traded against range and data rate.

Maintaining network connectivity with minimal duty cycle

Keeping a device "present" on a network without constant radio-on time usually means aligning the RTC wake schedule with the protocol's own timing grid — LoRaWAN beacon periods, BLE connection intervals, or MQTT keep-alive windows — rather than running an independent, uncoordinated wake timer. Drift between the device's RTC and the network's timing reference is the main failure mode here; periodic resynchronization (even just adjusting the RTC alarm offset after each successful network contact) keeps the wake windows aligned without requiring continuous listening.

Synchronizing data collection with wake intervals

Sensor sampling and radio wake don't have to share a period. A common pattern is sampling on a short RTC interval (e.g., every 5 minutes) into a small retained buffer, then transmitting on a longer interval (e.g., every hour) that batches several samples into one radio session — amortizing the radio's relatively high per-wake energy cost across multiple measurements. The right ratio depends on the sensor's required temporal resolution versus the radio's energy cost, which is where the device classification boundaries in IoT Device Classification: Constrained, Gateway, Cloud become relevant — a constrained end node and a gateway will land on very different buffering strategies for the same sensor data.

Sub-metering and energy reporting in deployed systems

For deployed energy-monitoring applications, the RTC-wake architecture itself becomes part of the measured system: sub-metering devices must report consumption readings on a schedule precise enough for billing or demand-response integration while staying within the same microamp-scale sleep budget as any other constrained node. The architectural patterns described here — alarm-based RTC wake, tickless scheduling, and batched radio transmission — are exactly what make that combination feasible, and the integration specifics for feeding readings into a building energy management system are covered in Energy Management IoT: Sub-Metering, BEMS Integration.

Learning

Sign in to track your progress.

Evidence

Public projects engineers linked to Low-Power Design: RTC Wake, Interrupt-Driven, Tickless.

Add evidence

No engineer has linked a project to this topic yet. Built something that proves it? Add the project and tag it with iot-connectivity-low-power-design-rtc-wake-interrupt-driven-tickles — it then shows here and on your public profile.