Concept Q&A
10 questions
Popular

Timers & PWM — Interview Questions & Answers

Common timer and PWM interview questions covering frequency calculation, duty cycle, capture/compare, dead-time, encoder mode, and timer synchronization.

Study the fundamentals first

Read the Timers & PWM topic page for in-depth concepts before practicing Q&A

Timer Architecture

QHow do you calculate the PWM frequency on an STM32 timer? Walk through the formula.

The PWM frequency is determined by three values: the timer input clock, the prescaler register, and the auto-reload register. The formula for edge-aligned (up-counting) mode is:

text
f_PWM = f_CLK / ((PSC + 1) * (ARR + 1))

The prescaler (PSC) divides the timer input clock — a PSC value of 0 means divide-by-1, a value of 71 means divide-by-72. The auto-reload register (ARR) sets the period — the timer counts from 0 to ARR, then resets, so the total number of counts per period is ARR + 1. The "+1" terms are critical interview details because the counter includes both 0 and the max value. For example, with a 72 MHz timer clock, PSC = 71, and ARR = 999: f_PWM = 72,000,000 / (72 * 1000) = 1,000 Hz.

A common follow-up is "how do you choose PSC and ARR for a target frequency?" The general approach: first decide the desired duty cycle resolution (more ARR steps = finer resolution), then calculate PSC to achieve it. For 1 kHz PWM with 1000 steps of resolution, you need (PSC + 1) * 1000 = 72,000,000 / 1000 = 72,000, so PSC + 1 = 72, giving PSC = 71. Always verify the actual frequency by plugging back into the formula, since integer-only registers may not divide evenly for all targets. For center-aligned mode, the effective frequency is halved because the counter counts up and then back down: f_PWM = f_CLK / ((PSC + 1) * 2 * ARR).

QHow do you handle timer overflow (update events) correctly?

Timer overflow occurs when the counter reaches ARR and wraps to 0 (in up-counting mode) or reaches 0 from ARR (in down-counting mode). The hardware sets the Update Event Flag (UIF) in the status register, and if the Update Interrupt Enable (UIE) bit is set, an interrupt request fires. Inside the ISR, you must clear the UIF flag before returning — failing to do so causes the interrupt to fire continuously, locking up the CPU in an infinite ISR loop. On STM32, this means TIMx->SR &= ~TIM_SR_UIF; as the first line of the handler (not the last, to avoid a race with the NVIC tail-chaining).

For counting events or measuring time beyond the timer's 16-bit range (0-65535), maintain a software overflow counter that increments in the update ISR. The total count is overflow_count * (ARR + 1) + current_counter. However, a subtle race condition exists: if you read the overflow count and the counter register non-atomically, an overflow that occurs between the two reads corrupts the result. The safe pattern is to read the overflow count, read the counter, then check UIF — if UIF is set and the counter value is small (meaning it just wrapped), add one to your overflow copy before computing the total.

c
uint32_t get_extended_count(void) {
uint32_t ovf = overflow_count;
uint32_t cnt = TIM2->CNT;
if ((TIM2->SR & TIM_SR_UIF) && cnt < (TIM2->ARR >> 1)) {
ovf++; // Overflow occurred between reads
}
return ovf * (TIM2->ARR + 1) + cnt;
}
QExplain the trade-off between PWM frequency and duty cycle resolution.

Both frequency and resolution are constrained by the timer clock. The duty cycle has (ARR + 1) discrete steps, and the minimum duty cycle increment is 1 / (ARR + 1). Higher PWM frequency requires a smaller ARR value (since f_PWM = f_CLK / ((PSC + 1) * (ARR + 1))), which directly reduces the number of available duty cycle steps. This is a fundamental hardware constraint that cannot be avoided — you are distributing a fixed number of timer clock ticks between frequency and resolution.

