This pattern helps a program quickly tell a task that something important happened in an interrupt. It avoids waiting and keeps the program fast and responsive.
ISR-to-task notification pattern in FreeRTOS
void ISR_Handler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(TaskHandle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void Task(void *pvParameters) {
for(;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// Handle event
}
}vTaskNotifyGiveFromISR() sends a notification from the interrupt to the task.
ulTaskNotifyTake() waits in the task until the notification arrives.
void ISR_Handler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(TaskHandle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}void Task(void *pvParameters) {
for(;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// Process event here
}
}This program creates a task that waits for notifications from an ISR. When the ISR runs, it notifies the task, which then prints a message.
#include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include <stdio.h> TaskHandle_t TaskHandle = NULL; void ISR_Handler(void) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; vTaskNotifyGiveFromISR(TaskHandle, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void Task(void *pvParameters) { for(;;) { ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // Simulate handling event printf("Task notified by ISR\n"); } } int main(void) { xTaskCreate(Task, "Task", configMINIMAL_STACK_SIZE, NULL, 1, &TaskHandle); vTaskStartScheduler(); return 0; }
Always use portYIELD_FROM_ISR() to switch to the task immediately if it has higher priority.
Make sure the task handle is valid before using it in the ISR.
Notifications are faster and use less memory than semaphores or queues for simple signaling.
The ISR-to-task notification pattern lets interrupts quickly tell tasks to run.
Use vTaskNotifyGiveFromISR() in the ISR and ulTaskNotifyTake() in the task.
This method is efficient and keeps your program responsive.
Practice
Solution
Step 1: Understand ISR and task roles
ISRs handle hardware events quickly, tasks do longer processing.Step 2: Identify notification purpose
The pattern lets ISR tell a task to run without delay.Final Answer:
To allow an interrupt to quickly notify a task to run -> Option AQuick Check:
ISR notifies task [OK]
- Thinking ISR creates tasks
- Believing tasks pause interrupts
- Confusing disabling interrupts with notifications
Solution
Step 1: Identify ISR notification function
Inside ISR, use vTaskNotifyGiveFromISR() to notify tasks.Step 2: Differentiate task functions
ulTaskNotifyTake() is used in tasks, not ISRs.Final Answer:
vTaskNotifyGiveFromISR() -> Option AQuick Check:
Notify from ISR = vTaskNotifyGiveFromISR() [OK]
- Using ulTaskNotifyTake() inside ISR
- Calling xTaskCreate() in ISR
- Using vTaskDelay() inside ISR
void ISR_Handler() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(taskHandle, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void TaskFunction(void *pvParameters) {
for(;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
printf("Task notified!\n");
}
}Solution
Step 1: Analyze ISR notification call
ISR calls vTaskNotifyGiveFromISR() to notify the task each time it runs.Step 2: Check task notification wait
Task waits indefinitely with ulTaskNotifyTake(), then prints on notification.Final Answer:
Task notified! (printed each time ISR runs) -> Option BQuick Check:
ISR notifies task -> prints each time [OK]
- Assuming task never wakes
- Confusing function parameters
- Thinking output prints only once
void ISR_Handler() {
vTaskNotifyGive(taskHandle);
}
void TaskFunction(void *pvParameters) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
printf("Notified\n");
}Solution
Step 1: Check ISR notification function
vTaskNotifyGive() is not safe inside ISR; must use vTaskNotifyGiveFromISR().Step 2: Verify task code correctness
TaskFunction can have single call; infinite loop is common but not error here.Final Answer:
Using vTaskNotifyGive() inside ISR instead of vTaskNotifyGiveFromISR() -> Option DQuick Check:
ISR notification function must end with FromISR [OK]
- Calling task functions inside ISR
- Ignoring FromISR suffix importance
- Assuming printf() is disallowed in tasks
Solution
Step 1: Understand multiple ISR notifications
Each ISR calls vTaskNotifyGiveFromISR() to increment notification count.Step 2: Task processes all notifications
Task uses ulTaskNotifyTake(pdTRUE, portMAX_DELAY) in a loop to clear all counts and process each notification.Final Answer:
Use ulTaskNotifyTake() with clear count and call vTaskNotifyGiveFromISR() in each ISR; task loops to process all notifications -> Option CQuick Check:
Multiple ISR notifications require counting and looping [OK]
- Assuming one notification covers all ISR events
- Using non-FromISR functions in ISR
- Ignoring notification count clearing
Ready to prove it?
Pass the test and this pattern moves unknown
