FreeRTOS任务通知

任务通知可以替代二进制信号量、计数信号量、事件组,可以替代长度为1的队列(可以保存一个32位整数或指针值),并且任务通知速度更快、使用的RAM更少。

 

 

先看一下任务TCB

/* 任务TCB */
typedef struct tskTaskControlBlock
{
    volatile StackType_t *pxTopOfStack;		/* 栈顶地址 */

    ListItem_t xStateListItem;			/* 状态列表项:运行、就绪、挂起、阻塞 */
    ListItem_t xEventListItem;			/* 事件列表项 */
    UBaseType_t uxPriority;			/* 优先级 */
    StackType_t *pxStack;			/* 栈指针 */
    char pcTaskName[configMAX_TASK_NAME_LEN];	/* 任务名 */

    ......

#if (configUSE_MUTEXES == 1)
    UBaseType_t uxBasePriority;		        /* 任务基础优先级 */
    UBaseType_t uxMutexesHeld;		        /* 互斥锁持有数量 */
#endif

    ......

#if (configUSE_TASK_NOTIFICATIONS == 1)
    volatile uint32_t ulNotifiedValue;	        /* 任务通知值 */
    volatile uint8_t ucNotifyState;             /* 任务通知状态 */
#endif

    ......
}tskTCB;
typedef tskTCB TCB_t;

任务通知有三种状态:taskNOT_WAITING_NOTIFICATION(非等待)、taskWAITING_NOTIFICATION(等待态)、taskNOTIFICATION_RECEIVED(接收态)

#define taskNOT_WAITING_NOTIFICATION	((uint8_t)0)
#define taskWAITING_NOTIFICATION	((uint8_t)1)
#define taskNOTIFICATION_RECEIVED	((uint8_t)2)

 

 

在任务初始化的时候,初始化任务通知值和任务通知状态

/* 初始化新任务TCB */
static void prvInitialiseNewTask(TaskFunction_t pxTaskCode, const char *const pcName, const uint32_t ulStackDepth, 
                                 void *const pvParameters, UBaseType_t uxPriority, TaskHandle_t *const pxCreatedTask, 
                                 TCB_t *pxNewTCB, const MemoryRegion_t *const xRegions)
{
	......

	#if (configUSE_TASK_NOTIFICATIONS == 1)
	{
		/* 任务通知值初始化为0 */
		pxNewTCB->ulNotifiedValue = 0;
		/* 任务通知状态初始化为不等待 */
		pxNewTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
	}
	#endif

	......
}

 

 

发送任务通知

任务通知有四种通信方式:任务通知相关位置位、任务通知值加一、设置任务通知值(覆盖型)、设置任务通知值(非覆盖型)

/* 发送任务通知 */
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 = xTaskToNotify;

	/* 进入临界区 */
	taskENTER_CRITICAL();
	{
		/* 保存之前的任务通知值 */
		if(pulPreviousNotificationValue != NULL)
		{
			*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
		}
		/* 原来的任务通知状态 */
		ucOriginalNotifyState = pxTCB->ucNotifyState;
		
		/* 将任务通知值状态设置为可以接收态 */
		pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;

		/* 任务通知操作方式 */
		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;

			default:
				configASSERT(pxTCB->ulNotifiedValue == ~0UL);
				break;
		}

		traceTASK_NOTIFY();

		/* 任务原先处于等待态 */
		if(ucOriginalNotifyState == taskWAITING_NOTIFICATION)
		{
			/* 将任务从延时列表中移除 */
			(void)uxListRemove(&(pxTCB->xStateListItem));
			/* 将任务重新插入就绪列表 */
			prvAddTaskToReadyList(pxTCB);

			configASSERT(listLIST_ITEM_CONTAINER(&(pxTCB->xEventListItem)) == NULL);

			#if (configUSE_TICKLESS_IDLE != 0)
			{
				prvResetNextTaskUnblockTime();
			}
			#endif

			/* 任务优先级高于当前任务优先级 */
			if(pxTCB->uxPriority > pxCurrentTCB->uxPriority)
			{
				/* 请求切换任务 */
				taskYIELD_IF_USING_PREEMPTION();
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	/* 退出临界区 */
	taskEXIT_CRITICAL();

	return xReturn;
}

 

 

接收任务通知值

进入之前先将ulBitsToClearOnEntry指定的任务通知值相关位清空,退出之前将ulBitsToClearOnExit指定的任务通知值相关位清空。

/* 接收任务通知值 */
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)
		{
			/* 在进入的时候将相关位清0 */
			pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;

			/* 将任务通知状态设置为等待态 */
			pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

			/* 等待时间大于0 */
			if(xTicksToWait > (TickType_t)0)
			{
				/* 将任务挂接到延时列表 */
				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)
		{
			*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
		}

		/* 任务通知状态不为可以接收态,说明超时 */
		if(pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED)
		{
			xReturn = pdFALSE;
		}
		/* 说明成功接收到通知值 */
		else
		{
			/* 退出之前清除相关位 */
			pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
			xReturn = pdTRUE;
		}

		/* 将任务通知状态设置为非等待态 */
		pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
	}
	/* 退出临界区 */
	taskEXIT_CRITICAL();

	return xReturn;
}

 

 

任务通知值减一

ulBitsToClearOnExit为真则在退出之前将任务通知值清空,为假则在退出之前将任务通知值减一。

/* 接收任务通知(减一或清零) */
uint32_t ulTaskNotifyTake(BaseType_t xClearCountOnExit, TickType_t xTicksToWait)
{
	uint32_t ulReturn;

	/* 进入临界区 */
	taskENTER_CRITICAL();
	{
		/* 当前任务通知值为0 */
		if(pxCurrentTCB->ulNotifiedValue == 0UL)
		{
			/* 任务通知设为等待态 */
			pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

			/* 等待时间大于0 */
			if(xTicksToWait > (TickType_t)0)
			{
				/* 将当前任务挂接到延时列表 */
				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;

		/* 任务通知值不为0 */
		if(ulReturn != 0UL)
		{
			/* 在退出之前将任务通知值清除 */
			if(xClearCountOnExit != pdFALSE)
			{
				pxCurrentTCB->ulNotifiedValue = 0UL;
			}
			/* 将任务通知值减1 */
			else
			{
				pxCurrentTCB->ulNotifiedValue = ulReturn - (uint32_t)1;
			}
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		/* 将任务通知状态设置为非等待态 */
		pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
	}
	/* 退出临界区 */
	taskEXIT_CRITICAL();

	return ulReturn;
}

 

你可能感兴趣的:(FreeRTOS)