FreeRTOS_Direct Task Notifications

Directory title

  • 1 Introduction
  • 2. TCB members
  • 3. Task notification API
    • 3.1, simplified version
      • 3.1.1, xTaskNotifyGive()
      • 3.1.2, ulTaskNotifyTake()
    • 3.2. Professional version
      • 3.2.1, xTaskNotify()
      • 3.2.2, xTaskNotifyWait()

1. Introduction

When we use queues, semaphores, and event groups, we need to create corresponding structures in advance, and the two parties communicate through the intermediate structures.

When using task notification, one task is allowed to directly notify another task to perform operations without going through an intermediate structure. The task notification structure is automatically created by the FreeRTOS kernel when the task is created, and will be directly associated with the corresponding task handle. (The TCB structure includes two members: an 8-bit notification status variable; a 32-bit notification value variable)

  • ISR can only send task notifications but cannot receive task notifications.
  • Notified data can only be used exclusively by the corresponding task.
  • The sender cannot enter the blocking state, and the receiver can block and wait.

2. TCB members

There are two members in the TCB (Task Control Block) structure:

  • uint8_t type, used to represent notification status
  • uint32_t type, used to represent notification values
typedef struct tskTaskControlBlock
{<!-- -->
     ···
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
    ···
} tskTCB;

The notification status has the following three values:

  • taskNOT_WAITING_NOTIFICATION indicates that the receiving task is not waiting for any notification
  • taskWAITING_NOTIFICATION indicates that the receiving task is currently waiting for notifications
  • taskNOTIFICATION_RECEIVED indicates that the receiving task has received the notification.

Notification values can be of many types:

  • count value
  • Bits (similar to event groups)
  • any value

Therefore, task notifications can be used instead of semaphores and event groups.

3. Task notification API

Task notification also has two sets of functions, a simplified version and a professional version.

Simplified version Professional version
Send notification xTaskNotifyGive/ vTaskNotifyGiveFromISR xTaskNotify /xTaskNotifyFromISR
Wait for notification ulTaskNotifyTake xTaskNotifyWait

3.1, simplified version

3.1.1, xTaskNotifyGive()

Send notification:

  • Increase the notification value by one
  • Change the notification status of the corresponding task to taskNOTIFICATION_RECEIVED, indicating that the data has been received.
/*for tasks*/
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
/*ISR use*/
void vTaskNotifyGiveFromISR(
TaskHandle_t xTaskHandle,
BaseType_t *pxHigherPriorityTaskWoken );

Parameters Description
xTaskToNotify Task handle, indicating which task is being notified
pxHigherPriorityTaskWoken The notified task may be in a blocking state. After this function sends a notification, it switches it from the blocking state to the ready state. If the priority of the awakened task is higher than the priority of the current task, “*pxHigherPriorityTaskWoken” is set to pdTRUE, which means that task switching is required before the interrupt returns.
Return value xTaskNotifyGive returns pdPASS; vTaskNotifyGiveFromISR has no return value

3.1.2, ulTaskNotifyTake()

Receive notifications:

  • If the notification value is equal to 0, you can enter blocking; if the notification value is greater than 0, you can enter the ready state.
  • Before the function returns, you can decrement the notification value by one or clear it to zero.
  • Equivalent to a binary, counting semaphore.
uint32_t ulTaskNotifyTake(
BaseType_t xClearCountOnExit,
TickType_t xTicksToWait );
Parameter Description
xClearCountOnExit pdTRUE: Clear the notification value to zero before the function returns; pdFALSE, if the notification value is greater than 0, reduce it by one
xTicksToWait If the notification cannot be obtained, You can enter the blocking state, xTicksToWait represents the blocking time. If it is set to 0, it will return directly; if it is set to portMAX_DELAY, it will wait until there is a notification.
Return value The function returns the notification value before it is cleared or decremented by one. If xTicksToWait is non-0, the return value has two situations: 1. Greater than 0: the notification value is increased before timeout 2. Equal to 0: no other task has increased the notification value, and the final timeout returns 0

3.2, Professional Edition

