A Pulse Width Modulation (PWM) signal is a digital square wave that simulates an analog voltage by rapidly switching between fully ON and fully OFF states at a specific frequency and duty cycle. When you ask "what is a PWM signal" at the workbench, the practical answer is that it is a microcontroller's trick for delivering variable power using only digital pins that can only output 0V or 3.3V/5V. Instead of dropping excess voltage across a resistor and wasting it as heat, PWM delivers full voltage in rapid bursts, letting the load's inertia or persistence of vision average out the power.

The Core Mechanics: Duty Cycle and Frequency

To use PWM effectively, you have to separate the two variables that define the waveform: duty cycle and frequency.

Duty Cycle is the percentage of time the signal is HIGH (ON) during a single cycle. A 50% duty cycle means the pin is ON for half the time and OFF for half the time. A 10% duty cycle means it is ON for only a tenth of the cycle.

Frequency is how many of those complete ON/OFF cycles happen per second, measured in Hertz (Hz).

The Faucet Analogy: Imagine a water faucet you can only snap fully open or fully closed. If you snap it open for 1 second and closed for 1 second (50% duty cycle, 0.5 Hz frequency), a bucket fills exactly half as fast as if it were open constantly. The water pressure (voltage) never changes, but the average flow (power) is cut in half.
Hardware Baseline: The classic Arduino Uno (ATmega328P) uses analogWrite() to output an 8-bit resolution (0-255) PWM signal at a fixed ~490 Hz on most pins. The ESP32-WROOM-32 uses the LEDC peripheral, offering up to 14-bit resolution and configurable frequencies from 1 Hz up to 40 MHz.

What PWM Actually Changes in Your Circuit

A common misconception is that PWM changes the voltage. It does not. If you feed a 5V PWM signal into an oscilloscope, you will see the trace snapping strictly between 0V and 5V. What PWM changes is the average power delivered to the load over time.

If you apply a 12V PWM signal at a 25% duty cycle to a DC motor, the motor windings are hit with a full 12V pulse, but the mechanical inertia of the rotor averages this out, spinning at roughly the same speed it would if fed a steady 3V DC source. However, because the instantaneous voltage is always 12V during the ON state, the motor maintains high torque at low speeds—something a true 3V analog supply would struggle to achieve due to stall currents.

According to Arduino's official analogWrite documentation, this switching behavior is highly efficient for driving high-current loads via MOSFETs, as the transistor spends almost all its time either fully saturated (low resistance, low heat) or fully cut off (zero current, zero heat).

Worked Example: Sizing a PWM Motor Drive on an ESP32

Let’s build a real circuit. You want to drive a 12V, 2A PC cooling fan at 60% speed using an ESP32-WROOM-32 (3.3V logic) and an IRLZ44N logic-level N-channel MOSFET.

  1. Calculate the Target Average: 12V × 0.60 = 7.2V average delivered to the fan.
  2. Choose the Frequency: DC motors and fans have physical coils that can vibrate if the PWM frequency falls within the human hearing range (20 Hz to 20 kHz). To avoid an annoying high-pitched "coil whine," we set the frequency to 25,000 Hz (25 kHz).
  3. Calculate the Duty Cycle Value: We will use an 8-bit resolution (0 to 255). 60% of 255 is 153.

Here is the complete, modern ESP32 Arduino Core code (v2.x/v3.x compatible) to drive this:

const int fanPin = 18;
const int pwmFreq = 25000; // 25 kHz to avoid audible coil whine
const int pwmResolution = 8; // 8-bit = 0 to 255

void setup() {
  // Modern ESP32 Arduino Core API for attaching PWM
  ledcAttach(fanPin, pwmFreq, pwmResolution);
  
  // Set fan to 60% speed (255 * 0.60 = 153)
  ledcWrite(fanPin, 153);
}

void loop() {
  // Fan runs continuously; add serial control or sensor logic here
  delay(1000);
}
CRITICAL HARDWARE WARNING: A cooling fan is an inductive load. When the MOSFET snaps OFF, the collapsing magnetic field in the fan's coils generates a massive reverse voltage spike (flyback voltage) that will instantly destroy your ESP32's GPIO pin or the MOSFET. You must wire a 1N4007 or 1N5819 flyback diode in reverse parallel across the fan's power terminals (cathode stripe pointing to 12V).

Where You Meet PWM in Practice (and Common Confusions)

You will encounter PWM in almost every embedded project, but the implementation changes drastically based on the load.

Where it is used:

  • LED Dimming: Human eyes have persistence of vision. A 1 kHz PWM signal turns the LED on and off too fast to see, appearing as a dimmer light.
  • Servo Positioning: RC servos use a very specific, slow PWM variant (50 Hz) where the absolute width of the HIGH pulse (usually 1000µs to 2000µs) dictates the shaft angle.
  • Switch-Mode Power Supplies (Buck/Boost Converters): PWM drives the switching transistor that chops DC voltage to be smoothed by an inductor and capacitor into a lower or higher DC voltage.

What people commonly confuse it with:

PWM vs. True Analog (DAC): A Digital-to-Analog Converter (DAC) outputs a true, steady DC voltage. If you read a PWM pin with a standard multimeter, the meter's internal low-pass filter will often display the "average" voltage, tricking you into thinking it's true analog. However, if you feed that PWM signal directly into an audio amplifier or a sensitive analog sensor, the high-frequency square wave will introduce massive noise. To convert PWM to true analog DC, you must pass it through an RC low-pass filter (a resistor and a capacitor).

Standard PWM vs. Servo PWM: Standard PWM cares about the ratio (duty cycle) regardless of frequency. Servo PWM cares about the absolute time the pulse is HIGH, and requires a strict 50 Hz (20ms period) frame. You cannot drive a standard hobby servo with a 1 kHz PWM signal, even if the duty cycle math looks correct.

Decision Tree: Picking the Right PWM Frequency and Hardware

Choosing the wrong frequency leads to flickering LEDs, whining motors, or jittery servos. Use this decision matrix to lock in your parameters.

Application Target Frequency Resolution Needed Recommended Hardware / Part
RC Servos 50 Hz (Strict) 16-bit (for 1µs precision) PCA9685 (I2C) or ESP32 LEDC
LED Dimming (Visual) 1 kHz - 5 kHz 8-bit to 12-bit Logic-level MOSFET (IRLZ44N) or TLC5940
LED Dimming (Camera/Video) 20 kHz - 25 kHz 10-bit+ Dedicated LED driver (AL8860)
DC Motor Speed Control 20 kHz - 25 kHz 8-bit DRV8871 or BTS7960 H-Bridge
Buck/Boost Converters 50 kHz - 500 kHz Hardware-managed Dedicated PWM IC (TL494) or MC34063

The Default Pick: If you are driving a generic DC motor or a high-power LED strip via a MOSFET and aren't sure what to set your microcontroller to, configure your timer for 25 kHz at 8-bit resolution. This sits safely above human hearing, prevents camera flicker, and provides 255 steps of smooth control without overloading the CPU with high-frequency interrupt overhead.

FAQ: Troubleshooting Common PWM Mistakes

Q: My DC motor emits a loud, high-pitched whine when running at low speeds.
Fix: Your PWM frequency is likely in the 400 Hz to 1 kHz range (the default for older Arduino analogWrite() sketches). The motor coils are physically vibrating at that acoustic frequency. Reconfigure your timer to 20 kHz or higher. Adafruit's guide on motor performance details how coil whine directly correlates to sub-ultrasonic PWM frequencies.

Q: My ESP32 randomly reboots or freezes when the PWM motor starts.
Fix: This is a brownout caused by voltage sag, or GPIO latch-up from inductive spikes. First, ensure you have a flyback diode across the motor. Second, power the motor from a separate 12V/5V supply, tying only the GND of the motor supply to the ESP32 GND. Never source motor current through the microcontroller's 3.3V/5V rail.

Q: My LED strip flickers when I record it with my smartphone camera.
Fix: Smartphone cameras use rolling shutters and often sample at 30, 60, or 120 fps. A 500 Hz PWM signal will cause visible banding or flicker on video. Push your LED PWM frequency to at least 5 kHz, ideally 20 kHz, to completely eliminate the beat-frequency interference with the camera sensor.