In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-03 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly explains the "FreeRTOS system delay case analysis", the content of the article is simple and clear, easy to learn and understand, now please follow the editor's train of thought slowly in depth, together to study and learn "FreeRTOS system delay case analysis"!
FreeRTOS provides two system delay functions: relative delay function vTaskDelay () and absolute delay function.
VTaskDelayUntil (). Relative delay means that each delay starts with the task execution function vTaskDelay (), and the delay ends at the specified time.
Absolute delay means that the task that calls the vTaskDelayUntil () function is performed at specified intervals. In other words: tasks are performed at a fixed frequency.
1. Relative delay function vTaskDelay ()
Consider the following task, task An enters a blocking state by calling the relative delay function vTaskDelay () after executing the task body code. In addition to task A, there are other tasks in the system, but task A has the highest priority.
Void vTaskA (void * pvParameters) {/ * blocks 500ms. Note: macro pdMS _ TO_TICKS is used to convert milliseconds to beats. This macro is only available in FreeRTOS V8.1.0 and above. If you use a lower version, you can use 500 / portTICK_RATE_MS * / const portTickType xDelay = pdMS_TO_TICKS (500); for ( ) {/ /... / here is the task body code / /... / * call the system delay function, blocking 500ms * / vTaskDelay (xDelay);}}
For such a task, the execution process is shown in figure 1-1. When task An obtains the right to use CPU, it first executes the body code of task A, and then calls the system delay function vTaskDelay () to enter the blocking state. After Task An enters the block, other tasks can be performed.
The FreeRTOS kernel periodically checks whether the blocking of task An is reached, and if the blocking time is reached, set task A to the ready state. Because task A has the highest priority, it preempts the CPU, executes the task body code again, and loops constantly.
As you can see from figure 1-1, each task A delay starts from the call to the delay function vTaskDelay (), and the delay starts relative to this time, so it is called the relative delay function.
You can also see from figure 1-1 that if an interruption occurs during the execution of task A, the execution cycle of task A becomes longer, so task A cannot be executed periodically using the relative delay function vTaskDelay ().
Figure 1-1: schematic diagram of relative delay function execution
Let's look at the source code.
Void vTaskDelay (const TickType_t xTicksToDelay) {BaseType_t xAlreadyYielded = pdFALSE; / * if the delay time is 0, the current task will not be added to the delay list * / if (xTicksToDelay > (TickType_t) 0U) {vTaskSuspendAll () {/ * remove the current task from the ready list and calculate the wake-up time based on the current system beat counter value, then add the task to the delay list * / prvAddCurrentTaskToDelayedList (xTicksToDelay, pdFALSE);} xAlreadyYielded = xTaskResumeAll () } / * Force a context switch * / if (xAlreadyYielded = = pdFALSE) {portYIELD_WITHIN_API ();}}
If the delay is greater than 0, the current task is removed from the ready list and added to the delay list. The function prvAddCurrentTaskToDelayedList () is called to complete this process. As we mentioned many times in the previous series of blog posts, there are many local static variables defined in tasks.c, one of which is defined as follows:
Static volatile TickType_t xTickCount = (TickType_t) 0U
This variable is used to count and record the number of system beat interruptions, which is cleared when the scheduler is started, and is added 1 each time the system beat clock is interrupted. This variable is used in the relative delay function. XTickCount represents the number of interruptions of the current system beat. This value plus the delay time specified in the parameter (in terms of the number of system beats) xTicksToDelay is the next time to wake up the task. XTickCount+ xTicksToDelay will be recorded in the task TCB and attached to the delay list along with the task.
We know that the variable xTickCount is of type TickType_t, and it will also overflow. In a 32-bit architecture, when the xTicksToDelay reaches 4294967295 and then increases, the overflow becomes 0. To solve the xTickCount overflow problem, FreeRTOS uses two delay lists: xDelayedTaskList1 and xDelayedTaskList2, and uses two list pointer type variables pxDelayedTaskList and pxOverflowDelayedTaskList to point to the above delay list 1 and 2, respectively (point the delay list pointer to the delay list when creating the task). By the way, the above two deferred list pointer variables and two deferred list variables are static local variables defined in tasks.c.
If the kernel detects a xTickCount+ xTicksToDelay overflow, it hangs the current task in the list pointed to by the list pointer pxOverflowDelayedTaskList, otherwise it hangs in the list pointed to by the list pointer pxDelayedTaskList.
Each time the system beat clock is interrupted, the interrupt service function checks the two delay lists to see if the delayed task expires, and if the time expires, the task is deleted from the delay list and rejoined the ready list. If the priority of the task newly added to the ready list is higher than the current task, a context switch is triggered.
two。 Absolute delay function vTaskDelayUntil ()
Considering the following task, Task B first calls the absolute delay function vTaskDelayUntil () to enter the blocking state, and when the blocking time arrives, the task body code is executed. Besides task B, there are other tasks in the system, but task B has the highest priority.
Void vTaskB (void * pvParameters) {static portTickType xLastWakeTime; const portTickType xFrequency = pdMS_TO_TICKS; / / initialize the variable xLastWakeTime with the current time, note that this is different from the vTaskDelay () function xLastWakeTime = xTaskGetTickCount (); for (;;) {/ * calls the system delay function and periodically blocks 500ms * / vTaskDelayUntil (& xLastWakeTime,xFrequency) / /. / / here is the task body code, which is executed periodically. Note that this is also different from the vTaskDelay () function / /...}}
For such a task, the execution process is shown in figure 2-1. When task B obtains the right to use CPU, first call the system delay function vTaskDelayUntil () to make the task enter the blocking state. After Task B enters the block, other tasks can be performed. The FreeRTOS kernel periodically checks whether the blocking of task An is reached, and if the blocking time is reached, set task A to the ready state.
Because task B has the highest priority, it preempts the CPU, and then executes the task body code. After the task body code is executed, it will continue to call the system delay function vTaskDelayUntil () to make the task into a blocking state, over and over again.
As you can see from figure 2-1, from the call to the function vTaskDelayUntil (), every fixed +
-cycle, the body code of task B will be executed once, even if task B is interrupted during execution, it will not affect the periodicity, but will shorten the execution time of other tasks! So this function is called the absolute delay function, and it can be used to periodically execute the body code of task A.
Figure 2-1: schematic diagram of absolute delay function execution
How does the function vTaskDelayUntil () be periodic? let's take a look at the source code.
Void vTaskDelayUntil (TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement) {TickType_t xTimeToWake;BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE; vTaskSuspendAll (); {/ * Save system beat interruption counter * / const TickType_t xConstTickCount = xTickCount; / * calculate the task's next wake-up time (expressed in the number of system beat interruptions) * / xTimeToWake = * pxPreviousWakeTime + xTimeIncrement / * * the last wake-up time is saved in pxPreviousWakeTime. It takes a certain amount of time to execute the task body code after wake-up. If the last wake-up time is greater than the current time, the beat counter overflowed * / if (xConstTickCount)
< *pxPreviousWakeTime ) { /*只有当周期性延时时间大于任务主体代码执行时间,才会将任务挂接到延时列表.*/ if( ( xTimeToWake < *pxPreviousWakeTime ) && ( xTimeToWake >XConstTickCount) {xShouldDelay = pdTRUE;}} else {/ * also ensures that the periodic delay time is greater than the task body code execution time * / if ((xTimeToWake)
< *pxPreviousWakeTime ) || ( xTimeToWake >XConstTickCount) {xShouldDelay = pdTRUE;}} / * update the wake-up time to prepare for the next call to this function. * / * pxPreviousWakeTime = xTimeToWake; if (xShouldDelay! = pdFALSE) {/ * add this task to the delay list. Note that the blocking time is not based on the current time, so the current system beat interrupt counter value * / prvAddCurrentTaskToDelayedList (xTimeToWake-xConstTickCount, pdFALSE) is subtracted;}} xAlreadyYielded = xTaskResumeAll () / * Force a context switch * / if (xAlreadyYielded = = pdFALSE) {portYIELD_WITHIN_API ();}}
Unlike the relative delay function vTaskDelay, this function adds a parameter pxPreviousWakeTime to point to a variable that holds the time that the last task was unblocked. This variable must be set to the number of interruptions in the current system beat at the beginning of the task (see Task B example above), and then the function vTaskDelayUntil () automatically updates the variable internally.
Because the variable xTickCount may overflow, the program must detect various overflow conditions and ensure that the delay period is not less than the task body code execution time. It is understandable that it is impossible to perform a task that takes 20 milliseconds to complete every 5 milliseconds.
If we represent the range of the variable xTickCount in Abscissa, the left end of the Abscissa is 0 and the right end is the maximum value that the variable xTickCount can represent. Only in the three cases shown in figure 2-2 can a task be added to the delay list.
In figure 2-2
* indicates the periodic delay time of the task between pxPreviousWakeTime and xTimeToWake
* the time between pxPreviousWakeTime and xConstTickCount indicates the execution time of the principal code of task B.
In figure 2-2
The first case deals with system beat interrupt counter (xConstTickCount) and wake-up time counter (xTimeToWake) overflow
The second case deals with wake-up time counter (xTimeToWake) overflow
The third case deals with conventional cases where there is no overflow.
As you can see from the figure, whether there is an overflow or no overflow, the current task body code must be executed before the next wake-up task. As shown in figure 2-2, the variable xTimeToWake is always greater than the variable xConstTickCount (each overflow equals a maximum Max).
Figure 2-2: three cases in which a task is added to the delay list
After the calculated wake-up time is legal, the current task is added to the delay list, and there are also two delay lists. Each time the system beat is interrupted, the interrupt service function checks the two delay lists to see if the delayed task expires, and if the time expires, delete the task from the delay list and rejoin the ready list. If the priority of the task newly added to the ready list is higher than the current task, a context switch is triggered.
Thank you for your reading, the above is the content of "FreeRTOS system delay example Analysis". After the study of this article, I believe you have a deeper understanding of the problem of FreeRTOS system delay example analysis, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.