rust-embedded/rust-raspberrypi-OS-tutorials · error

Error handling IRQ

Error message

Error handling IRQ

What it means

In the BCM peripheral interrupt controller, when a registered handler's handle() returns Err, .expect("Error handling IRQ") panics. The library escalates handler-internal failures because the interrupt cannot be confirmed serviced and the peripheral may remain in a pending state.

Source

Thrown at 20_timer_callbacks/kernel/src/bsp/device_driver/bcm/bcm2xxx_interrupt_controller/peripheral_ic.rs:158

            let enable_bit: u32 = 1 << (irq.get() % 32);

            // Writing a 1 to a bit will set the corresponding IRQ enable bit. All other IRQ enable
            // bits are unaffected. So we don't need read and OR'ing here.
            enable_reg.set(enable_bit);
        });
    }

    fn handle_pending_irqs<'irq_context>(
        &'irq_context self,
        _ic: &exception::asynchronous::IRQContext<'irq_context>,
    ) {
        self.handler_table.read(|table| {
            for irq_number in self.pending_irqs() {
                match table[irq_number] {
                    None => panic!("No handler registered for IRQ {}", irq_number),
                    Some(descriptor) => {
                        // Call the IRQ handler. Panics on failure.
                        descriptor.handler().handle().expect("Error handling IRQ");
                    }
                }
            }
        })
    }

    fn print_handler(&self) {
        use crate::info;

        info!("      Peripheral handler:");

        self.handler_table.read(|table| {
            for (i, opt) in table.iter().enumerate() {
                if let Some(handler) = opt {
                    info!("            {: >3}. {}", i, handler.name());
                }
            }
        });

View on GitHub (pinned to 644474cc09)

Solutions

  1. Trace the concrete Err returned by the failing handler and fix the device servicing logic (correct status/clear registers).
  2. Disable the IRQ while reconfiguring its device, then re-enable after the handler's invariants hold.
  3. Make handlers tolerant of spurious or shared-IRQ firings by acknowledging and returning Ok.
  4. Ensure the device behind the handler is fully initialized before its IRQ is unmasked.

Example fix

// before
fn handle(&self) -> Result<(), &'static str> {
    Err("M1 bit not set") // -> expect("Error handling IRQ") panic
}
// after
fn handle(&self) -> Result<(), &'static str> {
    self.timer.clear_matched();
    Ok(())
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the device can service its IRQ before enabling it:
if !gpio.event_config_valid(pin) { panic!("configure GPIO event before enabling its IRQ"); }

Prevention

When it happens

Trigger: The handler registered for a pending peripheral IRQ returns Err from handle() — its device-specific servicing logic fails (status bit not set as expected, clear operation rejected, internal invariant broken) at the moment the IRQ fires.

Common situations: System-timer handler invoked with a mismatched compare register configuration, GPIO handler triggered by a pin whose event configuration was changed after enabling the IRQ, drivers sharing IRQs with incompatible handlers, or handler state invalidated by re-initialization while the IRQ stays enabled.

Related errors


AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06). Data as JSON: /api/errors/1237c2396f52c807. Report an issue: GitHub.