Bird
Raised Fist0
FreeRTOSprogramming~10 mins

Deferred interrupt processing pattern in FreeRTOS - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Deferred interrupt processing pattern
Interrupt Occurs
↓
ISR runs briefly
↓
Signal a Task (e.g., via Queue or Semaphore)
↓
ISR Ends Quickly
↓
Task Awakened by Signal
↓
Task Does Heavy Processing
↓
Task Completes and Waits for Next Signal
When an interrupt happens, the ISR does minimal work and signals a task to handle the heavy work later.
Execution Sample
FreeRTOS
void ISR_Handler() {
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
  portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

void Task_Function(void *pvParameters) {
  for(;;) {
    xSemaphoreTake(xSemaphore, portMAX_DELAY);
    // Heavy processing here
  }
}
ISR signals a semaphore to wake a task that does the heavy processing outside the interrupt.
Execution Table
StepActionISR Running?Semaphore StateTask StateNotes
1Interrupt occursYesEmptyBlockedISR starts quickly
2ISR gives semaphoreYesGiven (Available)BlockedSignal sent to task
3ISR ends, yields if neededNoGiven (Available)Ready or RunningTask may run immediately
4Task takes semaphoreNoEmptyRunningTask wakes and starts heavy work
5Task does heavy processingNoEmptyRunningHeavy work done outside ISR
6Task waits for semaphore againNoEmptyBlockedWaits for next interrupt signal
7No interrupt, task blockedNoEmptyBlockedSystem idle or other tasks run
💡 ISR finishes quickly; heavy work deferred to task which waits on semaphore.
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4After Step 6
xHigherPriorityTaskWokenpdFALSEpdFALSE or pdTRUEUsed by portYIELD_FROM_ISRN/AN/A
SemaphoreEmptyGiven (Available)Given (Available)Empty (Taken)Empty (Waiting)
Task StateBlockedBlockedReady or RunningRunningBlocked
Key Moments - 3 Insights
Why does the ISR only signal the semaphore and not do the heavy processing?
Because the ISR must be very fast to avoid blocking other interrupts. The heavy work is done later by the task, as shown in execution_table step 2 and step 4.
What happens if the task is not ready when the ISR signals the semaphore?
The semaphore becomes available, and the task will wake up as soon as the scheduler runs it, shown in execution_table step 3.
Why do we use portYIELD_FROM_ISR after giving the semaphore?
To request a context switch immediately if the awakened task has higher priority, ensuring quick response, as in execution_table step 3.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 2, what is the state of the semaphore after ISR gives it?
AEmpty
BGiven (Available)
CTaken
DBlocked
💡 Hint
Check the 'Semaphore State' column at step 2 in the execution_table.
At which step does the task start running the heavy processing?
AStep 4
BStep 3
CStep 2
DStep 6
💡 Hint
Look at the 'Task State' and 'Notes' columns in the execution_table for when the task is 'Running' heavy work.
If portYIELD_FROM_ISR was not called, what might happen?
AThe semaphore would not be given
BThe ISR would run longer
CThe task might not run immediately after ISR
DThe task would never wake up
💡 Hint
Refer to the 'Notes' in step 3 about yielding from ISR to allow immediate task run.
Concept Snapshot
Deferred Interrupt Processing Pattern:
- ISR runs fast, does minimal work
- ISR signals a task via semaphore/queue
- Task wakes and does heavy processing
- Use portYIELD_FROM_ISR to switch quickly
- Keeps system responsive and efficient
Full Transcript
This pattern shows how an interrupt service routine (ISR) handles events quickly by signaling a task to do the heavy work later. When an interrupt occurs, the ISR runs briefly and gives a semaphore to unblock a task. The ISR then ends, possibly yielding to the task if it has higher priority. The task wakes up, takes the semaphore, and performs the heavy processing outside the interrupt context. This approach keeps the ISR short and the system responsive. The execution table traces each step: interrupt occurs, ISR signals semaphore, ISR ends, task wakes and processes, then waits again. Variables like the semaphore state and task state change accordingly. Key points include why the ISR avoids heavy work, how the task wakes, and the role of portYIELD_FROM_ISR. The visual quiz tests understanding of semaphore state, task running step, and the effect of yielding from ISR.

Practice

(1/5)
1. What is the main purpose of the deferred interrupt processing pattern in FreeRTOS?
easy
A. To move heavy processing from the ISR to a task for better system responsiveness
B. To execute all interrupt code inside the ISR for faster response
C. To disable all interrupts during task execution
D. To avoid using semaphores or queues in interrupt handling

Solution

  1. Step 1: Understand ISR limitations

    Interrupt Service Routines (ISRs) should be short to keep system responsive.
  2. Step 2: Role of deferred processing

    Heavy or time-consuming work is moved to a task, triggered by ISR using semaphores or queues.
  3. Final Answer:

    To move heavy processing from the ISR to a task for better system responsiveness -> Option A
  4. Quick Check:

    Deferred processing = move work out of ISR [OK]
Hint: Heavy work belongs in tasks, not ISRs [OK]
Common Mistakes:
  • Thinking all work should be done inside ISR
  • Believing interrupts should be disabled during tasks
  • Ignoring use of semaphores or queues
2. Which of the following is the correct way to notify a task from an ISR in FreeRTOS?
easy
A. vTaskDelay()
B. xSemaphoreGive()
C. xSemaphoreGiveFromISR()
D. xQueueSend()

Solution

  1. Step 1: Identify ISR-safe functions

    Functions called from ISRs must be ISR-safe variants, like xSemaphoreGiveFromISR().
  2. Step 2: Compare options

    xSemaphoreGive() is for tasks, not ISRs; vTaskDelay() is a task delay; xQueueSend() is not ISR-safe.
  3. Final Answer:

    xSemaphoreGiveFromISR() -> Option C
  4. Quick Check:

    Use FromISR functions inside ISRs [OK]
Hint: Use FromISR suffix functions inside ISRs [OK]
Common Mistakes:
  • Using task-only functions inside ISR
  • Calling blocking functions in ISR
  • Not using FromISR variants
3. Consider this snippet inside an ISR in FreeRTOS:
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
What is the purpose of portYIELD_FROM_ISR() here?
medium
A. To reset the semaphore count
B. To request a context switch if a higher priority task was woken
C. To delay the ISR until the task runs
D. To disable interrupts after giving the semaphore

Solution

  1. Step 1: Understand xHigherPriorityTaskWoken

    This flag indicates if giving the semaphore woke a higher priority task.
  2. Step 2: Role of portYIELD_FROM_ISR()

    If the flag is true, portYIELD_FROM_ISR() requests a context switch to run the higher priority task immediately.
  3. Final Answer:

    To request a context switch if a higher priority task was woken -> Option B
  4. Quick Check:

    portYIELD_FROM_ISR triggers context switch [OK]
Hint: portYIELD_FROM_ISR triggers immediate task switch [OK]
Common Mistakes:
  • Thinking it disables interrupts
  • Assuming it delays ISR execution
  • Confusing it with semaphore reset
4. You wrote this ISR code to notify a task:
void ISR_Handler(void) {
    xSemaphoreGive(xSemaphore);
}
Why might this cause problems in FreeRTOS?
medium
A. xSemaphoreGive() is not safe to call from an ISR
B. The semaphore is given twice accidentally
C. The ISR does not clear the interrupt flag
D. The task will never unblock

Solution

  1. Step 1: Check function usage in ISR

    xSemaphoreGive() is a task-level function and is not safe to call inside an ISR.
  2. Step 2: Correct function to use

    Inside ISR, xSemaphoreGiveFromISR() must be used to safely notify the task.
  3. Final Answer:

    xSemaphoreGive() is not safe to call from an ISR -> Option A
  4. Quick Check:

    Use FromISR functions in ISRs [OK]
Hint: Never call task functions inside ISR, use FromISR versions [OK]
Common Mistakes:
  • Calling task functions inside ISR
  • Forgetting to clear interrupt flags
  • Assuming semaphore gives always unblock tasks
5. You want to implement deferred interrupt processing where an ISR signals a task to process sensor data. Which sequence correctly follows FreeRTOS best practices?
hard
A. Task polls sensor data continuously, ISR disables interrupts
B. ISR processes sensor data directly, then calls vTaskDelay()
C. ISR sends data via xQueueSend(), task never blocks
D. ISR calls xSemaphoreGiveFromISR(), then task waits on semaphore and processes data

Solution

  1. Step 1: ISR role in deferred processing

    ISR should be short and only notify the task using xSemaphoreGiveFromISR().
  2. Step 2: Task role in processing

    The task waits on the semaphore and processes sensor data when notified.
  3. Final Answer:

    ISR calls xSemaphoreGiveFromISR(), then task waits on semaphore and processes data -> Option D
  4. Quick Check:

    ISR signals, task processes data [OK]
Hint: ISR signals; task does heavy work [OK]
Common Mistakes:
  • Doing heavy work inside ISR
  • Using blocking calls inside ISR
  • Not synchronizing task and ISR properly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard