Skip to content

Commit

Permalink
feat(led_strip): Support configure pixel orders
Browse files Browse the repository at this point in the history
  • Loading branch information
Kainarx committed Aug 20, 2024
1 parent 60c1426 commit 3c33ebf
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 39 deletions.
4 changes: 4 additions & 0 deletions led_strip/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.5.6

- Add pixel order configuration callback function to support user-defined pixel order.

## 2.5.5

- Simplified the led_strip component dependency, the time of full build with ESP-IDF v5.3 can now be shorter.
Expand Down
33 changes: 25 additions & 8 deletions led_strip/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ _Clear LED strip (turn off all LEDs)_
```c
esp_err_t led_strip_clear (
led_strip_handle_t strip
)
)
```

**Parameters:**
Expand All @@ -49,7 +49,7 @@ _Free LED strip resources._
```c
esp_err_t led_strip_del (
led_strip_handle_t strip
)
)
```

**Parameters:**
Expand All @@ -68,7 +68,7 @@ _Refresh memory colors to LEDs._
```c
esp_err_t led_strip_refresh (
led_strip_handle_t strip
)
)
```

**Parameters:**
Expand All @@ -95,7 +95,7 @@ esp_err_t led_strip_set_pixel (
uint32_t red,
uint32_t green,
uint32_t blue
)
)
```

**Parameters:**
Expand Down Expand Up @@ -123,7 +123,7 @@ esp_err_t led_strip_set_pixel_hsv (
uint16_t hue,
uint8_t saturation,
uint8_t value
)
)
```

**Parameters:**
Expand Down Expand Up @@ -152,7 +152,7 @@ esp_err_t led_strip_set_pixel_rgbw (
uint32_t green,
uint32_t blue,
uint32_t white
)
)
```

**Note:**
Expand Down Expand Up @@ -221,7 +221,7 @@ esp_err_t led_strip_new_rmt_device (
const led_strip_config_t *led_config,
const led_strip_rmt_config_t *rmt_config,
led_strip_handle_t *ret_strip
)
)
```

**Parameters:**
Expand Down Expand Up @@ -278,7 +278,7 @@ esp_err_t led_strip_new_spi_device (
const led_strip_config_t *led_config,
const led_strip_spi_config_t *spi_config,
led_strip_handle_t *ret_strip
)
)
```

**Note:**
Expand Down Expand Up @@ -307,6 +307,7 @@ Although only the MOSI line is used for generating the signal, the whole SPI bus
| ---: | :--- |
| enum | [**led\_model\_t**](#enum-led_model_t) <br>_LED strip model._ |
| enum | [**led\_pixel\_format\_t**](#enum-led_pixel_format_t) <br>_LED strip pixel format._ |
| enum | [**led\_pixel\_order\_index\_t**](#enum-led_pixel_order_index_t) <br>_LED strip pixel order index._ |
| struct | [**led\_strip\_config\_t**](#struct-led_strip_config_t) <br>_LED Strip Configuration._ |
| typedef struct [**led\_strip\_t**](#struct-led_strip_t) \* | [**led\_strip\_handle\_t**](#typedef-led_strip_handle_t) <br>_LED strip handle._ |

Expand Down Expand Up @@ -340,12 +341,28 @@ enum led_pixel_format_t {
};
```

### enum `led_pixel_order_index_t`

_LED strip pixel order index._

```c
enum led_pixel_order_index_t {
LED_PIXEL_INDEX_RED,
LED_PIXEL_INDEX_GREEN,
LED_PIXEL_INDEX_BLUE,
LED_PIXEL_INDEX_WHITE,
LED_PIXEL_INDEX_MAX
};
```

### struct `led_strip_config_t`

_LED Strip Configuration._

Variables:

