armhub.dev
Peripherals · 19 pages
Peripherals

Advanced control timers

TIM1 and TIM8 on STM32 — complementary PWM outputs, dead-time generator, break input, repetition counter, encoder and Hall sensor modes, and the master-slave synchronization that drives multi-timer motor-control pipelines.

7 min read · 1,496 wordsupdated · May 13, 2026

A "general-purpose" timer on Cortex-M does PWM, input capture, and basic counting. An advanced-control timer — TIM1 and TIM8 on STM32, HRTIM and TIM20 on some H7/G4 variants, eTPU on some NXP parts — is a different beast: complementary outputs, hardware dead-time, an emergency break input that asynchronously cuts PWM in nanoseconds, repetition counters for centered PWM, encoder and Hall interfaces, and synchronization links that let you wire a half-dozen timers into a single coherent motor-drive pipeline. This is the hardware that makes ARM Cortex-M competitive against dedicated DSPs and FPGAs in BLDC, PMSM, three-phase grid, and digital-PSU applications.

This page is a tour of what the advanced timer adds over the GP timer, with motor-control as the leading use case.

Advanced-control timer at a glance
STM32 instances
TIM1, TIM8 (most lines); TIM15/16/17 partial; HRTIM and TIM20 on G4/H7
Counter width
16-bit (TIM1/8); 32-bit on TIM2/5 (GP) — advanced timers are 16-bit
Channels
Up to 4 channels (CH1..CH4), each with main output OCx and complementary OCxN (CH1..CH3 only)
Counter modes
Up, down, center-aligned (modes 1/2/3 — interrupt at OVF, UDF, or both)
Dead-time
8-bit programmable in BDTR.DTG; up to 1023× counter clock with non-linear DTG encoding
Break input
BKIN pin — asynchronous, drives all OCx/OCxN to a safe inactive state in <1 timer-cycle
Repetition counter
8-bit RCR — update events fire only every (RCR+1) counter overflows

Complementary outputs and dead-time

The defining feature. Three-phase inverters need pairs of MOSFETs/IGBTs per phase — a high-side and a low-side device. They must never be on simultaneously, or the DC bus shorts through both transistors (a "shoot-through" event, typically destructive). The high-side and low-side gate signals must therefore be complementary with a tiny dead-time between turn-off of one and turn-on of the other.

The advanced timer's channels 1–3 each have a complementary output (CH1N, CH2N, CH3N) that mirrors the main output with inversion and an inserted dead-time. The dead-time generator (BDTR.DTG[7:0]) programs both the high-side-off-to-low-side-on delay and the low-side-off-to-high-side-on delay simultaneously (they're the same in standard configurations).

The dead-time-generator encoding is intentionally non-linear so a single 8-bit field can cover a wide range:

DTG[7:5]Step (timer cycles)Range
0xx1×0..127 cycles
10x2×128..254 cycles
1108×256..504 cycles
11116×512..1008 cycles

At a 170 MHz counter clock (typical G4), one cycle is ~5.9 ns. Range covers 6 ns to 6 µs — covering everything from low-voltage GaN to high-voltage IGBT drives.

// 500 ns dead-time at 170 MHz timer clock = 85 cycles, encoded as 0x55
TIM1->BDTR = (TIM1->BDTR & ~TIM_BDTR_DTG_Msk) | (85 << TIM_BDTR_DTG_Pos);

Break input — emergency stop

Most motor drives need a hardware-level emergency shutdown that cannot be defeated by a software bug. The break input (BKIN, BKIN2 on parts with two break inputs) is an asynchronous active-low (or polarity-configurable) pin that, when asserted, immediately forces all OCx/OCxN outputs to a programmed safe state (BDTR.OSSI and CCMRx.OCxIDLE/OCxNIDLE).

Crucially, the response is gate-level asynchronous: from the moment BKIN is asserted, the timer outputs hit the safe state within one to two timer-clock cycles. There is no software involvement, no interrupt latency, no chance for a stuck task to keep the inverter running.

Break sources can also include:

  • Comparator output — over-current detected by an external comparator with a hardware-defined trip threshold.
  • HSE clock failure — the CSS (Clock Security System) detects oscillator failure and asserts break.
  • MCU lockup — Cortex-M can be wired to assert break on hard-fault-detected.

Break is latched until cleared by software (BDTR.MOE = 0; ...; MOE = 1). The latch prevents jitter on the BKIN line from causing rapid re-enable.

Repetition counter — centered PWM update

In centered PWM mode (counter counts up to ARR then down to 0), each PWM period contains two overflow events: the OVF (at ARR) and the UDF (at 0). If you update PWM duty cycle on every overflow, you're updating twice per period — wasteful when the control loop runs once per period.

The repetition counter (RCR) solves this. RCR is an 8-bit downcounter loaded at every update event. The update event itself is delayed until RCR reaches 0, at which point it reloads and the cycle starts again. With RCR=1 in centered mode, updates fire once every two overflows — i.e. once per PWM period, at the bottom of the triangular waveform. With RCR=N, updates fire every (N+1) periods.

For a 20 kHz centered PWM (typical motor frequency), RCR=1 gives the control loop 50 µs to compute the next duty cycle. The DMA request and interrupt also fire on the update event, synchronizing ADC sampling, control computation, and PWM update into one tidy 20 kHz cycle.

