From c59f87a5d73a2d8a2085663ae329c4d7c75c83e3 Mon Sep 17 00:00:00 2001 From: Josh Hinnebusch Date: Sun, 6 Dec 2020 01:15:48 -0500 Subject: [PATCH] add definition WS2812_BYTE_ORDER to fix RGB LED issues (#10184) * add define for WS2812B-2020 to fix RGB issues * update driver doc * add WS2812_BYTE_ORDER definition to correct RGB byte issues * add definition variable thing * update per PR request * update per PR reqs * update per PR request * inital changes * move defines to color.h and add rgbw incase * Update docs/ws2812_driver.md Co-authored-by: Ryan Co-authored-by: hineybush Co-authored-by: Xelus22 Co-authored-by: Ryan --- docs/ws2812_driver.md | 11 +++++++++ drivers/chibios/ws2812.c | 7 ++++++ drivers/chibios/ws2812_pwm.c | 45 +++++++++++++++++++++++++++++++++--- drivers/chibios/ws2812_spi.c | 6 +++++ quantum/color.h | 20 +++++++++++++++- 5 files changed, 85 insertions(+), 4 deletions(-) diff --git a/docs/ws2812_driver.md b/docs/ws2812_driver.md index c1b96329e9c44a50c1fde33a1e715558be2cd4eb..da5db01dbde6f023c467946199e38432b4daa797 100644 --- a/docs/ws2812_driver.md +++ b/docs/ws2812_driver.md @@ -28,6 +28,17 @@ The default setting is 280 µs, which should work for most cases, but this can b #define WS2812_TRST_US 80 ``` +#### Byte Order + +Some variants of the WS2812 may have their color components in a different physical or logical order. For example, the WS2812B-2020 has physically swapped red and green LEDs, which causes the wrong color to be displayed, because the default order of the bytes sent over the wire is defined as GRB. +In this case, you can change the byte order by defining `WS2812_BYTE_ORDER` as one of the following values: + +| Byte order | Known devices | +|-----------------------------------|-------------------------------| +| `WS2812_BYTE_ORDER_GRB` (default) | Most WS2812's, SK6812, SK6805 | +| `WS2812_BYTE_ORDER_RGB` | WS2812B-2020 | + + ### Bitbang Default driver, the absence of configuration assumes this driver. To configure it, add this to your rules.mk: diff --git a/drivers/chibios/ws2812.c b/drivers/chibios/ws2812.c index 0440cac7550da0286c0883e11a1f92e5ee7834d9..504fb4f07488e4fb7a9d56c3c0a42c0d59bf25e4 100644 --- a/drivers/chibios/ws2812.c +++ b/drivers/chibios/ws2812.c @@ -89,9 +89,16 @@ void ws2812_setleds(LED_TYPE *ledarray, uint16_t leds) { for (uint8_t i = 0; i < leds; i++) { // WS2812 protocol dictates grb order +#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) sendByte(ledarray[i].g); sendByte(ledarray[i].r); sendByte(ledarray[i].b); +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB) + sendByte(ledarray[i].r); + sendByte(ledarray[i].g); + sendByte(ledarray[i].b); +#endif + #ifdef RGBW sendByte(ledarray[i].w); #endif diff --git a/drivers/chibios/ws2812_pwm.c b/drivers/chibios/ws2812_pwm.c index bfb44ce4a4e65b2c7b66ddf1b2beb466bded186e..14be0a9edcb32f3b743f0c200106e06d60878492 100644 --- a/drivers/chibios/ws2812_pwm.c +++ b/drivers/chibios/ws2812_pwm.c @@ -107,6 +107,7 @@ */ #define WS2812_BIT(led, byte, bit) (24 * (led) + 8 * (byte) + (7 - (bit))) +#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) /** * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given red bit * @@ -117,7 +118,7 @@ * * @return The bit index */ -#define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 1, (bit)) +# define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 1, (bit)) /** * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given green bit @@ -129,7 +130,7 @@ * * @return The bit index */ -#define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 0, (bit)) +# define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 0, (bit)) /** * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given blue bit @@ -141,7 +142,45 @@ * * @return The bit index */ -#define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 2, (bit)) +# define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 2, (bit)) + +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB) +/** + * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given red bit + * + * @note The red byte is the middle byte in the color packet + * + * @param[in] led: The led index [0, @ref RGBLED_NUM) + * @param[in] bit: The bit number [0, 7] + * + * @return The bit index + */ +# define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 0, (bit)) + +/** + * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given green bit + * + * @note The red byte is the first byte in the color packet + * + * @param[in] led: The led index [0, @ref RGBLED_NUM) + * @param[in] bit: The bit number [0, 7] + * + * @return The bit index + */ +# define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 1, (bit)) + +/** + * @brief Determine the index in @ref ws2812_frame_buffer "the frame buffer" of a given blue bit + * + * @note The red byte is the last byte in the color packet + * + * @param[in] led: The led index [0, @ref RGBLED_NUM) + * @param[in] bit: The bit index [0, 7] + * + * @return The bit index + */ +# define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 2, (bit)) +#endif /* --- PRIVATE VARIABLES ---------------------------------------------------- */ diff --git a/drivers/chibios/ws2812_spi.c b/drivers/chibios/ws2812_spi.c index 7a1d2f05daf7a89cf9b3c8af16cc86c1620e82c0..1dec1f51678f7d3a090e9f22881c2ba0556829fe 100644 --- a/drivers/chibios/ws2812_spi.c +++ b/drivers/chibios/ws2812_spi.c @@ -62,9 +62,15 @@ static uint8_t get_protocol_eq(uint8_t data, int pos) { static void set_led_color_rgb(LED_TYPE color, int pos) { uint8_t* tx_start = &txbuf[PREAMBLE_SIZE]; +#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.g, j); for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.r, j); for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j); +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB) + for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + j] = get_protocol_eq(color.r, j); + for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE + j] = get_protocol_eq(color.g, j); + for (int j = 0; j < 4; j++) tx_start[BYTES_FOR_LED * pos + BYTES_FOR_LED_BYTE * 2 + j] = get_protocol_eq(color.b, j); +#endif } void ws2812_init(void) { diff --git a/quantum/color.h b/quantum/color.h index 5c5a0f0ebd32e754778410cda2cedca4ee01d8c9..f0ee7827572febdf39724ab362505a449ab8e0fa 100644 --- a/quantum/color.h +++ b/quantum/color.h @@ -36,20 +36,38 @@ # define LED_TYPE RGB #endif -// WS2812 specific layout +#define WS2812_BYTE_ORDER_RGB 0 +#define WS2812_BYTE_ORDER_GRB 1 + +#ifndef WS2812_BYTE_ORDER +# define WS2812_BYTE_ORDER WS2812_BYTE_ORDER_GRB +#endif + typedef struct PACKED { +#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) uint8_t g; uint8_t r; uint8_t b; +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB) + uint8_t r; + uint8_t g; + uint8_t b; +#endif } cRGB; typedef cRGB RGB; // WS2812 specific layout typedef struct PACKED { +#if (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_GRB) uint8_t g; uint8_t r; uint8_t b; +#elif (WS2812_BYTE_ORDER == WS2812_BYTE_ORDER_RGB) + uint8_t r; + uint8_t g; + uint8_t b; +#endif uint8_t w; } cRGBW;