Pulse Width Modulation (PWM) is a technique that simulates a variable analog voltage by rapidly switching a digital microcontroller pin between HIGH and LOW and adjusting the ratio of ON time to the total cycle time. In a real circuit, PWM changes the average power delivered to a load without altering the peak voltage of your power supply, allowing a 3.3V digital logic pin to smoothly dim a 12V LED strip or control the RPM of a DC motor. Think of it like a water valve that you snap fully open and fully shut hundreds of times a second; the pipe never sees half-pressure, but the bucket filling at the end only gets half-full because the valve was closed half the time.

The Core Mechanism: Simulating Analog with Digital

Microcontrollers like the ESP32 or Arduino Uno cannot natively output true analog voltages (with the exception of specific DAC-equipped pins). Their GPIO pins are strictly digital: they output either 0V (LOW) or 3.3V/5V (HIGH). To control an analog behavior—like the brightness of an LED or the speed of a motor—we use the hardware timer peripherals built into the silicon to generate a square wave.

Key Terminology:
  • Frequency: How many complete ON/OFF cycles happen per second, measured in Hertz (Hz).
  • Period: The total time of one complete cycle (1 / Frequency).
  • Duty Cycle: The percentage of the period that the signal spends in the HIGH (ON) state.

If you set a PWM frequency of 1,000 Hz (1 kHz), the period is exactly 1 millisecond (1000 µs). If you set a 25% duty cycle, the pin stays HIGH for 250 µs and LOW for 750 µs. The load experiences the full supply voltage for a quarter of the time, resulting in an average voltage of 25% of the supply.

Worked Example: Driving a 12V PC Fan with an ESP32

Let’s look at a concrete bench scenario. You want to control a standard 12V, 0.5A PC cooling fan using an ESP32 DevKit v1. The ESP32 GPIO pins max out at roughly 40mA (absolute limit) and output 3.3V. You cannot wire the fan directly to the pin. Instead, you use the ESP32’s PWM signal to switch a logic-level N-channel MOSFET (like the IRLZ44N) that handles the 12V/0.5A load.

Here is the numeric breakdown for running the fan at 50% speed:

  • Target Frequency: 20,000 Hz (20 kHz). We choose this because it is above the upper limit of human hearing (~20 kHz), preventing the motor coils from emitting an audible high-pitched whine.
  • Period: 1 / 20,000 = 0.00005 seconds (50 µs).
  • Target Duty Cycle: 50%.
  • ON Time: 25 µs at 12V.
  • OFF Time: 25 µs at 0V.
  • Average Voltage: 6V.
The Kickstart Gotcha: If you apply a 50% duty cycle (6V average) to a fan that has a minimum start voltage of 7V, the fan will stall and just hum. The fix is a software kickstart: command 100% duty cycle for 200 milliseconds to overcome static friction, then drop to your target 50% duty cycle to maintain the lower RPM.

In modern ESP32 Arduino Core (v3.x), the LEDC (LED Control) peripheral handles this via simple API calls. Here is the exact code to implement the kickstart and 50% run:

// ESP32 Arduino Core v3.x LEDC API
const int FAN_PIN = 18;
const int PWM_FREQ = 20000; // 20kHz
const int PWM_RES = 10;     // 10-bit resolution (0-1023)

void setup() {
  // Attach the pin to the LEDC peripheral with freq and resolution
  ledcAttach(FAN_PIN, PWM_FREQ, PWM_RES);
  
  // Kickstart: 100% duty cycle (1023) for 200ms
  ledcWrite(FAN_PIN, 1023);
  delay(200);
  
  // Drop to 50% duty cycle (512)
  ledcWrite(FAN_PIN, 512);
}

void loop() {
  // Fan runs continuously at 50% average power
}

Where You Meet PWM in Practice (And What People Get Wrong)

You will encounter PWM in almost every embedded project. The three most common applications are:

  1. LED Dimming: Human eyes integrate light over time. A 10% duty cycle at 1 kHz looks exactly like a continuously dim LED operating at 10% brightness.
  2. DC Motor Speed Control: Motors have high inductance, which naturally smooths out the PWM square wave into a steady current flow through the coils.
  3. Servo Positioning: Standard RC servos ignore the average voltage and instead measure the exact width of the HIGH pulse (usually between 1000 µs and 2000 µs) to determine shaft angle.

The Great Confusion: PWM vs. True DAC
The most common mistake beginners make is confusing PWM with a true Digital-to-Analog Converter (DAC). If you measure a 50% duty cycle 12V PWM signal with a standard multimeter set to DC Volts, the meter's internal low-pass filter will read ~6.0V. This tricks you into thinking the pin is outputting a steady 6V. If you hook that same signal to an oscilloscope, you will see a harsh square wave slamming between 0V and 12V. A true DAC (like the MCP4725 breakout or the native DAC pins on an ESP32) outputs a perfectly flat, steady 6.0V line. If your load is highly sensitive to voltage ripple (like an audio amplifier input), PWM will introduce massive noise; you must use a true DAC or add a heavy RC low-pass filter to smooth the PWM into a true analog voltage.

Decision Tree: Picking Your Frequency and Resolution

Choosing the right PWM parameters is not arbitrary. Use this decision matrix to select the exact configuration for your specific load.

Load Type Recommended Frequency Recommended Resolution Concrete Pick & Rationale
Standard LEDs 1 kHz - 5 kHz 8-bit (0-255) Pick: 5 kHz, 8-bit. Prevents visible flicker on smartphone cameras while keeping CPU overhead minimal.
DC Motors / Fans 15 kHz - 25 kHz 10-bit (0-1023) Pick: 20 kHz, 10-bit. Pushes switching noise above human hearing; 10-bit gives 1024 speed steps for fine control.
Standard RC Servos 50 Hz (Fixed) 16-bit (0-65535) Pick: 50 Hz, 16-bit. 50Hz yields a 20ms period. 16-bit resolution allows microsecond-level precision for the 1-2ms pulse width required by servos.
Buck Converters (SMPS) 50 kHz - 500 kHz N/A (Analog feedback) Pick: 100 kHz. High frequency allows for physically smaller inductors and capacitors in the filter stage.

Hardware Implementation: The MOSFET Switch

When your PWM signal leaves the microcontroller and hits a high-power load, the physical wiring matters just as much as the code. If you are switching an inductive load (like a motor or a relay coil) with an N-channel MOSFET, you must include two passive components to prevent destroying your circuit:

  • Gate Pull-Down Resistor (10kΩ): Place this between the MOSFET gate and ground. When the ESP32 boots up, its GPIO pins are high-impedance (floating) before the code initializes. Without a pull-down, ambient noise can accidentally turn the MOSFET partially on, causing it to overheat and fail.
  • Flyback Diode (1N5819 Schottky): Place this in reverse bias across the motor terminals (cathode to 12V, anode to the MOSFET drain). When the MOSFET switches OFF, the motor’s magnetic field collapses and generates a massive reverse voltage spike (inductive kickback). The diode provides a safe path for this current to recirculate, protecting the MOSFET from avalanche breakdown.

FAQ: Common PWM Pitfalls

Q: Why does my LED flicker when I record it with my phone?
A: Smartphone cameras use rolling shutters that capture frames at specific intervals (often 30 or 60 fps). If your PWM frequency is too low (e.g., 60 Hz), the camera captures the OFF cycles as visible banding or flicker. Bump your frequency to 5 kHz to eliminate this.

Q: Can I use the ESP32's internal DAC instead of PWM for a motor?
A: No. The ESP32's internal DAC (pins 25 and 26) can only output up to ~3.3V and supply a maximum of roughly 10mA. A motor requires hundreds of milliamps. You must use PWM to switch an external power transistor.

Q: My MOSFET gets incredibly hot even at low duty cycles. Why?logic-level MOSFET. Standard MOSFETs require 10V on the gate to fully turn on (low Rds(on)). The ESP32 only provides 3.3V, leaving the MOSFET in its linear (high-resistance) region, acting like a giant resistor burning off power as heat. Always use logic-level parts like the IRLZ44N or IRLB8721 for 3.3V microcontrollers.

For deeper technical specifications on the ESP32's LEDC peripheral API, refer to the official Espressif Arduino Core Documentation. For foundational theory on square wave generation and duty cycle mathematics, the Electronics Tutorials PWM guide provides excellent oscilloscope trace comparisons.