没有合适的资源?快使用搜索试试~ 我知道了~
901-FreeRTOS202212‐xTaskNotifyGive() 与 xTaskNotifyGiveIndexed()
0 下载量 138 浏览量
2023-11-17
00:07:15
上传
评论
收藏 265KB PDF 举报
温馨提示
试读
1页
901-FreeRTOS202212‐xTaskNotifyGive() 与 xTaskNotifyGiveIndexed()函数
资源推荐
资源详情
资源评论
FreeRTOS202212‐xTaskNotifyGive()与xTaskNotifyGiveIndexed()
xTaskNotifyGive()是一个宏,宏展开是调用函数xTaskGenericNotify(),即向一个任务通知数组的首个元素发送一条任务通知。
xTaskNotifyGiveIndexed()也是一个宏,宏展开也是调用xTaskGenericNotify(),相比于xTaskNotifyGive()增加了索引参数,即向一个任务数组的指定索引位置发送一条任务通知。
以上两个函数都会将对方的任务通知值加1。可以作为二值信号量和计数信号量的一种轻量型的实现,速度更快,在这种情况下对象任务在等待任务通知的时候应该是使用函数ulTaskNotifyTake()或ulTaskNotifyTakeIndexed()。
流程图按红色框图执行
#define xTaskNotifyGive( xTaskToNotify ) \
xTaskGenericNotify ((xTaskToNotify),(tskDEFAULT_INDEX_TO_NOTIFY),( 0 ), eIncrement ,NULL)
#define xTaskNotifyGiveIndexed( xTaskToNotify , uxIndexToNotify ) \
xTaskGenericNotify ((xTaskToNotify),(uxIndexToNotify),( 0 ), eIncrement ,NULL)
/*‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐*/
#if (configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskGenericNotify ( TaskHandle_t xTaskToNotify , /*要通知的任务的句柄*/
UBaseType_t uxIndexToNotify , /*任务通知数组的索引值(任务通知相关数组下标,xTaskNotifyGive()默认为0,使用通知数组第一个元素)*/
uint32_t ulValue , /*要传递的通知值*/
eNotifyAction eAction , /*指定通知的动作*/
uint32_t * pulPreviousNotificationValue ) /*指向存储上一个通知值的变量的指针,如果不需要回传上一个通知值,则可以传递NULL*/
{
TCB_t * pxTCB ;
BaseType_t xReturn = pdPASS ;
uint8_t ucOriginalNotifyState ;
configASSERT ( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES );
configASSERT ( xTaskToNotify );
pxTCB = xTaskToNotify ;
taskENTER_CRITICAL ();
{
/*判断是否需要通知前的通知值*/
if ( pulPreviousNotificationValue != NULL )
{
/*获取发送通知前的通知值*/
* pulPreviousNotificationValue = pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ];
}
/*记录发送通知前的任务通知状态*/
ucOriginalNotifyState = pxTCB ‐> ucNotifyState [ uxIndexToNotify ];
/*将负责接收直达任务通知的TCB(任务控制块)中的任务通知状态设置为已收到任务通知态*/
pxTCB ‐> ucNotifyState [ uxIndexToNotify ]= taskNOTIFICATION_RECEIVED ;
switch ( eAction )
{
/*模拟事件组:将通知值的某些位置1*/
case eSetBits :
pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ]|= ulValue ;
break ;
/*模拟计数型信号量:将通知值+1*/
case eIncrement :
( pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ])++;
break ;
/*模拟队列:覆写通知值*/
case eSetValueWithOverwrite :
pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ]= ulValue ;
break ;
/*模拟队列:(不覆盖)写通知值*/
case eSetValueWithoutOverwrite :
/*如果不处于收到任务通知状态,说明通知值已被读走,可以写入*/
if ( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
{
pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ]= ulValue ;
}
else
{
/*Thevaluecouldnotbewrittentothetask.*/
/*无法将值写入任务*/
xReturn = pdFAIL ; /*通知值未被读走,不能覆写*/
}
break ;
/*只将任务标记为等待接收通知状态,并不修改通知值*/
case eNoAction :
/*Thetaskisbeingnotifiedwithoutitsnotifyvaluebeingupdated.*/
/*正在通知任务,但未更新其通知值*/
break ;
default :
/*Shouldnotgethereifallenumsarehandled.Artificiallyforceanassertbytestingavaluethecompilercan'tassumeisconst.*/
/*如果处理了所有枚举,则不应到达此处。通过测试编译器不能假定为常量的值来人为地强制断言*/
configASSERT ( xTickCount ==( TickType_t ) 0 );
break ;
}
traceTASK_NOTIFY ( uxIndexToNotify );
/*Ifthetaskisintheblockedstatespecificallytowaitforanotificationthenunblockitnow.*/
/*如果任务处于阻止状态,专门用于等待通知,则立即取消阻止*/
if ( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) /*如果在此之前,任务因等待任务通知而被阻塞(该任务为等待通知状态),则现在解除阻塞*/
{
/*将任务从所在任务状态链表(延时/挂起链表)中移出*/
listREMOVE_ITEM (&( pxTCB ‐> xStateListItem ));
/*将任务添加到就绪任务链表中*/
prvAddTaskToReadyList ( pxTCB );
/*Thetaskshouldnothavebeenonaneventlist.*/
/*该任务不应出现在事件链表中*/
configASSERT ( listLIST_ITEM_CONTAINER (&( pxTCB ‐> xEventListItem ))== NULL );
#if (configUSE_TICKLESS_IDLE != 0 )
{
/*IfataskisblockedwaitingforanotificationthenxNextTaskUnblockTimemightbesettotheblockedtask'stimeouttime.
IfthetaskisunblockedforareasonotherthanatimeoutxNextTaskUnblockTimeisnormallyleftunchanged,becauseitwillautomaticallygetresettoanewvaluewhenthetickcountequalsxNextTaskUnblockTime.
Howeverifticklessidlingisuseditmightbemoreimportanttoentersleepmodeattheearliestpossibletime‐soresetxNextTaskUnblockTimeheretoensureitisupdatedattheearliestpossibletime.*/
/*如果任务被阻止等待通知,则xNextTaskUnblockTime可能会设置为被阻止任务的超时时间。
如果由于超时以外的原因取消阻止任务,xNextTaskUnblockTime通常保持不变,因为当勾号计数等于xNextTTaskUnblocktime时,它将自动重置为新值。
然而,如果使用了无障碍空转,那么尽早进入睡眠模式可能更重要——因此,请在此处重置xNextTaskUnblockTime,以确保它在尽早更新*/
prvResetNextTaskUnblockTime (); /*更新下一个解除阻塞的任务*/
}
#endif
/*有任务解除阻塞后,就应该判断是否需要进行任务切换*/
if ( pxTCB ‐> uxPriority > pxCurrentTCB ‐> uxPriority )
{
/*Thenotifiedtaskhasapriorityabovethecurrentlyexecutingtasksoayieldisrequired.*/
/*通知的任务的优先级高于当前执行的任务,因此需要切换*/
taskYIELD_IF_USING_PREEMPTION (); /*悬起PendSV中断,准备进行任务切换*/
}
else
{
mtCOVERAGE_TEST_MARKER ();
}
}
else
{
mtCOVERAGE_TEST_MARKER ();
}
}
taskEXIT_CRITICAL ();
return xReturn ;
}
#endif /*configUSE_TASK_NOTIFICATIONS*/
/*‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐*/
xTaskGenericNotify ()
定义任务块指针
TCB_t * pxTCB ;
初始化返回值为pdPASS
BaseType_t xReturn = pdPASS ;
定义原始通知状态变量
uint8_t ucOriginalNotifyState ;
任务块指针指向要通知的任务句柄
pxTCB = xTaskToNotify ;
*
pxTCB
进入临界段
taskENTER_CRITICAL ();
栈顶*pxTopOfStack
volatile(portSTACK_TYPE)uint32_t(StackType_t)
xStateListItem
xEventListItem
任务栈起始地址*pxStack
任务名称,仅用于调试,字符串形式pcTaskName[configMAX_TASK_NAME_LEN]
uint8_t(char)
ulNotifiedValue [configTASK_NOTIFICATION_ARRAY_ENTRIES]
任务通知功能
volatileuint32_t
ucNotifyState [configTASK_NOTIFICATION_ARRAY_ENTRIES]
任务通知功能
volatileuint8_t
ucStaticallyAllocated
支持静态&动态内存
uint8_t
*pxTopOfStack
xLIST_ITEM(ListItem_t)
xStateListItem
xLIST_ITEM(ListItem_t)
xEventListItem
UBaseType_t(unsignedlong)
优先级
uxPriority=
*pxStack
volatile(portSTACK_TYPE)uint32_t(StackType_t)
pcTaskName [configMAX_TASK_NAME_LEN]
xItemValue
*pxNext
*pxPrevious
*pvOwner
*pvContainer
内核对象
链表对象
void
void
structxLIST_ITEM
structxLIST_ITEM
uint32_t/uint16_t(TickType_t)
节点排序值
tskTaskControlBlock(tskTCB)(TCB_t)
xMPUSettings
#if(portUSING_MPU_WRAPPERS==1)
xItemValue
*pxNext
*pxPrevious
*pvOwner
*pvContainer
内核对象
链表对象
void
void
structxLIST_ITEM
structxLIST_ITEM
uint32_t/uint16_t(TickType_t)
节点排序值
指向堆栈的最高有效地址
volatile(portSTACK_TYPE)uint32_t(StackType_t)
*pxEndOfStack
#if(portSTACK_GROWTH>0)
UBaseType_t(unsignedlong)
uxCriticalNesting
portCRITICAL_NESTING_IN_TCB==1
UBaseType_t(unsignedlong)
uxTCBNumber
#if(configUSE_TRACE_FACILITY==1)
UBaseType_t(unsignedlong)
uxTaskNumber
#if(configUSE_TRACE_FACILITY==1)
UBaseType_t(unsignedlong)
uxBasePriority
#if(configUSE_MUTEXES==1)
UBaseType_t(unsignedlong)
xxx
uxMutexesHeld
#if(configUSE_MUTEXES==1)
函数指针
(*)pxTaskTag
#if(configUSE_APPLICATION_TASK_TAG==1)
typedefBaseType_t(*TaskHookFunction_t)(void*)
xxx
*pvThreadLocalStoragePointers[configNUM_THREAD_LOCAL_STORAGE_POINTERS]
#if(configNUM_THREAD_LOCAL_STORAGE_POINTERS>0)
void
存储任务在“正在运行”状态下花费的时间
ulRunTimeCounter
#if(configGENERATE_RUN_TIME_STATS==1)
uint32_t
xxx
configTLS_BLOCK_TYPE xTLSBlock; /*
为任务分配一个
Newlibreent
结构体变量。
Newlib
是一个
C
库函数,并非
FreeRTOS
维护,
FreeRTOS
也不对使用结果负责。如果用户使用
Newlib
,必须熟知
Newlib
的细节
*/
#if((configUSE_NEWLIB_REENTRANT==1)||(configUSE_C_RUNTIME_TLS_SUPPORT==1))
struct_reent
xNewLib_reent
#if(configUSE_TASK_NOTIFICATIONS==1)
#if(configUSE_TASK_NOTIFICATIONS==1)
#if(tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE!=0)
ucDelayAborted
xxx
uint8_t
#if(INCLUDE_xTaskAbortDelay==1)
ulRLAR
ulRBAR
structMPURegionSettings(MPURegionSettings_t)
uint32_t
structMPU_SETTINGS(xMPU_SETTINGS)
ulMAIR0
uint32_t
uint32_t
xRegionsSettings[portTOTAL_NUM_REGIONS]
指向链表下一个节点
指向链表前一个节点
指向链表下一个节点
指向链表前一个节点
临界区嵌套深度
存储每次创建TCB时递增的数字
存储专门供第三方跟踪代码使用的数字
上次分配给任务的优先级‐由优先级继承机制使用
iTaskErrno
xxx
int
#if(configUSE_POSIX_ERRNO==1)
判断是否需要通知前的通知值 ?
if ( pulPreviousNotificationValue != NULL )
YES
NO
获取发送通知前的通知值
* pulPreviousNotificationValue = pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ];
记录发送通知前的任务通知状态
ucOriginalNotifyState = pxTCB ‐> ucNotifyState [ uxIndexToNotify ];
接收通知的TCB中的任务通知状态设置为已收到任务通知态
pxTCB ‐> ucNotifyState [ uxIndexToNotify ]= taskNOTIFICATION_RECEIVED ;
选择条件
switch ( eAction )
模拟事件组:
case eSetBits :
No
Yes
将通知值的某些位置1
pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ]|= ulValue ;
模拟计数型信号量:
case eIncrement :
No
Yes
break ;
将通知值+1
( pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ])++;
break ;
模拟可覆盖队列:
case eSetValueWithOverwrite :
No
Yes
覆写通知值
pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ]= ulValue ;
break ;
模拟不可覆盖队列:
case eSetValueWithoutOverwrite :
No
Yes
写入通知值
pxTCB ‐> ulNotifiedValue [ uxIndexToNotify ]= ulValue ;
break ;
不处于收到任务通知状态?
if ( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
No
Yes
复位返回值(未能写入)
xReturn = pdFAIL ;
不更新通知值:
case eNoAction :
No
Yes
break ;
默认 :
default :
Yes
break ;
任务正在等待此通知
if ( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
No
Yes
将任务从延时/挂起链表中移出
listREMOVE_ITEM (&( pxTCB ‐> xStateListItem ));
将任务插入到就绪链表中
prvAddTaskToReadyList ( pxTCB );
#启用低功耗模式
#if (configUSE_TICKLESS_IDLE != 0 )
No
Yes
重置延时链表下一个任务的解锁时间
prvResetNextTaskUnblockTime ();
此任务优先级高于当前任务优先级
if ( pxTCB ‐> uxPriority > pxCurrentTCB ‐> uxPriority )
No
Yes
悬起PendSV中断,准备进行任务切换
taskYIELD_IF_USING_PREEMPTION ();
退出临界区
taskEXIT_CRITICAL ();
结束返回
return xReturn ;
#define xTaskNotifyGive( xTaskToNotify ) \
xTaskGenericNotify ((xTaskToNotify),(tskDEFAULT_INDEX_TO_NOTIFY),( 0 ), eIncrement ,NULL)
#define xTaskNotifyGiveIndexed( xTaskToNotify , uxIndexToNotify ) \
xTaskGenericNotify ((xTaskToNotify),(uxIndexToNotify),( 0 ), eIncrement ,NULL)
BaseType_t xTaskGenericNotify ( TaskHandle_t xTaskToNotify , /*要通知的任务的句柄*/
UBaseType_t uxIndexToNotify , /*任务的指定通知(任务通知相关数组下标,xTaskNotifyGive()默认为0,使用数组第一个元素当做通知)*/
uint32_t ulValue , /*要传递的通知值*/
eNotifyAction eAction , /*指定通知的动作*/
uint32_t * pulPreviousNotificationValue ) /*指向存储上一个通知值的变量的指针,如果不需要回传上一个通知值,则可以传递NULL*/
功能
用于在任务中向指定任务发送任务通知,并更新对方的任务通知值(加1操作)。
参数
xTaskToNotify
正被通知的RTOS任务的句柄,且该任务的通知值正在递增。
要获取任务句柄,请使用xTaskCreate()创建任务并使用pxCreatedTask参数,或使用返回值创建任务xTaskCreateStatic()并存储该值,或在调用
xTaskGetHandle()中使用任务的名称。
当前执行的RTOS任务的句柄通过以下方式由xTaskGetCurrentTaskHandle()API函数返回。
uxIndexToNotify
目标任务通知值数组中的索引,通知值将发送给该索引。
uxIndexToNotify必须小于configTASK_NOTIFICATION_ARRAY_ENTRIES。xTaskNotifyGive()没有此参数,并且总是向索引0发送通知。
ulValue= 0
用于更新目标任务的通知值。请参阅下面eAction参数的说明。
eAction= eIncrement
指定通知如何更新任务的通知值(如果有的话)。
eAction的有效值如下:
eSetBits‐目标通知值与ulValue按位进行“或”运算。
在这种情况下,xTaskNotifyIndexed()总是返回pdPASS。
eNoAction
目标任务接收事件,但其通知值未更新。在这种情况下,不使用ulValue。
eSetBits
目标任务的通知值使用ulValue按位或运算。例如,如果ulValue设置为0x01,则将在目标任务的通知值中设置位0。同
样,如果ulValue为0x04,则将在目标任务的通知值中设置位2。通过这种方式,RTOS任务通知机制可以用作事件组的轻量
级替代方案。
eIncrement 目标任务的通知值自增1,使得调用xTaskNotify()相当于调用xTaskNotifyGive()。在这种情况下,不使用ulValue。
eSetValueWithOverwrite
目标任务的通知值无条件设置为ulValue。因此,RTOS任务通知机制可用作xQueueOverwrite()的轻量级替代方案。
eSetValueWithoutOrwrite
如果目标任务没有挂起的通知,则其通知值将设置为ulValue。
如果目标任务已经有挂起的通知,则不会更新其通知值,因为这样做会覆盖之前使用的值。在这种情况下,调用
xTaskNotify()失败,返回pdFALSE。
因此,RTOS任务通知机制可在长度为1的队列上用作xQueueSend()在长度为的轻量级替代方案。
pulPreviousNotificationValue= NULL
指向存储上一个通知值的变量的指针,如果不需要回传上一个通知值,则可以传递NULL
返回值
除了eAction被设置为eSetValueWithoutOverwrite且目标任务的通知值因目标任务已有挂起的通知而无法更新之外,在所有情况下均返回pdPASS。
每个任务都有一组“任务通知”(或仅“通知”),每个通知都包含状态和一个32位值。
直达任务通知是直接发送至任务的事件,可以取消阻塞接收任务,并可以选择通过多种方式更新接收任务的某个通知值。
例如,通知可覆盖接收任务的通知值中的一个,或仅设置更多位。
当任务通知用作轻量级且更快的二进制或计数信号量替代方案时,可以使用宏xTaskNotifyGive()。
FreeRTOS信号量通过使用xSemaphoreGive()API函数给出,而xTaskNotifyGive()与其等效,使用接收RTOS任务的一个通知值代替信号量。
xTaskNotifyGive()和xTaskNotifyGiveIndexed()是等效宏——唯一的区别是xTaskNotifyGiveIndexed()可以在始终在数组内任何任务通知上操作,而xTaskNotifyGive()始终在数组索引0处的任务通知上运
行。
当任务通知值用作二进制或等效计数信号量时,则被通知的任务应等待使用ulTaskNotifyTake()API函数的通知,而不是xTaskNotifyWait()API函数。
注意:数组中每个通知都独立运行——任务一次只能阻止数组中的一个通知,并且不会被发送到任何其他数组索引的通知取消阻止。
xTaskNotifyGive()不能从中断服务例程调用。使用vTaskNotifyGiveFromISR()代替。
configUSE_TASK_NOTIFICATIONS必须在FreeRTOSConfig.h中设置为1(或保留为未定义)才能使用这些宏。常量configTASK_NOTIFICATION_ARRAY_ENTRIES设置任务通知的每个任务数组中的索引数量。
向后兼容性信息:
在FreeRTOSV10.4.0之前,每个任务有一个单一的“通知值”,且所有任务通知API函数都在该值上运行。用通知值的数组更换单个通知值需要新的API函数集,该函数集应能在数组内处理。xTaskNotifyGive()
是原始API函数,并且通过始终在数组内索引0处的通知值上运行来保持向后兼容。调用xTaskNotifyGive()等于调用xTaskNotifyGiveIndexed(),其中uxIndexToNotify参数设置为0。
资源评论
weixin_43420126
- 粉丝: 1420
- 资源: 49
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功