In short: PWM generates an analog-like average from a digital pin by rapidly switching a fixed-frequency pulse and varying only its duty cycle, letting a cheap timer/counter deliver smooth motor speed and LED brightness without a DAC.
Pulse-Width Modulation (PWM) is the workhorse behind almost every "analog" output on a modern microcontroller. Rather than producing a true variable voltage, PWM toggles a pin between full ON and full OFF so fast that the load — a motor winding, an LED, a filter capacitor — responds only to the average. Master duty cycle, timer architecture, and resolution and you can control power delivery to within a fraction of a percent using nothing but a free-running counter and a comparator.
What duty cycle actually means
A PWM signal has a fixed period T (so a fixed frequency f = 1/T) and a variable high-time t_on. The duty cycle is simply D = t_on / T, expressed 0–100%. For a supply voltage V, the time-averaged output is V_avg = D × V. Drive a 12 V rail at 25% duty and the load sees an effective 3 V average. Nothing about the peak voltage changes — only how long each cycle stays high.
Key fact: Frequency sets how smooth the output feels; duty cycle sets how much power is delivered. They are independent knobs, which is exactly why PWM is so flexible.
How a timer actually builds the pulse
Inside the silicon, PWM is almost never done by toggling a pin in software — that wastes CPU and jitters badly. Instead a hardware timer/counter counts up from 0 to a top value (ARR on STM32, TOP/ICRn on AVR). A compare register (CCR / OCRn) holds a threshold. On every tick the counter value is compared: while counter < compare the output is high, otherwise low. The counter rolls over at TOP, restarting the cycle. The period is therefore set by TOP and the timer clock, while the compare value sets duty — entirely in hardware, with zero jitter and no CPU load once configured.
Resolution: the number of steps you can actually hit
PWM resolution is the granularity of the duty cycle, set by how many counter steps fit in one period. If TOP = 255 you have 8-bit resolution: 256 distinct levels, each worth 1/256 ≈ 0.39% of full scale. Crucially, there is a direct trade-off between frequency and resolution for a given timer clock:
PWM_freq = f_timer / (TOP + 1), so bits = log2(f_timer / PWM_freq)
| Timer clock | PWM frequency | TOP | Resolution |
|---|---|---|---|
| 16 MHz | 62.5 kHz | 255 | 8-bit (256 steps) |
| 16 MHz | 1 kHz | 15999 | ~14-bit |
| 84 MHz | 20 kHz | 4199 | ~12-bit |
| 84 MHz | 200 kHz | 419 | ~8.7-bit |
Key fact: Push PWM frequency up and resolution falls. At 200 kHz off an 84 MHz timer you only get ~420 steps — fine for a buck converter, too coarse for a 16-bit audio DAC emulation. Pick a faster timer clock or accept coarser control.
Motor control: why frequency matters
For a brushed DC motor the winding inductance acts as a low-pass filter, so the motor "sees" the average current. But the switching frequency is audible if it lands in the 1–15 kHz band — that's the annoying whine from cheap fans and toys. Engineers usually push the PWM above ~20 kHz (beyond human hearing) or deliberately drop it low to save switching losses in big H-bridges. For BLDC and stepper drives, PWM is paired with sophisticated commutation; tools like the modeling flows used by analog/power teams at firms running Cadence Virtuoso or Synopsys PrimeSim simulate the gate-drive PWM alongside dead-time to avoid shoot-through. Dead-time insertion — a few hundred nanoseconds where both half-bridge transistors are off — is itself a hardware feature of advanced timers (STM32 TIM1/TIM8).
Heavy PWM duty often pairs with DMA in embedded systems to stream whole duty-cycle tables into the compare register without CPU intervention — essential for sine-weighted PWM or servo sequences. For the fundamentals of the counters underneath, see our companion piece on timers and counters.
LED dimming and gamma
LEDs are current devices with near-instant response, so PWM dimming works beautifully — but the human eye is non-linear. A 50% duty cycle does not look half as bright; perceived brightness roughly follows a gamma curve (≈ output = duty^2.2). That is why quality dimmers apply a gamma lookup table before writing the compare register, and why higher resolution matters at the low end: 8-bit PWM gives harsh, visible steps in the bottom 10% of a dim. 10–12-bit PWM (or temporal dithering) smooths it. Keep LED PWM above ~200 Hz, or above ~1 kHz for anything on camera, to avoid visible flicker and the rolling-shutter banding that ruins video.
Practical pitfalls
- Edge-aligned vs center-aligned: center-aligned (up/down counting) halves harmonic content and is preferred for motor drives; it also halves the effective frequency, so recompute TOP.
- Glitch-free updates: write the new compare value into a shadow/preload register so it only takes effect at the next cycle boundary, preventing a runt pulse.
- 0% and 100%: some timers can't produce a true 0% or 100% because the compare equals the count boundary — check the datasheet if you need full off/on.
- Filter before measuring: if you feed PWM to an op-amp or ADC as a crude DAC, size the RC filter so its cutoff is well below the PWM frequency.
Want to configure STM32 and AVR timers for real motor and LED projects, with scope captures and gamma tables? Our Embedded Systems track on CourseTron courses walks you through PWM from first principles to a working BLDC driver.
If your work spills into custom power-management silicon, the design-services team at Avecas VLSI design services handles the analog PWM controllers behind these digital pins.
Frequently Asked Questions
Is PWM the same as a DAC?
No. A DAC produces a true variable voltage directly; PWM produces a switched square wave whose average approximates one. With an RC low-pass filter PWM can emulate a DAC, but with ripple and limited bandwidth set by the filter.
What PWM frequency should I use for a DC motor?
Above ~20 kHz to stay inaudible and keep current ripple low, unless switching losses in a high-power H-bridge force you lower. The motor's inductance filters the current, so frequency mainly affects audible noise, ripple and switching efficiency — not average speed.
Why does my LED flicker at low brightness?
Either the PWM frequency is too low (use >200 Hz, >1 kHz for camera) or the resolution is too coarse at the bottom of the range. Increase bits and apply a gamma lookup table so small duty steps map to small perceived steps.
How do I compute PWM resolution?
Resolution in bits is log2(f_timer / f_pwm). Raising PWM frequency for a fixed timer clock reduces the number of counter steps, so you trade frequency against resolution.