Course contentsShow
← Embedded Systems & Computer Architecture
Lesson 523 of 9367. Real-Time Operating Systems (RTOS)Free lesson

Handling Interrupt Latency in Inter-Task Communication

Develop interrupt-safe communication routines to pass data from high-priority hardware ISRs to background tasks without violating real-time scheduling constraints.

In this lesson, you will learn how to design interrupt-safe data pipelines that move information from high-priority ISRs to background tasks without causing system-wide jitter.

The Challenge of ISR-to-Task Communication

When an Interrupt Service Routine (ISR) receives data from hardware, it cannot perform blocking operations (like waiting for a mutex) because it must exit immediately to avoid violating real-time scheduling constraints. If an ISR attempts to update a shared variable or queue that a task is currently accessing, it risks data corruption or race conditions.

To maintain determinism, we decouple the ISR from the processing task using a non-blocking communication buffer. The goal is to keep the ISR execution time constant and minimal, moving the "heavy lifting" (processing) to a low-priority task.

Designing the Safe Pipeline

We use a lock-free structure or an RTOS-native "ISR-safe" queue to pass data. An ISR-safe primitive disables interrupts or uses atomic instructions to ensure that the task-level code cannot preempt the buffer update halfway through.

Consider this pattern for a producer (ISR) and consumer (Task):

// ISR: High Priority, must be fast
void Hardware_ISR(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    // Add data to a thread-safe queue
    // The "FromISR" suffix indicates an atomic, non-blocking operation
    xQueueSendFromISR(xDataQueue, &incomingData, &xHigherPriorityTaskWoken);
    
    // If the queue was full or a task was waiting, notify the scheduler
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

By using xQueueSendFromISR, the kernel manages the transition atomically. The xHigherPriorityTaskWoken flag is critical: it tells the scheduler whether the newly arrived data has made a high-priority task ready to run, allowing the kernel to trigger an immediate context switch only after the ISR completes.

This approach ensures that your ISR never waits for a resource, keeping its Worst-Case Execution Time (WCET) predictable. The task handles the data processing, effectively moving the computational burden out of the interrupt context and into the scheduled domain.

Key Takeaway: Always use non-blocking, interrupt-safe primitives to pass data from ISRs to tasks, ensuring the ISR remains short and deterministic by offloading processing to the task scheduler.