Electronics Design AU
RTOS

How Does FreeRTOS Tickless Idle Work for Low-Power Scheduling?

Last updated 8 July 2026 · 6 min read

Direct Answer

FreeRTOS tickless idle (enabled with configUSE_TICKLESS_IDLE) suppresses the periodic scheduler tick interrupt whenever the idle task determines no task will become ready before a known future time, and reprograms a single wake-up timer to fire at that time instead — allowing the MCU to enter a genuinely low-power sleep mode for the full idle interval rather than being woken every tick period (commonly 1 ms) just to find nothing to do. On waking, FreeRTOS corrects its internal tick count for however long the CPU actually slept, so task delays and timeouts remain accurate despite the tick having been stopped.

Detailed Explanation

In FreeRTOS's default scheduling mode, a hardware timer (SysTick on ARM Cortex-M parts) generates a periodic tick interrupt — commonly every 1 ms — which the scheduler uses to track time, expire delays and timeouts, and re-evaluate which task should run next. This tick fires continuously, even when every task is blocked and the idle task is the only thing "running." On a battery-powered product, that periodic interrupt is a problem: many MCU low-power modes save the most current only when left undisturbed for an extended period, and a 1 ms-period wake-up defeats the deepest sleep states before they can deliver any real power saving.

Tickless idle, enabled with configUSE_TICKLESS_IDLE set to 1 in FreeRTOSConfig.h, addresses this directly. Whenever the idle task runs and no task is ready, FreeRTOS calculates the number of tick periods until the next scheduled event — the soonest task delay or timeout expiry — and, if that interval is long enough to be worthwhile, calls the port-specific portSUPPRESS_TICKS_AND_SLEEP() function instead of leaving the periodic tick running. This function stops the tick timer, reprograms a wake-up timer (often the same timer peripheral, running in a different mode) to fire once, after the calculated idle interval, and puts the CPU into the platform's chosen low-power sleep mode.

Correcting the Tick Count on Wake

When the MCU wakes — either from the programmed wake-up timer or from an unrelated interrupt (a GPIO event, a peripheral completing a transfer) — portSUPPRESS_TICKS_AND_SLEEP() measures how much real time actually elapsed while sleeping and advances the RTOS tick count by that amount in one step, rather than one tick at a time. This keeps xTaskGetTickCount(), task delays, and timeouts accurate despite the tick interrupt having been silent for the entire sleep period — from the application's perspective, time has still passed correctly; only the mechanism used to track it changed.

The Minimum Idle Time Threshold

Entering and exiting a low-power sleep mode has overhead — reprogramming a timer, and on many MCUs, restarting a clock source or PLL on wake. configEXPECTED_IDLE_TIME_BEFORE_SLEEP sets a minimum number of idle ticks that must be available before FreeRTOS bothers entering tickless sleep at all; for very short idle windows, the overhead of sleeping and waking again would exceed any power saved, so the idle task simply spins normally instead.

Waking Early Safely

Because entering sleep mode isn't instantaneous, there's a brief window where an interrupt could make a task ready right as the MCU is about to sleep. Ports implement eTaskConfirmSleepModeStatus() (or equivalent logic) to re-check, with interrupts briefly disabled, that it is still safe to sleep immediately before actually doing so — aborting the sleep if a task became ready in that window, so a race doesn't delay a newly-ready task until the next wake timer expiry.

Practical Examples

A battery-powered environmental sensor node that wakes every few seconds to sample a sensor, publish a reading, and go back to sleep spends the vast majority of its life idle. With tickless idle enabled and the MCU's Stop or equivalent low-power mode entered during that idle time, the device's average current draw is dominated by sleep current rather than the periodic tick interrupt — often the difference between a device that lasts months on a coin cell and one that drains it in days, since a continuously firing 1 ms tick alone can prevent the MCU from ever reaching its lowest-current sleep state.

A product with mixed timing needs — a task that must respond to a communication interrupt within a few milliseconds, alongside a background task that only needs to run once a minute — benefits particularly from tickless idle, since FreeRTOS automatically calculates the correct sleep duration for whichever event is soonest, without firmware needing to manually track and coordinate sleep timing itself.

