Pulse Width Modulation (PWM) width is the exact amount of time a digital signal stays in the HIGH (ON) state during a single switching cycle, directly dictating the average power delivered to a load. When you write code to dim an LED or control a motor, you aren't actually changing the voltage level; your microcontroller is still outputting a hard 5V or 3.3V. Instead, you are changing the PWM width (often expressed as a duty cycle percentage) to alter the ratio of ON time to OFF time. This changes the effective average voltage the load experiences over time.
The most common point of confusion for makers is mixing up PWM width with PWM frequency. Width determines how much power is delivered (the duty cycle), while frequency determines how fast the ON/OFF switching happens (the period). If you want a motor to spin slower, you adjust the width. If you want to stop a motor from whining audibly, you adjust the frequency.
The Core Concept: Width vs. Frequency in Real Circuits
To understand what PWM width changes in a real installation, look at the relationship between the period (total cycle time) and the pulse width (ON time). The duty cycle is simply the width divided by the period, multiplied by 100.
Imagine you want to keep a room at exactly 70°F using a space heater that only has an ON and OFF switch. If you turn it ON for 3 seconds and OFF for 7 seconds, repeating this endlessly, the heater is ON for 30% of the time. The 'width' of your ON pulse is 3 seconds. The room's thermal mass smooths out the rapid switching, experiencing an average heat output of 30%. If you change the width to 8 seconds ON and 2 seconds OFF, the room gets 80% average heat. The switching speed (frequency) stays the same; only the width changes.
In a microcontroller circuit, the load (a motor winding, an LED phosphor, or a microcontroller's own internal RC filter) acts as the thermal mass, smoothing the digital pulses into an analog-like average voltage. If your logic high is 5V and your PWM width is set to a 20% duty cycle, a multimeter set to DC voltage will read exactly 1.0V at the pin.
Worked Numeric Example: ESP32 12-Bit LEDC Math
Let's look at a concrete numeric example using the ESP32-WROOM-32, which features a highly flexible LED Control (LEDC) peripheral. Unlike the standard Arduino Uno, which is hardcoded to 8-bit resolution (0-255) for analogWrite(), the ESP32 allows you to define both the frequency and the bit resolution.
The Scenario: You are driving a 12V DC cooling fan via a logic-level MOSFET (like an IRLZ44N) using an ESP32 GPIO pin. You want the fan to run at exactly 30% speed.
- Target Frequency: 5,000 Hz (5 kHz). This is above the human hearing range, eliminating high-pitched coil whine from the motor.
- Period Calculation: 1 / 5000 Hz = 0.0002 seconds, or 200 µs.
- Resolution: We will configure the ESP32 for 12-bit resolution, giving us a duty cycle range of 0 to 4095.
- Target Width (Time): 30% of the 200 µs period = 60 µs of HIGH time per cycle.
- Target Duty Value (Code): 30% of the 4095 maximum = 1228.5 (rounded to 1228).
In the Arduino IDE for ESP32, your setup code translates this math into hardware register configurations:
// Channel 0, 5000 Hz frequency, 12-bit resolution
ledcSetup(0, 5000, 12);
// Attach GPIO 18 to Channel 0
ledcAttachPin(18, 0);
// Write the calculated PWM width value (30% duty)
ledcWrite(0, 1228);
By setting the value to 1228, the ESP32 hardware timer holds the pin HIGH for exactly 60 µs, then LOW for 140 µs, repeating 5,000 times a second. The fan 'sees' an average voltage of 3.6V (30% of 12V) and spins accordingly.
Where You Meet PWM Width in Practice
Different components interpret PWM width in fundamentally different ways. Recognizing these differences prevents catastrophic hardware mistakes.
1. RC Servos (Absolute Time Width)
Standard hobby servos (like the SG90 or MG996R) do not care about duty cycle percentages; they care about absolute pulse width in microseconds. The standard frequency is fixed at 50 Hz (a 20,000 µs period). The servo's internal potentiometer reads the HIGH time: a 1,000 µs width means 0°, a 1,500 µs width means 90°, and a 2,000 µs width means 180°. If you change the frequency to 500 Hz, the servo will jitter violently or strip its gears because the internal timing circuit expects a pulse every 20 ms.
2. LEDs (Perceptual Width and Gamma)
LEDs respond to PWM width almost instantly. However, human eyes perceive brightness logarithmically, not linearly. If you set your PWM width to a 50% duty cycle, the LED is emitting 50% of the photons, but your eye will perceive it as roughly 75% as bright as full power. For high-end lighting projects, you must apply gamma correction to your width values in code to achieve linear visual fading.
3. DC Motors (Average Voltage)
DC motors act as massive low-pass filters due to their winding inductance and physical rotational inertia. They average the PWM width into a proportional speed. However, if your PWM width is set too low (e.g., 5% duty cycle) and the frequency is too low, the motor won't have enough torque to overcome static friction, resulting in a stalled motor that draws high current and overheats without spinning.
Decision Tree: Picking the Right Width and Hardware
Choosing the correct PWM width parameters and hardware depends entirely on your load. Use this decision path to select your microcontroller setup or external driver.
| Application / Load | Required PWM Width / Resolution | Frequency Target | Concrete Hardware / Function Pick |
|---|---|---|---|
| RC Servos & ESCs | Absolute width: 1000µs to 2000µs (High resolution needed for smooth steps) |
50 Hz (Strict) | Adafruit PCA9685 (I2C 16-channel board, Part #815) or ESP32 ledc at 16-bit. |
| High-Fidelity LED Dimming | 12-bit to 16-bit resolution (4095 to 65535 steps for smooth fades) |
5 kHz to 20 kHz (Eliminates camera flicker) |
ESP32 LEDC peripheral (12-bit) or TLC5940 constant current sink IC. |
| Basic DC Motor Speed | 8-bit resolution (255 steps is plenty for inertia loads) |
490 Hz to 1 kHz (Balances switching loss and whine) |
Arduino Uno analogWrite() on pins 5 or 6 (980 Hz) or pins 9-11 (490 Hz). |
| DAC / Analog Voltage Generation | 8-bit to 10-bit (Filtered through RC low-pass) |
30 kHz to 60 kHz (Pushes ripple out of audio band) |
Arduino Timer1 (custom 10-bit fast PWM) or dedicated MCP4725 I2C DAC. |
analogWrite() pins are created equal. On the Arduino Uno (ATmega328P), pins 5 and 6 run on Timer0 at 980 Hz, while pins 9, 10, and 11 run on Timers 1 and 2 at 490 Hz. If your motor whines on pin 9, move it to pin 5 to double the frequency, cutting the audible noise.
Common Mistakes and Edge Cases
Even experienced makers run into edge cases when manipulating PWM width across different logic families and loads.
The 5V to 3.3V Logic Trap
If you are reading a PWM signal from a 5V Arduino Uno using an ESP32 (which is strictly 3.3V tolerant on most GPIO pins), feeding a 5V PWM width directly into the ESP32 will fry the input buffer over time. You must use a bidirectional logic level converter (like the TXB0108) or a simple resistor voltage divider to drop the 5V HIGH state down to 3.3V before the ESP32 measures the pulse width.
Resolution vs. Frequency Trade-off
On hardware like the ESP32, PWM width resolution and frequency are inversely linked by the microcontroller's base clock (usually 80 MHz). If you demand a massive 16-bit resolution (65,535 steps), the maximum frequency you can achieve drops to roughly 1.2 kHz. If you need a 20 kHz frequency for a buck converter control loop, your resolution is capped at 12 bits (4095 steps). Always calculate your maximum theoretical frequency before writing your code: Max_Freq = 80,000,000 / (2 ^ resolution_bits).
MOSFET Gate Charge and Width Distortion
When driving high-power loads, you use a MOSFET. If you drive a large MOSFET (like an IRF3205) directly from a microcontroller GPIO pin, the pin cannot supply enough current to charge the MOSFET gate quickly. A 10 µs PWM width command might result in a 14 µs actual physical width at the load because the MOSFET takes 4 µs just to turn on and off. This distorts your duty cycle and causes massive heat dissipation in the MOSFET. Always use a dedicated gate driver IC (like the TC4420) between your microcontroller and power MOSFETs to ensure the physical PWM width matches your code.
FAQ: PWM Width Edge Cases
Can I use PWM width to control a standard AC dimmer?
No. Standard AC mains voltage is a sine wave, not a DC square wave. You cannot use standard microcontroller PWM width to chop an AC wave safely. For AC lighting, you must use phase-angle control (via a TRIAC) or zero-crossing detection to cut specific portions of the AC sine wave. Attempting to feed DC PWM into an AC circuit will destroy your components and create a severe shock hazard.
Why does my multimeter read 0V when measuring a fast PWM width?
Cheap digital multimeters sample voltage relatively slowly. If your PWM frequency is very high (e.g., 50 kHz) and the width is very narrow (e.g., 5% duty cycle), the multimeter's internal capacitor may not charge fast enough during the brief HIGH pulse to register a reading, defaulting to 0V. To accurately measure fast PWM widths, you must use an oscilloscope or a true-RMS multimeter with a fast sampling rate.
What happens if I set the PWM width to 100%?
At 100% duty cycle, the microcontroller stops switching and simply holds the pin continuously HIGH. This is perfectly safe and is the most efficient way to run a load, as it eliminates all switching losses in your MOSFETs or transistors. Conversely, 0% width holds the pin continuously LOW.
Understanding the distinction between the physical time of the pulse and the mathematical duty cycle is what separates basic blinking-LED projects from robust, professional-grade embedded designs. By matching your required PWM width parameters to the correct hardware timer and driver circuit, you ensure efficient power delivery and precise control over your physical loads.






