Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Onboard RGB LED

The ESP32-C5 board does not have a standard onboard LED. Instead, it has an addressable RGB LED connected to GPIO27. In a way, it is actually cool that our blinky program will be colorful. On the other side, for simple feedback where I use an onboard LED, I can’t use that simple way.

ESP32-C5 Onboard RGB LED
ESP32-C5 Onboard RGB LED

Let’s generate the project with esp-generate in headless mode.

esp-generate --headless -o esp32c5 -o defmt rgb-led

Dependencies

We will need two crates to work with the onboard RGB LED. The smart-leds crate provides a common interface for addressable LEDs such as WS2812 (NeoPixel) and APA102 (DotStar).

The esp-hal-smartled crate provides the ESP-HAL-specific implementation that uses the ESP32-C5’s RMT peripheral to generate the precise timing required by the WS2812B.

Add the following dependencies to your Cargo.toml:

esp-hal-smartled = "0.18.0"
smart-leds = "0.4.0"

Additional Imports

We will add the necessary imports. In future exercises, I may not add instructions to import when they are obvious. I always provide the finished project link, so you can check the imports there as well.

#![allow(unused)]
fn main() {
use esp_hal::rmt::Rmt;
use esp_hal::time::Rate;
use esp_hal::delay::Delay;
use esp_hal_smartled::{RmtSmartLeds, buffer_size, color_order};
use smart_leds::{RGB8, SmartLedsWrite};
}

Initialize RMT

First, let’s initialize the RMT peripheral. We will use an 80 MHz frequency.

#![allow(unused)]
fn main() {
let freq = Rate::from_mhz(80);
let rmt = Rmt::new(peripherals.RMT, freq).unwrap();
}

Configure the RGB LED

Next, we will configure the RMT channel to drive the WS2812B LED connected to GPIO27.

#![allow(unused)]
fn main() {
let mut led =
    RmtSmartLeds::<{ buffer_size::<RGB8>(1) }, _, RGB8, color_order::Grb>::new_with_memsize(
        esp_hal_smartled::WS2812_TIMING,
        rmt.channel0,
        peripherals.GPIO27,
        2,
        freq,
    )
    .unwrap();
}

The WS2812_TIMING provides the timing required by the WS2812B, while color_order::Grb specifies the order in which the LED expects the color values.

Main loop

Now we can use the write method to send RGB values to the LED. Let’s cycle through red, green, and blue with a 500 millisecond delay between each color.

#![allow(unused)]
fn main() {
 let delay = Delay::new();

loop {
    led.write([RGB8::new(255, 0, 0)]).unwrap();
    delay.delay_millis(500);

    led.write([RGB8::new(0, 255, 0)]).unwrap();
    delay.delay_millis(500);

    led.write([RGB8::new(0, 0, 255)]).unwrap();
    delay.delay_millis(500);
}
}

Clone the existing project

You can clone (or refer) project I created and navigate to the rgb-led folder.

git clone https://github.com/ImplFerris/esp32c5-projects
cd esp32c5-projects/rgb-led/

Run the program

Let’s flash the firmware and run it. If everything works, you should see the RGB LED cycle through red, green, and blue.

cargo run --release

I will avoid repeating this step in future exercises. If an exercise requires additional input, such as an environment variable, I will include the required command at that point.