Hello! Welcome to the fifth lesson in our module on Advanced System Optimization.
In our last lesson, we explored the different processor low-power modes like Sleep, Stop, and Standby. You learned that entering these modes is the key to reducing power consumption, but also that the system needs a wake-up source, like an interrupt, to resume execution.
This brings us to a fundamental challenge when using a Real-Time Operating System (RTOS): the periodic system tick interrupt, which is the heartbeat of the RTOS scheduler, constantly wakes the processor, preventing it from staying in deep sleep modes for any meaningful length of time.
Today's lesson addresses this exact problem and directly implements the learning outcome: Implement a tickless idle hook in an RTOS to place the processor in a low-power state. We will focus on FreeRTOS, a common RTOS in the automotive and embedded world, to understand this advanced power-saving technique.
1. The Problem: The Incessant Tick
In a typical RTOS configuration, a hardware timer (often the ARM Cortex-M's SysTick timer) is set up to generate an interrupt at a fixed rate, for example, every 1 millisecond (configTICK_RATE_HZ = 1000). This "tick" allows the RTOS to manage time-based events, such as task delays (vTaskDelay()) and timeouts on semaphores or queues.
When no application tasks are ready to run, the scheduler executes the Idle Task. The idle task is a natural place to put the processor into a low-power mode using a WFI (Wait For Interrupt) instruction.
Here's the conflict: even if all your tasks are sleeping for several seconds, the 1ms tick interrupt will faithfully fire, waking the CPU from its low-power state every single millisecond. This completely undermines the goal of saving power during long idle periods.
Low Power with FreeRTOS: Tickless Idle Mode
The article 'Low Power with FreeRTOS: Tickless Idle Mode' from the MCU on Eclipse blog provides an excellent visual explanation of this problem.
Read the sections 'FreeRTOS IDLE Task Hook', 'SysTick Interrupt', and 'Tickless Idle Mode'. Pay close attention to the logic analyzer screenshots that show the SysTick interrupt constantly waking the CPU, and then how tickless idle mode solves this.
2. The Solution: Tickless Idle
The "tickless idle" feature solves this by temporarily stopping the periodic tick interrupt when the system is idle.
Here is the core concept, illustrated by the diagram below: when the idle task runs, instead of just waiting for the next interrupt, the RTOS calculates how long it can sleep before the next task needs to run. It then programs a timer to wake it up at exactly that moment, stops the periodic tick, and enters a deep sleep mode.

The general flow of a tickless idle implementation is as follows:
- Calculate Idle Time: The RTOS scheduler determines the number of ticks until the next task is scheduled to wake up.
- Stop Periodic Tick: The periodic SysTick interrupt is disabled.
- Program One-Shot Wake-up: A timer is programmed to generate a single interrupt after the calculated idle duration. This could be the same SysTick timer re-purposed or a separate low-power timer (like an RTC).
- Enter Low-Power Mode: The processor enters a deep sleep mode (e.g., Stop mode) by executing a
WFIinstruction. - Wake-up & Compensate: When the processor wakes up (either from the programmed timer or another external interrupt), it calculates how many ticks were "suppressed" during sleep.
- Update Tick Count: The RTOS tick counter is manually incremented by the number of suppressed ticks to keep system time accurate.
- Resume Ticking: The periodic tick interrupt is re-enabled, and the scheduler proceeds as normal.
3. Implementing Tickless Idle in FreeRTOS
FreeRTOS provides a framework to implement this feature. Let's walk through the key components and steps. The primary function is vPortSuppressTicksAndSleep(), which is called automatically by the idle task when tickless idle is enabled.
To enable tickless idle, you set configUSE_TICKLESS_IDLE to 1 in your FreeRTOSConfig.h file.
// FreeRTOSConfig.h
#define configUSE_TICKLESS_IDLE 1
Now, let's break down the logic inside the weakly-defined vPortSuppressTicksAndSleep() function.
Using FreeRTOS tickless mode on LPC5500
The NXP Application Note 'Using FreeRTOS tickless mode on LPC5500' provides an excellent, code-level explanation of this process. While the hardware is specific, the FreeRTOS concepts are universal.
Read sections 2, 2.1, 2.2, and 2.3. These sections map directly to the steps we are about to discuss. Focus on understanding the sequence: How xExpectedIdleTime is calculated. The preparation before sleep (disabling SysTick, configuring a wake-up source). The process of waking up and compensating the tick counter with vTaskStepTick().
Based on the principles from the reading, here is the sequence of events you need to implement or customize:
a) Pre-Sleep Processing
Before the CPU goes to sleep, several things must happen. FreeRTOS provides a hook, configPRE_SLEEP_PROCESSING(), which is the ideal place for your platform-specific code.
#define configPRE_SLEEP_PROCESSING( x ) vPortPreSleepProcessing( x )
void vPortPreSleepProcessing( TickType_t xExpectedIdleTime )
{
// 1. Disable peripherals to save more power.
// For example: turn off ADC, DAC, high-speed buses.
// 2. Select and enter the desired low-power mode.
// This connects to our previous lesson!
// Instead of a simple __WFI(), you would call a platform-specific
// function to enter Stop or Deep Sleep mode.
// e.g., HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
This is where you apply your knowledge from the previous lesson. A simple __WFI() might only enter Sleep mode. To achieve microamp-level consumption, you must use this hook to enter a deeper mode like Stop or Standby.
b) Post-Sleep Processing
When the processor wakes up, it needs to restore the context. FreeRTOS provides a corresponding configPOST_SLEEP_PROCESSING() hook.
#define configPOST_SLEEP_PROCESSING( x ) vPortPostSleepProcessing( x )
void vPortPostSleepProcessing( TickType_t xExpectedIdleTime )
{
// 1. Re-initialize the system clock if waking from a deep sleep mode.
// As we learned, waking from Stop mode often requires re-enabling the PLL.
// e.g., SystemClock_Config();
// 2. Re-enable any peripherals that were turned off.
}
The most critical step here is re-configuring the system clock if you entered a mode that disabled it. Forgetting this is a common bug, where the CPU wakes up but runs at a very slow speed, causing all peripherals to malfunction.
Test your understanding!
You have enabled tickless idle and are using configPRE_SLEEP_PROCESSING() to enter STM32's Stop mode. Upon wake-up, you notice that your UART communication is garbled. What is the most likely cause of this issue?
Show answer
The most likely cause is that the system clock was not re-initialized in configPOST_SLEEP_PROCESSING(). Stop mode disables the high-speed clocks (HSI, HSE, PLL). When the CPU wakes, it might run on a default low-speed internal oscillator. The UART peripheral's baud rate is derived from the system clock. If the clock is wrong, the baud rate will be wrong, leading to garbled communication. The fix is to call the SystemClock_Config() function (or its equivalent) at the beginning of your post-sleep processing hook.
4. Advanced Customization and Considerations
For more advanced control, you can define configUSE_TICKLESS_IDLE as 2. This tells FreeRTOS that you will provide your own complete implementation of vPortSuppressTicksAndSleep(). This is useful when:
- You need to use a specific low-power timer (like an RTC or LPTMR) instead of the SysTick timer as the wake-up source. The SysTick timer is often tied to the CPU clock and stops in deep sleep modes.
- You need to handle more complex power-down sequences.
Using FreeRTOS tickless mode on LPC5500
For a practical example of this advanced customization, let's look at the NXP application note again.
Quickly read section 3 to see how configUSE_TICKLESS_IDLE is set to 2 to enable a custom implementation using the RTC. Then, skim section 4.2 to see how the configPRE_SLEEP_PROCESSING and configPOST_SLEEP_PROCESSING macros are used to implement even deeper sleep modes by disabling peripherals like the USART.
5. Interview Corner: Debugging Tickless Idle
Mastering this feature is a significant skill for a senior embedded role. An interviewer might ask: "You've implemented tickless idle, but your system's power consumption isn't as low as you expected. What would you investigate?"
Here’s how you could structure a comprehensive answer:
- Confirm the Mode: "First, I'd verify which low-power mode is actually being entered. Inside
configPRE_SLEEP_PROCESSING(), am I just calling__WFI()which enters a light sleep, or am I calling the platform's API to enter a true Stop or Deep Sleep mode? I'd use a debugger and a multimeter to correlate code execution with the actual current draw." - Look for Unwanted Wake-ups: "Next, I'd check for unintended wake-up sources. Even with the tick suppressed, any other enabled interrupt can wake the processor. This could be a noisy GPIO pin, a misconfigured peripheral, or even the debugger itself being connected. I would toggle a GPIO pin at the entry and exit of the sleep function to measure the actual sleep duration with a logic analyzer. If it's shorter than expected, it points to an unwanted wake-up."
- Check for Power-Hungry Peripherals: "I'd also review the pre-sleep hook to ensure I'm being aggressive enough with power saving. Did I leave a high-speed peripheral like an ADC, SPI, or DMA controller clocked and enabled? Effective clock gating—disabling clocks to unused modules before sleeping—is crucial. The current consumption difference between Stop mode with peripherals on vs. off can be substantial."
- Review Minimum Sleep Time: "Finally, I would check the
configEXPECTED_IDLE_TIME_BEFORE_SLEEPsetting. If this value is too small, the overhead of entering and exiting the low-power mode might consume more power than just staying in a light sleep. There's a break-even point, and I'd need to ensure we're only attempting deep sleep for sufficiently long idle periods."
Conclusion
Today you've bridged the gap between knowing about low-power modes and actively using them in a real-time system. The tickless idle feature is a powerful tool for building truly power-efficient embedded products.
Key Takeaways:
- Standard RTOS operation with a periodic tick prevents the CPU from staying in deep sleep.
- Tickless idle solves this by stopping the tick and programming a one-shot wake-up timer for the duration of the idle period.
- The core steps are: calculate idle time, stop the tick, program wake-up, sleep, wake up, compensate tick count, and resume ticking.
- FreeRTOS provides the
configPRE_SLEEP_PROCESSING()andconfigPOST_SLEEP_PROCESSING()hooks for you to insert platform-specific code to enter deep sleep modes and restore the system clock upon wake-up. - Debugging low-power issues involves checking the sleep mode itself, looking for unwanted wake-ups, and ensuring peripherals are properly power-gated.
Next Lesson Preview:
We touched on the importance of turning off peripheral clocks. In our next lesson, we will dive deeper into this topic: Implement clock gating by selectively enabling and disabling peripheral clocks to reduce dynamic power consumption. This technique is essential not only for pre-sleep preparation but also for saving power during the system's active states.