FreeRTOS时间管理
1. FreeRTOS延时函数
在使用FreeRTOS的过程中经常会在一个任务中使用延时函数对该任务延时,当执行延时函数的时候就会进行任务切换,并且此任务就会进入阻塞态,直到延时完成,任务重新进入就绪态
1.1 相对延时函数
相对延时函数vTaskDelay()在文件task.c中定义,功能是使任务进入阻塞态,根据传入的参数延时多少个tick(系统节拍),其函数原型如下:
函数原型:void vTaskDelay(TickType_t xTicksToDelay)
传 入 值:xTicksToDelay 延时周期
系统节拍周期为1000Hz,延时周期时基就是1ms;
系统节拍周期为100Hz,延时周期时基就是10ms;
函数实现的源码如下:
void vTaskDelay(const TickType_t xTicksToDelay){
BaseType_t xAlreadyYielded = pdFALSE;
if(xTicksToDelay > (TickType_t) 0U){
configASSERT( uxSchedulerSuspended == 0 );
vTaskSuspendAll();
{
traceTASK_DELAY();
prvAddCurrentTaskToDelayedList( xTicksToDelay, pdFALSE );
}
xAlreadyYielded = xTaskResumeAll();
}
else{
mtCOVERAGE_TEST_MARKER();
}
if(xAlreadyYielded == pdFALSE){
portYIELD_WITHIN_API();
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
prvAddCurrentTaskToDelayedList()函数用于将当前任务添加到等待列表中,文件task.c中定义,其源码如下:
static void prvAddCurrentTaskToDelayedList(TickType_t xTicksToWait,
const BaseType_t xCanBlockIndefinitely){
TickType_t xTimeToWake;
const TickType_t xConstTickCount = xTickCount;
if(uxListRemove( &( pxCurrentTCB->xStateListItem ) ) == ( UBaseType_t ) 0){
portRESET_READY_PRIORITY( pxCurrentTCB->uxPriority, uxTopReadyPriority );
}
else{
mtCOVERAGE_TEST_MARKER();
}
#if ( INCLUDE_vTaskSuspend == 1 )
{
if( ( xTicksToWait == portMAX_DELAY ) && ( xCanBlockIndefinitely != pdFALSE ) ){
vListInsertEnd( &xSuspendedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else{
xTimeToWake = xConstTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
if( xTimeToWake < xConstTickCount){
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else{
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
if( xTimeToWake < xNextTaskUnblockTime ){
xNextTaskUnblockTime = xTimeToWake;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
#else
{
xTimeToWake = xConstTickCount + xTicksToWait;
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB->xStateListItem ), xTimeToWake );
if( xTimeToWake < xConstTickCount ){
vListInsert( pxOverflowDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
}
else{
vListInsert( pxDelayedTaskList, &( pxCurrentTCB->xStateListItem ) );
if( xTimeToWake < xNextTaskUnblockTime ){
xNextTaskUnblockTime = xTimeToWake;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
( void ) xCanBlockIndefinitely;
}
#endif
}
1.2 绝对延时函数
绝对延时函数vTaskDelayUntil()在文件task.c中定义,功能是使任务进入阻塞态,直到一个绝对延时时间到达,其函数原型如下:
函数原型:void vTaskDelayUntil(TickType_t *pxPreviousWakeTime,TickType_t xTimeIncrement)
传 入 值:pxPreviousWakeTime 记录任务上一次唤醒系统节拍值
xTimeIncrement 相对于pxPreviousWakeTime,本次延时的节拍数
函数实现的源码如下:
void vTaskDelayUntil(TickType_t * const pxPreviousWakeTime,
const TickType_t xTimeIncrement){
TickType_t xTimeToWake;
BaseType_t xAlreadyYielded, xShouldDelay = pdFALSE;
vTaskSuspendAll();
{
const TickType_t xConstTickCount = xTickCount;
xTimeToWake = *pxPreviousWakeTime + xTimeIncrement;
if( xConstTickCount < *pxPreviousWakeTime){
if((xTimeToWake < *pxPreviousWakeTime)&&(xTimeToWake > xConstTickCount)){
xShouldDelay = pdTRUE;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
else{
if((xTimeToWake < *pxPreviousWakeTime)||(xTimeToWake > xConstTickCount)){
xShouldDelay = pdTRUE;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
*pxPreviousWakeTime = xTimeToWake;
if( xShouldDelay != pdFALSE ){
traceTASK_DELAY_UNTIL( xTimeToWake );
prvAddCurrentTaskToDelayedList( xTimeToWake - xConstTickCount, pdFALSE );
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
xAlreadyYielded = xTaskResumeAll();
if( xAlreadyYielded == pdFALSE ){
portYIELD_WITHIN_API();
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
1.3 调度器挂起和恢复
调度器挂起函数vTaskSuspendAll()源码如下:
void vTaskSuspendAll(void){
++uxSchedulerSuspended;
}
调度器恢复函数xTaskResumeAll()源码如下:
BaseType_t xTaskResumeAll(void){
TCB_t *pxTCB = NULL;
BaseType_t xAlreadyYielded = pdFALSE;
taskENTER_CRITICAL();
{
--uxSchedulerSuspended;
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){
if( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U ){
while( listLIST_IS_EMPTY( &xPendingReadyList ) == pdFALSE ){
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xPendingReadyList ) );
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){
xYieldPending = pdTRUE;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
if( pxTCB != NULL ){
prvResetNextTaskUnblockTime();
}
{
UBaseType_t uxPendedCounts = uxPendedTicks;
if( uxPendedCounts > ( UBaseType_t ) 0U ){
do
{
if( xTaskIncrementTick() != pdFALSE ){
xYieldPending = pdTRUE;
}
else{
mtCOVERAGE_TEST_MARKER();
}
--uxPendedCounts;
} while( uxPendedCounts > ( UBaseType_t ) 0U );
uxPendedTicks = 0;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
if( xYieldPending != pdFALSE ){
#if( configUSE_PREEMPTION != 0 )
{
xAlreadyYielded = pdTRUE;
}
#endif
taskYIELD_IF_USING_PREEMPTION();
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
return xAlreadyYielded;
}
2. FreeRTOS系统时钟节拍
不管是什么系统,运行都需要系统时钟节拍,xTickCount就是FreeRTOS的系统时钟节拍计数器。每个滴答定时器中断中xTickCount会加一,xTickCount的具体操作过程是在函数xTaskIncrementTick()中进行的
2.1 SysTick初始化
系统节拍初始化函数vPortSetupTimerInterrupt(),在port.c文件中定义,其源码如下:
void vPortSetupTimerInterrupt( void ){
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK_BIT | portNVIC_SYSTICK_INT_BIT | portNVIC_SYSTICK_ENABLE_BIT );
}
2.2 SysTick中断服务函数
系统节拍中断服务函数xPortSysTickHandler(),其源码如下:
void xPortSysTickHandler( void ){
vPortRaiseBASEPRI();
{
if( xTaskIncrementTick() != pdFALSE ){
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
vPortClearBASEPRIFromISR();
}
2.3 SysTick任务调度
系统节拍任务调度函数xTaskIncrementTick(),其源码如下:
BaseType_t xTaskIncrementTick( void ){
TCB_t * pxTCB;
TickType_t xItemValue;
BaseType_t xSwitchRequired = pdFALSE;
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ){
const TickType_t xConstTickCount = xTickCount + 1;
xTickCount = xConstTickCount;
if( xConstTickCount == ( TickType_t ) 0U ){
taskSWITCH_DELAYED_LISTS();
}
else{
mtCOVERAGE_TEST_MARKER();
}
if( xConstTickCount >= xNextTaskUnblockTime ){
for( ;; ){
if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ){
xNextTaskUnblockTime = portMAX_DELAY;
break;
}
else{
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList );
xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
if( xConstTickCount < xItemValue ){
xNextTaskUnblockTime = xItemValue;
break;
}
else{
mtCOVERAGE_TEST_MARKER();
}
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL ){
( void ) uxListRemove( &( pxTCB->xEventListItem ) );
}
else{
mtCOVERAGE_TEST_MARKER();
}
prvAddTaskToReadyList( pxTCB );
#if ( configUSE_PREEMPTION == 1 )
{
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority ){
xSwitchRequired = pdTRUE;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
}
}
}
#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
{
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 ){
xSwitchRequired = pdTRUE;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
}
else{
++uxPendedTicks;
}
#if ( configUSE_PREEMPTION == 1 )
{
if( xYieldPending != pdFALSE ){
xSwitchRequired = pdTRUE;
}
else{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
return xSwitchRequired;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)