Skip to content

Commit

Permalink
feat(led_strip): Support more pixel orders of 3 colors
Browse files Browse the repository at this point in the history
  • Loading branch information
Kainarx committed Jun 20, 2024
1 parent d9b31d9 commit 65e14f5
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 26 deletions.
2 changes: 1 addition & 1 deletion led_strip/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "2.5.4"
version: "2.5.5"
description: Driver for Addressable LED Strip (WS2812, etc)
url: https://github.com/espressif/idf-extra-components/tree/master/led_strip
dependencies:
Expand Down
12 changes: 9 additions & 3 deletions led_strip/include/led_strip_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ extern "C" {
* @brief LED strip pixel format
*/
typedef enum {
LED_PIXEL_FORMAT_GRB, /*!< Pixel format: GRB */
LED_PIXEL_FORMAT_GRBW, /*!< Pixel format: GRBW */
LED_PIXEL_FORMAT_INVALID /*!< Invalid pixel format */
LED_PIXEL_FORMAT_GRB, /*!< Pixel format: GRB */
LED_PIXEL_FORMAT_GBR, /*!< Pixel format: GBR */
LED_PIXEL_FORMAT_RGB, /*!< Pixel format: RGB */
LED_PIXEL_FORMAT_RBG, /*!< Pixel format: RBG */
LED_PIXEL_FORMAT_BGR, /*!< Pixel format: BGR */
LED_PIXEL_FORMAT_BRG, /*!< Pixel format: BRG */
LED_PIXEL_FORMAT_3COLORS_MAX, /*!< Pixel format max of 3 colors */
LED_PIXEL_FORMAT_GRBW, /*!< Pixel format: GRBW */
LED_PIXEL_FORMAT_INVALID /*!< Invalid pixel format */
} led_pixel_format_t;

/**
Expand Down
52 changes: 44 additions & 8 deletions led_strip/src/led_strip_rmt_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ typedef struct {
led_strip_t base;
rmt_channel_handle_t rmt_chan;
rmt_encoder_handle_t strip_encoder;
led_pixel_format_t led_pixel_format;
uint32_t strip_len;
uint8_t bytes_per_pixel;
uint8_t pixel_buf[];
Expand All @@ -38,10 +39,45 @@ static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uin
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
uint32_t start = index * rmt_strip->bytes_per_pixel;
// In thr order of GRB, as LED strip like WS2812 sends out pixels in this order
rmt_strip->pixel_buf[start + 0] = green & 0xFF;
rmt_strip->pixel_buf[start + 1] = red & 0xFF;
rmt_strip->pixel_buf[start + 2] = blue & 0xFF;
// Support all kinds of pixel order
uint8_t r = 0, b = 0, g = 0;
switch (rmt_strip->led_pixel_format) {
case LED_PIXEL_FORMAT_GRB:
r = 1;
g = 0;
b = 2;
break;
case LED_PIXEL_FORMAT_GBR:
r = 2;
g = 0;
b = 1;
break;
case LED_PIXEL_FORMAT_RGB:
r = 0;
g = 1;
b = 2;
break;
case LED_PIXEL_FORMAT_RBG:
r = 0;
g = 2;
b = 1;
break;
case LED_PIXEL_FORMAT_BGR:
r = 2;
g = 1;
b = 0;
break;
case LED_PIXEL_FORMAT_BRG:
r = 1;
g = 2;
b = 0;
break;
default:
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid pixel format");
}
rmt_strip->pixel_buf[start + g] = green & 0xFF;
rmt_strip->pixel_buf[start + r] = red & 0xFF;
rmt_strip->pixel_buf[start + b] = blue & 0xFF;
if (rmt_strip->bytes_per_pixel > 3) {
rmt_strip->pixel_buf[start + 3] = 0;
}
Expand Down Expand Up @@ -101,10 +137,10 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format");
uint8_t bytes_per_pixel = 3;
if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) {
bytes_per_pixel = 4;
} else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) {
if (led_config->led_pixel_format < LED_PIXEL_FORMAT_3COLORS_MAX) {
bytes_per_pixel = 3;
} else if (led_config->led_pixel_format > LED_PIXEL_FORMAT_3COLORS_MAX) {
bytes_per_pixel = 4;
} else {
assert(false);
}
Expand Down Expand Up @@ -139,7 +175,7 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
};
ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed");


rmt_strip->led_pixel_format = led_config->led_pixel_format;
rmt_strip->bytes_per_pixel = bytes_per_pixel;
rmt_strip->strip_len = led_config->max_leds;
rmt_strip->base.set_pixel = led_strip_rmt_set_pixel;
Expand Down
51 changes: 44 additions & 7 deletions led_strip/src/led_strip_rmt_dev_idf4.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ static uint32_t led_t1l_ticks = 0;
typedef struct {
led_strip_t base;
rmt_channel_t rmt_channel;
led_pixel_format_t led_pixel_format;
uint32_t strip_len;
uint8_t bytes_per_pixel;
uint8_t buffer[0];
Expand Down Expand Up @@ -83,10 +84,45 @@ static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uin
led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base);
ESP_RETURN_ON_FALSE(index < rmt_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of the maximum number of leds");
uint32_t start = index * rmt_strip->bytes_per_pixel;
// In thr order of GRB
rmt_strip->buffer[start + 0] = green & 0xFF;
rmt_strip->buffer[start + 1] = red & 0xFF;
rmt_strip->buffer[start + 2] = blue & 0xFF;
// Support all kinds of pixel order
uint8_t r = 0, b = 0, g = 0;
switch (rmt_strip->led_pixel_format) {
case LED_PIXEL_FORMAT_GRB:
r = 1;
g = 0;
b = 2;
break;
case LED_PIXEL_FORMAT_GBR:
r = 2;
g = 0;
b = 1;
break;
case LED_PIXEL_FORMAT_RGB:
r = 0;
g = 1;
b = 2;
break;
case LED_PIXEL_FORMAT_RBG:
r = 0;
g = 2;
b = 1;
break;
case LED_PIXEL_FORMAT_BGR:
r = 2;
g = 1;
b = 0;
break;
case LED_PIXEL_FORMAT_BRG:
r = 1;
g = 2;
b = 0;
break;
default:
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid pixel format");
}
rmt_strip->pixel_buf[start + g] = green & 0xFF;
rmt_strip->pixel_buf[start + r] = red & 0xFF;
rmt_strip->pixel_buf[start + b] = blue & 0xFF;
if (rmt_strip->bytes_per_pixel > 3) {
rmt_strip->buffer[start + 3] = 0;
}
Expand Down Expand Up @@ -127,10 +163,10 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
ESP_RETURN_ON_FALSE(dev_config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, TAG, "DMA is not supported");

uint8_t bytes_per_pixel = 3;
if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) {
bytes_per_pixel = 4;
} else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) {
if (led_config->led_pixel_format < LED_PIXEL_FORMAT_3COLORS_MAX) {
bytes_per_pixel = 3;
} else if (led_config->led_pixel_format > LED_PIXEL_FORMAT_3COLORS_MAX) {
bytes_per_pixel = 4;
} else {
assert(false);
}
Expand Down Expand Up @@ -175,6 +211,7 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l
// adapter to translates the LES strip date frame into RMT symbols
rmt_translator_init((rmt_channel_t)dev_config->rmt_channel, ws2812_rmt_adapter);

rmt_strip->led_pixel_format = led_config->led_pixel_format;
rmt_strip->bytes_per_pixel = bytes_per_pixel;
rmt_strip->rmt_channel = (rmt_channel_t)dev_config->rmt_channel;
rmt_strip->strip_len = led_config->max_leds;
Expand Down
51 changes: 44 additions & 7 deletions led_strip/src/led_strip_spi_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ typedef struct {
led_strip_t base;
spi_host_device_t spi_host;
spi_device_handle_t spi_device;
led_pixel_format_t led_pixel_format;
uint32_t strip_len;
uint8_t bytes_per_pixel;
uint8_t pixel_buf[];
Expand All @@ -51,12 +52,47 @@ static esp_err_t led_strip_spi_set_pixel(led_strip_t *strip, uint32_t index, uin
{
led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base);
ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs");
// LED_PIXEL_FORMAT_GRB takes 72bits(9bytes)
// 3 pixels take 72bits(9bytes)
uint8_t r = 0, b = 0, g = 0;
switch (spi_strip->led_pixel_format) {
case LED_PIXEL_FORMAT_GRB:
r = 1;
g = 0;
b = 2;
break;
case LED_PIXEL_FORMAT_GBR:
r = 2;
g = 0;
b = 1;
break;
case LED_PIXEL_FORMAT_RGB:
r = 0;
g = 1;
b = 2;
break;
case LED_PIXEL_FORMAT_RBG:
r = 0;
g = 2;
b = 1;
break;
case LED_PIXEL_FORMAT_BGR:
r = 2;
g = 1;
b = 0;
break;
case LED_PIXEL_FORMAT_BRG:
r = 1;
g = 2;
b = 0;
break;
default:
ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid pixel format");
}
uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
memset(spi_strip->pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
__led_strip_spi_bit(green, &spi_strip->pixel_buf[start]);
__led_strip_spi_bit(red, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]);
__led_strip_spi_bit(blue, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]);
__led_strip_spi_bit(green, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * g]);
__led_strip_spi_bit(red, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * r]);
__led_strip_spi_bit(blue, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * b]);
if (spi_strip->bytes_per_pixel > 3) {
__led_strip_spi_bit(0, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]);
}
Expand Down Expand Up @@ -126,10 +162,10 @@ esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const l
ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format");
uint8_t bytes_per_pixel = 3;
if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRBW) {
bytes_per_pixel = 4;
} else if (led_config->led_pixel_format == LED_PIXEL_FORMAT_GRB) {
if (led_config->led_pixel_format < LED_PIXEL_FORMAT_3COLORS_MAX) {
bytes_per_pixel = 3;
} else if (led_config->led_pixel_format > LED_PIXEL_FORMAT_3COLORS_MAX) {
bytes_per_pixel = 4;
} else {
assert(false);
}
Expand Down Expand Up @@ -187,6 +223,7 @@ esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const l
ESP_GOTO_ON_FALSE((clock_resolution_khz < LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 + 300) && (clock_resolution_khz > LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000 - 300), ESP_ERR_NOT_SUPPORTED, err,
TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz);

spi_strip->led_pixel_format = led_config->led_pixel_format;
spi_strip->bytes_per_pixel = bytes_per_pixel;
spi_strip->strip_len = led_config->max_leds;
spi_strip->base.set_pixel = led_strip_spi_set_pixel;
Expand Down

0 comments on commit 65e14f5

Please sign in to comment.