ESP32s with an RGB LED reference

Hi all. I am working with an ESP32s with a common anode RGB LED. I am trying to get different colors by varying the colors using PWM. I've looked at different examples, but I can't get this to work.

I am using the following circuit:

ESP32RGBSchem

I am using the RGB LED example ledCWrite_RGB01 which I include here for completeness. Any orientation is welcomed and appreciated. Thank you!

/*
  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 = A4;
uint8_t ledG = A5;
uint8_t ledB = A18; 

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

What pin number do those map to on an ESP32?

With an ESP32 I use GPIO_NUM_X where X= the GPIO number I am going to use.

uint8_t ledR = GPIO_NUM_4;
uint8_t ledG = GPIO_NUM_5;
uint8_t ledB = GPIO_NUM_18;

You also need to add resistors the the LED, at the moment, you will burn out the LED or the ESP32!

1 Like

Aaargh! My bad! The circuit does use resistors, which I forgot to include in the diagram. Apologies.

Yup, that got it to work. Now I am left wondering how this example was ever supposed to work. Thanks!

1 Like

After testing, I see that the LED does not mix the colors correctly to create the illusion of a non primary color. For example, for the orange color, instead of looking orange, it looks like green and red. I used the following code for this color:

    ledcWrite(1, 0); // write red component to channel 1, etc.
    ledcWrite(2, 127);   
    ledcWrite(3, 256);

Here, 0 presents fully ON and 256 represents fully OFF. I plan on experimenting more, but I wonder if the type/quality RGB LED has anything to do with it. Is there any specific type of RGB LED that is recommend for the Arduino and/or ESP32? I do not need high power, a normal LED will do. The one I am currently using is the following:

I can change this if a more suitable item is recommended. Thanks!

You will need to adjust the resistor values to match the LED colour intensities.

Generally green LEDs are MUCH less efficient then red or blue - depending on whether they are GaP or InGaN. The quoted 3.5V Vf would indicate they are InGaN.

You will need to adjust the resistor values to match the LED colour intensities.

Generally green LEDs are MUCH less efficient then red or blue - depending on whether they are GaP or InGaN.

D65 target white
The commonly used 3:6:1 RGB mixing ratio is derived from this early research .. ref:

https://www.ledsmagazine.com/smart-lighting-iot/color-tuning/article/16695054/understand-rgb-led-mixing-ratios-to-realize-optimal-color-in-signs-and-displays-magazine

ledcSetup(1, 12000, 8); // 12 kHz PWM, 8-bit resolution

if you are using an 8-bit resolution

ledcWrite(3, 256);

then 255 is your highest value, 256 is 9-bit.
Also a lower frequency may yield better results, try 1Khz. I use a higher resolution as well in combination with a curve calculation which uses something like a cosine curve.

Thanks for the feedback. The original sketch, in its comments, suggested using 256 if the LED did not completely shut off. I changed it to test, and forgot to change it back. But yeah, I am not sure what's up with feeding 256 to a function that only accepts 8 bit values.

I'll have to remind myself to change that back to 255.

Thanks! I'll have a look at the link. I'll see about those resistors. Right now it was easy for me to just use a bunch of 330 Ohm resistors.