1. Concept of Task Notifications
Task notification functionality was introduced in FreeRTOS starting from version V8.2.0. Each task has a 32-bit notification value, and task notifications can replace binary semaphores, counting semaphores, event groups, and even queues of length 1 (used to pass a 32-bit integer or pointer value). Compared to traditional communication methods, task notifications are more efficient, save memory space, and do not require the creation of additional communication objects (such as semaphores or queues).
2. Advantages of Task Notifications
- Performance Advantage: Using task notifications to unblock tasks is about 45% faster than using traditional communication methods like semaphores.
- Memory Savings: There is no need to create additional semaphores, queues, etc., for task notifications, saving RAM memory space.
- Simplified Design: The use of task notifications is simpler and more direct, without the need to create complex communication objects.
3. Using Task Notifications
To use task notifications, you need to set the macro <span>configUSE_TASK_NOTIFICATIONS</span>
to 1 in the <span>FreeRTOSConfig.h</span>
file. Typically, this macro is enabled by default.
There are several ways to send task notifications:
- Send notification without overwriting unread notification values
-
If the task already has unread notification values, new notifications will not overwrite the old notification values.
-
Regardless of whether the task has unread notification values, the new notification value will directly overwrite the old value.
-
You can use the notification value as an event group by setting certain bits of the notification value.
-
You can increment the notification value to use it as a counting semaphore.
4. Task Notification API Functions
1. xTaskNotify()
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction );
- xTaskToNotify: The task handle to notify.
- ulValue: The notification value.
- eAction: Specifies the notification method, which can be one of the following:
<span>eSetBits: Set certain bits of the notification value (can use the notification as an event group).</span>
<span>eIncrement: Increment the notification value (can use the notification as a counting semaphore).</span>
<span>eSetValueWithOverwrite: Directly overwrite the notification value.</span>
<span>eSetValueWithoutOverwrite: Do not overwrite if there are unread notification values.</span>
2. xTaskNotifyGive()
void xTaskNotifyGive( TaskHandle_t xTaskToNotify );
- xTaskToNotify: The task handle to notify. This function is a simplified version of
<span>xTaskNotify()</span>
used to increment the notification value.
3. ulTaskNotifyTake()
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait );
- xClearCountOnExit: Specifies whether to clear the notification value upon exit.
- xTicksToWait: The time to wait for the notification.
4. xTaskNotifyWait()
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait );
- ulBitsToClearOnEntry: Certain bits of the notification value to clear upon entering the function.
- ulBitsToClearOnExit: Certain bits of the notification value to clear upon exiting the function.
- pulNotificationValue: Pointer to the notification value.
- xTicksToWait: The time to wait for the notification.
5. Example of Using Task Notifications
Below is a simple example of using task notifications, demonstrating how to use task notifications to replace semaphores.
// Task A: Wait for Task B to send a notificationvoid TaskA(void *pvParameters) { uint32_t ulNotificationValue;
for (;;) { // Wait for notification, do not clear bits, and specify maximum wait time ulNotificationValue = ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
if (ulNotificationValue > 0) { // Perform action after receiving notification } }}
// Task B: Send notification to Task Avoid TaskB(void *pvParameters) { for (;;) { // Perform some operations in Task B
// Send notification to Task A, using increment notification value method xTaskNotifyGive(xTaskAHandle);
// Wait for the next notification vTaskDelay(pdMS_TO_TICKS(1000)); }}
6. Limitations of Task Notifications
Although task notifications have significant advantages, they also have the following limitations:
- Single-task Reception: Task notifications can only be received by one specified task and cannot be used for synchronization of multiple tasks.
- Non-blocking Sending: The task sending the notification will not be blocked due to a failed send.
7. Conclusion
Task notifications provide an efficient and flexible inter-task communication method for FreeRTOS, which can replace traditional mechanisms like semaphores and queues. In scenarios requiring efficient communication involving only a single task, task notifications are an ideal choice. However, for scenarios requiring synchronization of multiple tasks, traditional IPC mechanisms still have their unique advantages.