WS2812
We all love colorful blinking LEDs, right? There’s a simple API for
accessing the five individually addressable RGB LEDs on the Badge’s
kite. The API is found inside a separate ESP-IDF compontent
ws2812 that is intended as a [git submodule]
(https://github.com/badgeteam/esp32-component-ws2812). If you started
your app development from the [template app]
(https://github.com/badgeteam/mch2022-template-app), it should be
already set up.
There’s a sixth RGB LED on the board (next to the top corner of the display). This LED is controlled via the ICE40 FPGA (see its driver for details).
The LEDs are WS2812-compatible. If you’re not already familiar with these LEDs: Each LED contains red, green and blue LED and a tiny controller that receives 24 bit RGB data from a single serial data line. Further data bits are pushed through to its data output, which is connected to the next LED. This allows many LEDs in a string to be individually controlled.
The LED power supply is switched (together with the SD card). Before using the LEDs, set IO19 (GPIO_SD_PWR) to 1.
Before controlling the LEDs, the driver has to be set up with
the data line connected to the LEDs (GPIO_LED_DATA). If you
want to control other WS2812 LEDs (e.g. connected to one of the
extension connectors), you can specify a different value.
Setting the LEDs is pretty straightforward: Set up an array of 15 unsigned brightness values (R,G,B for 5 LEDs).
A minimal example to set all LEDs to red:
uint8_t red[] = {0,255,0,0,255,0,0,255,0,0,255,0,0,255,0};
// turn on LED power
gpio_set_direction(GPIO_SD_PWR, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_SD_PWR, 1);
// initialize WS2812 driver to the appropriate data pin
ws2812_init(GPIO_LED_DATA);
ws2812_send_data(red, sizeof(red));
To animate, change the array values and repeat ws2812_send_data
in regular intervals.
Addressable LEDs on an SAO
The LEDs on an add-on are a different story: they hang off the SAO
connector, and that pin belongs to the RP2040, not to the ESP32. So the
ws2812 component above does not reach them. Instead you ask the RP2040
to shift the data out for you, over the I2C link the badge already uses
for the buttons.
The RP2040 drives the WS2812 chain on SAO_IO0, which is pin 5 of the
SAO connector — the pin the standard reserves as
the data line for addressable LEDs. It can hold up to 10 LEDs. The
API lives in the mch2022-rp2040
component
that the template app already includes, and needs RP2040 firmware
version 9 or newer.
Set it up once:
RP2040* rp2040 = get_rp2040();
rp2040_set_gpio_dir(rp2040, 0, true); // SAO IO0 becomes an output
rp2040_set_ws2812_mode(rp2040, 1); // 1 = enabled, 24-bit RGB
rp2040_set_ws2812_length(rp2040, 5); // number of LEDs on the add-on
Then write the LEDs and push the buffer out:
for (uint8_t i = 0; i < 5; i++) {
rp2040_set_ws2812_data(rp2040, i, 0x00FF0000); // red
}
rp2040_ws2812_trigger(rp2040);
Each value is one 32-bit word, and WS2812 LEDs take their colors in GRB
order: green in bits 31-24, red in bits 23-16, blue in bits 15-8. The
lowest byte is the white channel, which only 32-bit RGBW LEDs use.
Nothing lights up until rp2040_ws2812_trigger runs, so you can stage a
whole frame and show it at once.
Example app
mch2022-tilde-ws2812-sao-test-app
by Renze Nicolai is the template app with exactly this added: it sets up
the five LEDs of the tilde add-on, then fades each color up and down,
first across all five LEDs together and then one LED at a time. It is a
short read and a good starting point for your own add-on.
RGBW mode needs a firmware newer than 0x0C
Mode 2 selects 32-bit RGBW output. On every released RP2040 firmware up
to and including 0x0C it turns the LEDs off instead: the switch enables
the output and then falls through into the disable case.
The fix is
on master and is not in a release yet, so a badge you did not build the
firmware for yourself still has this. Use mode 1 there.