The professional version of the notification function xTaskNotify can achieve more functions:

  • Let the notification value of the receiving task be increased by one: then xTaskNotify() is equivalent to xTaskNotifyGive()
  • Set a certain bit or certain bits of the notification value of the receiving task. This is a lightweight and more efficient event group.
  • Write a new value to the notification value of the receiving task: the writing is successful only after the last notification value is read. This is a lightweight, length-1 queue
  • Overwrite the notification value of the receiving task with a new value: the overwriting is successful regardless of whether the last notification value was read. Similar to the xQueueOverwrite() function, this is a lightweight mailbox.

Receive notification function:

  • You can make the task wait (you can add a timeout) until the task status is “pending” (that is, there is data)
  • You can also clear the specified bit of the notification value when the function enters or exits.

3.2.1, xTaskNotify()

Send notification function:

/*Used in tasks*/
BaseType_t xTaskNotify(
TaskHandle_t xTaskToNotify,
uint32_tulValue,
 eNotifyAction eAction );
/*Used in ISR*/
BaseType_t xTaskNotifyFromISR(
TaskHandle_t xTaskToNotify,
uint32_tulValue,
eNotifyAction eAction,
BaseType_t *pxHigherPriorityTaskWoken );
Parameters Description
xTaskToNotify Task handle, indicating which task to send notification
ulValue The use of parameter ulValue is determined by eAction
eAction See table below
pxHigherPriorityTaskWoken Once pxHigherPriorityTaskWoken is set to pdTRUE, the FreeRTOS kernel will respond based on the task being notified. The priority is context switched with the priority of other tasks, giving control to the awakened high-priority task. This can ensure that high-priority tasks run as quickly as possible and improve the responsiveness and real-time performance of the system
Return value pdPASS: Success

eAction parameter description:

eAction value Description
eNoAction Only the update notification status is “pending”, and ulValue is not used. This option is equivalent to a lightweight, more efficient binary semaphore.
eSetBits Notification value = original notification value
eIncrement Notification value = original notification value + 1, ulValue is not used. Equivalent to lightweight, more efficient binary semaphores and counting semaphores. Equivalent to the **xTaskNotifyGive()** function.
eSetValueWithoutOverwrite Does not overwrite. If the notification status is “pending” (indicating that there is unread data), this call to xTaskNotify will do nothing and return pdFAIL. If the notification status is not “pending” (meaning there is no new data), then: notification value = ulValue.
eSetValueWithOverwrite Overwrite. However, regardless of whether the notification status is “pendng”, notification value = ulValue.

3.2.2, xTaskNotifyWait()

Receive notification function:

BaseType_t xTaskNotifyWait(
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
Parameter Description
ulBitsToClearOnEntry Before waiting for an event to occur, specific bits of the old notification value need to be cleared. The clearing operation will only be performed when the notification status is not “pending”. If the incoming value is 0x01, it means that bit0 of the notification value is to be cleared. If the incoming value is 0xffffffff or ULONG_MAX, it means that all bits are to be cleared, that is, the notification value is set to 0
ulBitsToClearOnExit Before the function exits, if not When exiting because of timeout, but exiting because data is obtained: notification value = notification value & amp; ~(ulBitsToClearOnExit). The notification value is assigned to “*pulNotificationValue” before clearing certain bits. For example, entering 0x03 means clearing bit0 and bit1 of the notification value; passing in 0xffffffff, which is ULONG_MAX, means clearing all bits, that is, setting the value to 0
pulNotificationValue is used to retrieve the notification value. When the function exits, assign the notification value to “*pulNotificationValue” before clearing it using ulBitsToClearOnExit. If you do not need to retrieve the notification value, you can set it to NULL
xTicksToWait The timeout for the task to enter the blocking state, which is waiting for the notification state to change to ” pending”. 0: No waiting, return immediately; portMAX_DELAY: Wait until the notification status changes to “pending”; Other values: Tick Count, you can use *pdMS_TO_TICKS()* to convert ms to Tick Count
Return value pdPASS: Success This means that xTaskNotifyWait successfully obtained the notification: pdFAIL: No notification was received.