FreeRTOS Learning Notes (Part 10) β€” System Delays

πŸŽ€ Article Author: Ertu Electronics🌸 Follow the public account at the end of the article for more materials and project files!🐸 Looking forward to learning and exchanging ideas together!

FreeRTOS Learning Notes (Part 10) β€” System Delays
Article Cover

1. Concepts of Relative Delay and Absolute Delay

First, let’s understand the concepts of relative delay and absolute delay.

  • β€’ Relative Delay refers to the delay for a specified duration starting from the current moment.
  • β€’ Absolute Delay is calculated based on a fixed time reference point to ensure that tasks run at strict intervals.

These two concepts come from some official explanations; I hope everyone can understand them. I would like to explain them in a simpler way to clarify what relative delay and absolute delay are.

1.1 Relative Delay

Those who have experience with bare-metal development should know that we often use the delay function to implement delays. Typically, this delay method is achieved through blocking or executing no-operations. However, this type of delay can be affected by interrupts. For example, if we use the delay function to delay for 100ms, and an interrupt occurs during this delay, the actual delay time will be longer than the set time. The delay function we use is a typical example of relative delay. In FreeRTOS, there is also a relative delay function β€” vTaskDelay(). This function is influenced by higher-priority tasks and interrupts, resulting in an actual delay time greater than the set time. Therefore, relative delays are usually used in scenarios where strict periodicity is not required, such as blinking an LED.

1.2 Absolute Delay

In FreeRTOS, there is an absolute delay function β€” vTaskDelayUntil(). So, what is absolute delay? In bare-metal development, we often place certain tasks in a timer to ensure that they execute at fixed intervals. This type of delay, which utilizes hardware timer interrupts or compare match functions to trigger operations (such as setting flags or calling callback functions) at fixed time points, can be understood as an absolute delay (to be precise, this timer interrupt will not be interrupted by other interrupts). The vTaskDelayUntil() function is used to ensure that a task that needs to execute at a fixed cycle can do so stably over the long term.

2. FreeRTOS Relative Delay and Absolute Delay Functions

2.1 Relative Delay Function vTaskDelay()

void vTaskDelay( const TickType_t xTicksToDelay )

We will not go into too much detail about the specific implementation of this function, but we will introduce some details. If we take a closer look at the function’s input parameter<span>xTicksToDelay </span>, we can see that the function takesthe number of system ticks to delay, not how many milliseconds or seconds. When using it, we need to pay attention to this, and the specific time needs to be converted based on our system clock frequency.

To avoid having to calculate the corresponding system tick count for each delay, FreeRTOS provides a macro to help us convert delay time to system ticks. We can usepdMS_TO_TICKS() to automatically convert delay time into tick counts.

2.2 Absolute Delay Function vTaskDelayUntil()

We will not introduce the specific implementation of the function again.

void vTaskDelayUntil( TickType_t * const  pxPreviousWakeTime,const TickType_t  xTimeIncrement )

This function has two input parameters:

  • β€’ pxPreviousWakeTime: The last wake time, which needs to be initialized to the system clock tick count when entering the task’s while loop.
  • β€’ xTimeIncrement: The number of ticks the task needs to delay.

We will analyze how the vTaskDelayUntil() function implements absolute delay through its application. Suppose we have a task function:

void TestTask(void *pvParameters)
{
    TickType_t xLastWakeTime = xTaskGetTickCount(); // Initialize the reference time to the current Tick
    const TickType_t xPeriod = pdMS_TO_TICKS(100);  // Define the period as 100ms (ensure configTICK_RATE_HZ supports this)

    while (1) {
        // Task main code (execution time may vary)
        do_work();

        // Absolute delay, ensuring the next wake time is strictly xPeriod apart
        vTaskDelayUntil(&amp;xLastWakeTime, xPeriod);
    }
}

At the start of the task, we first call the xTaskGetTickCount() function to get the current system clock tick count. At the end of the task, we call the vTaskDelayUntil() function to implement absolute delay.

For example, if our current xLastWakeTime is 120 Ticks and the set xPeriod is 50 Ticks, then according to the requirement, we should end the delay when the system clock tick count reaches 170. If, for some reason, when we reach the vTaskDelayUntil() function, the system tick value has already reached 168, then the vTaskDelayUntil() function will only complete a delay of two system ticks, ensuring that the task execution is completed when the system tick value is 170, and it will automatically update the value of xLastWakeTime to 170 for the next delay preparation. Therefore, we do not need to call xTaskGetTickCount() each time to get the current tick count.

From the above introduction, we can see that the delay time of the vTaskDelayUntil() function is flexible and will adjust the blocking time based on the execution time of the task, ensuring that the task can stably execute according to a time cycle over the long term.

Let’s think about it: if the execution time of the task exceeds the set cycle time, what should we do?

Continuing with the previous example, if our current xLastWakeTime is 120 Ticks and the set xPeriod is 50 Ticks, we should end the delay when the system clock tick count reaches 170. However, if for some reason, the execution time of the task exceeds the cycle time, causing the system tick value to exceed 170 when we reach the vTaskDelayUntil() function, say it has reached 200 Ticks, then the system has missed the theoretical wake time. The vTaskDelayUntil() will not block the task anymore and will automatically set the value of xLastWakeTime to 170 to prevent the cycle from drifting further.

Why is xLastWakeTime set to 170? Why not continue running with the current value of 200?

Setting it to 170 is to ensure that the task strictly follows the set cycle over the long term, meaning 120β†’170β†’220β†’270…, if a timeout occurs causing the cycle to be inaccurate, we need to correct the cycle back to its original track rather than directly setting it to 200, which would lead to cycle drift. Therefore, the update of xLastWakeTime follows certain rules:

xLastWakeTime = xLastWakeTime + xPeriod * n

In the above example, when we reach the vTaskDelayUntil() function, the system tick value is 200, and the target value is 170, with a difference of 30 < 50 (target cycle), so n equals 1. Therefore, xLastWakeTime will be set to 120 + 50 * 1. If when reaching the vTaskDelayUntil() function, the system tick value is 270, then xLastWakeTime will be set to 120 + 50 * 2.

FreeRTOS Learning Notes (Part 10) β€” System Delays

FreeRTOS Learning Notes (Part 10) β€” System DelaysAbout UsFreeRTOS Learning Notes (Part 10) β€” System DelaysWeChat Public Account | QQ | Learning GroupFreeRTOS Learning Notes (Part 10) β€” System DelaysFreeRTOS Learning Notes (Part 10) β€” System DelaysFreeRTOS Learning Notes (Part 10) β€” System DelaysScan to FollowDiscover more unique contentFreeRTOS Learning Notes (Part 10) β€” System DelaysShareFreeRTOS Learning Notes (Part 10) β€” System DelaysSaveFreeRTOS Learning Notes (Part 10) β€” System DelaysViewFreeRTOS Learning Notes (Part 10) β€” System DelaysLike

Leave a Comment