Interrupts, Shared Data, and Atomic Operations
Interrupts let firmware respond quickly to hardware events. They also introduce concurrency: an interrupt service routine can run between two instructions in main code.
Learning Objectives
By the end of this lesson, you should be able to:
- explain why ISR-shared data needs special care;
- use
volatilefor visibility without confusing it with atomicity; - protect multi-step updates with critical sections;
- design simple interrupt-to-main communication.
The Interrupt Model
The foreground code did not choose the interruption point.
Volatile Flags
static volatile bool uart_rx_ready;
void UART_IRQHandler(void)
{
uart_rx_ready = true;
}
int main(void)
{
while (!uart_rx_ready) {
/* sleep or poll */
}
}
volatile ensures the main loop reloads the flag. It does not make complex operations atomic.
Atomicity
An operation is atomic if it cannot be interrupted halfway in a way that exposes a broken intermediate state.
On an 8-bit CPU, reading a 16-bit counter may require two byte reads. An ISR could update the counter between those reads.
static volatile uint16_t tick_count;
uint16_t ticks_snapshot(void)
{
uint16_t snapshot;
disable_interrupts();
snapshot = tick_count;
enable_interrupts();
return snapshot;
}
Keep critical sections short.
Shared Ring Buffer Pattern
Only one context should update each index when possible. For example, the ISR updates head, while main updates tail.
ISR Rules
- Keep ISRs short.
- Avoid blocking waits.
- Avoid heavy formatting and dynamic allocation.
- Clear or acknowledge the interrupt source correctly.
- Defer processing to the main loop or a task when possible.
Common Mistakes
- Assuming
volatile count++is atomic. - Calling slow drivers from an ISR.
- Forgetting to clear the interrupt flag.
- Sharing multi-byte variables without a critical section.
- Disabling interrupts for too long.
Summary
Interrupts are powerful because they react quickly, but they create shared-data problems. Use volatile for visibility, critical sections for atomic snapshots or updates, and small ISRs that hand work to foreground code.