Consider a concrete example with a 72 MHz timer clock and PSC = 0: at 1 kHz PWM, ARR = 71999, giving 72000 duty cycle steps (approximately 16.1 bits of resolution). At 100 kHz, ARR = 719, giving only 720 steps (approximately 9.5 bits). At 1 MHz, ARR = 71, giving just 72 steps (approximately 6.2 bits). For a motor controller that needs 10-bit resolution (1024 steps) at 20 kHz, the required timer clock is at least 20,000 * 1024 = 20.48 MHz — easily achievable with any modern MCU.

When the application demands both high frequency and fine resolution beyond what the timer clock supports, the solutions are: (1) use a faster timer clock if the MCU permits it, (2) use dithering — alternate between adjacent duty cycle values across multiple PWM periods so the time-averaged duty cycle has higher effective resolution than any single period, or (3) use a dedicated PWM controller IC with higher bit-depth counters (some motor control ICs have 300+ MHz counter clocks).

PWM Generation

QHow do you control the duty cycle of a PWM signal?

The duty cycle is set by the Capture/Compare Register (CCR) relative to the ARR value. In edge-aligned PWM mode 1 (the most common configuration), the output is active (high) while the counter value is less than CCR, and inactive (low) from CCR to ARR. The formula is:

text
Duty cycle = CCR / (ARR + 1) * 100%

For example, with ARR = 999 and CCR = 250, the duty cycle is 250/1000 = 25%. Setting CCR = 0 gives 0% duty (always low), and setting CCR to a value equal to or greater than ARR + 1 gives 100% duty (always high). The critical insight is that ARR controls the frequency and CCR controls the duty cycle independently — you can change duty cycle on the fly by writing to CCR without affecting frequency. In PWM mode 2, the polarity is inverted: the output is inactive while the counter is less than CCR and active above it.

To prevent glitches when updating CCR mid-cycle, enable the preload feature (OCxPE bit in the CCMRx register). With preload enabled, writes to CCR go into a shadow register, and the actual CCR is updated atomically at the next counter overflow (update event). Without preload, writing a new CCR value while the counter is between the old and new CCR values can produce a partial-width or extra-width pulse for that one period. The ARPE bit provides the same protection for the ARR register. Always enable both preloads in any application where glitch-free updates matter (motor control, LED dimming, power converters).

QWhat is the difference between center-aligned and edge-aligned PWM?

In edge-aligned mode, the counter counts up from 0 to ARR, generates an overflow event, resets to 0, and repeats. This produces a sawtooth waveform. PWM transitions happen at two points: the output goes high at counter reset (0) and goes low when the counter reaches CCR. All PWM channels on the timer switch at the same counter-reset instant, creating simultaneous current transients. Edge-aligned is simpler to understand and is the default for most applications — LED dimming, servo control, simple power regulation.

In center-aligned mode, the counter counts up from 0 to ARR, then counts back down from ARR to 0, creating a triangular waveform. PWM transitions happen symmetrically — the output toggles once on the up-count when the counter reaches CCR, and again on the down-count when it passes back through CCR. This produces pulses that are centered within each period. The PWM frequency is halved for the same ARR value because one full up-down cycle takes 2 * ARR clock ticks: f_PWM = f_CLK / ((PSC + 1) * 2 * ARR).

Center-aligned mode is strongly preferred for motor control because the symmetric switching pattern spreads current transients across the period rather than concentrating them at the counter reset. In a 3-phase inverter, this reduces peak current ripple, lowers audible noise, and significantly reduces EMI. It also creates a natural ADC sampling point at the center of the PWM period (counter = 0 or counter = ARR), where the current waveform is at its midpoint and most representative of the average value — this is critical for field-oriented control (FOC) algorithms. The cost is reduced frequency for a given ARR and slightly more complex timing analysis.

Input Capture and Output Compare

QWhat is the difference between input capture and output compare modes?