- void(\* config_pixel_order <br>User callback function of configuring pixel order

- struct led\_strip\_config\_t::@2 flags <br>Extra driver flags

- uint32\_t invert_out <br>Invert output signal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@
#include "esp_err.h"

// GPIO assignment
#define LED_STRIP_BLINK_GPIO 2
#define LED_STRIP_BLINK_GPIO 8
// Numbers of the LED in the strip
#define LED_STRIP_LED_NUMBERS 24
#define LED_STRIP_LED_NUMBERS 1

static const char *TAG = "example";


void config_order(uint8_t *order)
{
order[LED_PIXEL_INDEX_RED] = 1;
order[LED_PIXEL_INDEX_GREEN] = 0;
order[LED_PIXEL_INDEX_BLUE] = 2;
}

led_strip_handle_t configure_led(void)
{
// LED strip general initialization, according to your led board design
Expand All @@ -26,6 +34,7 @@ led_strip_handle_t configure_led(void)
.led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip
.led_model = LED_MODEL_WS2812, // LED strip model
.flags.invert_out = false, // whether to invert the output signal
.config_pixel_order = config_order,
};

// LED strip backend configuration: SPI
Expand All @@ -52,7 +61,7 @@ void app_main(void)
if (led_on_off) {
/* Set the LED pixel using RGB from 0 (0%) to 255 (100%) for each color */
for (int i = 0; i < LED_STRIP_LED_NUMBERS; i++) {
ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 5, 5, 5));
ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 0, 0, 20));
}
/* Refresh the strip to send data */
ESP_ERROR_CHECK(led_strip_refresh(led_strip));
Expand Down
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.5"
version: "2.5.6"
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: 12 additions & 0 deletions led_strip/include/led_strip_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@ typedef enum {
LED_MODEL_INVALID /*!< Invalid LED strip model */
} led_model_t;

/**
* @brief LED strip pixel order index
*/
typedef enum {
LED_PIXEL_INDEX_RED, /*!< Red pixel index */
LED_PIXEL_INDEX_GREEN, /*!< Green pixel index */
LED_PIXEL_INDEX_BLUE, /*!< Blue pixel index */
LED_PIXEL_INDEX_WHITE, /*!< White pixel index */
LED_PIXEL_INDEX_MAX /*!< Max pixel index */
} led_pixel_order_index_t;

/**
* @brief LED strip handle
*/
Expand All @@ -43,6 +54,7 @@ typedef struct {
uint32_t max_leds; /*!< Maximum LEDs in a single strip */
led_pixel_format_t led_pixel_format; /*!< LED pixel format */
led_model_t led_model; /*!< LED model */
void (*config_pixel_order)(uint8_t *led_pixel_offset); /*!< User callback function of configuring pixel order */

struct {
uint32_t invert_out: 1; /*!< Invert output signal */
Expand Down
34 changes: 24 additions & 10 deletions led_strip/src/led_strip_rmt_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ typedef struct {
rmt_encoder_handle_t strip_encoder;
uint32_t strip_len;
uint8_t bytes_per_pixel;
uint8_t led_pixel_offset[LED_PIXEL_INDEX_MAX];
uint8_t pixel_buf[];
} led_strip_rmt_obj;

Expand All @@ -38,12 +39,15 @@ 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;
uint8_t *pixel_buf = rmt_strip->pixel_buf;
uint8_t *offset = rmt_strip->led_pixel_offset;
// Support all kinds of pixel order
pixel_buf[start + offset[LED_PIXEL_INDEX_RED]] = red & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_GREEN]] = green & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_BLUE]] = blue & 0xFF;

if (rmt_strip->bytes_per_pixel > 3) {
rmt_strip->pixel_buf[start + 3] = 0;
pixel_buf[start + offset[LED_PIXEL_INDEX_WHITE]] = 0;
}
return ESP_OK;
}
Expand All @@ -53,12 +57,14 @@ static esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index
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");
ESP_RETURN_ON_FALSE(rmt_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel");
uint8_t *buf_start = rmt_strip->pixel_buf + index * 4;
uint32_t start = index * rmt_strip->bytes_per_pixel;
uint8_t *pixel_buf = rmt_strip->pixel_buf;
uint8_t *offset = rmt_strip->led_pixel_offset;
// SK6812 component order is GRBW
*buf_start = green & 0xFF;
*++buf_start = red & 0xFF;
*++buf_start = blue & 0xFF;
*++buf_start = white & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_RED]] = red & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_GREEN]] = green & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_BLUE]] = blue & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_WHITE]] = white & 0xFF;
return ESP_OK;
}

Expand Down Expand Up @@ -139,6 +145,14 @@ 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");

if (led_config->config_pixel_order) {
led_config->config_pixel_order(rmt_strip->led_pixel_offset);
} else {
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_RED] = 1;
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_GREEN] = 0;
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_BLUE] = 2;
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_WHITE] = 3;
}

