其他分享
首页 > 其他分享> > FreeRTOS任务通知

FreeRTOS任务通知

作者:互联网

从FreeRTOSv8.2.0版本开始,FreeRTOS新增了任务通知(Task Notifictions)这个功能,可以使用任务通知来代替信号量、消息队列、事件标志组等这些东西。使用任务通知的话效率会更高。

一、任务通知简介

任务通知在FreeRTOS中是一个可选的功能,要使用任务通知的话就需要将宏configUSE_TASK_NOTIFICATIONS定义为1。FreeRTOS的每个任务都有一个32位的通知值,任务控制块中的成员变量ulNotifiedValue就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任务的任务通知值,任务通知可以通过如下方法更新接收任务的通知值:

合理、灵活的使用上面这些更改任务通知值的方法可以在一些场合中替代队列、二值信号量、计数型信号量和事件标志组。使用任务通知来实现二值信号量功能的时候,解除任务阻塞的时间比直接使用二值信号量要快45%,并且使用的RAM更少!任务通知的发送使用函数xTaskNotify()或者xTaskNotifyGive() (还有此函数的中断版本)来完成,这个通知值会一直被保存着,直到接收任务调用函数xTaskNotifyWait()或者ulTaskNotifyTake()来获取这个通知值。假如接收任务因为等待任务通知而阻塞的话那么在接收到任务通知以后就会解除阻塞态。任务通知虽然可以提高速度,并且减少RAM的使用,但是任务通知也是有使用限制的:

二、任务发送通知相关API函数详解

1、任务通知发送函数
任务通知发送函数共有6个,如下表所示:

函数描述
xTaskNotify()发送通知,带有通知值并且不保留接收任务原通知值,用在任务中。
xTaskNotifyFromISR()发送通知,函数xTaskNotify()的中断版本。
xTaskNotifyGive()发送通知,不带通知值并且不保留接收任务的通知值,此函数会将接收任务的通知值加一,用于任务中。
vTaskNotifyGiveFromISR()发送通知,函数xTaskNotifyGive()的中断版本。
xTaskNotifyAndQuery()发送通知,带有通知值并且保留接收任务的原通知值,用在任务中。
XTaskNotiryAndQueryFromISR()发送通知,函数xTaskNotifyAndQuery()的中断版本,用在中断服务函数中。
BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify,
uint32_t ulValue
eNotifyAction eAction)
参数描述
xTaskToNotify任务句柄,指定任务通知是发送给哪个任务的。
ulValue任务通知值。
eAction任务通知更新的方法,eNotifyAction是个枚举类型,在文件task.h中有定义
返回值pdFAIL:当参数eAction设置为eSetValueWithoutOverwrite的时候,如果任务通知值没有更新成功就返回pdFAIL。pdPASS:eAction设置为其他选项的时候统一返回pdPASS。

注意:eActiond 取值

typedef enum
{
eNoAction=0,
eSetBits,//更新指定的bit
elncrement,//通知值加一
eSetValueWithOverwrite,//覆写的方式更新通知值
eSetValueWithoutOverwrite//不覆写通知值
}eNotifyAction;

此参数可以选择枚举类型中的任意一个,不同的应用环境其选择也不同。

