Index
In FreeRTOS, task notifications provide a lightweight mechanism for inter-task communication and synchronization, acting as a simpler alternative to semaphores and queues. Each task has its own notification value, which other tasks or ISRs (Interrupt Service Routines) can increment, decrement, or set directly.
Key Features of Task Notifications
- Lightweight: Less overhead than using semaphores or queues.
- Direct-to-task: Notifications are sent directly to a specific task, making them ideal for simple signaling.
- Binary or Counting: Notifications can act as either binary (similar to a binary semaphore) or counting (similar to a counting semaphore).
Example Scenario: Using Task Notifications for Inter-Task Communication
Let’s say we have two tasks:
- Task 1: Simulates sensor data processing.
- Task 2: Notified by Task 1 to perform an action (like toggling an LED) after Task 1 completes processing.
In this example, Task 1 will send a notification to Task 2 after completing its work, and Task 2 will respond when it receives the notification.
Example Code:
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#define LED_PIN 2 // GPIO for LED output
TaskHandle_t xTask2Handle = NULL; // Handle for Task 2
// Task 1: Simulates sensor processing and notifies Task 2
void vTask1(void *pvParameters) {
while (1) {
printf("Task 1: Processing sensor data...\n");
vTaskDelay(pdMS_TO_TICKS(2000)); // Simulate data processing time
// Send notification to Task 2 after processing
printf("Task 1: Notifying Task 2\n");
xTaskNotifyGive(xTask2Handle);
// Delay to simulate periodic sensor processing
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
// Task 2: Waits for notification from Task 1 and toggles LED
void vTask2(void *pvParameters) {
// Configure LED_PIN as output
gpio_pad_select_gpio(LED_PIN);
gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT);
while (1) {
// Wait for notification from Task 1
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// Toggle LED and print message
static int ledState = 0;
ledState = !ledState;
gpio_set_level(LED_PIN, ledState);
printf("Task 2: Received notification, toggling LED\n");
}
}
void app_main() {
// Create Task 2
xTaskCreate(vTask2, "Task 2", 2048, NULL, 1, &xTask2Handle);
// Create Task 1
xTaskCreate(vTask1, "Task 1", 2048, NULL, 1, NULL);
}
Explanation of the Code
- Defining the LED Pin:
LED_PIN
is the GPIO pin connected to an LED, which will be toggled by Task 2.
- Task 1 (Sensor Processing):
- Task 1 simulates sensor data processing, which takes 2 seconds.
- After processing, Task 1 sends a notification to Task 2 using
xTaskNotifyGive(xTask2Handle)
. - It then waits for a second before processing again, simulating periodic sensor reads.
- Task 2 (LED Toggle on Notification):
- Task 2 waits for a notification using
ulTaskNotifyTake()
, which blocks it until a notification is received. - When notified by Task 1, Task 2 toggles the LED and prints a message.
- Task 2 waits for a notification using
- Task Creation in
app_main()
:- Task 2 is created first and assigned a handle (
xTask2Handle
) so that Task 1 can send it notifications. - Task 1 is created afterward and does not need a handle, as it does not need notifications from other tasks.
- Task 2 is created first and assigned a handle (
Explanation of Task Notification Functions
xTaskNotifyGive()
:- Sends a notification to a specified task. Here, Task 1 uses
xTaskNotifyGive()
to notify Task 2.
- Sends a notification to a specified task. Here, Task 1 uses
ulTaskNotifyTake()
:- Blocks the calling task (in this case, Task 2) until it receives a notification.
- The first parameter (
pdTRUE
) clears the notification value after receiving it, treating this as a binary notification. - The second parameter (
portMAX_DELAY
) indicates that the task will wait indefinitely for a notification.
Output Explanation
When running this code, you should see:
- Task 1 repeatedly printing:
Task 1: Processing sensor data...
Task 1: Notifying Task 2
2. Task 2 responding each time with:
Task 2: Received notification, toggling LED
The LED connected to LED_PIN
will toggle each time Task 2 receives a notification from Task 1.
Summary
- Task Notifications: Provide simple, efficient inter-task signaling.
xTaskNotifyGive()
: Used by Task 1 to notify Task 2 upon completing a task.ulTaskNotifyTake()
: Allows Task 2 to wait for a notification and toggle the LED upon receiving it.
This approach is efficient for scenarios requiring lightweight task synchronization without needing the complexity of semaphores or queues.