Input capture uses the timer to measure external signals. When an edge is detected on the timer's input pin (TIx), the timer's current count value is latched into the CCR register, preserving a precise timestamp of when the edge occurred. By capturing timestamps of successive edges, firmware can calculate signal frequency, period, pulse width, or duty cycle without any CPU timing involvement. For example, capturing two consecutive rising edges and computing the difference gives the period. Capturing a rising edge and the next falling edge gives the pulse width. This is the basis for tachometers, frequency counters, ultrasonic distance sensors, and IR remote decoders. Input capture can also trigger DMA to store a sequence of timestamps without CPU intervention — essential for decoding complex pulse trains.

Output compare uses the timer to generate precisely timed output events. When the counter matches the CCR value, the hardware can toggle, set, clear, or freeze the output pin — all in hardware with zero CPU latency. PWM generation is the most common output compare application. Outside of PWM, output compare is used for one-shot pulse generation, precise timing of external events (triggering an ADC conversion, firing a strobe), and generating waveforms with specific timing relationships. The fundamental difference is directionality: input capture reads external timing into the MCU, while output compare drives MCU timing out to the external world.

A common interview trap: candidates conflate input capture with simply reading a GPIO pin in an interrupt. The key difference is that input capture latches the counter value at the exact instant of the edge in hardware, giving sub-microsecond timing precision. A GPIO interrupt only tells you an edge happened — by the time the ISR reads the timer counter, interrupt latency (potentially several microseconds with higher-priority interrupts pending) has corrupted the measurement.

QHow does encoder mode work on STM32 timers?

Encoder mode configures a timer to decode quadrature encoder signals using two input channels (TI1 and TI2, typically mapped to CH1 and CH2 pins). A quadrature encoder produces two square waves 90 degrees out of phase — when the shaft rotates forward, channel A leads channel B by 90 degrees; when it rotates backward, B leads A. The timer hardware decodes this phase relationship automatically: the counter increments for forward rotation and decrements for reverse rotation, all with zero CPU overhead.

Three encoder modes are available: Mode 1 counts on TI1 edges only (2x resolution), Mode 2 counts on TI2 edges only (2x resolution), and Mode 3 counts on both edges of both channels — giving 4x resolution (four counts per encoder slot). For a 1000-line encoder in Mode 3, you get 4000 counts per revolution, corresponding to 0.09-degree angular resolution. The timer hardware also includes digital noise filters (ICxF bits) that reject glitches shorter than a configurable number of clock cycles — essential in electrically noisy motor environments.

The counter naturally handles direction changes without software logic. Firmware simply reads TIMx->CNT to get the current position. For absolute position tracking beyond the 16-bit counter range (0-65535), enable the update interrupt and maintain a software overflow/underflow counter, extending the range to 32 bits. The counter direction bit (DIR in the CR1 register) indicates the current rotation direction. ARR is typically set to the maximum (0xFFFF for 16-bit timers or 0xFFFFFFFF for 32-bit timers) to maximize the range before overflow.

Motor Control

QWhat is dead-time insertion, and why is it critical for motor control?

Dead-time insertion adds a brief delay between turning off one transistor in a half-bridge and turning on the complementary transistor on the opposite side. This delay is necessary because power MOSFETs and IGBTs do not turn off instantaneously — the gate charge must be removed and the current through the device must fall to zero, a process that takes tens to hundreds of nanoseconds depending on the device. If the complementary transistor turns on before the first one has fully turned off, both transistors conduct simultaneously, creating a direct short circuit from the power rail to ground. This shoot-through event causes massive current spikes (potentially hundreds of amps for microseconds) that can destroy both FETs instantly, damage the gate drivers, and create severe EMI events.

On STM32, the advanced timers (TIM1, TIM8) provide complementary output channel pairs (CHx and CHxN) with a hardware dead-time generator controlled by the DTG field in the BDTR (Break and Dead-Time Register). The dead-time duration is specified in timer clock ticks and typically ranges from 100 ns to 2 us, depending on the FET switching characteristics. The DTG field uses a non-linear encoding that provides fine resolution at short dead-times and coarser steps at longer values. The dead-time must be longer than the worst-case turn-off time of the transistor (including driver propagation delay) but short enough to avoid excessive output waveform distortion.