BaseType_t xTaskNotifyFromlSR(TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
BaseType_t*pxHigherPriorityTaskWoken);
参数描述
xTaskToNotify任务句柄,指定任务通知是发送给哪个任务的。
ulValue任务通知值。
eAction任务通知更新的方法。
pxHigherPriorityTaskWoken记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值pdFAIL:当参数eAction设置为eSetValueWithoutOverwrite的时候,如果任务通知值没有更新成功就返回pdFAIL。pdPASS:eAction设置为其他选项的时候统一返回pdPASS。
BaseType_txTaskNotifyGive(TaskHandle_t xTaskToNotify);
参数描述
xTaskToNotify任务句柄,指定任务通知是发送给哪个任务的。
返回值pdPASS:此函数只会返回pdPASS。
void vTaskNotifyGiveFromlSR(TaskHandle_t xTaskHandle,
BaseType_t* pxHigherPriorityTaskWoken);
参数描述
xTaskToNotify任务句柄,指定任务通知是发送给哪个任务的。
pxHigherPriorityTaskWoken记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。
BaseType_txTaskNotifyAndQuery(TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t*pulPreviousNotificationValue);
参数描述
xTaskToNotify任务句柄,指定任务通知是发送给哪个任务的。
ulValue任务通知值。
eAction任务通知更新的方法。
pulPreviousNotificationValue用来保存更新前的任务通知值。
返回值pdFAIL:当参数eAction设置为eSetValueWithoutOverwrite的时候,如果任务通知值没有更新成功就返回pdFAIL。pdPASS:eAction设置为其他选项的时候统一返回pdPASS。
BaseType_t xTaskNotifyAndQueryFromISR(TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t* pulPreviousNotificationValue,
BaseType_t*pxHigherPriorityTaskWoken);
参数描述
xTaskToNotify任务句柄,指定任务通知是发送给哪个任务的。
ulValue任务通知值。
eAction任务通知更新的方法。
pulPreviousNotificationValue用来保存更新前的任务通知值。
pxHigherPriorityTaskWoken记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值pdFAIL:当参数eAction设置为eSetValueWithoutOverwrite的时候,如果任务通知值没有更新成功就返回pdFAIL。pdPASS:eAction设置为其他选项的时候统一返回pdPASS。

2、任务通知通用发送函数详解

BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
{
TCB_t * pxTCB;
BaseType_t xReturn = pdPASS;
uint8_t ucOriginalNotifyState;

	configASSERT( xTaskToNotify );
	pxTCB = ( TCB_t * ) xTaskToNotify;

	taskENTER_CRITICAL();
	{
		if( pulPreviousNotificationValue != NULL )(1)
		{
			*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;(2)
		}

		ucOriginalNotifyState = pxTCB->ucNotifyState;(3)

		pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;(4)

		switch( eAction )
		{
			case eSetBits	:(5)
				pxTCB->ulNotifiedValue |= ulValue;
				break;

			case eIncrement	:(6)
				( pxTCB->ulNotifiedValue )++;
				break;

			case eSetValueWithOverwrite	:(7)
				pxTCB->ulNotifiedValue = ulValue;
				break;

			case eSetValueWithoutOverwrite :(8)
				if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
				{
					pxTCB->ulNotifiedValue = ulValue;
				}
				else
				{
					/* The value could not be written to the task. */
					xReturn = pdFAIL;
				}
				break;

			case eNoAction:
				/* The task is being notified without its notify value being
				updated. */
				break;
		}

		traceTASK_NOTIFY();
//如果任务因为等待任务通知而进入阻塞态的话就解除阻塞态
		if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )(9)
		{
			( void ) uxListRemove( &( pxTCB->xStateListItem ) );(10)
			prvAddTaskToReadyList( pxTCB );(11)
//省略条件编译
			if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )(12)
			{
				/* 解除阻塞的任务优先级比当前运行的优先级高,所以需要任务切换。 */
				taskYIELD_IF_USING_PREEMPTION();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	taskEXIT_CRITICAL();

	return xReturn;(13)
}
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
{
TCB_t * pxTCB;
uint8_t ucOriginalNotifyState;
BaseType_t xReturn = pdPASS;
UBaseType_t uxSavedInterruptStatus;

	configASSERT( xTaskToNotify );
	portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
	pxTCB = ( TCB_t * ) xTaskToNotify;
	uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
	{
		if( pulPreviousNotificationValue != NULL )(1)
		{
			*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
		}

		ucOriginalNotifyState = pxTCB->ucNotifyState;(2)
		pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;(3)

		switch( eAction )(4)
		{
			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
				{
					/* The value could not be written to the task. */
					xReturn = pdFAIL;
				}
				break;

			case eNoAction :
				/* The task is being notified without its notify value being
				updated. */
				break;
		}

		traceTASK_NOTIFY_FROM_ISR();

//如果任务因为等待任务通知而进入阻塞态的话就需要解除阻塞
		if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )(5)
		{
			/* The task should not have been on an event list. */
			configASSERT( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL );

			if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )(6)
			{
				( void ) uxListRemove( &( pxTCB->xStateListItem ) );
				prvAddTaskToReadyList( pxTCB );
			}
			else(7)
			{
				vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
			}
/*解除阻塞的任务优先级比当前运行任务的优先级高,所以需要标记在退出中断服务函数的时候需要任务切换*/
			if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )(8)
			{
				if( pxHigherPriorityTaskWoken != NULL )
				{
					*pxHigherPriorityTaskWoken = pdTRUE;
				}
				else
				{
					xYieldPending = pdTRUE;
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
	}
	portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

	return xReturn;
}

三、任务获取通知相关API函数详解

1、获取任务通知
获取任务通知的函数有两个,如下表所示:

函数描述
ulTaskNotifyTake()获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。当任务通知用作二值信号量或者计数信号量的时候使用此函数来获取信号量。
xTaskNotifyWait()等待任务通知,比ulTaskNotifyTak()更为强大,全功能版任务通知获取函数。
uint32_tulTaskNotifyTake(BaseType_t xClearCountOnExit,
TickType_t xTicksToWait);
参数描述
XClearCountOnExit参数为pdFALSE的话在退出函数ulTaskNotifyTake()的时候任务通知值减一,类似计数型信号量。当此参数为pdTRUE的话在退出函数的时候任务任务通知值清零,类似二值信号量。
xTickToWait阻塞时间。
返回值任何值:任务通知值减少或者清零之前的值

此函数在文件task.c中定义,函数源码如下:

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
{
uint32_t ulReturn;

	taskENTER_CRITICAL();
	{
		if( pxCurrentTCB->ulNotifiedValue == 0UL )(1)
		{
			pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;(2)

			if( xTicksToWait > ( TickType_t ) 0 )(3)
			{
				prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
				traceTASK_NOTIFY_TAKE_BLOCK();
				portYIELD_WITHIN_API();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	taskEXIT_CRITICAL();

	taskENTER_CRITICAL();
	{
		traceTASK_NOTIFY_TAKE();
		ulReturn = pxCurrentTCB->ulNotifiedValue;(4)

		if( ulReturn != 0UL )(5)
		{
			if( xClearCountOnExit != pdFALSE )(6)
			{
				pxCurrentTCB->ulNotifiedValue = 0UL;
			}
			else
			{
				pxCurrentTCB->ulNotifiedValue = ulReturn - 1;(7)
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;(8)
	}
	taskEXIT_CRITICAL();
	return ulReturn;
}
BaseType_txTaskNotifyWait(uint32_tulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t*pulNotificationValue,
TickType_t xTicksToWait);
参数描述
ulBitsToClearOnEntry当没有接收到任务通知的时候将任务通知值与此参数的取反值进行按位与运算,当此参数为0xffffffff或者ULONG_MAX的时候就会将任务通知值清零。
ulBitsToClearOnExit如果接收到了任务通知,在做完相应的处理退出函数之前将任务通知值与此参数的取反值进行按位与运算,当此参数为0xffffffff或者ULONG_MAX的时候就会将任务通知值清零。
pulNotificationValue此参数用来保存任务通知值。
xTickToWait阻塞时间。
返回值pdTRUE:获取到了任务通知。pdFALSE:任务通知获取失败。

此函数在文件task.c有定义,源代码为:


BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
	{
	BaseType_t xReturn;

		taskENTER_CRITICAL();
		{
			if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )(1)
			{
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;(2)
				pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;(3)

				if( xTicksToWait > ( TickType_t ) 0 )(4)
				{
					prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
					traceTASK_NOTIFY_WAIT_BLOCK();

					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		taskEXIT_CRITICAL();

		taskENTER_CRITICAL();
		{
			traceTASK_NOTIFY_WAIT();

			if( pulNotificationValue != NULL )(5)
			{
				*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
			}
			if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )(6)
			{
				xReturn = pdFALSE;
			}
			else
			{
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;(7)
				xReturn = pdTRUE;
			}

			pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;(8)
		}
		taskEXIT_CRITICAL();

		return xReturn;
	}

标签:eAction,函数,FreeRTOS,通知,pxTCB,任务,uint32
来源: https://blog.csdn.net/weixin_44502943/article/details/121021103