STM32 Timer Input Capture Guide
Pulse and PWM Measurement, Input Capture with DMA, Encoder Mode and Overflow Handling
1. Introduction — Measuring the Outside World with the Timer
Timers are the STM32 peripheral that most often decides whether a design is elegant or clumsy. Input capture turns a timer into a precise time stamping engine: a rising edge on a pin latches the counter value into the capture register, and the difference between two latches is the period, the pulse width or the duty cycle with a resolution set only by the timer clock and the prescaler. Compared with reading a GPIO and calling a microsecond delay function, input capture gives nanosecond-level timing with no CPU involvement, no interrupt latency jitter in the measurement itself, and the ability to capture at rates far beyond what software polling can follow. This guide covers the input capture path from pin to register, the prescaler/ARR arithmetic that sets range and resolution, PWM input mode, the DMA burst mode for long buffers of captures, encoder mode for quadrature signals, the overflow and edge cases that silently corrupt measurements, and a complete worked example that measures a 50 Hz–5 kHz PWM signal with 1 µs resolution. It complements the STM32 timer/PWM and DMA design guides on this site.
2. The Input Capture Path
Physically, an input capture channel consists of: a GPIO pin in alternate function mode, the alternate function mux to the timer channel, an edge detector (rising, falling or both), an optional digital filter and prescaler on the input, an input selection (direct, indirect, or TRC), and the capture/compare register (CCR). When the selected edge occurs, the current counter (CNT) value is copied into CCR and the corresponding CCxIF flag is set. The measurement is therefore:
ΔT = (CCR2 − CCR1) / f_timer, with f_timer = f_tim_clk / (PSC + 1)
The timer clock is typically the APB timer clock (which may be twice the APB clock, depending on the clock tree configuration), so the first step is always to know the actual timer clock frequency. The input filter (ICF bits) samples the input with a digital filter clock derived from f_DTS, letting you reject spikes shorter than the chosen window — essential when the signal comes from a cable or a mechanical switch. The input prescaler (ICPS) divides the captured events, useful for very fast signals where you want one capture every N edges. The capture prescaler (CCxPSC, on newer families) further divides. On an STM32F4 running at 168 MHz with an APB2 timer clock of 168 MHz, no prescaler gives 5.95 ns resolution; a prescaler of 167 gives 1 µs resolution and a 32-bit (or 16-bit with ARR) range of 65 ms. The resolution/range trade is the first design decision, and the timer’s PWM frequency and period arithmetic is quickly verified with the STM32 timer PWM calculator.
3. Modes of Measurement
| Mode | Configuration | Measures | Caveat |
|---|---|---|---|
| Simple capture (1 channel) | CCxS = input, edge = rising | Period (from consecutive captures) | Software must handle the difference and the overflow |
| PWM input (2 channels, 1 pin) | CH1 rising → IC1, CH2 falling → IC2, same TI1 | Period (IC1) and pulse width (IC2) | Requires the slave mode reset or careful ARR handling |
| Dual-edge on one channel | Edge = both, capture both | Period and pulse alternately | Software must know which edge was captured |
| Capture + DMA burst | DMA on the CCx event, fixed buffer | Long streams of timestamps | Circular buffer and index management |
| Encoder mode | Both channels, TI1/TI2 quadrature | Position and direction | Counts ×1/×2/×4 depending on the mode |
PWM input mode is the most useful for reading a servo signal, a tachometer or a PWM sensor: the hardware routes the same pin (TI1) to both capture channels, one on the rising edge and one on the falling edge, so that reading CCR1 and CCR2 gives the period and the high time in a single pass with no software arbitration. Many STM32 families even support a “PWM input with reset” slave mode in which the counter is reset by the rising edge, making CCR1 the period and CCR2 the pulse width directly. The measurement’s accuracy is then limited by the timer clock and by the input filter’s delay, not by the interrupt latency — which is the whole point of using the hardware.
4. DMA Burst and the Capture Buffer
To capture a continuous stream (for example, decoding a 100 kHz signal whose period varies, or recording the timing of many events), route the capture event to a DMA request. The standard pattern uses a circular DMA buffer of e.g. 256 × 32-bit words, with the DMA transferring the CCR value (or the whole timer register set in “DMA burst” mode, which copies several registers per request) into the array. The CPU then processes the buffer in blocks, using the DMA’s half-transfer and transfer-complete interrupts to know which half is ready. Key details: (a) the buffer must be aligned and, on some families, the DMA requests must be configured in the DMAR field of TIMx_DCR; (b) a capture that occurs while the DMA is serving the previous request is lost, so the buffer length and the CPU’s processing rate must match the event rate (a 1 MHz capture stream cannot be processed by an interrupt-driven design, but a DMA-fed buffer can); (c) the timer’s overflow must be counted or reconstructed, because a 16-bit counter wraps and the timestamps alone are ambiguous — either use a longer timer, or capture the overflow flag through another channel/IT and reconstruct, or reset the counter from the signal (slave reset mode). The DMA stream allocation and its request mapping are quick to check with the DMA stream allocator.
5. Code Snippet — PWM Input with DMA on an STM32F4
The following uses TIM2 with HAL: channel 1 on PA0 in PWM input mode, DMA2 Stream 5 on the channel 1 capture request. Every rising-edge capture writes CCR1 and CCR2 into a two-word circular buffer.
/* TIM2 clock 84 MHz (APB1 x2). Prescaler 84 -> 1 MHz (1 us resolution). */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 84 - 1; /* 1 MHz counter */
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFF; /* free running */
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_IC_Init(&htim2);
/* Channel 1 rising -> IC1, channel 2 falling -> IC2, slave reset on TI1FP1 */
TIM_SlaveConfigTypeDef sSlave = {0};
sSlave.SlaveMode = TIM_SLAVEMODE_RESET;
sSlave.InputTrigger = TIM_TS_TI1FP1;
HAL_TIM_SlaveConfigSynchro(&htim2, &sSlave);
TIM_IC_InitTypeDef sIC = {0};
sIC.ICPolarity = TIM_ICPOLARITY_RISING;
sIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sIC.ICPrescaler = TIM_ICPSC_DIV1;
sIC.ICFilter = 0x8; /* 8-sample digital filter */
HAL_TIM_IC_ConfigChannel(&htim2, &sIC, TIM_CHANNEL_1);
sIC.ICPolarity = TIM_ICPOLARITY_FALLING;
sIC.ICSelection = TIM_ICSELECTION_INDIRECTTI;
HAL_TIM_IC_ConfigChannel(&htim2, &sIC, TIM_CHANNEL_2);
/* Circular DMA: every CC1 event copies CCR1+CCR2 into buf[2] */
hcap.Instance = DMA2_Stream5;
hcap.Init.Channel = DMA_CHANNEL_3;
hcap.Init.Direction = DMA_PERIPH_TO_MEMORY;
hcap.Init.PeriphInc = DMA_PINC_DISABLE;
hcap.Init.MemInc = DMA_MINC_ENABLE;
hcap.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hcap.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hcap.Init.Mode = DMA_CIRCULAR;
HAL_DMA_Init(&hcap);
HAL_DMA_Start(&hcap, (uint32_t)&TIM2->CCR1, (uint32_t)buf, 256);
__HAL_TIM_ENABLE_DMA(&htim2, TIM_DMA_CC1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_2);
/* Processing: with slave reset, buf[0] = period (CCR1), buf[1] = pulse (CCR2) */
uint32_t period_us = buf[0] + 1; /* 1 us tick */
uint32_t pulse_us = buf[1] + 1;
uint32_t duty_permille = (1000UL * pulse_us) / period_us;
Two practical notes on the snippet: with slave reset mode the counter restarts on every rising edge, so the overflow handling disappears and the arithmetic is trivial — this is the configuration to prefer whenever the signal is periodic. And the DMA request TIM_DMA_CC1 must be enabled after the DMA stream is started, otherwise the first requests are lost.
6. Encoder Mode and Overflow Handling
For quadrature encoders, encoder mode decodes the two channels in hardware: the counter increments or decrements according to the phase relationship and the configured counting mode (×1, ×2 or ×4). The count gives position; the difference over a sampling interval gives velocity, which for motor control should be computed with a fixed sampling period so that the velocity estimate stays consistent. The classic pitfalls: (a) a 16-bit counter wraps, so the delta between two samples must be computed modulo 65536 (in C, int16_t delta = (int16_t)(now - prev); handles the wrap correctly); (b) missing edges from a slow opto-coupler or a long cable attenuate the signal and lose counts — use the digital filter and check the encoder’s edge rate against the timer’s filter clock; (c) the count direction depends on the encoder’s A/B polarity, so a swapped pair inverts the velocity sign without affecting the position magnitude; (d) the encoder’s mechanical Z/index channel should be captured to establish an absolute reference, not polled. Overflow handling is the single most common source of “the speed reading occasionally jumps” complaints in timer-based measurement: every path that computes a difference between two counter values must have a defined behaviour when the counter wrapped, either by using a 32-bit timer, by reconstructing the overflow count, or by resetting the counter from the signal itself.
7. Worked Example — Measuring a 50 Hz–5 kHz PWM Signal with 1 µs Resolution
Target: read an RC receiver’s PWM output (50 Hz, 1–2 ms pulse), a fan tachometer (up to 5 kHz, 50% duty) and an analog sensor’s PWM (1 kHz, variable duty) with 1 µs resolution and no CPU-side timing. MCU: STM32F4 at 84 MHz APB1 timer clock.
- Timer clock chain: APB1 = 42 MHz, timer clock = 84 MHz. Prescaler = 83 → 1.0 MHz counter, 1 µs per tick. The prescaler/ARR arithmetic is confirmed with the STM32 timer PWM calculator.
- Range: 50 Hz period = 20 ms = 20 000 counts, inside the 16-bit range (65 535) with margin; the 5 kHz case is 200 counts. No ARR wrap issue for these signals, but with a 1 µs tick and a 50 Hz signal the counter is idle 90% of the time — that is fine and costs nothing.
- Configuration: PWM input mode with slave reset on TI1FP1, IC1 on rising, IC2 on indirect falling, digital filter 8 samples at f_DTS = f_TIM/32 ≈ 2.6 MHz → filters pulses shorter than ~3 µs. Increase the filter for a noisy tachometer cable; the filter adds latency but not error to a periodic measurement.
- DMA: circular buffer of 128 × 2 words on DMA2 Stream 5 (channel 3 for TIM2_CH1 on the F4). At 5 kHz the event rate is 5 000 captures/s × 2 words = 40 kB/s, trivial for the DMA; the CPU processes the buffer every 10 ms and applies a median filter to reject outliers.
- Validation: feed a calibrated signal generator at 50 Hz / 1.5 ms and 5 kHz / 50%, confirm the readings against a scope; check the error budget: 1 tick quantisation (±1 µs), the input filter delay (constant, cancels in period measurement), the reference clock tolerance (the HSE crystal, ±20 ppm in this case → negligible compared with the 1 µs tick).
- Edge cases: at power-up, before the first valid capture, the buffer holds zeros → initialize the buffer to a sentinel and ignore the first sample; if the signal disappears, the counter free-runs and the DMA stops → use a timeout on the DMA’s transfer-complete or a periodic check that buf[0] changed, and report a signal-lost flag rather than a stale reading.
8. Clocking, Resolution Arithmetic and Prescaler Strategy
Every input-capture design begins with an arithmetic question: what resolution and what maximum interval do I need, and what prescaler and counter width give me both? The relationships are simple but the trade-off is not always obvious. The capture resolution is one counter tick:
t_tick = PSC_divisions / f_timer , t_max = (ARR_max + 1) · t_tick = 2^N · t_tick
where the timer’s input clock f_timer comes from APB with the timer’s own doubling rule (on most STM32 families, if the APB prescaler is greater than 1, the timer clock is twice the APB clock), PSC_divisions = PSC + 1, and N is the counter width (16 bits for TIM2–TIM5 on many parts, 32 bits for TIM2/TIM5 on some families). The design tension: a fine resolution (small t_tick) with a 16-bit counter limits the measurable interval to 65536 ticks — at 1 µs resolution that is only 65.5 ms, so a 1 Hz input (1 s period) would overflow the counter many times before the next edge arrives. Solutions, in order of preference:
- Choose the prescaler from the longest interval, then check the resolution. For a 50 Hz–5 kHz measurement (period 200 µs–20 ms), a 1 µs tick needs 20000 counts for the longest period, well inside 16 bits (65535). A 1 µs tick from a 72 MHz timer needs PSC = 71.
- Count overflows in software and combine. If the interval can exceed the counter’s range, enable the update interrupt (or use its flag), increment a software overflow counter, and reconstruct the interval as
(N_overflows · 2^N) + (capture2 − capture1)with attention to the wrap-around. This extends the measurable interval arbitrarily at the cost of a periodic interrupt and careful handling of the race between the overflow flag and the capture flag (read the flags and the counter in a defined order, and re-check). - Use a 32-bit timer where the family provides one — the cleanest solution when it is available.
- Adaptive prescaler: for a very wide input range (from Hz to tens of kHz), change the prescaler dynamically based on the measured period — but note the capture must not be taken during the prescaler change (the first capture after a PSC write is unreliable), so allow one input period to pass before trusting a sample.
- Resolution versus jitter: a tick of 1 µs quantises the measurement to ±1 µs (±0.5 µs if the input is asynchronous and averaged). Averaging N periods reduces the random component by √N but not the quantisation, so the required resolution must come from the tick, not from averaging alone.
Two practical notes complete the picture. First, the counter’s clock and the timer’s input must be synchronous for some capture modes (the input filter and the edge detector run on the timer clock), so the maximum input frequency is bounded not only by the counter width but by the input filter’s sampling: the digital filter (CKD/ICF bits) samples the input at f_DTS, and a filter length of 8 requires the input’s high and low times to exceed several DTS periods. Above a few hundred kilohertz, disable or shorten the filter and consider routing the signal to an external clock input instead of an input-capture channel. Second, watch the interactions between channels: all channels of one timer share the prescaler and the counter, so if one channel needs a 1 µs tick and another a 100 µs tick, they cannot share a timer instance — split them across timers, or restructure the measurement.
9. Verification Patterns and Debugging the Capture Path
Input capture is one of the easier peripherals to debug because every failure leaves a trace, but the traces must be interpreted in the right order. The procedure below resolves the vast majority of “the measurement is wrong” reports in a few minutes.
- Signal present at the pin? Probe the pin with a scope, at the package if possible. A signal that is present at the sensor and absent at the pin is a wiring, pull-up or alternate-function problem, not a timer problem. Confirm the GPIO mode is the alternate function for the timer channel and that the pin’s alternate-function selection register (AFRL/AFRH, or the AF matrix on newer families) really points at the timer.
- Captures arriving? Set a breakpoint or count interrupts; if the capture flag (CCxIF) never sets, the channel is not connected or the edge polarity is wrong (many timer channels default to a polarity that ignores the edge you expect). If the flag sets but the value reads 0, the capture is being read before the transfer is complete — read the capture register through the channel’s data register with the correct order, and clear the flag after reading.
- Period plausible but wrong by a constant factor? A factor of exactly 2 is almost always the APB timer clock doubling rule or a wrong prescaler divisor (PSC + 1 versus PSC). A factor equal to the number of overflows is the overflow accounting being missed.
- Jitter of a few counts? Expected: one count of quantisation plus the input filter’s sampling uncertainty. If the jitter is hundreds of counts, suspect a competing DMA channel, a low-priority interrupt that delays the read in non-DMA mode, or an unstable clock source (HSI versus a crystal).
- Works at low frequency, fails at high? The input filter’s sampling clock (fDTS) and its filter length set a minimum pulse width; shorten or disable the filter, and confirm the counter’s period is shorter than the input period.
- Value jumps by the full counter range? A wrap-around that is not handled: test the software with a period longer than 65536 ticks deliberately, and confirm the difference calculation handles the borrow correctly.
The verification pattern to build into the firmware is a self-test that does not depend on the device under test: drive the input from the MCU’s own timer (a second timer in PWM mode, outputting a known frequency and duty cycle into the capture channel through a short jumper). The measured value can then be compared against the nominal in software, and a pass/fail flag can be reported over the diagnostic interface. This “loopback calibration” catches prescaler arithmetic errors, wrong clock assumptions and DMA mapping mistakes within seconds of boot, and it is the single most valuable test to have in an instrument that must be trusted in the field.
10. Common Mistakes
- Wrong timer clock assumption: the APB timer clock is often ×2 the APB clock (or ×1 on some families); the measured resolution will be off by that factor if the prescaler is computed from the wrong base.
- Ignoring the overflow: a difference of two 16-bit captures computed without wrap handling produces a “negative period” every 65 535 ticks.
- Filtering the input too aggressively: the digital filter’s delay is constant (harmless for a period) but can completely reject a short pulse if the filter window exceeds the pulse width.
- Enabling the DMA request before starting the stream: the initial captures are lost and the buffer’s phase is unknown; start the stream first, then enable the request.
- Using interrupt-per-edge for fast signals: the CPU saturates and the timestamp jitter becomes the interrupt latency; use capture + DMA.
- Not validating the signal’s presence: the last captured value looks like a valid reading forever, even after the signal disappears; add a staleness check.
11. FAQ
Q: How do I get better than 1 µs resolution? A: Lower the prescaler (a 168 MHz timer gives 5.95 ns per tick) or use an input capture prescaler with the counter running faster; the limit is the timer clock and the input filter’s sampling clock.
Q: Can I capture on a pin that is not the channel’s default? A: Yes — use the GPIO alternate function mapping and the TIMx remap (or the AF matrix on newer families); only one alternate function can be active per pin.
Q: Why does my duty cycle read slightly wrong? A: The indirect channel’s polarity and the slave-reset configuration must match; also check the input filter delay affects the rising and falling edges equally (it should, in the same channel’s filter).
Q: Should I use one timer per signal? A: Prefer a timer with two channels per signal (PWM input mode) and share nothing; a timer per signal is acceptable and simplifies the DMA mapping when the count of signals is small.
12. Conclusion
Input capture turns the STM32 timer into a precise, CPU-free time measurement engine: pick the timer clock and prescaler for the required resolution and range, choose the mode that matches the signal (simple capture, PWM input, dual edge, encoder), stream the captures with DMA when the rate is high, and handle the overflow and staleness cases explicitly. Configured correctly, the measurement is accurate to the timer clock, immune to interrupt jitter, and leaves the CPU free for the actual application.