This is a small WS2812 ‘object’ written in plain C. It controls a WS2812 led strip using the programmable IO feature of the RP2040.
- Copy
ws2812.c
,ws2812.h
andws2812.pio
into your project directory - Add
pico_generate_pio_header(YourProject ${CMAKE_CURRENT_LIST_DIR}/WS2812.pio)
to yourCMakeLists.txt
(Replacing YourProject with the name of your project, duh :D) - Add the
ws2812.c
to your add_executable instruction of your CMakeLists.txt - Make sure
hardware_pio
is included within thetarget_link_libraries
instruction of yourCMakeLists.txt
In your sources:
- get a ws2812 ‘Object’ using
ws2812_initialize()
Depending on what LED strip you have (with a value for white or without) you need to pass is_rgbw as true or false. - Set LED colors using
ws2812_set_LED()
andws2812_fill()
These functions take a uint32_t to set the color. Use the provided functions (e.g.ws2812_urgb_grbu32()
) to pack RGB (0-255) values into such an uint32_t. Most WS2812 strips take GRB values, so usews2812_urgb_grbu32()
, for strips that use RGB usews2812_urgb_rgbu32()
and for RGBW usews2812_urgb_wrgbu32()
. If you have a very special LED strip that takes a completely different format, you can also build your own uint32_t and pass that intows2812_set_LED()
.
#include "pico/stdlib.h"
#include "bsp/board.h"
#include "WS2812.pio.h"
#include "ws2812.h"
#define LED_PIN 2
#define NUM_LEDS 3
#define STATE_MACHINE 0
#define IS_RGBW false
struct WS2812* led_strip;
int main(void) {
board_init();
stdio_init_all();
// Create a WS2812 object
led_strip = ws2812_initialize(pio0, STATE_MACHINE, LED_PIN, NUM_LEDS, IS_RGBW);
// fill the whole LED strip with white
ws2812_fill(led_strip, ws2812_urgb_grbu32(255, 255, 255));
// write the data do the strip
ws2812_show(led_strip);
while (1) {
// set first LED to red
ws2812_set_led(led_strip, 0, ws2812_urgb_grbu32(255, 0, 0));
// set second LED to green
ws2812_set_led(led_strip, 1, ws2812_urgb_grbu32(0, 255, 0));
// set third LED to blue
ws2812_set_led(led_strip, 2, ws2812_urgb_grbu32(0, 0, 255));
// write the data do the strip
ws2812_show(led_strip);
sleep_ms(1000);
}
}
This assumes you have a working arm-none-eabi-gcc for the Pico
Clone this repo:
git clone https://github.com/Schievel1/ws2812_pico_sdk.git
cd ws2812_pico_sdk
Update the pico-sdk submodule:
git submodule update --init --recursive
Build:
mkdir build
cd build
cmake ..
make ws2812-example
ForsakenNGS has two WS2812 libraries is C++ that are more sophisticated. The newer one is huge, can be adapted to other LED types and contains tons of functions like filling a strip with a gradient or rainbow colors. (https://github.com/ForsakenNGS/PicoLED)
The older one is more specific to the WS2812 and contains only the basic functions like this one I wrote (https://github.com/ForsakenNGS/Pico_WS2812)
However, I tend to refrain having C++ in my projects, because once you pull one C++ thing in it tends to spread.
For a more baremetal approach you can also use the bare functions provided by the Pico-SDK: https://github.com/raspberrypi/pico-examples/tree/master/pio/ws2812