The Embedded New Testament

The "Holy Bible" for embedded engineers


Project maintained by theEmbeddedGeorge Hosted on GitHub Pages — Theme by mattgraham

⚡ Interrupts and Exceptions

Mastering Interrupt Handling, ISR Design, and Exception Management
Learn to implement robust interrupt systems, design efficient ISRs, and handle exceptions for reliable embedded systems


📋 Table of Contents


🎯 Overview

Interrupts and exceptions are fundamental mechanisms that allow embedded systems to respond to external events and handle errors efficiently. Understanding interrupt handling is crucial for real-time system design and reliable embedded applications.


🚀 Quick Reference: Key Facts


🔍 Visual Understanding

Interrupt Processing Flow

Normal Execution → Interrupt Occurs → Context Save → ISR Execution → Context Restore → Resume Execution
     ↓                    ↓              ↓           ↓              ↓              ↓
   Main Loop        Hardware Event   Save Regs   Process IRQ   Restore Regs   Continue

Interrupt Priority and Nesting

Priority 0 (Highest) ──┐
                        ├── Can interrupt any lower priority
Priority 1 ────────────┤
                        ├── Cannot interrupt Priority 0
Priority 2 ────────────┤
                        └── Cannot interrupt Priority 0 or 1
Priority 3 (Lowest) ───┘

Exception vs Interrupt Handling

Exceptions (Internal)     Interrupts (External)
     ↓                          ↓
Hardware Faults          Peripheral Events
Memory Violations        GPIO Changes
Illegal Instructions     Timer Expiry
Stack Overflow          Communication Events

🧠 Conceptual Foundation

The Interrupt-Driven Paradigm

Interrupts represent a fundamental shift from polling-based systems to event-driven architectures. Instead of continuously checking for events, the system waits for hardware to signal when something needs attention. This paradigm enables:

Why Interrupts and Exceptions Matter

Interrupts are the backbone of real-time embedded systems. They enable:

The Interrupt Design Challenge

Designing interrupt systems involves balancing several competing concerns:


🎯 Core Concepts

Concept: Interrupt Vector Table and Handler Registration

Why it matters: The vector table is the central nervous system of interrupt handling. It maps each interrupt source to its corresponding handler function, enabling the CPU to jump to the right code when interrupts occur.

Minimal example

// Basic interrupt handler registration
typedef void (*interrupt_handler_t)(void);

// Simple vector table structure
typedef struct {
    interrupt_handler_t reset_handler;
    interrupt_handler_t nmi_handler;
    interrupt_handler_t hardfault_handler;
    interrupt_handler_t irq_handlers[16];  // External interrupts
} vector_table_t;

// Register a handler for a specific interrupt
void register_interrupt_handler(uint8_t irq_number, interrupt_handler_t handler) {
    if (irq_number < 16) {
        vector_table.irq_handlers[irq_number] = handler;
    }
}

Try it: Create a simple vector table with handlers for timer and UART interrupts.

Takeaways

Concept: Interrupt Service Routine Design Principles

Why it matters: ISR design directly impacts system responsiveness and reliability. Poorly designed ISRs can cause missed interrupts, priority inversion, and system instability.

Minimal example

// Good ISR design - minimal and fast
volatile bool data_ready = false;
volatile uint8_t received_data = 0;

void uart_rx_isr(void) {
    // Clear interrupt flag immediately
    UART1->SR &= ~UART_SR_RXNE;
    
    // Minimal processing - just capture data
    received_data = UART1->DR;
    data_ready = true;
    
    // Let main loop handle the data processing
}

Try it: Design an ISR for a GPIO button press that sets a flag for main loop processing.

Takeaways

Concept: Interrupt Priority and Nesting Management

Why it matters: Proper priority management ensures critical interrupts get immediate attention while preventing priority inversion and ensuring system responsiveness.

Minimal example

// Configure interrupt priorities
void configure_interrupt_priorities(void) {
    // Set system timer to highest priority (lowest number)
    NVIC_SetPriority(SysTick_IRQn, 0);
    
    // Set UART to medium priority
    NVIC_SetPriority(UART1_IRQn, 2);
    
    // Set GPIO to lower priority
    NVIC_SetPriority(EXTI0_IRQn, 4);
    
    // Enable all interrupts
    NVIC_EnableIRQ(SysTick_IRQn);
    NVIC_EnableIRQ(UART1_IRQn);
    NVIC_EnableIRQ(EXTI0_IRQn);
}

Try it: Configure three interrupts with different priorities and observe nesting behavior.

Takeaways

Concept: Exception Handling and Fault Recovery

Why it matters: Exceptions represent system errors that must be handled gracefully. Proper exception handling prevents system crashes and enables recovery from transient faults.

Minimal example

// Basic hard fault handler
void hardfault_handler(void) {
    // Capture fault information
    uint32_t fault_address = SCB->MMFAR;  // Memory fault address
    uint32_t fault_status = SCB->CFSR;    // Combined fault status
    
    // Log fault information (if possible)
    log_fault_info(fault_address, fault_status);
    
    // Attempt recovery or reset
    if (can_recover_from_fault(fault_status)) {
        // Try to continue
        return;
    } else {
        // Reset system if recovery not possible
        system_reset();
    }
}

Try it: Implement a fault handler that logs error information and attempts recovery.

Takeaways


🧪 Guided Labs

Lab 1: Interrupt Latency Measurement

Objective: Measure the time from interrupt trigger to ISR execution.

Steps:

  1. Configure a timer interrupt with known frequency
  2. Use GPIO toggles to mark interrupt entry/exit
  3. Measure timing with oscilloscope or logic analyzer
  4. Compare measured vs. theoretical latency

Expected Outcome: Understanding of interrupt overhead and factors affecting latency.

Lab 2: Priority Nesting Demonstration

Objective: Observe how interrupt priorities affect nesting behavior.

Steps:

  1. Configure multiple interrupts with different priorities
  2. Trigger interrupts simultaneously
  3. Observe execution order and nesting
  4. Analyze priority inversion scenarios

Expected Outcome: Understanding of interrupt priority mechanisms and nesting behavior.

Lab 3: Exception Handling Implementation

Objective: Implement robust exception handling for system faults.

Steps:

  1. Set up exception handlers for common faults
  2. Implement fault logging and recovery mechanisms
  3. Test fault scenarios (invalid memory access, divide by zero)
  4. Verify recovery behavior

Expected Outcome: Practical experience with exception handling and fault recovery.


Check Yourself

Basic Understanding

Practical Application

Advanced Concepts



🎯 Practical Considerations

System-Level Design Decisions

Performance and Optimization

Debugging and Testing


📚 Additional Resources

Books

Online Resources


Next Topic: Reset ManagementTimer/Counter Programming