LED Control (LEDC)

About

The LED control (LEDC) peripheral is primarly designed to control the intensity of LEDs, although it can also be used to generate PWM signals for other purposes.

ESP32 SoCs has from 6 to 16 channels (variates on socs, see table below) which can generate independent waveforms, that can be used for example to drive RGB LED devices.

ESP32 SoC

Number of LEDC channels

ESP32

16

ESP32-S2

8

ESP32-C3

6

ESP32-S3

8

Arduino-ESP32 LEDC API

ledcSetup

This function is used to setup the LEDC channel frequency and resolution.

double ledcSetup(uint8_t channel, double freq, uint8_t resolution_bits);
  • channel select LEDC channel to config.

  • freq select frequency of pwm.

  • resolution_bits select resolution for ledc channel.

    • range is 1-14 bits (1-20 bits for ESP32).

This function will return frequency configured for LEDC channel. If 0 is returned, error occurs and ledc channel was not configured.

ledcWrite

This function is used to set duty for the LEDC channel.

void ledcWrite(uint8_t chan, uint32_t duty);
  • chan select the LEDC channel for writing duty.

  • duty select duty to be set for selected channel.

ledcRead

This function is used to get configured duty for the LEDC channel.

uint32_t ledcRead(uint8_t chan);
  • chan select LEDC channel to read the configured duty.

This function will return duty set for selected LEDC channel.

ledcReadFreq

This function is used to get configured frequency for the LEDC channel.

double ledcReadFreq(uint8_t chan);
  • chan select the LEDC channel to read the configured frequency.

This function will return frequency configured for selected LEDC channel.

ledcWriteTone

This function is used to setup the LEDC channel to 50 % PWM tone on selected frequency.

double ledcWriteTone(uint8_t chan, double freq);
  • chan select LEDC channel.

  • freq select frequency of pwm signal.

This function will return frequency set for channel. If 0 is returned, error occurs and ledc cahnnel was not configured.

ledcWriteNote

This function is used to setup the LEDC channel to specific note.

double ledcWriteNote(uint8_t chan, note_t note, uint8_t octave);
  • chan select LEDC channel.

  • note select note to be set.

NOTE_C

NOTE_Cs

NOTE_D

NOTE_Eb

NOTE_E

NOTE_F

NOTE_Fs

NOTE_G

NOTE_Gs

NOTE_A

NOTE_Bb

NOTE_B

  • octave select octave for note.

This function will return frequency configured for the LEDC channel according to note and octave inputs. If 0 is returned, error occurs and the LEDC channel was not configured.

ledcAttachPin

This function is used to attach the pin to the LEDC channel.

void ledcAttachPin(uint8_t pin, uint8_t chan);
  • pin select GPIO pin.

  • chan select LEDC channel.

ledcDetachPin

This function is used to detach the pin from LEDC.

void ledcDetachPin(uint8_t pin);
  • pin select GPIO pin.

ledcChangeFrequency

This function is used to set frequency for the LEDC channel.

double ledcChangeFrequency(uint8_t chan, double freq, uint8_t bit_num);
  • channel select LEDC channel.

  • freq select frequency of pwm.

  • bit_num select resolution for LEDC channel.

    • range is 1-14 bits (1-20 bits for ESP32).

This function will return frequency configured for the LEDC channel. If 0 is returned, error occurs and the LEDC channel frequency was not set.

analogWrite

This function is used to write an analog value (PWM wave) on the pin. It is compatible with Arduinos analogWrite function.

void analogWrite(uint8_t pin, int value);
  • pin select the GPIO pin.

  • value select the duty cycle of pwm. * range is from 0 (always off) to 255 (always on).

Example Applications

LEDC software fade example:

/*
 LEDC Software Fade

 This example shows how to software fade LED
 using the ledcWrite function.

 Code adapted from original Arduino Fade example:
 https://www.arduino.cc/en/Tutorial/Fade

 This example code is in the public domain.
 */

// use first channel of 16 channels (started from zero)
#define LEDC_CHANNEL_0     0

// use 12 bit precission for LEDC timer
#define LEDC_TIMER_12_BIT  12

// use 5000 Hz as a LEDC base frequency
#define LEDC_BASE_FREQ     5000

// fade LED PIN (replace with LED_BUILTIN constant for built-in LED)
#define LED_PIN            5

int brightness = 0;    // how bright the LED is
int fadeAmount = 5;    // how many points to fade the LED by

// Arduino like analogWrite
// value has to be between 0 and valueMax
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
  // calculate duty, 4095 from 2 ^ 12 - 1
  uint32_t duty = (4095 / valueMax) * min(value, valueMax);

  // write duty to LEDC
  ledcWrite(channel, duty);
}

