ESP32 Basics: Generating a PWM Signal on the ESP32
Introduction
If you've played around with Arduino before, you're familiar with how simple it is to generate a PWM signal using the analogWrite() function—just specify the pin to use and the duty cycle, and you're good to go. The ESP32 offers even more flexibility with its PWM capabilities, allowing for precise control over frequency and resolution.
ESP32 PWM Pins
The ESP32 supports PWM on any GPIO pin. It has 16 independent PWM channels that can be configured to generate signals with different properties. Here's what you need to know about ESP32's PWM capabilities:
- 16 independent channels for PWM generation
- Each channel can be assigned to any GPIO pin
- Independent frequency and duty cycle control per channel
- High-resolution phase shift capability
PWM Frequency
The ESP32 allows you to set PWM frequencies from a few Hz up to 40MHz, making it suitable for a wide range of applications. The frequency can be set independently for each channel, giving you maximum flexibility in your projects.
ledcSetup(pwmChannel, frequency, resolution);
PWM Resolution
You can configure the PWM resolution from 1 to 16 bits, allowing for precise control over the duty cycle. Higher resolution means finer control over the output signal, but may require a lower frequency.
Note: The maximum frequency depends on the resolution. Higher resolution requires lower frequency.
Duty Cycle
The duty cycle determines the average output voltage and can be set with high precision thanks to the configurable resolution. For example, with 8-bit resolution, you can set values from 0 to 255.
ledcWrite(pwmChannel, dutyCycle);
Example 1 - Fading an LED
Let's look at a practical example of using PWM to fade an LED. This example demonstrates how to set up a PWM channel and gradually change the duty cycle to create a smooth fading effect.
Wiring
Connect an LED to GPIO pin 2 through a 220Ω resistor to ground. The LED's anode (longer leg) should connect to GPIO 2 through the resistor, and the cathode (shorter leg) should connect to ground.
Code
// https://docs.espressif.com/projects/arduino-esp32/en/latest/api/ledc.html #includeconst int PWM_FREQ = 500; // 500 Hz frequency const int PWM_RESOLUTION = 8; // 8-bit resolution (0-255) const int LED_OUTPUT_PIN = 21; // LED connected to GPIO18 const int MAX_DUTY_CYCLE = (1 << PWM_RESOLUTION) - 1; // Max duty cycle based on resolution const int DELAY_MS = 4; // delay between fade increments void setup() { Serial.begin(115200); // Attach LED to a PWM channel, with given frequency and resolution ledcAttach(LED_OUTPUT_PIN, PWM_FREQ, PWM_RESOLUTION); Serial.println("PWM LED Control Initialized"); } void loop() { // Fade in (increase brightness) for (int dutyCycle = 0; dutyCycle <= MAX_DUTY_CYCLE; dutyCycle++) { ledcWrite(LED_OUTPUT_PIN, dutyCycle); delay(DELAY_MS); } // Fade out (decrease brightness) for (int dutyCycle = MAX_DUTY_CYCLE; dutyCycle >= 0; dutyCycle--) { ledcWrite(LED_OUTPUT_PIN, dutyCycle); delay(DELAY_MS); } }