Design Considerations

  • Tickless idle changes power behaviour but not the RTOS's fundamental scheduling correctness — task priorities, blocking calls, and timeouts all continue to work exactly as documented; enabling it is a configuration change, not an architectural rewrite, for firmware whose task/timeout structure is already correct.
  • Combine with the MCU's own low-power modes deliberately. Tickless idle decides when to attempt sleep; the port's portSUPPRESS_TICKS_AND_SLEEP() implementation decides what sleep mode to enter. See STM32 Stop/Standby/Sleep modes or ESP32 Deep Sleep for the platform-specific low-power modes tickless idle can be paired with — the RTOS layer and the MCU layer need to agree on which peripherals stay powered and which wake sources are configured.
  • Peripherals with their own timing requirements need care. A peripheral that expects to be serviced at a fixed interval (some UART or SPI DMA patterns, certain timer-driven sampling) may not tolerate the RTOS entering deep sleep between service intervals — audit which peripherals are active before relying on tickless idle to reach a deep sleep state.
  • Measure actual current, don't assume. As with any low-power configuration, the real sleep current depends on which clocks, peripherals, and power domains the specific port's sleep implementation leaves active — verify with a current analyser on the target hardware rather than assuming the datasheet's lowest-power figure applies automatically once tickless idle is enabled.

For FreeRTOS-based products where battery life is a hard requirement, Zeus Design's firmware team designs RTOS task architecture and low-power scheduling together, rather than retrofitting power management after the task structure is already fixed.

Common Mistakes

  • Enabling tickless idle without also configuring the MCU's actual low-power mode correctly — tickless idle only creates the opportunity to sleep deeply; if the port's sleep implementation (or the application's own configuration) doesn't put the MCU into a genuinely low-current state, the current savings won't materialise even though the tick has stopped.
  • Assuming task delays remain tick-accurate to the millisecond during tickless operation — the tick count correction is accurate in aggregate, but individual wake events carry the sleep/wake latency described above; hard real-time deadlines should be validated on hardware, not assumed from the nominal tick period alone.
  • Forgetting that a peripheral requiring continuous servicing will stall while the MCU sleeps — a UART receiving data with no wake-capable interrupt configured, for example, will lose bytes if the RTOS enters a low-power mode that disables that peripheral's clock mid-transfer.
  • Leaving configEXPECTED_IDLE_TIME_BEFORE_SLEEP at an unsuitable value for the platform's actual sleep/wake overhead — too low a threshold makes the system attempt tickless sleep for idle periods too short to benefit, spending more time entering and exiting sleep than it saves.

Frequently Asked Questions

Does tickless idle work on every FreeRTOS port automatically?
No. Tickless idle requires the specific port to implement portSUPPRESS_TICKS_AND_SLEEP(), which reprograms the platform's sleep timer and enters the appropriate low-power mode for that MCU. Not every official FreeRTOS port provides this — the ARM Cortex-M port using the SysTick timer is common and widely used, and vendor SDKs (ESP-IDF, for example) provide their own tickless implementations. Check the specific port's documentation before assuming tickless idle is available.
How is tickless idle different from an MCU's own Stop or Deep Sleep mode?
They operate at different layers and are normally used together. An MCU low-power mode (see STM32 Stop/Standby or ESP32 Deep Sleep) is a hardware state the chip enters; tickless idle is the RTOS-level mechanism that decides when it's safe to enter that state and for how long, given the scheduler's knowledge of pending task timeouts. Without tickless idle, the periodic 1 ms scheduler tick would wake the MCU out of a low-power mode every tick period regardless of whether any task actually needed to run, largely defeating the purpose of entering that mode in the first place.
Can tickless idle cause a task to run late?
Yes, by a bounded amount. Waking from a low-power mode takes non-zero time (clock/PLL restart, peripheral re-initialisation), and the wake-up timer itself has finite resolution — both add a small amount of jitter to when a task actually resumes relative to its nominal wake time. For most application-level timing (sensor polling, periodic transmission) this jitter is negligible; for hard real-time deadlines in the microsecond range, tickless idle's wake latency should be measured on the target hardware and budgeted for explicitly.

References

Related Questions

Related Forum Discussions