Timers & Interrupts
How hardware timers generate precise timing without CPU polling, and how interrupts let firmware react to events in real time.
GPIO, serial protocols, and analog I/O cover how firmware moves data. Timers and interrupts are what let firmware time things precisely and react to events without burning CPU cycles on polling.
Timers
A hardware timer is a register that increments on every clock tick (or every Nth tick, via a prescaler) and can trigger an event when it reaches a target value. This offloads precise timing from software loops, which are at the mercy of compiler optimization and interrupt jitter, onto dedicated silicon.
timer_frequency = clock_frequency / (prescaler + 1)
overflow_period = (auto_reload_value + 1) / timer_frequencyWorked example: a 16 MHz clock, prescaler of 15999, and auto-reload value of 999 gives:
timer_frequency = 16,000,000 / 16,000 = 1,000 Hz
overflow_period = 1,000 / 1,000 = 1 secondThis is the standard pattern for generating a precise 1 Hz tick without any CPU polling — the timer counts independently of whatever the main program is doing.
Interrupts
An interrupt lets a peripheral suspend normal program execution and jump to a dedicated handler the instant an event occurs — a timer overflow, an incoming UART byte, a GPIO edge — instead of the CPU repeatedly polling a status flag.
volatile uint32_t tick_count = 0;
void TIM2_IRQHandler(void) {
if (TIM2_SR & TIM_SR_UIF) { // overflow flag set
TIM2_SR &= ~TIM_SR_UIF; // clear it
tick_count++;
}
}Two rules matter once interrupts are involved:
- Any variable shared between an interrupt handler and main-line code must be
volatile— and for anything wider than the platform's atomic access width, it needs explicit protection (disabling interrupts briefly, or a hardware atomic instruction). - Keep interrupt handlers short. A handler that runs too long delays every lower-priority interrupt and can blow timing budgets elsewhere in the system. The common pattern is to do the minimum in the handler (clear the flag, capture data, set a flag) and defer the rest to the main loop or a task.
Polling vs. interrupts vs. DMA
| Approach | CPU involvement | Best for |
|---|---|---|
| Polling | Continuous, blocks other work | Simple, latency-insensitive bare-metal loops |
| Interrupt | Brief, only on event | Sporadic events: button press, UART byte |
| DMA | None — peripheral writes memory directly | High-throughput streams: ADC sampling, audio |
Understanding when to escalate from polling to interrupts to DMA is one of the more practical judgment calls in embedded firmware. It's also exactly where bare-metal loops start to strain under multiple competing timing demands — which is what the next lesson, Real-Time Systems & RTOS, is built to handle.