Encoder mode and Hall sensor mode

The advanced timer (and the GP timers TIM2/3/4/5) supports two specialized capture modes used in motor control:

Encoder mode (quadrature)

Two channels (CH1, CH2) connect to an incremental encoder's A and B signals. The timer counts up on one A/B phase relation and down on the other, so the counter directly tracks shaft position. Four counting modes:

ModeCounts on
Encoder 1CH1 edges only
Encoder 2CH2 edges only
Encoder 3Both CH1 and CH2 edges (4× decoding)

Mode 3 gives 4× the encoder's PPR (pulses per revolution) for sub-degree resolution on cheap 1024-PPR encoders. Index pulse handling is done by configuring CH3 or CH4 in input-capture-with-reset mode to zero the counter on every index.

Hall sensor mode

BLDC motors use three 120°-spaced Hall sensors that provide commutation timing. The timer's "Hall sensor interface" (SMCR.TS = 0b101, SMCR.SMS = 0b100) XORs the three Hall inputs and triggers on any change, capturing the time between commutation events. A second timer channel (CH2 with TI1F_ED trigger) measures the time-from-last-Hall, giving you rotor velocity and the precise commutation moment.

// Hall sensor input configuration
TIM1->CCMR1 = (1 << TIM_CCMR1_CC1S_Pos);          // CH1 as input from TI1
TIM1->CCER  = TIM_CCER_CC1E | TIM_CCER_CC1NE;     // both edges
TIM1->SMCR  = (5 << TIM_SMCR_TS_Pos)              // TI1F_ED as trigger
            | (4 << TIM_SMCR_SMS_Pos);            // reset mode on trigger
TIM1->CR2  |= TIM_CR2_TI1S;                       // XOR Hall A, B, C onto TI1

Master-slave synchronization

A typical motor-control loop uses several timers in lockstep:

  • TIM1 — generates the three-phase PWM.
  • ADC — triggered by TIM1 update or compare event to sample currents at a specific point in the PWM cycle (typically the center of the low-side conduction window, when measurement noise is lowest).
  • TIM6 or TIM7 — drives the high-rate control loop timing.
  • TIM4 — speed measurement from encoder.

These have to be precisely synchronized — the ADC must sample at the exact PWM moment that gives the cleanest current reading, and the control loop must run at the exact rate that matches the PWM update.

The synchronization mechanism is the TRGO (Trigger Output) of each timer feeding into the TRGI (Trigger Input) of another:

Source TRGO eventSink behavior (TRGI in slave mode)
ResetSlave counter resets when source TRGO fires
GatedSlave counts only while source TRGO is high
TriggerSlave starts on source TRGO rising edge
External clock 1Slave clocked by source TRGO

The TIM1 → ADC trigger uses a separate ADC trigger source mux rather than TRGO — the ADC has its own input mux that can latch off OC4REF, OC1REF, OC2REF, TRGO, etc. The CubeMX configurator hides this; in register code, set ADCx_CFGR.EXTSEL to the appropriate value.

Output compare modes

The advanced timer's output-compare units have eight modes selectable per channel via CCMRx.OCxM:

ModeBehaviour
0 FrozenCompare match has no effect on output
1 Active on matchSet high on compare
2 Inactive on matchSet low on compare
3 ToggleFlip on every match
4 Force inactiveOutput forced low until mode changes
5 Force activeOutput forced high
6 PWM mode 1Active until match, then inactive
7 PWM mode 2Inactive until match, then active

PWM modes 1 and 2 are the standard. The difference is just the polarity of the output relative to the compare value. Combined with CCER.CCxP (output polarity) and CCER.CCxNP (complementary polarity), every reasonable PWM output configuration is achievable.

For BLDC commutation, modes 4 and 5 are useful: by switching a channel's mode in software (or via the COM commutation event), you force the output to a constant level corresponding to the current Hall sector.

HRTIM — the high-resolution timer

Some STM32 parts (G4, H7) include the High-Resolution Timer (HRTIM): six timer units (TIMA..TIMF) running at 5.44 GHz effective resolution (using an internal 6× DLL on a 906 MHz reference). Each unit has dual outputs with dead-time and break support, like an advanced control timer but with picosecond placement of PWM edges.

HRTIM is overkill for motor control — the application is digital power supplies, resonant LLC converters, and class-D audio where edge placement to <500 ps matters for harmonic shaping. Programming is complex (the HRTIM is essentially a small dedicated PWM coprocessor), but for high-end SMPS designs nothing else on Cortex-M comes close.

Common pitfalls

  • Forgetting BDTR.MOE — the master output enable bit gates all OCx/OCxN outputs. Without setting it, your beautifully configured PWM produces zero edges. Easy to miss because the bit is in BDTR, not where you'd expect.
  • Dead-time too short — typical IGBT switching takes 200–500 ns of t_off. A 100 ns dead-time on an IGBT inverter causes shoot-through. Always derive dead-time from gate-driver datasheet timing.
  • Break input held asserted — if BKIN is held low at startup (e.g. by an over-current sensor that's noisy on power-up), MOE will never enable. Always check the break-flag status before declaring "PWM doesn't work."
  • Encoder counter overflow — 16-bit counter with a high-resolution encoder overflows every few seconds. Either use a 32-bit timer (TIM2/5) or implement an overflow-counted virtual 32-bit position in software.

Cross-references