Merge pull request #10762 from g3gg0/add_SK6812_RGBW

add SK6812 RGBW 4-channel LEDs
This commit is contained in:
Štěpán Dalecký 2021-12-23 08:57:14 +01:00 committed by GitHub
commit ac7774cc73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 10 deletions

View File

@ -89,6 +89,8 @@ It could be possible to be able to specify the timings required via CLI if users
* Fits well under motors on mini 250 quads.
* [Adafruit NeoPixel Stick](https://www.adafruit.com/products/1426) (works well)
* Measured current consumption in all white mode ~ 350 mA.
* [Aliexpress SK6812 RBGWW strip](https://www.aliexpress.com/wholesale?SearchText=rgbw+sk6812) (works well)
* Alternative [Adafruit NeoPixel Stick RGBW](https://www.adafruit.com/product/2869)
### WS2811 vs WS2812
@ -97,6 +99,8 @@ The [WS2811](https://cdn-shop.adafruit.com/datasheets/WS2811.pdf) is a LED drive
The [WS2812](https://cdn-shop.adafruit.com/datasheets/WS2812.pdf) is integrated into the package of a 50:50 LED rather than as a separate device. It accepts data in the form of 8 bits each of Green-Red-Blue.
With the [SK6812](https://cdn-shop.adafruit.com/product-files/1138/SK6812+LED+datasheet+.pdf) also GRBW variants are supported, which have a fourth (white) channel and such provide a much cleaner white color.
It is thus possible, depending on the LED board/strip being used that either Red-Green-Blue or Green-Red-Blue encoding may be required. This may be controlled by setting the following.
```
@ -107,8 +111,14 @@ or
```
set ledstrip_grb_rgb = GRB
```
or
```
set ledstrip_grb_rgb = GRBW
```
Then confirm the required setting by simply setting an LED to be green. If it lights up red, you have the wrong setting.
Afterwards check if the second LED also lights up red - if not, you might have 4-color SK6812 LEDs and would have to select GRBW.
## Connections

View File

@ -366,7 +366,7 @@ static const char * const lookupOverclock[] = {
#ifdef USE_LED_STRIP
static const char * const lookupLedStripFormatRGB[] = {
"GRB", "RGB"
"GRB", "RGB", "GRBW"
};
#endif

View File

@ -31,6 +31,7 @@
#include <string.h>
#include "platform.h"
#include "common/maths.h"
#ifdef USE_LED_STRIP
@ -139,8 +140,8 @@ void ws2811LedStripEnable(void)
const hsvColor_t hsv_black = { 0, 0, 0 };
setStripColor(&hsv_black);
// RGB or GRB ordering doesn't matter for black
ws2811UpdateStrip(LED_RGB, 100);
// RGB or GRB ordering doesn't matter for black, use 4-channel LED configuraton to make sure all channels are zero
ws2811UpdateStrip(LED_GRBW, 100);
ws2811Initialised = true;
}
@ -153,23 +154,34 @@ bool isWS2811LedStripReady(void)
STATIC_UNIT_TESTED void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color, unsigned ledIndex)
{
uint32_t bits_per_led;
uint32_t packed_colour;
switch (ledFormat) {
case LED_RGB: // WS2811 drivers use RGB format
packed_colour = (color->rgb.r << 16) | (color->rgb.g << 8) | (color->rgb.b);
bits_per_led = 24;
break;
case LED_GRBW: // SK6812 drivers use this
{
/* reconstruct white channel from RGB, making the intensity a bit nonlinear, but thats fine for this use case */
uint8_t white = MIN(MIN(color->rgb.r, color->rgb.g), color->rgb.b);
packed_colour = (color->rgb.g << 24) | (color->rgb.r << 16) | (color->rgb.b << 8) | (white);
bits_per_led = 32;
break;
}
case LED_GRB: // WS2812 drivers use GRB format
default:
packed_colour = (color->rgb.g << 16) | (color->rgb.r << 8) | (color->rgb.b);
bits_per_led = 24;
break;
}
unsigned dmaBufferOffset = 0;
for (int index = 23; index >= 0; index--) {
ledStripDMABuffer[ledIndex * WS2811_BITS_PER_LED + dmaBufferOffset++] = (packed_colour & (1 << index)) ? BIT_COMPARE_1 : BIT_COMPARE_0;
for (int index = bits_per_led-1; index >= 0; index--) {
ledStripDMABuffer[ledIndex * bits_per_led + dmaBufferOffset++] = (packed_colour & (1 << index)) ? BIT_COMPARE_1 : BIT_COMPARE_0;
}
}

View File

@ -26,11 +26,11 @@
#define WS2811_LED_STRIP_LENGTH 32
#define WS2811_BITS_PER_LED 24
#define WS2811_BITS_PER_LED_MAX 32
#if defined(USE_WS2811_SINGLE_COLOUR)
#define WS2811_DATA_BUFFER_SIZE 1
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE * WS2811_BITS_PER_LED)
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE * WS2811_BITS_PER_LED_MAX)
// Do 2 extra iterations of the DMA transfer with the output set to low to generate the > 50us delay.
#define WS2811_DELAY_ITERATIONS 2
#else
@ -38,7 +38,7 @@
// for 50us delay
#define WS2811_DELAY_BUFFER_LENGTH 42
// number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes)
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE * WS2811_BITS_PER_LED + WS2811_DELAY_BUFFER_LENGTH)
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE * WS2811_BITS_PER_LED_MAX + WS2811_DELAY_BUFFER_LENGTH)
#endif
#ifdef USE_LEDSTRIP_CACHE_MGMT
@ -64,7 +64,8 @@ extern uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
// Enumeration to match the string options defined in lookupLedStripFormatRGB in settings.c
typedef enum {
LED_GRB,
LED_RGB
LED_RGB,
LED_GRBW
} ledStripFormatRGB_e;
void ws2811LedStripInit(ioTag_t ioTag);