FreeRTOS Learning: Interrupt Management

Scan to followLearn Embedded Together, learn and grow together

FreeRTOS Learning: Interrupt Management

This is a series of introductory articles on FreeRTOS. While organizing my own knowledge, I hope to help beginners quickly get started and master the basic principles and usage methods of FreeRTOS.

FreeRTOS Quick Start – Initial Exploration of the System

FreeRTOS official Chinese website is now online!

FreeRTOS Coding Standards and Data Types

FreeRTOS Quick Start – Task Management

FreeRTOS Learning: Detailed Explanation of Message Queues

FreeRTOS Learning: Counting Semaphores

FreeRTOS Learning: Mutex Semaphores

FreeRTOS Learning: Event Groups

FreeRTOS Learning: Task Notifications

FreeRTOS Learning: Software Timers

FreeRTOS Learning: Memory Management

FreeRTOS Learning: Resource Management

This article introduces the interrupt management related content of FreeRTOS.

As a real-time operating system, the interrupt management mechanism is one of its core functions.

Good interrupt management is crucial for the performance of real-time systems, as it directly affects the system’s response time, throughput, and reliability.

The Importance of Interrupts in RTOS

In real-time operating systems, interrupts are the primary mechanism for notifying the CPU of external events.

Compared to polling, interrupts provide faster response times because the CPU is only notified when an event occurs, rather than continuously checking the event status.

Characteristics of Interrupt Handling

FreeRTOS’s interrupt management has the following characteristics:

  • Supports interrupt nesting
  • Provides interrupt-safe APIs (FromISR versions)
  • Configurable interrupt priorities
  • Works in conjunction with the task scheduler
  • Lightweight design, suitable for resource-constrained embedded systems

FreeRTOS Interrupt Mechanism

Interrupt Priorities

FreeRTOS uses numerical values to represent priorities, with higher numbers indicating higher priorities.

In most architectures:

  • configMAX_SYSCALL_INTERRUPT_PRIORITY: Defines the highest priority (numerically lowest) of interrupts that FreeRTOS can manage
  • configKERNEL_INTERRUPT_PRIORITY: Defines the interrupt priority used by the kernel itself
/* Typical configuration example (ARM Cortex-M) */
#define configKERNEL_INTERRUPT_PRIORITY 255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 191

Interrupt Service Routines (ISR)

ISRs in FreeRTOS must follow specific rules:

void vAnInterruptHandler(void)
{
    /* Interrupt handling prologue */
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    /* Actual interrupt handling */
    // ... interrupt handling logic
    
    /* May need to wake a task */
    xHigherPriorityTaskWoken = pdTRUE;
    
    /* Interrupt handling epilogue */
    portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}

Critical Section Protection

