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.

  • 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:
  • CPU frequency
  • number of instructions
  • compiler optimization
  • pipeline and cache behavior

So your “delay” is actually:
instruction count × execution time per instruction

Change any of those → the delay changes.

3. Why It Breaks

Optimization
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:
  • 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:
  • 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:
  • 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:

  • 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:
  • 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
Delay loops depend on execution.
Timers depend on hardware.
Only one is stable.