ESP32

ESP32 Basics: Generating a PWM Signal on the ESP32

ESP32 GPIO PWM ESP32 PWM Tutorial Frequency Duty Cycle

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

#include 

const 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);
    }
}