FreeRTOS provides two critical section protection mechanisms:

  1. taskENTER_CRITICAL() / taskEXIT_CRITICAL()
  • Completely disables interrupts
  • Applicable in task context
  • taskENTER_CRITICAL_FROM_ISR() / taskEXIT_CRITICAL_FROM_ISR()
    • Used in ISR
    • Only disables interrupts with a priority lower than configMAX_SYSCALL_INTERRUPT_PRIORITY

    Interrupt and Task Communication

    Waking Tasks from Interrupts

    FreeRTOS provides several mechanisms for passing information from interrupts to tasks:

    1. Binary Semaphores: Used for simple event notifications

      void vISRHandler(void)
      {
          BaseType_t xHigherPriorityTaskWoken = pdFALSE;
          xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);
          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
      }
      
    2. Counting Semaphores: Used to count the number of occurrences of events

      void vISRHandler(void)
      {
          BaseType_t xHigherPriorityTaskWoken = pdFALSE;
          xSemaphoreGiveFromISR(xCountingSemaphore, &xHigherPriorityTaskWoken);
          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
      }
      
    3. Queues: Used to pass data

      void vISRHandler(void)
      {
          BaseType_t xHigherPriorityTaskWoken = pdFALSE;
          uint32_t ulDataToSend = 123;
          xQueueSendToBackFromISR(xQueue, &ulDataToSend, &xHigherPriorityTaskWoken);
          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
      }
      
    4. Direct Task Notifications: The most efficient communication method

      void vISRHandler(void)
      {
          BaseType_t xHigherPriorityTaskWoken = pdFALSE;
          vTaskNotifyGiveFromISR(xTaskHandle, &xHigherPriorityTaskWoken);
          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
      }
      

    Deferred Interrupt Handling

    For time-consuming interrupt handling, a “deferred interrupt handling” mode can be adopted:

    1. Only perform the necessary handling in the ISR (e.g., clearing the interrupt flag)
    2. Wake a high-priority task via semaphore or task notification
    3. Complete the remaining handling work in that task

    This mode can significantly reduce interrupt disable time and improve system responsiveness.

    FreeRTOS Interrupt API

    Common FromISR APIs

    FreeRTOS provides a series of dedicated APIs for interrupt context, which end with “FromISR”:

    • <span>xQueueSendToBackFromISR() / xQueueSendToFrontFromISR()</span>
    • <span>xQueueReceiveFromISR()</span>
    • <span>xSemaphoreGiveFromISR()</span>
    • <span>xSemaphoreTakeFromISR()</span>
    • <span>xTaskResumeFromISR()</span>
    • <span>vTaskNotifyGiveFromISR()</span>
    • <span>xTaskNotifyFromISR()</span>

    Usage Example

    // Queue sending example
    void vUARTInterruptHandler(void)
    {
        BaseType_t xHigherPriorityTaskWoken = pdFALSE;
        char cReceivedChar;
        
        // Read UART data
        cReceivedChar = UART_DR;
        
        // Send to queue
        if(xQueueSendToBackFromISR(xUARTQueue, &amp;cReceivedChar, &amp;xHigherPriorityTaskWoken) != pdPASS)
        {
            // Queue is full, handle error
        }
        
        // If needed, perform context switch
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
    

    Interrupt Nesting and Priority Management

    Interrupt Nesting

    FreeRTOS fully supports interrupt nesting. When one interrupt is executing, a higher-priority interrupt can preempt the current interrupt.

    Priority Grouping

    On architectures like ARM Cortex-M, FreeRTOS uses a priority grouping mechanism:

    // Set priority grouping on ARM Cortex-M
    NVIC_SetPriorityGrouping(4); // 4 bits for preemption priority, 0 bits for sub-priority
    

    Interrupt Priority Configuration

    // Configure UART interrupt priority
    NVIC_SetPriority(UART_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY - 1);
    

    Usage Recommendations

    Principles for Optimizing Interrupt Handling

    1. Keep ISRs Short: Only do the necessary work
    2. Avoid Blocking Calls: Do not use non-FromISR APIs in ISRs
    3. Set Priorities Reasonably: Set critical interrupts to high priority, but not higher than configMAX_SYSCALL_INTERRUPT_PRIORITY
    4. Use Deferred Handling: Delegate time-consuming operations to tasks
    5. Minimize Critical Sections: Minimize interrupt disable time

    Common Mistakes and Avoidance Methods

    1. Using Non-FromISR APIs in ISRs
    • Error: Using xQueueSend() instead of xQueueSendFromISR()
    • Consequence: May lead to system crashes or data corruption
  • Forgetting to Check Return Values of FromISR Functions
    • Error: Ignoring the return value of xQueueSendFromISR()
    • Consequence: May lose important data
  • Improper Interrupt Priority Settings
    • Error: Setting interrupt priority higher than configMAX_SYSCALL_INTERRUPT_PRIORITY
    • Consequence: FreeRTOS cannot manage these interrupts, potentially leading to data races
  • Excessive Interrupt Disable Time
    • Error: Performing time-consuming operations in critical sections
    • Consequence: Increases system latency, affecting real-time performance

    Port Layer and Hardware-Related Handling

    Key Points for Porting

    FreeRTOS’s interrupt management relies on the hardware abstraction layer, with key porting functions including:

    • <span>portENABLE_INTERRUPTS() / portDISABLE_INTERRUPTS()</span>
    • <span>portSET_INTERRUPT_MASK_FROM_ISR() / portCLEAR_INTERRUPT_MASK_FROM_ISR()</span>
    • <span>portYIELD_FROM_ISR()</span>

    Context Switching Mechanism

    When an interrupt may cause a higher-priority task to become ready, FreeRTOS performs context switching in one of the following ways:

    1. Manual Switching: Call<span>portYIELD_FROM_ISR(xHigherPriorityTaskWoken)</span>
    2. Automatic Switching: Some ports automatically check the switch flag upon exiting the interrupt

    Debugging and Troubleshooting

    Common Debugging Tips

    1. Check Interrupt Priorities: Ensure that all interrupts using FreeRTOS APIs have priorities not higher than configMAX_SYSCALL_INTERRUPT_PRIORITY
    2. Use Tracing Tools: FreeRTOS provides trace macros to log interrupt and task activities
    3. Check Stack Usage: Ensure that the interrupt stack is sufficiently large
    4. Validate FromISR API Usage: Ensure that only FromISR versions of APIs are used in ISRs

    Typical Problem Solutions

    Problem 1: System crashes in interrupt

    • Possible Cause: Non-FromISR APIs used in ISR
    • Solution: Check all ISRs to ensure only FromISR version APIs are used

    Problem 2: Data loss or corruption

    • Possible Cause: Improper interrupt priority settings leading to data races
    • Solution: Reconfigure interrupt priorities to ensure critical resources are protected

    Problem 3: System response is slow

    • Possible Cause: Long interrupt handling times
    • Solution: Adopt deferred interrupt handling mode, moving time-consuming operations to tasks

    Conclusion

    FreeRTOS’s interrupt management provides a powerful and flexible mechanism for handling hardware events while maintaining system real-time performance and reliability.

    By properly using interrupt priorities, FromISR APIs, and task communication mechanisms, developers can build efficient and responsive embedded systems.

    FreeRTOS Learning: Interrupt Management

    Follow 【Learn Embedded Together】 to become better together..

    If you find this article helpful, click “Share”, “Like”, or “Recommend”!

    Leave a Comment