kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Plasma WS2812: Add RGBW and color-order support
rodzic
693e84c73d
commit
6ce80cd289
|
@ -26,9 +26,9 @@ const uint N_LEDS = 30;
|
|||
//plasma::APA102 led_strip(N_LEDS, pio0, 0, plasma::PIN_DAT, plasma::PIN_CLK);
|
||||
|
||||
// WS28X-style LEDs with a single signal line. AKA NeoPixel
|
||||
// by default the WS2812 LED strip will be 400KHz, RGB with no white element
|
||||
plasma::WS2812 led_strip(N_LEDS, pio0, 0, plasma::PIN_DAT);
|
||||
|
||||
|
||||
Button button_a(plasma::BUTTON_A, Polarity::ACTIVE_LOW, 50);
|
||||
Button button_b(plasma::BUTTON_B, Polarity::ACTIVE_LOW, 50);
|
||||
RGBLED led(plasma::LED_R, plasma::LED_G, plasma::LED_B);
|
||||
|
|
|
@ -43,6 +43,7 @@ bool APA102::dma_timer_callback(struct repeating_timer *t) {
|
|||
}
|
||||
|
||||
void APA102::update(bool blocking) {
|
||||
if(dma_channel_is_busy(dma_channel) && !blocking) return;
|
||||
while(dma_channel_is_busy(dma_channel)) {}; // Block waiting for DMA finish
|
||||
pio->txf[sm] = 0x00000000; // Output the APA102 start-of-frame bytes
|
||||
dma_channel_set_trans_count(dma_channel, num_leds, false);
|
||||
|
@ -62,7 +63,7 @@ bool APA102::stop() {
|
|||
|
||||
void APA102::clear() {
|
||||
for (auto i = 0u; i < num_leds; ++i) {
|
||||
buffer[i].rgb(0, 0, 0);
|
||||
set_rgb(i, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,12 +76,12 @@ void APA102::set_hsv(uint32_t index, float h, float s, float v) {
|
|||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: buffer[index].rgb(v, t, p); break;
|
||||
case 1: buffer[index].rgb(q, v, p); break;
|
||||
case 2: buffer[index].rgb(p, v, t); break;
|
||||
case 3: buffer[index].rgb(p, q, v); break;
|
||||
case 4: buffer[index].rgb(t, p, v); break;
|
||||
case 5: buffer[index].rgb(v, p, q); break;
|
||||
case 0: set_rgb(index, v, t, p); break;
|
||||
case 1: set_rgb(index, q, v, p); break;
|
||||
case 2: set_rgb(index, p, v, t); break;
|
||||
case 3: set_rgb(index, p, q, v); break;
|
||||
case 4: set_rgb(index, t, p, v); break;
|
||||
case 5: set_rgb(index, v, p, q); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,9 +46,9 @@ namespace plasma {
|
|||
void rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
this->r = r;
|
||||
this->g = g;
|
||||
this->b = b;
|
||||
this->b = b;;
|
||||
}
|
||||
RGB() : sof(0b11101111), b(0), g(0), r(0) {}
|
||||
RGB() : sof(0b11101111), b(0), g(0), r(0) {};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
RGB *buffer;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace plasma {
|
||||
|
||||
WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, RGB* buffer) : buffer(buffer), num_leds(num_leds), pio(pio), sm(sm) {
|
||||
WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, bool rgbw, COLOR_ORDER color_order, RGB* buffer) : buffer(buffer), num_leds(num_leds), color_order(color_order), pio(pio), sm(sm) {
|
||||
uint offset = pio_add_program(pio, &ws2812_program);
|
||||
|
||||
pio_gpio_init(pio, pin);
|
||||
|
@ -11,7 +11,7 @@ WS2812::WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq, RGB* buffer
|
|||
pio_sm_config c = ws2812_program_get_default_config(offset);
|
||||
sm_config_set_sideset_pins(&c, pin);
|
||||
|
||||
sm_config_set_out_shift(&c, false, true, 24); // Discard first (APA102 global brightness) byte. TODO support RGBW WS281X LEDs
|
||||
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24); // Discard first (APA102 global brightness) byte. TODO support RGBW WS281X LEDs
|
||||
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||
|
||||
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
|
||||
|
@ -42,6 +42,7 @@ bool WS2812::dma_timer_callback(struct repeating_timer *t) {
|
|||
}
|
||||
|
||||
void WS2812::update(bool blocking) {
|
||||
if(dma_channel_is_busy(dma_channel) && !blocking) return;
|
||||
while(dma_channel_is_busy(dma_channel)) {}; // Block waiting for DMA finish
|
||||
dma_channel_set_trans_count(dma_channel, num_leds, false);
|
||||
dma_channel_set_read_addr(dma_channel, buffer, true);
|
||||
|
@ -60,7 +61,7 @@ bool WS2812::stop() {
|
|||
|
||||
void WS2812::clear() {
|
||||
for (auto i = 0u; i < num_leds; ++i) {
|
||||
buffer[i].rgb(0, 0, 0);
|
||||
set_rgb(i, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,17 +74,36 @@ void WS2812::set_hsv(uint32_t index, float h, float s, float v) {
|
|||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: buffer[index].rgb(v, t, p); break;
|
||||
case 1: buffer[index].rgb(q, v, p); break;
|
||||
case 2: buffer[index].rgb(p, v, t); break;
|
||||
case 3: buffer[index].rgb(p, q, v); break;
|
||||
case 4: buffer[index].rgb(t, p, v); break;
|
||||
case 5: buffer[index].rgb(v, p, q); break;
|
||||
case 0: set_rgb(index, v, t, p); break;
|
||||
case 1: set_rgb(index, q, v, p); break;
|
||||
case 2: set_rgb(index, p, v, t); break;
|
||||
case 3: set_rgb(index, p, q, v); break;
|
||||
case 4: set_rgb(index, t, p, v); break;
|
||||
case 5: set_rgb(index, v, p, q); break;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812::set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b) {
|
||||
buffer[index].rgb(r, g, b);
|
||||
void WS2812::set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
switch(color_order) {
|
||||
case COLOR_ORDER::RGB:
|
||||
buffer[index].rgb(r, g, b, w);
|
||||
break;
|
||||
case COLOR_ORDER::RBG:
|
||||
buffer[index].rgb(r, b, g, w);
|
||||
break;
|
||||
case COLOR_ORDER::GRB:
|
||||
buffer[index].rgb(g, r, b, w);
|
||||
break;
|
||||
case COLOR_ORDER::GBR:
|
||||
buffer[index].rgb(g, b, r, w);
|
||||
break;
|
||||
case COLOR_ORDER::BRG:
|
||||
buffer[index].rgb(b, r, g, w);
|
||||
break;
|
||||
case COLOR_ORDER::BGR:
|
||||
buffer[index].rgb(b, g, r, w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812::set_brightness(uint8_t b) {
|
||||
|
|
|
@ -30,6 +30,14 @@ namespace plasma {
|
|||
static const uint SERIAL_FREQ_400KHZ = 400000;
|
||||
static const uint SERIAL_FREQ_800KHZ = 800000;
|
||||
static const uint DEFAULT_SERIAL_FREQ = SERIAL_FREQ_400KHZ;
|
||||
enum class COLOR_ORDER {
|
||||
RGB,
|
||||
RBG,
|
||||
GRB,
|
||||
GBR,
|
||||
BRG,
|
||||
BGR
|
||||
};
|
||||
#pragma pack(push, 1)
|
||||
union alignas(4) RGB {
|
||||
struct {
|
||||
|
@ -42,19 +50,20 @@ namespace plasma {
|
|||
void operator=(uint32_t v) {
|
||||
srgb = v;
|
||||
};
|
||||
void brightness(uint8_t b) {};;
|
||||
void rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
void rgb(uint8_t r, uint8_t g, uint8_t b, uint8_t w=0) {
|
||||
this->r = r;
|
||||
this->g = g;
|
||||
this->b = b;
|
||||
}
|
||||
RGB() : r(0), g(0), b(0), w(0) {}
|
||||
this->w = w;
|
||||
};
|
||||
RGB() : r(0), g(0), b(0), w(0) {};
|
||||
};
|
||||
#pragma pack(pop)
|
||||
RGB *buffer;
|
||||
uint32_t num_leds;
|
||||
COLOR_ORDER color_order;
|
||||
|
||||
WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq=DEFAULT_SERIAL_FREQ, RGB* buffer=nullptr);
|
||||
WS2812(uint num_leds, PIO pio, uint sm, uint pin, uint freq=DEFAULT_SERIAL_FREQ, bool rgbw=false, COLOR_ORDER color_order=COLOR_ORDER::RGB, RGB* buffer=nullptr);
|
||||
~WS2812() {
|
||||
stop();
|
||||
clear();
|
||||
|
@ -68,7 +77,7 @@ namespace plasma {
|
|||
void update(bool blocking=false);
|
||||
void clear();
|
||||
void set_hsv(uint32_t index, float h, float s, float v);
|
||||
void set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b);
|
||||
void set_rgb(uint32_t index, uint8_t r, uint8_t g, uint8_t b, uint8_t w=0);
|
||||
void set_brightness(uint8_t b);
|
||||
RGB get(uint32_t index) {return buffer[index];};
|
||||
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
The Plasma library is intended to drive APA102 / DotStar™ or WS2812 / NeoPixel™ LEDs on the Plasma 2040 board, though it can be used with your own custom pins/wiring.
|
||||
|
||||
- [Notes On PIO Limitations](#notes-on-pio-limitations)
|
||||
- [APA102](#apa102)
|
||||
- [WS2812](#ws2812)
|
||||
- [Getting Started](#getting-started)
|
||||
- [RGBW and Setting Colour Order](#rgbw-and-setting-colour-order)
|
||||
- [Set An LED](#set-an-led)
|
||||
- [RGB](#rgb)
|
||||
- [HSV](#hsv)
|
||||
- [Set Brightness](#set-brightness)
|
||||
- [WS2812](#ws2812)
|
||||
- [APA102](#apa102)
|
||||
- [Getting Started](#getting-started-1)
|
||||
- [Set An LED](#set-an-led-1)
|
||||
- [RGB](#rgb-1)
|
||||
|
@ -24,7 +25,7 @@ The WS2812 and APA102 drivers use the PIO hardware on the RP2040. There are only
|
|||
|
||||
In most cases you'll use `0` for PIO and `0` for PIO state-machine, but you should change these if you plan on running different strand types together, or if you're using something else that uses PIO.
|
||||
|
||||
## APA102
|
||||
## WS2812
|
||||
|
||||
### Getting Started
|
||||
|
||||
|
@ -45,6 +46,28 @@ Start the LED strip by calling `start`. This sets up a timer which tells the RP2
|
|||
led_strip.start(FPS)
|
||||
```
|
||||
|
||||
### RGBW and Setting Colour Order
|
||||
|
||||
Some WS2812-style LED strips have varying colour orders and support an additional white element. Two keyword arguments are supplied to configure this:
|
||||
|
||||
```
|
||||
import plasma
|
||||
|
||||
LEDS = 30
|
||||
FPS = 60
|
||||
|
||||
led_strip = plasma.WS2812(LEDS, 0, 0, 15, rgbw=True, color_order=plasma.COLOR_ORDER_GRB)
|
||||
```
|
||||
|
||||
The available orders are defined as constants in `plasma`:
|
||||
|
||||
* `COLOR_ORDER_RGB`
|
||||
* `COLOR_ORDER_RBG`
|
||||
* `COLOR_ORDER_GRB`
|
||||
* `COLOR_ORDER_GBR`
|
||||
* `COLOR_ORDER_BRG`
|
||||
* `COLOR_ORDER_BGR`
|
||||
|
||||
### Set An LED
|
||||
|
||||
You can set the colour of an LED in either the RGB colourspace, or HSV (Hue, Saturation, Value). HSV is useful for creating rainbow patterns.
|
||||
|
@ -75,7 +98,7 @@ led_strip.set_brightness(15)
|
|||
|
||||
You can set brightness from `0` to `31`. This directly maps to the 5-bit brightness value sent to the APA102 LEDs.
|
||||
|
||||
## WS2812
|
||||
## APA102
|
||||
|
||||
### Getting Started
|
||||
|
||||
|
|
|
@ -62,6 +62,13 @@ STATIC const mp_map_elem_t plasma_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_PIN_LED_B), MP_ROM_INT(18) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PIN_BUTTON_A), MP_ROM_INT(12) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_PIN_BUTTON_B), MP_ROM_INT(13) },
|
||||
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_RGB), MP_ROM_INT(0x00) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_RBG), MP_ROM_INT(0x01) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_GRB), MP_ROM_INT(0x02) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_GBR), MP_ROM_INT(0x03) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_BRG), MP_ROM_INT(0x04) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_COLOR_ORDER_BGR), MP_ROM_INT(0x05) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_plasma_globals, plasma_globals_table);
|
||||
|
||||
|
|
|
@ -60,7 +60,9 @@ mp_obj_t PlasmaWS2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
|||
ARG_sm,
|
||||
ARG_dat,
|
||||
ARG_freq,
|
||||
ARG_buffer
|
||||
ARG_buffer,
|
||||
ARG_rgbw,
|
||||
ARG_color_order
|
||||
};
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_num_leds, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
|
@ -69,6 +71,8 @@ mp_obj_t PlasmaWS2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
|||
{ MP_QSTR_dat, MP_ARG_REQUIRED | MP_ARG_INT },
|
||||
{ MP_QSTR_freq, MP_ARG_INT, {.u_int = WS2812::DEFAULT_SERIAL_FREQ} },
|
||||
{ MP_QSTR_buffer, MP_ARG_OBJ, {.u_obj = nullptr} },
|
||||
{ MP_QSTR_rgbw, MP_ARG_BOOL, {.u_bool = false} },
|
||||
{ MP_QSTR_color_order, MP_ARG_INT, {.u_int = (uint8_t)WS2812::COLOR_ORDER::RGB} },
|
||||
};
|
||||
|
||||
// Parse args.
|
||||
|
@ -80,6 +84,8 @@ mp_obj_t PlasmaWS2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
|||
int sm = args[ARG_sm].u_int;
|
||||
int dat = args[ARG_dat].u_int;
|
||||
int freq = args[ARG_freq].u_int;
|
||||
bool rgbw = args[ARG_rgbw].u_bool;
|
||||
WS2812::COLOR_ORDER color_order = (WS2812::COLOR_ORDER)args[ARG_color_order].u_int;
|
||||
|
||||
void *buffer = nullptr;
|
||||
|
||||
|
@ -96,7 +102,7 @@ mp_obj_t PlasmaWS2812_make_new(const mp_obj_type_t *type, size_t n_args, size_t
|
|||
self->base.type = &PlasmaWS2812_type;
|
||||
self->buf = buffer;
|
||||
|
||||
self->ws2812 = new WS2812(num_leds, pio, sm, dat, freq, (WS2812::RGB *)buffer);
|
||||
self->ws2812 = new WS2812(num_leds, pio, sm, dat, freq, rgbw, color_order, (WS2812::RGB *)buffer);
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue