Просмотр исходного кода

Add RGBW LED support

main_ledos
PaulStoffregen 4 лет назад
Родитель
Сommit
072fcd30a8
3 измененных файлов: 205 добавлений и 40 удалений
  1. +94
    -30
      WS2812Serial.cpp
  2. +55
    -10
      WS2812Serial.h
  3. +56
    -0
      examples/BasicTest_RGBW/BasicTest_RGBW.ino

+ 94
- 30
WS2812Serial.cpp Просмотреть файл

@@ -213,6 +213,8 @@ bool WS2812Serial::begin()

void WS2812Serial::show()
{
uint32_t microseconds_per_led, bytes_per_led;

// wait if prior DMA still in progress
#if defined(KINETISK)
while ((DMA_ERQ & (1 << dma->channel))) {
@@ -230,33 +232,95 @@ void WS2812Serial::show()
//Serial.println("After Yield");
#endif
// copy drawing buffer to frame buffer
const uint8_t *p = drawBuffer;
const uint8_t *end = p + (numled * 3);
uint8_t *fb = frameBuffer;
while (p < end) {
uint8_t b = *p++;
uint8_t g = *p++;
uint8_t r = *p++;
uint32_t n=0;
switch (config) {
case WS2812_RGB: n = (r << 16) | (g << 8) | b; break;
case WS2812_RBG: n = (r << 16) | (b << 8) | g; break;
case WS2812_GRB: n = (g << 16) | (r << 8) | b; break;
case WS2812_GBR: n = (g << 16) | (b << 8) | r; break;
case WS2812_BRG: n = (b << 16) | (r << 8) | g; break;
case WS2812_BGR: n = (b << 16) | (g << 8) | r; break;
if (config < 6) {
// RGB
const uint8_t *p = drawBuffer;
const uint8_t *end = p + (numled * 3);
uint8_t *fb = frameBuffer;
while (p < end) {
uint8_t b = *p++;
uint8_t g = *p++;
uint8_t r = *p++;
uint32_t mult = brightness + 1;
b = (b * mult) >> 8;
g = (g * mult) >> 8;
r = (r * mult) >> 8;
uint32_t n=0;
switch (config) {
case WS2812_RGB: n = (r << 16) | (g << 8) | b; break;
case WS2812_RBG: n = (r << 16) | (b << 8) | g; break;
case WS2812_GRB: n = (g << 16) | (r << 8) | b; break;
case WS2812_GBR: n = (g << 16) | (b << 8) | r; break;
case WS2812_BRG: n = (b << 16) | (r << 8) | g; break;
case WS2812_BGR: n = (b << 16) | (g << 8) | r; break;
}
const uint8_t *stop = fb + 12;
do {
uint8_t x = 0x08;
if (!(n & 0x00800000)) x |= 0x07;
if (!(n & 0x00400000)) x |= 0xE0;
n <<= 2;
*fb++ = x;
} while (fb < stop);
}
microseconds_per_led = 30;
bytes_per_led = 12;
} else {
// RGBW
const uint8_t *p = drawBuffer;
const uint8_t *end = p + (numled * 4);
uint8_t *fb = frameBuffer;
while (p < end) {
uint8_t b = *p++;
uint8_t g = *p++;
uint8_t r = *p++;
uint8_t w = *p++;
uint32_t mult = brightness + 1;
b = (b * mult) >> 8;
g = (g * mult) >> 8;
r = (r * mult) >> 8;
w = (w * mult) >> 8;
uint32_t n=0;
switch (config) {
case WS2812_RGBW: n = (r << 24) | (g << 16) | (b << 8) | w; break;
case WS2812_RBGW: n = (r << 24) | (b << 16) | (g << 8) | w; break;
case WS2812_GRBW: n = (g << 24) | (r << 16) | (b << 8) | w; break;
case WS2812_GBRW: n = (g << 24) | (b << 16) | (r << 8) | w; break;
case WS2812_BRGW: n = (b << 24) | (r << 16) | (g << 8) | w; break;
case WS2812_BGRW: n = (b << 24) | (b << 16) | (r << 8) | w; break;
case WS2812_WRGB: n = (w << 24) | (r << 16) | (g << 8) | b; break;
case WS2812_WRBG: n = (w << 24) | (r << 16) | (b << 8) | g; break;
case WS2812_WGRB: n = (w << 24) | (g << 16) | (r << 8) | b; break;
case WS2812_WGBR: n = (w << 24) | (g << 16) | (b << 8) | r; break;
case WS2812_WBRG: n = (w << 24) | (b << 16) | (r << 8) | g; break;
case WS2812_WBGR: n = (w << 24) | (b << 16) | (g << 8) | r; break;
case WS2812_RWGB: n = (r << 24) | (w << 16) | (g << 8) | b; break;
case WS2812_RWBG: n = (r << 24) | (w << 16) | (b << 8) | g; break;
case WS2812_GWRB: n = (g << 24) | (w << 16) | (r << 8) | b; break;
case WS2812_GWBR: n = (g << 24) | (w << 16) | (b << 8) | r; break;
case WS2812_BWRG: n = (b << 24) | (w << 16) | (r << 8) | g; break;
case WS2812_BWGR: n = (b << 24) | (w << 16) | (g << 8) | r; break;
case WS2812_RGWB: n = (r << 24) | (g << 16) | (w << 8) | b; break;
case WS2812_RBWG: n = (r << 24) | (b << 16) | (w << 8) | g; break;
case WS2812_GRWB: n = (g << 24) | (r << 16) | (w << 8) | b; break;
case WS2812_GBWR: n = (g << 24) | (b << 16) | (w << 8) | r; break;
case WS2812_BRWG: n = (b << 24) | (r << 16) | (w << 8) | g; break;
case WS2812_BGWR: n = (b << 24) | (g << 16) | (w << 8) | r; break;
}
const uint8_t *stop = fb + 16;
do {
uint8_t x = 0x08;
if (!(n & 0x80000000)) x |= 0x07;
if (!(n & 0x40000000)) x |= 0xE0;
n <<= 2;
*fb++ = x;
} while (fb < stop);
}
const uint8_t *stop = fb + 12;
do {
uint8_t x = 0x08;
if (!(n & 0x00800000)) x |= 0x07;
if (!(n & 0x00400000)) x |= 0xE0;
n <<= 2;
*fb++ = x;
} while (fb < stop);
microseconds_per_led = 40;
bytes_per_led = 16;
}
// wait 300us WS2812 reset time
uint32_t min_elapsed = (numled * 30) + 300;
uint32_t min_elapsed = (numled * microseconds_per_led) + 300;
if (min_elapsed < 2500) min_elapsed = 2500;
uint32_t m;
while (1) {
@@ -267,24 +331,24 @@ void WS2812Serial::show()
prior_micros = m;
// start DMA transfer to update LEDs :-)
#if defined(KINETISK)
dma->sourceBuffer(frameBuffer, numled * 12);
dma->sourceBuffer(frameBuffer, numled * bytes_per_led);
dma->transferSize(1);
dma->transferCount(numled * 12);
dma->transferCount(numled * bytes_per_led);
dma->disableOnCompletion();
dma->enable();
#elif defined(KINETISL)
dma->CFG->SAR = frameBuffer;
dma->CFG->DSR_BCR = 0x01000000;
dma->CFG->DSR_BCR = numled * 12;
dma->CFG->DSR_BCR = numled * bytes_per_led;
dma->CFG->DCR = DMA_DCR_ERQ | DMA_DCR_CS | DMA_DCR_SSIZE(1) |
DMA_DCR_SINC | DMA_DCR_DSIZE(1) | DMA_DCR_D_REQ;
#elif defined(__IMXRT1062__)
// See if we need to muck with DMA cache...
if ((uint32_t)frameBuffer >= 0x20200000u) arm_dcache_flush(frameBuffer, numled * 12);
if ((uint32_t)frameBuffer >= 0x20200000u) arm_dcache_flush(frameBuffer, numled * bytes_per_led);
dma->sourceBuffer(frameBuffer, numled * 12);
dma->sourceBuffer(frameBuffer, numled * bytes_per_led);
// dma->transferSize(1);
dma->transferCount(numled * 12);
dma->transferCount(numled * bytes_per_led);
dma->disableOnCompletion();

/* Serial.printf("%x %x:", (uint32_t)dma, (uint32_t)dma->TCD);

+ 55
- 10
WS2812Serial.h Просмотреть файл

@@ -33,6 +33,31 @@
#define WS2812_GBR 3
#define WS2812_BRG 4
#define WS2812_BGR 5
#define WS2812_RGBW 6
#define WS2812_RBGW 7
#define WS2812_GRBW 8
#define WS2812_GBRW 9
#define WS2812_BRGW 10
#define WS2812_BGRW 11
#define WS2812_WRGB 12
#define WS2812_WRBG 13
#define WS2812_WGRB 14
#define WS2812_WGBR 15
#define WS2812_WBRG 16
#define WS2812_WBGR 17
#define WS2812_RWGB 18
#define WS2812_RWBG 19
#define WS2812_GWRB 20
#define WS2812_GWBR 21
#define WS2812_BWRG 22
#define WS2812_BWGR 23
#define WS2812_RGWB 24
#define WS2812_RBWG 25
#define WS2812_GRWB 26
#define WS2812_GBWR 27
#define WS2812_BRWG 28
#define WS2812_BGWR 29


class WS2812Serial {
public:
@@ -41,19 +66,26 @@ public:
frameBuffer((uint8_t *)fb), drawBuffer((uint8_t *)db) {
}
bool begin();
void setPixel(uint32_t num, int color) {
void setPixel(uint32_t num, uint32_t color) {
if (num >= numled) return;
num *= 3;
drawBuffer[num+0] = color & 255;
drawBuffer[num+1] = (color >> 8) & 255;
drawBuffer[num+2] = (color >> 16) & 255;
if (config < 6) {
num *= 3;
drawBuffer[num+0] = color & 255;
drawBuffer[num+1] = (color >> 8) & 255;
drawBuffer[num+2] = (color >> 16) & 255;
} else {
num *= 4;
drawBuffer[num+0] = color & 255;
drawBuffer[num+1] = (color >> 8) & 255;
drawBuffer[num+2] = (color >> 16) & 255;
drawBuffer[num+3] = (color >> 24) & 255;
}
}
void setPixel(uint32_t num, uint8_t red, uint8_t green, uint8_t blue) {
if (num >= numled) return;
num *= 3;
drawBuffer[num+0] = blue;
drawBuffer[num+1] = green;
drawBuffer[num+2] = red;
setPixel(num, Color(red, green, blue));
}
void setPixel(uint32_t num, uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
setPixel(num, Color(red, green, blue, white));
}
void clear() {
memset(drawBuffer, 0, numled * 3);
@@ -70,9 +102,21 @@ public:
void setPixelColor(uint16_t num, uint8_t red, uint8_t green, uint8_t blue) {
setPixel(num, red, green, blue);
}
void setPixelColor(uint16_t num, uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
setPixel(num, red, green, blue, white);
}
void setBrightness(uint8_t n) {
brightness = n;
}
uint8_t getBrightness() {
return brightness;
}
uint32_t Color(uint8_t red, uint8_t green, uint8_t blue) {
return (red << 16) | (green << 8) | blue;
}
uint32_t Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t white) {
return (white << 24) | (red << 16) | (green << 8) | blue;
}
private:
const uint16_t numled;
const uint8_t pin;
@@ -81,6 +125,7 @@ private:
uint8_t *drawBuffer;
DMAChannel *dma = nullptr;
uint32_t prior_micros = 0;
uint8_t brightness = 255;
#if defined(__IMXRT1062__) // Teensy 3.x
IMXRT_LPUART_t *uart = nullptr;
#endif

+ 56
- 0
examples/BasicTest_RGBW/BasicTest_RGBW.ino Просмотреть файл

@@ -0,0 +1,56 @@
/* WS2812Serial BasicTest Example

Test LEDs by turning then 7 different colors.

This example code is in the public domain. */

#include <WS2812Serial.h>

const int numled = 20;
const int pin = 1;

// Usable pins:
// Teensy LC: 1, 4, 5, 24
// Teensy 3.2: 1, 5, 8, 10, 31 (overclock to 120 MHz for pin 8)
// Teensy 3.5: 1, 5, 8, 10, 26, 32, 33, 48
// Teensy 3.6: 1, 5, 8, 10, 26, 32, 33
// Teensy 4.0: 1, 8, 14, 17, 20, 24, 29, 39

byte drawingMemory[numled*4]; // 4 bytes per LED for RGBW
DMAMEM byte displayMemory[numled*16]; // 16 bytes per LED for RGBW

WS2812Serial leds(numled, displayMemory, drawingMemory, pin, WS2812_GRBW);

#define RED 0x00FF0000
#define GREEN 0x0000FF00
#define BLUE 0x000000FF
#define YELLOW 0x00FFD000
#define PINK 0x44F00080
#define ORANGE 0x00FF4200
#define WHITE 0xAA000000

void setup() {
leds.begin();
leds.setBrightness(200); // 0=off, 255=brightest
}

void loop() {
// change all the LEDs in 1.5 seconds
int microsec = 1500000 / leds.numPixels();

colorWipe(RED, microsec);
colorWipe(GREEN, microsec);
colorWipe(BLUE, microsec);
colorWipe(YELLOW, microsec);
colorWipe(PINK, microsec);
colorWipe(ORANGE, microsec);
colorWipe(WHITE, microsec);
}

void colorWipe(int color, int wait_us) {
for (int i=0; i < leds.numPixels(); i++) {
leds.setPixel(i, color);
leds.show();
delayMicroseconds(wait_us);
}
}

Загрузка…
Отмена
Сохранить