FreeRTOS的任务调度一般使用系统滴答时钟,每次系统节拍时钟发生中断后加1,用来记录系统节拍时钟中断的次数,内核会将所有阻塞的任务跟这个变量比较,以判断是否超时,若超时意味着等待时间到达,可以执行。
变量xTickCount的数据类型跟具体硬件有关,32位架构硬件一般是无符号32位变量、8位或16位架构一般是无符号16位变量。即便是32位变量,xTickCount累加到0xFFFFFFFF后也会溢出。因此,在程序中要判断变量xTickCount是否溢出。如果溢出(xTickCount为0),则调用宏taskSWITCH_DELAYED_LISTS()交换延时列表指针和溢出延时列表指针。
taskSWITCH_DELAYED_LISTS()
{
List_t *pxTemp;
configASSERT( ( listLIST_IS_EMPTY( pxDelayedTaskList ) ) );
pxTemp = pxDelayedTaskList;
pxDelayedTaskList = pxOverflowDelayedTaskList;
pxOverflowDelayedTaskList = pxTemp;
xNumOfOverflows++;
prvResetNextTaskUnblockTime();
}
为了解决xTickCount溢出问题,FreeRTOS使用了两个延时列表:xDelayedTaskList1和xDelayedTaskList2。并使用延时列表指针pxDelayedTaskList和溢出延时列表指针pxOverflowDelayedTaskList分别指向上面的延时列表1和延时列表2(在创建任务时将延时列表指针指向延时列表)。
Note:上面的两个延时列表指针变量和两个延时列表变量都是在tasks.c中定义的静态局部变量。
例如使用API延时函数vTaskDelay( xTicksToDelay ) 将任务延时xTicksToDelay个系统节拍周期,延时函数会以当前的系统节拍中断次数xTickCount为参考,这个值加上参数规定的延时时间xTicksToDelay,即xTickCount+ xTicksToDelay,就是下次唤醒任务的时间。xTickCount+xTicksToDelay会被记录到任务TCB中,随着任务一起挂接到延时列表。如果内核判断出xTickCount+ xTicksToDelay溢出(大于32位可以表示的最大值),就将当前任务挂接到列表指针pxOverflowDelayedTaskList指向的列表中,否则就挂接到列表指针pxDelayedTaskList指向的列表中。任务按照延时时间,顺序的插入到延时列表中。
xTimeToWake = xTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE(&(pxCurrentTCB->xStateListItem), xTimeToWake);
/*时间值已经溢出*/
if (xTimeToWake < xTickCount)
{
vListInsert(pxOverflowDelayedTaskList, &(pxCurrentTCB->xStateListItem));
}
else
{
vListInsert(pxDelayedTaskList, &(pxCurrentTCB->xStateListItem));
if (xTimeToWake < xNextTaskUnblockTime)
{
xNextTaskUnblockTime = xTimeToWake;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
所以当系统节拍中断次数计数器xTickCount溢出时,必须将延时列表指针pxDelayedTaskList和溢出延时列表指针pxOverflowDelayedTaskList交换以便正确处理延时的任务。