void setup() {
  // Setup timer and attach timer to a led pin
  ledcSetup(LEDC_CHANNEL_0, LEDC_BASE_FREQ, LEDC_TIMER_12_BIT);
  ledcAttachPin(LED_PIN, LEDC_CHANNEL_0);
}

void loop() {
  // set the brightness on LEDC channel 0
  ledcAnalogWrite(LEDC_CHANNEL_0, brightness);

  // change the brightness for next time through the loop:
  brightness = brightness + fadeAmount;

  // reverse the direction of the fading at the ends of the fade:
  if (brightness <= 0 || brightness >= 255) {
    fadeAmount = -fadeAmount;
  }
  // wait for 30 milliseconds to see the dimming effect
  delay(30);
}

LEDC Write RGB example:

/*
  ledcWrite_RGB.ino
  Runs through the full 255 color spectrum for an rgb led 
  Demonstrate ledcWrite functionality for driving leds with PWM on ESP32
 
  This example code is in the public domain.
  
  Some basic modifications were made by vseven, mostly commenting.
 */
 
// Set up the rgb led names
uint8_t ledR = 2;
uint8_t ledG = 4;
uint8_t ledB = 5; 

uint8_t ledArray[3] = {1, 2, 3}; // three led channels

const boolean invert = true; // set true if common anode, false if common cathode

uint8_t color = 0;          // a value from 0 to 255 representing the hue
uint32_t R, G, B;           // the Red Green and Blue color components
uint8_t brightness = 255;  // 255 is maximum brightness, but can be changed.  Might need 256 for common anode to fully turn off.

// the setup routine runs once when you press reset:
void setup() 
{            
  Serial.begin(115200);
  delay(10); 
  
  ledcAttachPin(ledR, 1); // assign RGB led pins to channels
  ledcAttachPin(ledG, 2);
  ledcAttachPin(ledB, 3);
  
  // Initialize channels 
  // channels 0-15, resolution 1-16 bits, freq limits depend on resolution
  // ledcSetup(uint8_t channel, uint32_t freq, uint8_t resolution_bits);
  ledcSetup(1, 12000, 8); // 12 kHz PWM, 8-bit resolution
  ledcSetup(2, 12000, 8);
  ledcSetup(3, 12000, 8);
}

// void loop runs over and over again
void loop() 
{
  Serial.println("Send all LEDs a 255 and wait 2 seconds.");
  // If your RGB LED turns off instead of on here you should check if the LED is common anode or cathode.
  // If it doesn't fully turn off and is common anode try using 256.
  ledcWrite(1, 255);
  ledcWrite(2, 255);
  ledcWrite(3, 255);
  delay(2000);
  Serial.println("Send all LEDs a 0 and wait 2 seconds.");
  ledcWrite(1, 0);
  ledcWrite(2, 0);
  ledcWrite(3, 0);
  delay(2000);
 
  Serial.println("Starting color fade loop.");
  
 for (color = 0; color < 255; color++) { // Slew through the color spectrum

  hueToRGB(color, brightness);  // call function to convert hue to RGB

  // write the RGB values to the pins
  ledcWrite(1, R); // write red component to channel 1, etc.
  ledcWrite(2, G);   
  ledcWrite(3, B); 
 
  delay(100); // full cycle of rgb over 256 colors takes 26 seconds
 }
 
}

// Courtesy http://www.instructables.com/id/How-to-Use-an-RGB-LED/?ALLSTEPS
// function to convert a color to its Red, Green, and Blue components.

void hueToRGB(uint8_t hue, uint8_t brightness)
{
    uint16_t scaledHue = (hue * 6);
    uint8_t segment = scaledHue / 256; // segment 0 to 5 around the
                                            // color wheel
    uint16_t segmentOffset =
      scaledHue - (segment * 256); // position within the segment

    uint8_t complement = 0;
    uint16_t prev = (brightness * ( 255 -  segmentOffset)) / 256;
    uint16_t next = (brightness *  segmentOffset) / 256;

    if(invert)
    {
      brightness = 255 - brightness;
      complement = 255;
      prev = 255 - prev;
      next = 255 - next;
    }

    switch(segment ) {
    case 0:      // red
        R = brightness;
        G = next;
        B = complement;
    break;
    case 1:     // yellow
        R = prev;
        G = brightness;
        B = complement;
    break;
    case 2:     // green
        R = complement;
        G = brightness;
        B = next;
    break;
    case 3:    // cyan
        R = complement;
        G = prev;
        B = brightness;
    break;
    case 4:    // blue
        R = next;
        G = complement;
        B = brightness;
    break;
   case 5:      // magenta
    default:
        R = brightness;
        G = complement;
        B = prev;
    break;
    }
}