一、基础知识
[FreeRTOS 基础知识] 任务通知 概念
[FreeRTOS 内部实现] 创建任务 xTaskCreate函数解析
二、内部机制解析
任务通知结构体
每个任务都会有个TCB结构体,该结构体保存任务的状态。
这个结构体中有两个成员用于任务通知使用。如下图:(结构体还有其他成员,这里省略)
typedef struct tskTaskControlBlock
{
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
} tskTCB;
ulNotifiedValue成员 保存该任务通知的值
ucNotifyState成员 保存任务通知的状态
任务通知状态有三种:
taskNOT_WAITING_NOTIFICATION:任务没有在等待通知。
taskWAITING_NOTIFICATION:任务正在等待通知。
taskNOTIFICATION_RECEIVED:任务已经接收到通知。
发送通知函数 xTaskNotify
xTaskNotify(): 向指定任务发送通知,并可选择如何更新接收任务的通知值。
#define xTaskNotify( xTaskToNotify, ulValue, eAction ) xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL )
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
参数解析:
TaskHandle_t xTaskToNotify : 目标任务句柄
uint32_t ulValue : 通知值
eNotifyAction eAction :更新方式,包括通知事件不去更新通知值;设置通知值的位;通知值递增;覆盖通知值操作
uint32_t *pulPreviousNotificationValue:更改前的通知值
typedef enum
{
eNoAction = 0, /* Notify the task without updating its notify value. */
eSetBits, /* Set bits in the task's notification value. */
eIncrement, /* Increment the task's notification value. */
eSetValueWithOverwrite, /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */
eSetValueWithoutOverwrite /* Set the task's notification value if the previous value has been read by the task. */
} eNotifyAction;
函数内部解析:
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
// 1、从参数中获取目标任务TCB结构体
-> pxTCB = ( TCB_t * ) xTaskToNotify;
// 2、判断是否返回更新前的通知值
-> if( pulPreviousNotificationValue != NULL )
*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
// 3、记录更新前通知状态,并初始化状态
-> ucOriginalNotifyState = pxTCB->ucNotifyState;
-> pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
// 4、根据传入的更新方式参数,决定通知值的变化
switch( eAction )
{
case eSetBits :
pxTCB->ulNotifiedValue |= ulValue;
break;
case eIncrement :
( pxTCB->ulNotifiedValue )++;
break;
case eSetValueWithOverwrite :
pxTCB->ulNotifiedValue = ulValue;
break;
case eSetValueWithoutOverwrite :
if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
{
pxTCB->ulNotifiedValue = ulValue;
}
else
{
xReturn = pdFAIL;
}
break;
case eNoAction:
break;
}
// 5、如果之前的链表状态是等待
-> if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
// (1)从xStateListItem 移除
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
// (2)添加到ReadyList
prvAddTaskToReadyList( pxTCB );
任务通知等待 xTaskNotifyWait
xTaskNotifyWait(): 允许任务等待接收通知,并可以设置在进入和退出时要清零的通知比特位。
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
参数解析:
uint32_t ulBitsToClearOnEntry :在函数的入口处,清除哪些位
uint32_t ulBitsToClearOnExit : 在函数的出口处,清除哪些位
uint32_t *pulNotificationValue:用来保存读出的数据
TickType_t xTicksToWait:等待数据时间
函数内部解析:
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
-> taskENTER_CRITICAL(); // 关中断
// 判断当前的任务状态不为taskNOTIFICATION_RECEIVED ,表示说任务现在还没有接收到通知
-> if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
{
pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry; // 把相应的位清零
pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; // 将标志位设置为等待状态
// 如果任务需要等待的话,
if( xTicksToWait > ( TickType_t ) 0 )
{
// 将当前任务添加到delay链表
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
traceTASK_NOTIFY_WAIT_BLOCK();
}
}
// 任务被唤醒后
// 任务通知的value值返回
*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
// 如果任务状态不为taskNOTIFICATION_RECEIVED 模式,则返回false
if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
xReturn = pdFALSE;
else
{
// 将任务通知值value值清零,返回true
pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
xReturn = pdTRUE;
}
// 将任务通知改为 不等待通知状态
pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
小结: