Skip to content

Latest commit

 

History

History
951 lines (754 loc) · 30.5 KB

File metadata and controls

951 lines (754 loc) · 30.5 KB

🔌 External Interrupts

Quick Reference: Key Facts

  • External Interrupts allow embedded systems to respond immediately to external events without polling
  • Edge-Triggered Interrupts are triggered on signal transitions (rising/falling edges) and are event-based
  • Level-Triggered Interrupts are triggered when signals remain at specific levels and require manual clearing
  • Interrupt Priority determines which interrupt takes precedence when multiple interrupts occur simultaneously
  • Interrupt Latency is the time from interrupt occurrence to handler execution and affects real-time performance
  • Debouncing is essential for mechanical switches to eliminate false triggers from contact bounce
  • Interrupt Service Routines (ISRs) must be fast, efficient, and avoid blocking operations
  • Interrupt Masking prevents interrupt re-entry during critical sections or long handlers

Mastering External Interrupt Handling for Responsive Embedded Systems
Learn to implement edge/level triggered interrupts, debouncing techniques, and interrupt-driven designs


📋 Table of Contents


🎯 Overview

External interrupts allow embedded systems to respond immediately to external events without polling. They are essential for real-time applications, user interfaces, and efficient system design.

Concept: Edges vs levels, and clearing the source

Choose edges to capture transitions; levels to detect sustained conditions. Always clear the source appropriately and consider masking during long handlers.

Key Concepts

  • Interrupt Vector Table - Maps interrupt sources to handler functions
  • Interrupt Priority - Determines which interrupt takes precedence
  • Interrupt Latency - Time from interrupt occurrence to handler execution
  • Debouncing - Eliminating false triggers from mechanical switches

Interviewer intent (what they’re probing)

  • Can you choose edge vs level correctly and explain why?
  • Do you know how to keep ISRs short and safe?
  • Can you reason about latency, priority, and masking?

🔍 Visual Understanding

Edge vs Level Triggered Interrupts

Edge-Triggered Interrupts
Input Signal
   ^
   │    ┌─────────────────┐
   │    │                 │
   │    │                 │
   │    │                 │
   +──────────────────────────-> Time
   ▲         ▼
Rising    Falling
 Edge      Edge

Interrupt Triggers
   ^
   │    │         │
   │    │         │
   │    │         │
   +──────────────────────────-> Time
   │<->│ Interrupt│<->│ Interrupt
       │  Trigger │   │  Trigger

Level-Triggered Interrupts
Input Signal
   ^
   │    ┌─────────────────┐
   │    │                 │
   │    │                 │
   │    │                 │
   +──────────────────────────-> Time
   │<->│ High Level │<->│ Low Level
       │  Trigger   │   │  Trigger

Interrupt Processing Flow

Interrupt Processing Pipeline
┌─────────────────────────────────────────────────────────────┐
│                    External Event                          │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐   │
│  │   Hardware  │───▶│ Interrupt   │───▶│   CPU Core  │   │
│  │   Detection │    │ Controller  │    │  Response   │   │
│  └─────────────┘    └─────────────┘    └─────────────┘   │
│         │                   │                   │         │
│         ▼                   ▼                   ▼         │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐   │
│  │   Signal    │    │   Priority  │    │   Context   │   │
│  │  Condition  │    │  Resolution │    │  Switching  │   │
│  └─────────────┘    └─────────────┘    └─────────────┘   │
│         │                   │                   │         │
│         ▼                   ▼                   ▼         │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐   │
│  │   ISR       │    │   Return    │    │   Resume    │   │
│  │ Execution   │    │   to ISR    │    │   Main      │   │
│  │             │    │             │    │   Program   │   │
│  └─────────────┘    └─────────────┘    └─────────────┘   │
└─────────────────────────────────────────────────────────────┘

Interrupt Priority and Nesting

Interrupt Priority Levels
┌─────────────────────────────────────────────────────────────┐
│                    Priority Hierarchy                      │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐         │
│  │   High      │ │   Medium    │ │    Low      │         │
│  │ Priority    │ │  Priority   │ │  Priority   │         │
│  │ (Level 0)   │ │ (Level 1)   │ │ (Level 2)   │         │
│  └─────────────┘ └─────────────┘ └─────────────┘         │
│         │               │               │                 │
│         ▼               ▼               ▼                 │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐         │
│  │   Can       │ │   Can       │ │   Cannot    │         │
│  │ Interrupt   │ │ Interrupt   │ │ Interrupt   │         │
│  │   All       │ │   Lower     │ │   Higher    │         │
│  │   Levels    │ │   Levels    │ │   Levels    │         │
│  └─────────────┘ └─────────────┘ └─────────────┘         │
└─────────────────────────────────────────────────────────────┘

🧠 Conceptual Foundation

The Interrupt-Driven Paradigm

External interrupts represent a fundamental shift from polling-based to event-driven system design. Instead of continuously checking for external conditions, the system waits for events and responds immediately when they occur.

Key Characteristics:

  • Event-Driven: System responds to external events rather than continuously monitoring
  • Real-Time Response: Immediate reaction to external stimuli without software delays
  • Efficient Resource Usage: CPU can perform other tasks while waiting for events
  • Deterministic Latency: Predictable response time for time-critical applications

Why External Interrupts Matter

External interrupts are essential for modern embedded systems:

  • Real-Time Performance: Immediate response to external events is critical for safety and control systems
  • Power Efficiency: Systems can sleep while waiting for events, dramatically reducing power consumption
  • User Experience: Responsive interfaces require immediate reaction to user inputs
  • System Reliability: Interrupts enable systems to respond to critical events like power failures or safety conditions

The Interrupt Design Challenge

Designing effective interrupt systems involves balancing multiple competing requirements:

  • Response Time: Fast response requires efficient ISRs and proper priority management
  • Reliability: Robust operation must handle noise, glitches, and multiple simultaneous events
  • Power Efficiency: Interrupts should enable power-saving modes while maintaining responsiveness
  • System Complexity: Interrupt-driven systems can be more complex to debug and maintain

🔄 Interrupt Types

1. Edge-Triggered Interrupts

Triggered when signal transitions from one state to another.

// Edge-triggered interrupt configuration
typedef enum {
    RISING_EDGE,    // 0 → 1 transition
    FALLING_EDGE,   // 1 → 0 transition
    BOTH_EDGES      // Both transitions
} edge_type_t;

typedef struct {
    uint8_t pin;
    edge_type_t edge;
    uint8_t priority;
    void (*handler)(void);
} external_interrupt_config_t;

2. Level-Triggered Interrupts

Triggered when signal remains at a specific level.

// Level-triggered interrupt configuration
typedef enum {
    HIGH_LEVEL,     // Trigger when high
    LOW_LEVEL       // Trigger when low
} level_type_t;

typedef struct {
    uint8_t pin;
    level_type_t level;
    uint8_t priority;
    void (*handler)(void);
} level_interrupt_config_t;

Edge vs Level Triggered

Edge-Triggered Advantages

  • Event-based - Captures transitions without level polling
  • Lower power consumption - Interrupt clears automatically
  • Better for high-frequency signals - No continuous triggering

Edge-Triggered Disadvantages

  • Susceptible to noise - False triggers from glitches
  • Requires debouncing - Mechanical switches need filtering

Level-Triggered Advantages

  • Simple implementation - Direct level detection
  • Good for slow signals - No missed events during processing

Level-Triggered Disadvantages

  • Continuous triggering - Must clear source and/or mask interrupt
  • Higher power consumption - Interrupt remains active until cleared
  • May require masking - To avoid re-entry during long handlers

⚙️ Interrupt Configuration

1. GPIO Interrupt Setup

// Configure GPIO for external interrupt
void configure_external_interrupt(uint8_t pin, edge_type_t edge) {
    // Enable GPIO clock
    RCC->AHB1ENR |= (1 << GPIO_PORT(pin));
    
    // Configure GPIO as input with pull-up
    GPIO_TypeDef *port = GPIO_BASE(pin);
    uint8_t pin_num = GPIO_PIN_NUM(pin);
    
    // Set as input
    port->MODER &= ~(3 << (pin_num * 2));
    
    // Configure pull resistors per board design (pull-up OR pull-down)
    port->PUPDR &= ~(3 << (pin_num * 2));
    if (edge == FALLING_EDGE) {
        port->PUPDR |= (1 << (pin_num * 2)); // pull-up
    } else if (edge == RISING_EDGE) {
        port->PUPDR |= (2 << (pin_num * 2)); // pull-down
    }
    
    // Configure interrupt trigger
    configure_interrupt_trigger(pin, edge);
    
    // Enable interrupt in NVIC with appropriate priority
    enable_nvic_interrupt(EXTI_IRQn);
}

2. Interrupt Trigger Configuration

// Configure interrupt trigger type
void configure_interrupt_trigger(uint8_t pin, edge_type_t edge) {
    uint8_t pin_num = GPIO_PIN_NUM(pin);
    uint8_t exti_line = pin_num;
    
    // Enable SYSCFG clock
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
    
    // Connect GPIO to EXTI line
    SYSCFG->EXTICR[exti_line / 4] &= ~(0xF << ((exti_line % 4) * 4));
    SYSCFG->EXTICR[exti_line / 4] |= (GPIO_PORT(pin) << ((exti_line % 4) * 4));
    
    // Configure trigger type
    switch (edge) {
        case RISING_EDGE:
            EXTI->RTSR |= (1 << exti_line);
            EXTI->FTSR &= ~(1 << exti_line);
            break;
        case FALLING_EDGE:
            EXTI->FTSR |= (1 << exti_line);
            EXTI->RTSR &= ~(1 << exti_line);
            break;
        case BOTH_EDGES:
            EXTI->RTSR |= (1 << exti_line);
            EXTI->FTSR |= (1 << exti_line);
            break;
    }
    
    // Enable interrupt
    EXTI->IMR |= (1 << exti_line);
}

🔄 Debouncing Techniques

1. Software Debouncing

// Software debouncing with timer
typedef struct {
    uint8_t pin;
    uint32_t last_trigger_time;
    uint32_t debounce_delay;
    bool last_state;
} debounce_config_t;

debounce_config_t debounce_configs[MAX_INTERRUPTS];

// Debounced interrupt handler
void debounced_interrupt_handler(uint8_t pin) {
    uint32_t current_time = get_system_tick();
    debounce_config_t *config = &debounce_configs[pin];
    
    // Check if enough time has passed since last trigger
    if (current_time - config->last_trigger_time < config->debounce_delay) {
        return; // Ignore this trigger
    }
    
    // Read current pin state
    bool current_state = read_gpio_pin(pin);
    
    // Only process if state actually changed
    if (current_state != config->last_state) {
        config->last_state = current_state;
        config->last_trigger_time = current_time;
        
        // Process the actual interrupt
        process_interrupt_event(pin, current_state);
    }
}

2. Hardware Debouncing

// Hardware debouncing circuit analysis
/*
    Hardware debouncing options:
    
    1. RC Filter:
       Switch --[R]--+--[C]-- GND
                     |
                   Input Pin
    
    2. Schmitt Trigger:
       Switch --[R]-- Schmitt Trigger -- Input Pin
    
    3. Bounce Suppression IC:
       Switch -- Bounce Suppression IC -- Input Pin
*/

