Interrupts
~15 min
Polling vs Interrupts
Polling
With polling, the CPU constantly checks the state of a peripheral in a loop. This is simple to implement but wastes CPU cycles — the processor is busy-waiting even when nothing is happening.
#![allow(unused)] fn main() { loop { if button.is_low() { // react to button press } // CPU is busy-waiting here, doing nothing useful } }
Interrupts
With interrupts, the hardware notifies the CPU when an event occurs. The CPU can sleep or do other work in the meantime, only waking when needed. This is more efficient but requires additional setup.
#![allow(unused)] fn main() { loop { // CPU can sleep or do other work // it is idle until an event occurs } // Hardware triggers this handler automatically #[handler] fn gpio_handler() { // react to the event } }
Components of Interrupt Code
Interrupt code is formed of three components:
- Global Shared Data — Any data that needs to be shared between the main thread and the interrupt handler
- Interrupt Setup — Configuring the interrupt per peripheral (what event to listen for, enabling it, moving data to shared state)
- Interrupt Service Routine (ISR) — The code that reacts to the interrupt event
// 1. Global Shared Data static SHARED: Mutex<RefCell<Option<Input>>> = Mutex::new(RefCell::new(None)); fn main() { // ... peripheral setup ... // 2. Interrupt Setup button.listen(Event::FallingEdge); critical_section::with(|cs| { SHARED.borrow_ref_mut(cs).replace(button); }); } // 3. Interrupt Service Routine #[handler] fn gpio_handler() { critical_section::with(|cs| { // handle event, clear interrupt }); }
Setup Happens in the Configure Stage
Setup entails three steps:
-
Configuring the interrupt — What do we want to listen to?
- Edge events (rising, falling, any)
- Level events (high, low)
-
Enabling the interrupt — Allowing the interrupt events to go through
- Peripheral-level enable
- Interrupt controller enable
-
Configuring global shared data — Setting up shared state
Mutex<RefCell<Option<T>>>pattern- Moving peripherals into global statics via
critical_section