5.5.3 · D5Embedded Systems & Real-Time Software

Question bank — Timers — PWM generation, input capture, output compare

1,928 words9 min readBack to topic

Before we start, three plain-word reminders so no symbol below is unearned:

  • CNT = the counting register — it climbs one step per timer tick, like a clock hand sweeping.
  • ARR = the "top" the count wraps at. The counter shows distinct values per lap because it also shows .
  • CCR = a threshold/snapshot register. In compare mode you write it (it decides when the pin flips); in capture mode the hardware writes it (it records where CNT was when an edge hit).
  • PSC = prescaler — divides the source clock by to slow ticks down.

True or false — justify

Timer compare mode makes the pin the cause of the counter's value.
False. In compare/PWM the counter is the cause (Time → Pin): when CNT reaches CCR the hardware acts on the pin. The pin driving the counter is capture (Pin → Time), the opposite arrow.
Setting PSC = 72 divides a 72 MHz clock down to exactly 1 MHz.
False. The divider is , so PSC=72 divides by 73. You want PSC=71 for a divide-by-72 giving 1 MHz. The +1 exists so PSC=0 divides by 1, never by 0.
A PWM signal's frequency changes when you change the duty cycle.
False. Frequency is fixed by ARR (the whole lap length). Duty is CCR/(ARR+1) — moving CCR only shifts where HIGH turns to LOW inside the same-length lap, so period and frequency stay put.
Writing CCR = ARR gives exactly 100% duty cycle.
False. True 100% needs HIGH for all ticks, so you need CCR = ARR+1 (or the chip's special force-high). At CCR = ARR the pin still drops LOW for the single last tick.
In toggle output-compare mode, one match produces one full output period.
False. A toggle flips the pin, so it takes two matches (HIGH→LOW then LOW→HIGH) to complete one period. That is why output frequency = match-rate ÷ 2.
Doing PWM in a software while-loop with delay() is just as accurate as timer hardware.
False. Software timing jitters whenever an interrupt or other task steals CPU cycles, and it burns the CPU doing nothing but waiting. The timer peripheral flips the pin in hardware at the exact tick, independent of what the CPU is doing.
If two input captures give c2 < c1, the measurement is corrupt and must be discarded.
False. A smaller second value usually just means the counter wrapped between edges. The real elapsed count is , which recovers the correct positive value — no data is lost.
For a servo we should compute a duty-cycle percentage and set CCR from that.
False (in spirit). A servo reads pulse width in microseconds, not a percentage of the period. It is cleaner to pick 1 µs ticks and set CCR directly to the desired width (e.g. 1500 for 1.5 ms), so a period change never silently rescales your angle.
The counter makes exactly ARR ticks per cycle.
False. It makes ticks, because count 0 is a real tick too. Dropping the +1 makes your period slightly short and your PWM frequency slightly high — measurable on a scope.
Input capture has the same latency problem as reading a pin in a polling loop.
False. Capture is the whole point: the hardware snapshots CNT into CCR at the instant the edge arrives, before any software runs. Software latency after that only delays when you read the snapshot, not the recorded time itself.

Spot the error

"PWM period = ARR / f_clk, so with ARR=999 and 72 MHz the period is about 13.9 µs."
Two errors: it ignores the prescaler and the +1. Correct is . Both +1s and the actual PSC must appear.
"Prescaler set to 71 means each tick is 71 clock cycles long."
Off by one. PSC=71 divides by , so each tick is 72 source cycles, giving .
"Duty = CCR/ARR × 100%, and at CCR=ARR you're at 100%."
The denominator must be , not . With , reaching 100% needs ; at you are just below full.
"To make a 500 kHz square wave in toggle mode I need matches at 500 kHz."
You need matches at 1 MHz — twice the output — because two toggles make one full period. Match rate must be .
"c1=65000, c2=500 on a 16-bit timer, so elapsed = 500 − 65000 = −64500 ticks."
The negative result is the tell-tale of a wrap. Apply the modulo: ticks. Never trust a negative elapsed time.
"Since capture writes CNT into CCR, I can also read the live counter from CCR at any moment."
CCR holds the frozen value from the last edge, not the live count. The live value is in CNT; CCR only updates on the next capture event.
"I set the compare pin as a plain GPIO output, so PWM should appear on it."
The pin must be switched to its Alternate Function so the timer — not the GPIO output register — drives it. See GPIO and Alternate Functions. In plain GPIO mode the timer's signal never reaches the pin.

Why questions

Why does the prescaler divide by PSC+1 instead of PSC?
So the register can express divide-by-1. If it divided by PSC, then PSC=0 would mean divide-by-0 (undefined), and you could never run the timer at full clock speed. The +1 shifts the whole range up by one.
Why is data flow "Time → Pin" for compare but "Pin → Time" for capture?
Compare uses the counter as the trigger — when it hits CCR the hardware moves the pin, so the timer commands the world. Capture uses an external edge as the trigger — the pin event tells the hardware to record the counter, so the world commands the timer. Same compare/capture unit, opposite causal arrow.
Why does the mod handle counter overflow correctly in a capture measurement?
The counter lives on a ring of size (it wraps back to 0). Subtracting two positions on a ring and taking mod gives the true forward distance travelled, even if the ring's zero was crossed once in between. See Interrupts and NVIC for counting multiple overflows.
Why can't we just use a bigger ARR and skip prescaling entirely?
ARR is a fixed-width register (often 16-bit, max 65535). At high clock speeds a 16-bit ARR can only stretch the period so far before overflowing. The prescaler slows each tick first, letting the same ARR span a much longer real time. Both knobs together give the full range — see Clock Tree and Prescalers.
Why does an LED at 25% duty look dim rather than flicker, if it's really turning fully on and off?
When the PWM frequency is well above the eye's flicker-fusion rate (~a few hundred Hz), your eye time-averages the light and perceives only the fraction of on-time. So 25% on-time reads as 25% brightness, not flicker.
Why measure frequency with input capture instead of counting edges over a fixed second?
Capture measures one period directly with tick-level precision, so it responds within a single cycle and stays accurate at low frequencies where edge-counting would need to wait a whole second for enough events. Edge-counting is better only for very high, steady frequencies.
Why does toggle mode give a perfectly 50%-duty square wave for free?
Because each match flips the state and matches occur at even spacing, HIGH and LOW each last exactly one match-interval. Equal halves means 50% duty automatically — no CCR comparison needed inside the period.

Edge cases

What does the pin do at CCR = 0 in "HIGH while CNT < CCR" PWM?
CNT < 0 is never true, so the pin stays LOW the entire lap — that's 0% duty, the fully-off case.
What happens to output frequency if you set ARR = 0?
The counter has only one value (0) and wraps every single tick, so the period collapses to one tick. Frequency becomes itself — the fastest, degenerate case.
Two capture edges arrive with c1 == c2. What does that mean?
Either the two edges landed in the same tick (period shorter than one tick — you need finer ticks) or the counter wrapped an exact whole number of laps. Mod gives , which is ambiguous; you must also track overflow interrupts to tell these apart.
The measured signal's period is longer than one full counter lap. Is the mod formula enough?
No. A single mod only unwraps one overflow. For multi-lap periods you must count overflow interrupts and use elapsed ; the bare mod would report a spuriously short time.
CCR is set larger than ARR+1. What duty results?
CNT never reaches such a large CCR, so the pin stays HIGH for the whole lap — the 100% (fully-on) case, clamped by the counter's maximum.
At the exact wrap moment, is the last tick (count = ARR) counted or skipped?
It is counted. The lap is — that's ticks — and only after showing ARR does the counter reload to 0. Skipping it is exactly the "period uses ARR not ARR+1" mistake.
A motor PWM is set to a valid duty but the shaft doesn't turn until ~15%. Bug in the timer?
No — that's the motor/driver's static friction and dead-zone, not the timer. The PWM is faithfully producing the commanded duty; low duties simply don't deliver enough torque. See Motor Control and H-Bridges.

Recall One-line self-audit

Cover every answer above and re-derive the reason, not just the verdict. If you can explain each with a picture (the counter as a sweeping clock hand, CCR as a mark on the dial), you own the topic.

Connections

  • GPIO and Alternate Functions — the pin must be in AF mode for compare/PWM to reach it.
  • Interrupts and NVIC — overflow ISRs let capture measure multi-lap periods.
  • Clock Tree and Prescalers — the source of and the reason ARR alone isn't enough.
  • Motor Control and H-Bridges — where a "valid duty, no motion" edge case comes from.
  • Servo and ESC Control — why pulse-width, not duty-%, is the right mental model.
  • Encoder Mode — a capture-cousin where the timer counts quadrature edges.