Pulse Width Modulation (PWM) signals are digital square waves that simulate analog voltage levels by rapidly switching a digital pin between HIGH (ON) and LOW (OFF) states at a fixed frequency, where the ratio of ON time to the total period dictates the average power delivered to a load. While a microcontroller GPIO pin can only output its fixed logic voltage (e.g., 3.3V or 5V), PWM changes the average power and current delivered to a load without altering the peak voltage, allowing low-voltage digital logic to efficiently control high-power analog devices like motors, heaters, and LED arrays.

The Core Mechanics and Microcontroller Limits

A PWM signal is defined by two primary parameters: frequency (how many complete ON/OFF cycles occur per second, measured in Hertz) and duty cycle (the percentage of one period that the signal remains HIGH). If a 5V pin outputs a 50% duty cycle at 1,000 Hz, it is switching between 5V and 0V every millisecond, spending 0.5ms at 5V and 0.5ms at 0V.

Not all microcontrollers handle PWM identically. Hardware timer limitations dictate the maximum frequency and resolution (the granularity of the duty cycle steps). Below is a specification matrix for common maker boards as of their current 2026 hardware revisions.

Microcontroller Default / Max Frequency Resolution (Bits) Hardware Peripheral Best Use Case
Arduino Uno (ATmega328P) 490 Hz / 31.25 kHz 8-bit (0-255) Timer0, Timer1, Timer2 Basic LED dimming, simple hobby servos
ESP32-WROOM-32 5 kHz / 40 MHz Up to 16-bit (0-65535) LEDC / MCPWM High-res motor control, precision LED dimming
Raspberry Pi Pico (RP2040) 1 kHz / 125 MHz 16-bit (0-65535) PWM Slices (8 total) Audio generation, multi-channel synchronous PWM
STM32F103C8T6 (Blue Pill) 1 kHz / 72 MHz 16-bit (0-65535) Advanced-control Timers (TIM1-4) 3-phase BLDC motor commutation, SMPS
ESP32 API Update (2026): If you are following older tutorials, you will see ledcSetup() and ledcAttachPin(). In Arduino-ESP32 Core v3.x (based on ESP-IDF v5.1+), the legacy LEDC API was deprecated. Use the simplified ledcAttach(pin, freq, resolution) and ledcWrite(pin, duty) functions instead. See the official Espressif LEDC documentation for the current implementation.

Worked Example: Sizing a MOSFET for a 12V PWM Load

Let’s look at a real-world circuit: dimming a 12V, 5A (60W) LED strip using an ESP32 (3.3V logic) and an IRLZ44N logic-level N-channel MOSFET. We want to run the LEDs at 40% brightness.

The Math and the Trap

  • Target Duty Cycle: 40% (0.4).
  • Average Voltage: 12V × 0.4 = 4.8V.
  • Average Current: 5A × 0.4 = 2.0A.

Here is where beginners make a critical error. The MOSFET does not see a continuous 2.0A. It sees the full 5.0A for 40% of the time, and 0A for 60% of the time. Your MOSFET must be rated for the peak current (5A), not the average current. The IRLZ44N is rated for 47A continuous, so it handles the 5A peak easily.

However, switching losses matter. If we set the ESP32 PWM frequency to 5,000 Hz, the MOSFET transitions between the cutoff and saturation regions 10,000 times per second. During these microsecond transitions, the MOSFET has both high voltage across it and high current through it, generating heat. For a 5A load at 5 kHz, an IRLZ44N will run warm but safe without a heatsink. If you push the frequency to 100 kHz to eliminate audible whine, switching losses will spike, and you will need a dedicated gate driver (like a TC4420) to charge and discharge the MOSFET's gate capacitance fast enough to prevent thermal runaway.

Where You Meet PWM Signals in Practice

PWM is the backbone of modern embedded power control. You will encounter it in these specific scenarios:

  • RC Servos and ESCs: Standard hobby servos expect a 50 Hz PWM signal where the pulse width (typically 1ms to 2ms) dictates the shaft angle. Electronic Speed Controllers (ESCs) for drones use this same 50Hz baseline, though modern protocols like DShot use digital packet timing rather than analog pulse widths.
  • PC Cooling Fans: 4-pin PWM fans operate at a much higher 25 kHz frequency. This is intentionally above the human hearing range to prevent the fan motor coils from emitting an audible high-pitched whine (magnetostriction) at lower frequencies.
  • Switching Regulators (Buck/Boost): Inside a buck converter, a PWM signal drives the internal switch. By feeding the output voltage back into an error amplifier that adjusts the PWM duty cycle, the regulator maintains a steady DC output despite varying input voltages.
  • Audio Generation: Microcontrollers without true Digital-to-Analog Converters (DACs), like the ATmega328P, use high-frequency PWM (e.g., 62.5 kHz on Timer1) combined with an external RC low-pass filter to synthesize analog audio waveforms.

Common Confusions: PWM vs. True Analog and PFM

The Multimeter Trap: PWM is NOT True Analog

If you output a 5V PWM signal at 50% duty cycle and measure it with a standard digital multimeter (DMM) set to DC voltage, the meter will likely display 2.5V. This is an illusion caused by the DMM’s internal low-pass filter averaging the rapid switching. An oscilloscope will reveal the truth: the pin is strictly toggling between 0V and 5V.

If you feed this raw 50% PWM signal directly into an audio amplifier or an analog sensor input, the receiving circuit will react to the harsh 5V square wave edges, causing distortion or erratic readings. To convert PWM to a true analog DC voltage, you must pass it through an RC low-pass filter. The cutoff frequency ($f_c$) of the filter must be significantly lower than the PWM frequency. Using the formula $f_c = \frac{1}{2 \pi R C}$, a 10kΩ resistor and a 1μF capacitor yields a cutoff of ~16 Hz, which will smoothly filter a 1 kHz PWM signal into a clean DC voltage. For deeper theory on Arduino PWM implementation and limits, refer to the official language reference.

PWM vs. PFM (Pulse Frequency Modulation)

In PWM, the frequency is fixed and the pulse width (ON time) varies to regulate power. In PFM, the pulse width (or ON time) is fixed, and the frequency varies. PFM is rarely used in microcontroller GPIO toggling but is heavily used in modern switching power supplies. At light loads, a PFM controller skips pulses (lowering the frequency) to minimize switching losses, drastically improving battery life in IoT devices compared to fixed-frequency PWM regulators.

Frequently Asked Questions

Why does my PWM-controlled motor whine at low speeds?
At low frequencies (1kHz - 5kHz), the rapid magnetic expansion and contraction of the motor windings (magnetostriction) create acoustic vibrations in the human hearing range. Increase your PWM frequency above 20 kHz to push the noise into the ultrasonic spectrum.

Can I use any GPIO pin for PWM on an Arduino?
No. On the Arduino Uno, only pins 3, 5, 6, 9, 10, and 11 support hardware analogWrite() PWM. Using software-based PWM libraries on other pins consumes heavy CPU cycles and introduces timing jitter.

Do I need a flyback diode for PWM switching?
If you are switching an inductive load (like a relay coil, solenoid, or DC motor), yes. When the PWM signal goes LOW, the collapsing magnetic field generates a massive reverse voltage spike that will instantly destroy your MOSFET or microcontroller. Always place a flyback diode (e.g., 1N4007 or Schottky SS34) in reverse parallel across the inductive load.