Optimizing Microcontroller PWM Timing for High-Speed Motor Control
High‑speed motors are the beating heart of drones, e‑bikes, and 3‑D printers. One missed microsecond in the PWM signal can turn a smooth spin into a jittery wobble, and nobody wants a wobble when the propeller is humming at 20 kHz. In this post I’ll walk you through the practical steps I use at Precision Pulse to tighten PWM timing, keep the motor happy, and avoid the dreaded “ghost‑speed” glitches.
Why PWM Timing Matters
Pulse‑Width Modulation (PWM) is the simplest way to tell a motor how much power to apply. The microcontroller toggles a pin on and off, and the motor driver averages the voltage over each cycle. If the on‑time (the “pulse”) is 30 % of the period, the motor sees roughly 30 % of the supply voltage.
When you push the motor into the high‑speed regime—say 10 kHz or more—the margin for error shrinks dramatically. A jitter of just 0.5 µs can shift the effective duty cycle enough to cause audible noise, torque ripple, or even stall. That’s why precise PWM timing isn’t a nice‑to‑have; it’s a must‑have for reliable high‑speed control.
Understanding PWM Basics
What is PWM?
PWM stands for Pulse‑Width Modulation. Think of it as a light switch that flickers so fast you can’t see the flicker, only the average brightness. The two numbers that define it are frequency (how many cycles per second) and duty cycle (the percentage of each cycle the switch stays on).
The Timing Chain
- Timer peripheral – Generates the base clock for PWM.
- Prescaler – Divides the main clock to a lower frequency the timer can handle.
- Auto‑reload register (ARR) – Sets the period of the PWM wave.
- Capture/Compare register (CCR) – Sets the on‑time within that period.
If any of these registers are updated at the wrong moment, the hardware may latch a stale value, causing a one‑cycle glitch.
Common Timing Pitfalls
1. Interrupt Latency
Most hobbyists enable PWM inside a timer‑interrupt routine. The interrupt itself can be delayed by higher‑priority tasks, causing the duty cycle to drift. In my early e‑bike experiments I saw the motor “stutter” every few seconds because a UART receive interrupt stole cycles from the PWM update.
Fix: Use the timer’s built‑in “shadow register” feature (often called “preload”). Write the new CCR value, then let the hardware swap it at the next update event. This removes the need for a software‑controlled toggle inside the ISR.
2. Clock Source Drift
If the timer runs off the main system clock and you later switch the CPU to a low‑power mode, the clock frequency may change. The PWM frequency will follow, and the motor may hear a sudden pitch change.
Fix: Choose a dedicated peripheral clock (e.g., the APB1 timer clock on STM32) that stays constant, or lock the system clock before enabling PWM.
3. Edge Alignment vs. Center Alignment
Edge‑aligned PWM starts each cycle at a fixed edge (usually the rising edge). Center‑aligned PWM flips the polarity halfway through the period, which can reduce electromagnetic interference (EMI) but also doubles the effective switching frequency seen by the motor driver.
Fix: For high‑speed motors, edge‑aligned PWM is usually simpler and more predictable. Use center‑aligned only if you have a strong reason, such as strict EMI limits.
Step‑by‑Step Optimization Guide
Step 1: Pick the Right Timer Resolution
The timer’s count range determines how finely you can set the duty cycle. A 16‑bit timer at 72 MHz with a prescaler of 1 gives a period of 65536 / 72 MHz ≈ 0.91 µs. That’s a resolution of about 0.1 % at 20 kHz—more than enough for most motor drives.
If you need finer granularity, either increase the timer clock (some MCUs allow a “timer clock multiplier”) or use a higher‑resolution timer (e.g., a 32‑bit timer on a Cortex‑M4).
Step 2: Freeze the Update Point
Most MCUs have a “PWM mode 1” where the CCR value is copied to a shadow register at the next update event. Enable this mode and avoid writing to CCR inside the main loop. Instead, compute the new duty cycle in a variable, then write it once per control loop iteration.
// Example for STM32
TIM1->CCR1 = new_duty; // writes to shadow register
// hardware swaps at next update event automatically
Step 3: Use DMA for Bulk Updates
If you are driving a multi‑phase motor (e.g., a three‑phase BLDC) you need three PWM channels updated simultaneously. Instead of three separate writes, set up a DMA channel that streams an array of CCR values to the timer registers. The DMA transfer completes in a single bus cycle, guaranteeing perfect synchronicity.
Step 4: Verify with an Oscilloscope
A quick visual check saves hours of debugging. Probe the PWM pin and the motor driver’s gate signal. Look for:
- Consistent period (no missing cycles).
- Stable duty cycle steps (no jitter beyond 0.1 %).
- Clean edges (no ringing).
If you see occasional “spikes,” check for stray interrupts or power‑supply dips.
Step 5: Guard Against Over‑Current
High‑speed motors draw peak currents that can momentarily sag the supply voltage, pulling the timer clock down if it’s derived from the same source. Use a separate crystal or PLL for the timer, or add a small capacitor (10 µF) close to the MCU’s VDD pin to smooth out the dip.
Personal Anecdote: The Day My Drone Took Off Without a Prop
During a prototype flight test, I accidentally left the PWM prescaler set to “divide by 8.” The motor driver still saw a PWM signal, but the frequency dropped from 20 kHz to 2.5 kHz. The motor spun slowly, the prop didn’t generate lift, and the drone hovered like a confused hummingbird. The lesson? Always double‑check the prescaler before the first flight. A single line in the init code saved me a broken prop and a bruised ego.
Quick Checklist for High‑Speed PWM
- Timer clock stable? Use a dedicated peripheral clock.
- Prescaler set correctly? Verify the resulting PWM frequency.
- Shadow registers enabled? Avoid ISR‑based updates.
- DMA ready? Use it for multi‑channel synchronicity.
- Oscilloscope sanity check? Look for missing cycles and edge ringing.
By following these steps, you’ll get a PWM signal that is as steady as a metronome, even when the motor is screaming at 30 kHz. The result is smoother torque, less noise, and a happier motor—exactly the kind of outcome we aim for at Precision Pulse.
- → How to Design a Precise LED Dimmer Using a Rheostat – Complete Wiring Diagram & Calculations @rheostatrealm
- → Step-by-Step Guide: Building a DIY Variable-Speed Motor Controller with a Rheostat @rheostatrealm
- → Choosing the Right Test Probe for High Frequency PCB Debugging: A Practical Guide @probeleadinsights
- → Calibrating Test Leads for Precise Voltage Measurements @probeleadinsights
- → How to Quickly Identify Resistor Values with a Simple Color‑Code Cheat Sheet @resistorrealm