Timers: Delay Loops vs Hardware Timers
One burns CPU cycles.
One uses dedicated hardware.
Only one gives reliable timing.
1. The First Approach Everyone Tries
You need a delay.
So you write a loop.
It works… for now.
So you write a loop.
- run N iterations
- assume it equals time
It works… for now.
2. What a Delay Loop Really Is
A delay loop is not measuring time.
It’s just executing instructions.
Its duration depends on:
So your “delay” is actually:
Change any of those → the delay changes.
It’s just executing instructions.
Its duration depends on:
- CPU frequency
- number of instructions
- compiler optimization
- pipeline and cache behavior
So your “delay” is actually:
instruction count × execution time per instructionChange any of those → the delay changes.
3. Why It Breaks
Optimization
At higher optimization (
CPU Frequency
If the clock changes:
Interrupts
If interrupts occur:
So delay loops are: non-deterministic in real systems.
At higher optimization (
-O2, -O3):
- the loop may get shortened
- instructions may be removed
- sometimes the loop disappears entirely
CPU Frequency
If the clock changes:
- delay scales directly
- 2× clock → half the delay
Interrupts
If interrupts occur:
- loop execution pauses
- the delay becomes significantly longer than expected
So delay loops are: non-deterministic in real systems.
4. Hardware Timers — Different Model
Timers are independent peripherals.
They run based on:
Once configured:
Timing becomes based strictly on clock cycles, not instruction flow.
They run based on:
- the system clock or a prescaler
- dedicated hardware counters
Once configured:
- they increment regardless of CPU execution
- they generate events on match/overflow
Timing becomes based strictly on clock cycles, not instruction flow.
5. Why Timers Are Reliable
Hardware timers provide:
Even if the CPU is busy, interrupts occur, or code changes, the timer keeps counting correctly.
- deterministic timing
- independence from code execution
- consistent behavior across builds
Even if the CPU is busy, interrupts occur, or code changes, the timer keeps counting correctly.
6. CPU Cost Comparison
Delay Loop:
Hardware Timer:
- CPU fully occupied
- no parallel work
- power inefficient
Hardware Timer:
- near-zero CPU usage
- CPU can sleep or execute other tasks
- interrupt only when needed
7. Real Failure Cases
Delay loops fail in real firmware when:
These bugs are incredibly subtle because: the logic looks correct, but the timing is not.
- communication timing drifts (UART, SPI, I2C)
- protocol delays become inaccurate
- watchdog timing is miscalculated
- system behavior inexplicably changes after turning on optimization
These bugs are incredibly subtle because: the logic looks correct, but the timing is not.
8. Practical Firmware Thinking
Use delay loops only when:
Use timers when:
Next
→ ISR Rules
- you need very short delays (microseconds or less)
- doing early bring-up before timers are ready
- non-critical timing
Use timers when:
- timing strictly matters
- the system scales in complexity
- interrupts exist in the system