// Calculate RC values for debouncing
void calculate_debounce_values(uint32_t bounce_time_ms, uint32_t *r_value, uint32_t *c_value) {
    // Typical bounce time: 1-50ms
    // RC time constant should be > bounce_time/3
    
    uint32_t rc_time = bounce_time_ms * 3; // 3x bounce time for safety
    
    // Choose standard values
    *c_value = 0.1; // 0.1μF
    *r_value = (rc_time * 1000) / (*c_value * 1000); // R = t/(C*1000) for μF
}

3. Advanced Debouncing

// State machine debouncing
typedef enum {
    DEBOUNCE_IDLE,
    DEBOUNCE_WAIT,
    DEBOUNCE_CONFIRMED
} debounce_state_t;

typedef struct {
    debounce_state_t state;
    uint32_t start_time;
    uint32_t debounce_time;
    bool stable_state;
} debounce_state_machine_t;

void debounce_state_machine(debounce_state_machine_t *sm, bool current_input) {
    uint32_t current_time = get_system_tick();
    
    switch (sm->state) {
        case DEBOUNCE_IDLE:
            if (current_input != sm->stable_state) {
                sm->state = DEBOUNCE_WAIT;
                sm->start_time = current_time;
            }
            break;
            
        case DEBOUNCE_WAIT:
            if (current_time - sm->start_time >= sm->debounce_time) {
                if (current_input != sm->stable_state) {
                    sm->stable_state = current_input;
                    sm->state = DEBOUNCE_CONFIRMED;
                    // Process state change
                    process_state_change(sm->stable_state);
                } else {
                    sm->state = DEBOUNCE_IDLE;
                }
            }
            break;
            
        case DEBOUNCE_CONFIRMED:
            sm->state = DEBOUNCE_IDLE;
            break;
    }
}

🎯 Interrupt Service Routines

1. Basic ISR Structure

// External interrupt service routine
void EXTI0_IRQHandler(void) {
    // Check if interrupt is pending
    if (EXTI->PR & (1 << 0)) {
        // Clear pending bit
        EXTI->PR = (1 << 0);
        
        // Process interrupt
        process_external_interrupt(0);
    }
}

// Generic external interrupt handler
void process_external_interrupt(uint8_t pin) {
    // Read pin state
    bool pin_state = read_gpio_pin(pin);
    
    // Process based on application
    switch (pin) {
        case BUTTON_PIN:
            handle_button_press(pin_state);
            break;
        case SENSOR_PIN:
            handle_sensor_interrupt(pin_state);
            break;
        default:
            // Unknown pin
            break;
    }
}

2. ISR Best Practices

// ISR with minimal processing
void EXTI15_10_IRQHandler(void) {
    // Check which pins triggered
    uint16_t pending = EXTI->PR & 0xFC00; // Pins 10-15
    
    if (pending) {
        // Clear pending bits
        EXTI->PR = pending;
        
        // Set flag for main loop processing
        for (int i = 10; i <= 15; i++) {
            if (pending & (1 << i)) {
                set_interrupt_flag(i);
            }
        }
    }
}

// Main loop processes interrupt flags
void main_loop(void) {
    while (1) {
        // Check for pending interrupts
        for (int i = 0; i < MAX_INTERRUPTS; i++) {
            if (check_interrupt_flag(i)) {
                clear_interrupt_flag(i);
                process_interrupt_event(i);
            }
        }
        
        // Other main loop tasks
        process_system_tasks();
    }
}

⏱️ Interrupt Latency

1. Latency Components

// Interrupt latency analysis
typedef struct {
    uint32_t hardware_latency;    // Time to enter ISR
    uint32_t software_latency;    // Time in ISR
    uint32_t context_switch;      // Time to save/restore context
    uint32_t total_latency;       // Total response time
} interrupt_latency_t;

// Measure interrupt latency
void measure_interrupt_latency(void) {
    uint32_t start_time, end_time;
    
    // Configure test interrupt
    configure_test_interrupt();
    
    // Start measurement
    start_time = get_high_resolution_timer();
    
    // Trigger interrupt
    trigger_test_interrupt();
    
    // Measure in ISR
    end_time = get_high_resolution_timer();
    
    // Calculate latency
    uint32_t latency = end_time - start_time;
    
    // Report results
    printf("Interrupt latency: %lu cycles\n", latency);
}

2. Latency Optimization

// Optimized ISR for minimal latency
__attribute__((interrupt)) void optimized_isr(void) {
    // Use registers directly (no function calls)
    // Minimize stack usage
    // Avoid complex operations
    
    // Quick state check
    if (GPIOA->IDR & (1 << 0)) {
        // Set flag immediately
        interrupt_flags |= (1 << 0);
    }
    
    // Clear interrupt
    EXTI->PR = (1 << 0);
}

🎯 Best Practices

1. ISR Design Guidelines

// ISR design checklist
/*
    □ Keep ISRs short and fast
    □ Avoid function calls when possible
    □ Use volatile for shared variables
    □ Clear interrupt flags early
    □ Don't use blocking operations
    □ Avoid floating-point operations
    □ Use appropriate interrupt priorities
    □ Test interrupt timing
    □ Handle interrupt nesting properly
    □ Document interrupt dependencies
*/

// Good ISR example
volatile uint32_t interrupt_counter = 0;

void good_isr_example(void) {
    // Clear interrupt immediately
    EXTI->PR = (1 << 0);
    
    // Simple operation
    interrupt_counter++;
    
    // Set flag for main loop
    interrupt_pending = true;
}

2. Interrupt Priority Management

// Configure interrupt priorities
void configure_interrupt_priorities(void) {
    // Set priority grouping
    NVIC_SetPriorityGrouping(3); // 4 bits for preemption, 0 for sub
    
    // Configure priorities (lower number = higher priority)
    NVIC_SetPriority(EXTI0_IRQn, 1);      // High priority
    NVIC_SetPriority(EXTI1_IRQn, 2);      // Medium priority
    NVIC_SetPriority(EXTI2_IRQn, 3);      // Low priority
    
    // Enable interrupts
    NVIC_EnableIRQ(EXTI0_IRQn);
    NVIC_EnableIRQ(EXTI1_IRQn);
    NVIC_EnableIRQ(EXTI2_IRQn);
}

⚠️ Common Pitfalls

1. Missing Interrupt Clearing

// WRONG: Missing interrupt clear
void bad_isr_example(void) {
    // Process interrupt
    process_interrupt();
    // Missing: EXTI->PR = (1 << pin);
}

// CORRECT: Clear interrupt flag
void good_isr_example(void) {
    // Clear interrupt flag first
    EXTI->PR = (1 << 0);
    
    // Process interrupt
    process_interrupt();
}

2. Long ISR Execution

// WRONG: Long operations in ISR
void bad_long_isr(void) {
    EXTI->PR = (1 << 0);
    
    // Don't do this in ISR!
    for (int i = 0; i < 1000; i++) {
        process_data();
    }
}

// CORRECT: Set flag and return
void good_short_isr(void) {
    EXTI->PR = (1 << 0);
    
    // Set flag for main loop
    data_processing_pending = true;
}

3. Race Conditions

// WRONG: Race condition with shared variable
volatile bool button_pressed = false;

void isr_with_race(void) {
    EXTI->PR = (1 << 0);
    button_pressed = true; // Race condition possible
}

// CORRECT: Atomic operation
volatile uint32_t button_flags = 0;

void isr_without_race(void) {
    EXTI->PR = (1 << 0);
    __atomic_or_fetch(&button_flags, 1, __ATOMIC_RELEASE);
}

💡 Examples

1. Button Interrupt with Debouncing

// Button interrupt implementation
#define BUTTON_PIN     0
#define DEBOUNCE_MS    50

volatile bool button_pressed = false;
volatile uint32_t last_button_time = 0;

void EXTI0_IRQHandler(void) {
    if (EXTI->PR & (1 << BUTTON_PIN)) {
        EXTI->PR = (1 << BUTTON_PIN);
        
        uint32_t current_time = get_system_tick();
        
        // Software debouncing
        if (current_time - last_button_time > DEBOUNCE_MS) {
            button_pressed = true;
            last_button_time = current_time;
        }
    }
}

// Main loop processes button press
void main_loop(void) {
    while (1) {
        if (button_pressed) {
            button_pressed = false;
            handle_button_action();
        }
        
        // Other tasks
        process_system_tasks();
    }
}

2. Sensor Interrupt with Edge Detection

// Sensor interrupt with edge detection
#define SENSOR_PIN     1
#define SENSOR_RISING  1
#define SENSOR_FALLING 0

volatile uint32_t sensor_rising_count = 0;
volatile uint32_t sensor_falling_count = 0;

void EXTI1_IRQHandler(void) {
    if (EXTI->PR & (1 << SENSOR_PIN)) {
        EXTI->PR = (1 << SENSOR_PIN);
        
        // Read current pin state
        bool current_state = (GPIOA->IDR & (1 << SENSOR_PIN)) ? 1 : 0;
        
        if (current_state == SENSOR_RISING) {
            sensor_rising_count++;
        } else {
            sensor_falling_count++;
        }
    }
}

3. Multiple Interrupt Sources

// Multiple interrupt sources with priority
#define INT_PIN_1      0
#define INT_PIN_2      1
#define INT_PIN_3      2

volatile uint32_t interrupt_flags = 0;

void EXTI0_IRQHandler(void) {
    if (EXTI->PR & (1 << INT_PIN_1)) {
        EXTI->PR = (1 << INT_PIN_1);
        interrupt_flags |= (1 << INT_PIN_1);
    }
}

void EXTI1_IRQHandler(void) {
    if (EXTI->PR & (1 << INT_PIN_2)) {
        EXTI->PR = (1 << INT_PIN_2);
        interrupt_flags |= (1 << INT_PIN_2);
    }
}

void EXTI2_IRQHandler(void) {
    if (EXTI->PR & (1 << INT_PIN_3)) {
        EXTI->PR = (1 << INT_PIN_3);
        interrupt_flags |= (1 << INT_PIN_3);
    }
}

// Process interrupts in priority order
void process_interrupts(void) {
    if (interrupt_flags & (1 << INT_PIN_1)) {
        interrupt_flags &= ~(1 << INT_PIN_1);
        process_high_priority_interrupt();
    }
    
    if (interrupt_flags & (1 << INT_PIN_2)) {
        interrupt_flags &= ~(1 << INT_PIN_2);
        process_medium_priority_interrupt();
    }
    
    if (interrupt_flags & (1 << INT_PIN_3)) {
        interrupt_flags &= ~(1 << INT_PIN_3);
        process_low_priority_interrupt();
    }
}

🧪 Guided Labs

Lab 1: Basic External Interrupt Implementation

  1. Setup: Configure GPIO pin for external interrupt with edge detection
  2. Test: Connect a button and verify interrupt triggering on press/release
  3. Measure: Use oscilloscope to measure interrupt latency and response time
  4. Optimize: Implement debouncing and measure its effect on reliability

Lab 2: Interrupt Priority and Nesting

  1. Configure: Set up multiple interrupt sources with different priorities
  2. Test: Trigger interrupts simultaneously and observe priority handling
  3. Analyze: Measure interrupt nesting behavior and context switching overhead
  4. Validate: Verify that higher priority interrupts can preempt lower ones

Lab 3: Advanced Interrupt Techniques

  1. Implement: Level-triggered interrupts with proper source clearing
  2. Design: Interrupt-driven state machine for complex event handling
  3. Optimize: Minimize ISR execution time and measure performance impact
  4. Debug: Use logic analyzer to trace interrupt timing and identify bottlenecks

✅ Check Yourself

Understanding Check

  • Can you explain the difference between edge-triggered and level-triggered interrupts?
  • Do you understand how interrupt priorities affect system behavior?
  • Can you describe the interrupt processing pipeline and latency sources?
  • Do you know when to use edge vs level triggering for different applications?

Application Check

  • Can you configure external interrupts with proper edge/level detection?
  • Can you implement effective debouncing for mechanical switches?
  • Can you design interrupt service routines that minimize execution time?
  • Can you handle multiple interrupt sources with proper priority management?

Analysis Check

  • Can you measure and analyze interrupt latency and response time?
  • Can you identify and resolve interrupt-related race conditions?
  • Can you optimize interrupt systems for power efficiency and performance?
  • Can you debug complex interrupt-driven systems effectively?

🔗 Cross-links

🎯 Interview Questions

Basic Questions

  1. What is the difference between edge-triggered and level-triggered interrupts?

    • Edge-triggered: Triggered on signal transition (0→1 or 1→0)
    • Level-triggered: Triggered when signal remains at specific level
    • Edge-triggered is more common for external interrupts
  2. How do you implement debouncing for a mechanical switch?

    • Software: Timer-based delay, state machine
    • Hardware: RC filter, Schmitt trigger, bounce suppression IC
    • Best approach depends on requirements and constraints
  3. What is interrupt latency and how do you minimize it?

    • Time from interrupt occurrence to handler execution
    • Minimize by: Short ISRs, proper priorities, avoid function calls

Advanced Questions

  1. How do you handle multiple interrupt sources with different priorities?

    • Configure NVIC priorities
    • Use interrupt nesting if supported
    • Process in priority order in main loop
  2. What are the common pitfalls when implementing external interrupts?

    • Missing interrupt flag clearing
    • Long ISR execution time
    • Race conditions with shared variables
    • Improper debouncing
  3. How do you measure and optimize interrupt latency?

    • Use high-resolution timer
    • Profile ISR execution time
    • Optimize for minimal processing in ISR

Practical Questions

  1. Design an interrupt-driven button interface with debouncing.

    // Configure button interrupt
    void configure_button_interrupt(void) {
        // GPIO as input with pull-up
        GPIO_InitTypeDef gpio_init = {0};
        gpio_init.Pin = BUTTON_PIN;
        gpio_init.Mode = GPIO_MODE_IT_FALLING;
        gpio_init.Pull = GPIO_PULLUP;
        HAL_GPIO_Init(BUTTON_PORT, &gpio_init);
        
        // Enable interrupt
        HAL_NVIC_SetPriority(BUTTON_IRQn, 1, 0);
        HAL_NVIC_EnableIRQ(BUTTON_IRQn);
    }
  2. Implement a sensor interrupt that counts rising edges.

    volatile uint32_t edge_count = 0;
    
    void sensor_isr(void) {
        if (EXTI->PR & (1 << SENSOR_PIN)) {
            EXTI->PR = (1 << SENSOR_PIN);
            edge_count++;
        }
    }

🧪 Guided Labs

  1. Debouncing comparison
  • Implement software debouncing vs hardware RC filter; measure response time and reliability.
  1. Edge vs level triggering
  • Configure the same pin for both edge and level interrupts; observe behavior differences.

✅ Check Yourself

  • When should you use level-triggered interrupts instead of edge-triggered?
  • How do you handle multiple interrupt sources on the same pin?

🔗 Cross-links

  • Hardware_Fundamentals/Interrupts_Exceptions.md for interrupt handling
  • Hardware_Fundamentals/Digital_IO_Programming.md for pin configuration

🔗 Related Topics


📚 Resources

Books

  • "Making Embedded Systems" by Elecia White
  • "Programming Embedded Systems" by Michael Barr
  • "Real-Time Systems" by Jane W. S. Liu

Online Resources


Next Topic: Watchdog TimersInterrupts and Exceptions