Task notifications and queues are ways tasks in FreeRTOS communicate. Understanding their speed helps you pick the best one for your program.
Task notification vs queue performance in FreeRTOS
/* Task Notification Example */ void vTaskFunction(void *pvParameters) { uint32_t ulNotificationValue; for (;;) { /* Wait for notification */ xTaskNotifyWait(0x00, 0xffffffff, &ulNotificationValue, portMAX_DELAY); /* Process notification value */ } } /* Queue Example */ QueueHandle_t xQueue; void vSenderTask(void *pvParameters) { int dataToSend = 100; for (;;) { xQueueSend(xQueue, &dataToSend, portMAX_DELAY); } } void vReceiverTask(void *pvParameters) { int receivedData; for (;;) { xQueueReceive(xQueue, &receivedData, portMAX_DELAY); /* Process receivedData */ } }
Task notifications are like fast signals with optional 32-bit data.
Queues can hold multiple items and are more flexible but slower.
/* Empty queue scenario */ QueueHandle_t xQueue = xQueueCreate(5, sizeof(int)); int receivedValue; if (xQueueReceive(xQueue, &receivedValue, 0) == pdPASS) { // Got data } else { // Queue empty }
/* Single element notification */ uint32_t notificationValue = 0; xTaskNotifyGive(taskHandle); if (xTaskNotifyWait(0, 0xffffffff, ¬ificationValue, portMAX_DELAY) == pdTRUE) { // Notification received }
/* Notification at task start */ // Task waits indefinitely for notification before proceeding xTaskNotifyWait(0, 0xffffffff, NULL, portMAX_DELAY);
/* Queue full scenario */ QueueHandle_t xQueue = xQueueCreate(2, sizeof(int)); int data = 10; xQueueSend(xQueue, &data, 0); xQueueSend(xQueue, &data, 0); BaseType_t result = xQueueSend(xQueue, &data, 0); // result will be errQUEUE_FULL
This program creates two tasks: one waits for a task notification, the other waits for data from a queue. It sends a notification and queue data, then prints what each task receives.
#include "FreeRTOS.h" #include "task.h" #include "queue.h" #include <stdio.h> QueueHandle_t xQueue; TaskHandle_t xTaskHandle; void vTaskNotificationReceiver(void *pvParameters) { uint32_t ulNotificationValue; printf("TaskNotificationReceiver: Waiting for notification...\n"); xTaskNotifyWait(0x00, 0xffffffff, &ulNotificationValue, portMAX_DELAY); printf("TaskNotificationReceiver: Received notification with value %lu\n", ulNotificationValue); vTaskDelete(NULL); } void vQueueReceiver(void *pvParameters) { int receivedValue; printf("QueueReceiver: Waiting for queue data...\n"); xQueueReceive(xQueue, &receivedValue, portMAX_DELAY); printf("QueueReceiver: Received queue data %d\n", receivedValue); vTaskDelete(NULL); } int main(void) { xQueue = xQueueCreate(1, sizeof(int)); if (xQueue == NULL) { printf("Failed to create queue\n"); return 1; } xTaskCreate(vTaskNotificationReceiver, "NotifyReceiver", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle); xTaskCreate(vQueueReceiver, "QueueReceiver", configMINIMAL_STACK_SIZE, NULL, 1, NULL); printf("Sending notification to task...\n"); xTaskNotifyGive(xTaskHandle); int dataToSend = 42; printf("Sending data to queue...\n"); xQueueSend(xQueue, &dataToSend, 0); vTaskStartScheduler(); // Should never reach here return 0; }
Task notifications are faster because they avoid the overhead of queues and copying data.
Queues use more memory and CPU time but can hold multiple messages and larger data.
Common mistake: Using task notifications for large or multiple messages instead of queues.
Use task notifications for simple signaling or small data; use queues for complex or multiple messages.
Task notifications are lightweight and fast for simple signals.
Queues are flexible and can hold multiple or larger messages but are slower.
Choose based on your data size and communication needs.