In short: Tickless mode lets an RTOS stop its periodic SysTick interrupt during idle, reprogram a wake-up timer for the exact moment the next task becomes ready, and drop the MCU into a deep low-power state in between — cutting idle current from milliamps to microamps without losing timekeeping.
On a battery-powered sensor node, the CPU is busy for perhaps 1% of its life. The other 99% it is waiting — for a timer, a sensor sample, a radio packet. A classic RTOS wastes that waiting: its scheduler tick fires every millisecond, waking the core 1,000 times a second just to discover nothing is ready to run. Tickless idle eliminates that waste, and it is one of the most common deep-dive questions in embedded and low-power firmware interviews.
Why the periodic tick is the enemy of sleep
A preemptive RTOS such as FreeRTOS or Zephyr keeps time with a hardware timer — on Arm Cortex-M, the 24-bit SysTick counter — configured to interrupt at a fixed rate, typically configTICK_RATE_HZ = 1000 (1 ms). Each interrupt increments the tick count, decrements delay timers, and checks whether a higher-priority task is now ready.
The problem: every one of those interrupts pulls the core out of WFI (Wait-For-Interrupt) sleep. An STM32L4 in Stop 2 mode draws roughly 2 µA; the same part running at 80 MHz draws 10 mA — a factor of 5,000. If you wake 1,000 times a second, each wake costing microseconds of active current plus the energy to restart clocks and flash, you can burn an order of magnitude more energy than the actual workload needs. On a CR2032 coin cell (≈220 mAh) the difference is measured in years versus weeks.
Key fact: A fixed 1 ms tick on a Cortex-M wakes the CPU 86.4 million times per day. If each wake-and-return costs just 3 µs of active time, that is ~260 seconds of needless CPU-on time daily — pure wasted charge.
How tickless actually works
When the scheduler has no ready task, it runs the idle task. In tickless mode (FreeRTOS: configUSE_TICKLESS_IDLE = 1) the idle task does four things before sleeping:
- Find the next deadline. The kernel knows the soonest timer/delay expiry — call it N ticks away. This is the expected idle time.
- Reprogram a timer for N ticks. SysTick is stopped. A timer that keeps running in deep sleep (an STM32 LPTIM clocked from the 32.768 kHz LSE, or a Nordic RTC) is loaded to fire in exactly N ticks' worth of time.
- Enter the deepest safe sleep state with WFI — Stop mode on STM32, SYSTEM ON idle on nRF52.
- On wake, correct the OS clock. Whether the wake was the scheduled timer (full N elapsed) or an earlier interrupt (a packet arrived early), the code reads the low-power timer and tells the kernel exactly how many ticks really passed, so no time is lost.
That last step is the subtle one. The system clock must stay monotonic and accurate even though the "heartbeat" went silent. FreeRTOS exposes vPortSuppressTicksAndSleep( xExpectedIdleTime ) as the weak hook you override to implement all of this against your silicon.
Picking the wake timer: the heart of the design
SysTick cannot be the wake source — it is usually clocked from the core/HCLK, which halts in deep sleep. You need a peripheral that runs in the low-power domain:
| MCU family | Low-power timer | Typical source | Deep state |
|---|---|---|---|
| STM32L4/L5 | LPTIM1 | LSE 32.768 kHz | Stop 2 (~2 µA) |
| Nordic nRF52 | RTC1 | 32.768 kHz LFCLK | SYSTEM ON idle (~1.9 µA) |
| TI MSP430 | Timer_A (ACLK) | 32 kHz crystal | LPM3 (~1 µA) |
The timer resolution sets your worst-case timing error. A 32.768 kHz clock ticks every ~30.5 µs, so a 1 ms OS tick is 32.768 counts — not an integer. Good ports accumulate the fractional remainder to avoid long-term drift, exactly as a leap-second correction does.
Key fact: At 32.768 kHz, one OS tick of 1 ms equals 32.768 timer counts. Rounding to 33 counts per tick adds ~0.7% error — about 10 minutes of drift per day — unless the fractional part is carried forward.
Worked example: a 10-second sensor cycle
Suppose a task does vTaskDelay(pdMS_TO_TICKS(10000)) between sensor reads. With a 1 ms tick the kernel would wake 10,000 times. In tickless mode the idle hook sees xExpectedIdleTime = 10000, caps it to the timer's maximum reload, loads LPTIM for that interval, and enters Stop. The core sleeps for the full 10 s drawing ~2 µA, wakes once, reads the real elapsed count, advances the tick count by 10,000, and runs the task. One wake instead of ten thousand. Vendor tools such as STM32CubeMonitor-Power or the Nordic Power Profiler Kit II let you confirm the current trace actually flattens to the µA floor between reads.
Pitfalls that trip people up
- Peripherals that stall sleep. A DMA transfer, an active UART, or a debugger attached (SWD keeps clocks alive) will prevent the deep state. Always verify the real current, not the datasheet number.
- Latency on wake. Restarting the HSI/PLL and waking flash costs microseconds. For hard-real-time deadlines, budget that exit latency — see our note on low-power modes on the MCU.
- Timer overflow. If the next deadline exceeds the low-power timer's range, clamp to the max reload and loop — don't under-sleep and silently lose time.
- Shared wake sources. An unrelated interrupt (button, radio) wakes the core early; your correction logic must read elapsed time and recompute, covered alongside the FreeRTOS idle hook and power management.
Want to build a coin-cell sensor node that lasts years, not weeks? Our CourseTron Embedded Low-Power Firmware course walks you through porting tickless idle to real STM32 and nRF52 hardware with live current measurement. For custom silicon and board bring-up, our partners at Avecas design services take low-power SoCs from spec to tape-out.
Frequently asked questions
Does tickless mode break vTaskGetTickCount()?
No. A correct port updates the kernel's tick count from the low-power timer on every wake, so xTaskGetTickCount() stays accurate to within one timer resolution. Timekeeping is preserved; only the periodic interrupt is suppressed.
What is the difference between WFI and tickless idle?
WFI is a single CPU instruction that halts the core until any interrupt. Tickless idle is the kernel-level policy that stops the scheduler tick and reprograms a wake timer so the WFI can last the full idle window instead of being interrupted every millisecond.
Can I use tickless mode with a hard real-time deadline?
Yes, if you account for wake-up latency. Exiting Stop mode and restarting clocks takes microseconds to tens of microseconds; add that to your worst-case response time. If a deadline is tighter than the exit latency, use a shallower sleep state for that task.
Why not just lower the tick rate to 100 Hz instead?
A slower tick saves some energy but worsens timing granularity and still wakes the core on a fixed cadence. Tickless gives you fine 1 ms resolution and microamp idle current — you stop paying for ticks you don't use, rather than trading resolution for power.