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

Communicating Between Interrupts and RTOS Tasks

Learners will utilize thread-safe primitives like interrupt-safe queues to pass data from hardware events to scheduled tasks without corrupting system state.

In this lesson, you will learn how to bridge the gap between hardware-triggered events and task-level processing using interrupt-safe communication primitives.

The Challenge of Context

When hardware triggers an Interrupt Service Routine (ISR), the CPU stops your current task to handle the event immediately. Because an ISR runs outside the normal scheduler's control, you cannot use standard blocking mechanisms like Mutexes or standard blocking Queues. If an ISR calls a function that attempts to wait for a resource, the system will likely crash or trigger a fault, as ISRs must never block or sleep.

The Solution: Interrupt-Safe Primitives

To move data from an ISR to a waiting task, we use "Interrupt-Safe" primitives—often referred to as "From-ISR" variants of standard communication objects. These primitives are designed to perform non-blocking, atomic operations that update the system state without needing to wait for a context switch.

Consider a system receiving bytes from a UART peripheral. The ISR captures the byte, but the complex logic to process that data belongs in a dedicated task. You would use an interrupt-safe queue to push the byte:

// Inside the UART Interrupt Service Routine
void UART_IRQHandler(void) {
    char data = Read_UART_Register();
    
    // Use an interrupt-safe version of the queue send function
    // This will not block, ensuring the ISR finishes quickly
    if (xQueueSendFromISR(uartQueue, &data, NULL) == pdPASS) {
        // Data successfully queued for a task to process
    }
}

Ensuring Data Integrity

When calling these functions, the "From-ISR" suffix is your signal that the function is designed to handle the race conditions inherent in preempting the scheduler. Often, these functions include a final argument (like pxHigherPriorityTaskWoken in many RTOS kernels) that allows the ISR to notify the kernel if the data just added caused a blocked task to become ready. If that occurs, the kernel can perform a context switch immediately upon exiting the ISR, ensuring the system remains responsive.

By using these specialized primitives, you keep your ISR execution time minimal while safely offloading data processing to the task level, preserving the deterministic nature of your real-time system.

Key Takeaway: Never use blocking synchronization primitives inside an ISR; always use "From-ISR" variants to safely pass data to tasks without stalling the processor or corrupting the kernel state.