A critical safety point: never implement dead-time in software alone. Software dead-time relies on CPU timing between writing two GPIO pins, which is vulnerable to interrupt latency — a single ill-timed interrupt could eliminate the dead-time entirely, causing shoot-through. The hardware dead-time generator in the timer operates independently of the CPU and guarantees the minimum dead-time under all conditions. The BDTR register also includes a break input (BRK) that immediately forces all outputs to a safe state (high-impedance or predetermined level) in response to an external fault signal — such as an over-current detector.

QWhat is one-pulse mode (OPM), and when would you use it?

One-pulse mode configures the timer to generate a single pulse of precise duration in response to a trigger event, then stop automatically. When triggered (by software, an external signal, or another timer), the counter starts from zero. The output remains inactive until the counter reaches CCR (this is the configurable delay before the pulse), then goes active. When the counter reaches ARR, the output deactivates and the counter stops — the OPM bit in CR1 prevents the counter from restarting. The result is one pulse with a programmable delay of CCR ticks and a width of (ARR - CCR) ticks, all generated entirely in hardware.

This is useful for generating precise one-shot timing events without continuous CPU involvement: producing an exact-width reset pulse for an external IC, triggering a camera shutter or strobe light for a measured duration, controlling solenoid activation time, or creating a programmable monostable (one-shot) multivibrator. The advantage over software timing (delay loops or timer ISRs) is that the pulse width is cycle-accurate and independent of CPU load or interrupt latency. The trigger source flexibility is also valuable — you can chain one-pulse mode with input capture so that a specific external event automatically produces a hardware-timed response pulse with zero software latency.

One subtlety: after the pulse completes, the timer is stopped and must be re-armed before it can generate another pulse. This means OPM is not suitable for repetitive pulse generation — use standard PWM for that. For retriggerable one-shot behavior (restart the pulse if a new trigger arrives before the current pulse finishes), you need to configure the slave mode controller to reset the counter on each trigger, combined with OPM.

Timer Synchronization

QHow can you synchronize multiple timers, and why would you need to?

STM32 timers can be interconnected using the internal master/slave trigger system. A master timer outputs a trigger signal (TRGO — Trigger Output) on configurable events: counter enable, overflow (update), compare match, or output compare pulse. A slave timer receives this trigger through internal trigger inputs (ITR0 through ITR3, each hard-wired to a specific master timer) and responds according to its configured slave mode — it can start, stop, reset, gate, or clock its counter based on the trigger.

Common use cases include: (1) Cascading timers for extended counting range — a master timer's overflow event clocks a slave timer, creating a 32-bit counter from two 16-bit timers. This is essential when TIM2/TIM5 (the 32-bit timers) are unavailable. (2) Synchronized multi-phase PWM — all PWM channels across multiple timers start counting at exactly the same instant. This is critical for 3-phase motor control where the phase relationships between U, V, and W PWM signals must be exact. Even a few clock cycles of skew between timer starts can cause current imbalance and torque ripple. (3) Timer-triggered ADC sampling — a timer TRGO triggers ADC conversions at precise intervals with zero CPU intervention and zero jitter, far more accurate than software-triggered sampling. (4) Gated counting — one timer enables another only during a measurement window, useful for frequency counting applications.

The internal trigger routing (which ITR connects to which timer) is fixed in silicon and varies between STM32 families. Getting the mapping wrong is a common bug — always consult the reference manual's "TIMx internal trigger connection" table. For example, on STM32F4, TIM1's TRGO is connected to TIM2's ITR0, TIM3's ITR0, and TIM4's ITR0 — but TIM8's TRGO connects to different ITR inputs on each slave. There is no way to change these mappings in software; if the required trigger path does not exist, you must use a different timer combination or route the trigger through a GPIO pin and use external trigger mode.