rmt_strip->bytes_per_pixel = bytes_per_pixel;
rmt_strip->strip_len = led_config->max_leds;
Expand Down
22 changes: 17 additions & 5 deletions led_strip/src/led_strip_rmt_dev_idf4.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typedef struct {
rmt_channel_t rmt_channel;
uint32_t strip_len;
uint8_t bytes_per_pixel;
uint8_t led_pixel_offset[LED_PIXEL_INDEX_MAX];
uint8_t buffer[0];
} led_strip_rmt_obj;

Expand Down Expand Up @@ -83,12 +84,14 @@ 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;
uint8_t *pixel_buf = rmt_strip->buffer;
uint8_t *offset = rmt_strip->led_pixel_offset;
// Support all kinds of pixel order
pixel_buf[start + offset[LED_PIXEL_INDEX_RED]] = red & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_GREEN]] = green & 0xFF;
pixel_buf[start + offset[LED_PIXEL_INDEX_BLUE]] = blue & 0xFF;
if (rmt_strip->bytes_per_pixel > 3) {
rmt_strip->buffer[start + 3] = 0;
rmt_strip->buffer[start + offset[LED_PIXEL_INDEX_WHITE]] = 0;
}
return ESP_OK;
}
Expand Down Expand Up @@ -175,6 +178,15 @@ 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);

if (led_config->config_pixel_order) {
led_config->config_pixel_order(rmt_strip->led_pixel_offset);
} else {
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_RED] = 1;
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_GREEN] = 0;
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_BLUE] = 2;
rmt_strip->led_pixel_offset[LED_PIXEL_INDEX_WHITE] = 3;
}

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
38 changes: 26 additions & 12 deletions led_strip/src/led_strip_spi_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
#include "esp_check.h"
#include "esp_rom_gpio.h"
#include "soc/spi_periph.h"
#include "hal/spi_hal.h"
#include "led_strip.h"
#include "led_strip_interface.h"
#include "hal/spi_hal.h"

#define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000) // 2.5MHz resolution
#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4
Expand All @@ -28,6 +28,7 @@ typedef struct {
spi_device_handle_t spi_device;
uint32_t strip_len;
uint8_t bytes_per_pixel;
uint8_t led_pixel_offset[LED_PIXEL_INDEX_MAX];
uint8_t pixel_buf[];
} led_strip_spi_obj;

Expand All @@ -51,14 +52,16 @@ 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)
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]);
uint8_t *pixel_buf = spi_strip->pixel_buf;
uint8_t *offset = spi_strip->led_pixel_offset;
memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);

Check warning

Code scanning / clang-tidy

Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning

Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
__led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * offset[LED_PIXEL_INDEX_RED]]);
__led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * offset[LED_PIXEL_INDEX_GREEN]]);
__led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * offset[LED_PIXEL_INDEX_BLUE]]);
if (spi_strip->bytes_per_pixel > 3) {
__led_strip_spi_bit(0, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]);
__led_strip_spi_bit(0, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * LED_PIXEL_INDEX_WHITE]);
}
return ESP_OK;
}
Expand All @@ -70,12 +73,14 @@ static esp_err_t led_strip_spi_set_pixel_rgbw(led_strip_t *strip, uint32_t index
ESP_RETURN_ON_FALSE(spi_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel");
// LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes)
uint32_t start = index * spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
uint8_t *pixel_buf = spi_strip->pixel_buf;
uint8_t *offset = spi_strip->led_pixel_offset;
// SK6812 component order is GRBW
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(white, &spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]);
memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);

Check warning

Code scanning / clang-tidy

Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling] Warning

Call to function 'memset' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memset_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
__led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * offset[LED_PIXEL_INDEX_RED]]);
__led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * offset[LED_PIXEL_INDEX_GREEN]]);
__led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * offset[LED_PIXEL_INDEX_BLUE]]);
__led_strip_spi_bit(white, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * offset[LED_PIXEL_INDEX_WHITE]]);

return ESP_OK;
}
Expand Down Expand Up @@ -187,6 +192,15 @@ 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);

if (led_config->config_pixel_order) {
led_config->config_pixel_order(spi_strip->led_pixel_offset);
} else {
spi_strip->led_pixel_offset[LED_PIXEL_INDEX_RED] = 1;
spi_strip->led_pixel_offset[LED_PIXEL_INDEX_GREEN] = 0;
spi_strip->led_pixel_offset[LED_PIXEL_INDEX_BLUE] = 2;
spi_strip->led_pixel_offset[LED_PIXEL_INDEX_WHITE] = 3;
}

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 3c33ebf

Please sign in to comment.