From 9a664de4ccdc5971b20e648d0174e2afa31cad30 Mon Sep 17 00:00:00 2001 From: Chen Jichang Date: Tue, 22 Oct 2024 13:19:43 +0800 Subject: [PATCH 1/2] feat(led_strip): Support configure pixel orders --- led_strip/CHANGELOG.md | 4 ++ led_strip/CMakeLists.txt | 2 +- led_strip/README.md | 8 ++- led_strip/api.md | 67 ++++++++++++++----- .../main/led_strip_rmt_ws2812_main.c | 20 +++--- .../main/led_strip_spi_ws2812_main.c | 20 +++--- led_strip/idf_component.yml | 2 +- led_strip/include/led_strip.h | 25 ++++++- led_strip/include/led_strip_types.h | 17 ++--- led_strip/src/led_strip_common.c | 37 ++++++++++ led_strip/src/led_strip_common.h | 41 ++++++++++++ led_strip/src/led_strip_rmt_dev.c | 42 ++++++------ led_strip/src/led_strip_rmt_dev_idf4.c | 29 ++++---- led_strip/src/led_strip_spi_dev.c | 44 ++++++------ 14 files changed, 248 insertions(+), 110 deletions(-) create mode 100644 led_strip/src/led_strip_common.c create mode 100644 led_strip/src/led_strip_common.h diff --git a/led_strip/CHANGELOG.md b/led_strip/CHANGELOG.md index 66906b6c71..bfbb0c7315 100644 --- a/led_strip/CHANGELOG.md +++ b/led_strip/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.6.0 + +- Add pixel order configuration 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. diff --git a/led_strip/CMakeLists.txt b/led_strip/CMakeLists.txt index a4e576be7a..13c35ec3d3 100644 --- a/led_strip/CMakeLists.txt +++ b/led_strip/CMakeLists.txt @@ -1,6 +1,6 @@ include($ENV{IDF_PATH}/tools/cmake/version.cmake) -set(srcs "src/led_strip_api.c") +set(srcs "src/led_strip_api.c" "src/led_strip_common.c") set(public_requires) # Starting from esp-idf v5.x, the RMT driver is rewritten diff --git a/led_strip/README.md b/led_strip/README.md index bb08cca95d..6634b4f7cf 100644 --- a/led_strip/README.md +++ b/led_strip/README.md @@ -21,9 +21,11 @@ led_strip_handle_t led_strip; led_strip_config_t strip_config = { .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line .max_leds = 1, // The number of LEDs in the strip, - .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip + .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip .led_model = LED_MODEL_WS2812, // LED strip model .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) + .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. + Here set to the default GRB order to demonstrate usage */ }; led_strip_rmt_config_t rmt_config = { @@ -57,9 +59,11 @@ led_strip_handle_t led_strip; led_strip_config_t strip_config = { .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line .max_leds = 1, // The number of LEDs in the strip, - .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip + .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip .led_model = LED_MODEL_WS2812, // LED strip model .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) + .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. + Here set to the default GRB order to demonstrate usage */ }; led_strip_spi_config_t spi_config = { diff --git a/led_strip/api.md b/led_strip/api.md index 8fc04af4f4..1f589c75bf 100644 --- a/led_strip/api.md +++ b/led_strip/api.md @@ -21,6 +21,13 @@ | esp\_err\_t | [**led\_strip\_set\_pixel\_hsv**](#function-led_strip_set_pixel_hsv) ([**led\_strip\_handle\_t**](#typedef-led_strip_handle_t) strip, uint32\_t index, uint16\_t hue, uint8\_t saturation, uint8\_t value)
_Set HSV for a specific pixel._ | | esp\_err\_t | [**led\_strip\_set\_pixel\_rgbw**](#function-led_strip_set_pixel_rgbw) ([**led\_strip\_handle\_t**](#typedef-led_strip_handle_t) strip, uint32\_t index, uint32\_t red, uint32\_t green, uint32\_t blue, uint32\_t white)
_Set RGBW for a specific pixel._ | +## Macros + +| Type | Name | +| ---: | :--- | +| define | [**LED\_STRIP\_SET\_RGBW\_ORDER**](#define-led_strip_set_rgbw_order) (R, G, B, W) (R << 0 \| G << 2 \| B << 4 \| W << 6)
_Help macro to set pixel RGBW color order The default order of the four-color LED strips is GRBW. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ | +| define | [**LED\_STRIP\_SET\_RGB\_ORDER**](#define-led_strip_set_rgb_order) (R, G, B) (R << 0 \| G << 2 \| B << 4)
_Help macro to set pixel RGB color order The default order of the three-color LED strips is GRB. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ | + ## Functions Documentation ### function `led_strip_clear` @@ -178,6 +185,45 @@ Also see `led_strip_set_pixel` if you only want to specify the RGB part of the c - ESP\_ERR\_INVALID\_ARG: Set RGBW color for a specific pixel failed because of an invalid argument - ESP\_FAIL: Set RGBW color for a specific pixel failed because other error occurred +## Macros Documentation + +### define `LED_STRIP_SET_RGBW_ORDER` + +_Help macro to set pixel RGBW color order The default order of the four-color LED strips is GRBW. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ + +```c +#define LED_STRIP_SET_RGBW_ORDER (R, G, B, W) (R << 0 | G << 2 | B << 4 | W << 6) +``` + +**Parameters:** + +- `R` The position of the red channel in the color order. +- `G` The position of the green channel in the color order. +- `B` The position of the blue channel in the color order. +- `W` The position of the white channel in the color order. + +**Note:** + +The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. + +### define `LED_STRIP_SET_RGB_ORDER` + +_Help macro to set pixel RGB color order The default order of the three-color LED strips is GRB. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ + +```c +#define LED_STRIP_SET_RGB_ORDER (R, G, B) (R << 0 | G << 2 | B << 4) +``` + +**Parameters:** + +- `R` The position of the red channel in the color order. +- `G` The position of the green channel in the color order. +- `B` The position of the blue channel in the color order. + +**Note:** + +The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. + ## File include/led_strip_rmt.h ## Structures and Types @@ -306,7 +352,6 @@ Although only the MOSI line is used for generating the signal, the whole SPI bus | Type | Name | | ---: | :--- | | enum | [**led\_model\_t**](#enum-led_model_t)
_LED strip model._ | -| enum | [**led\_pixel\_format\_t**](#enum-led_pixel_format_t)
_LED strip pixel format._ | | struct | [**led\_strip\_config\_t**](#struct-led_strip_config_t)
_LED Strip Configuration._ | | typedef struct [**led\_strip\_t**](#struct-led_strip_t) \* | [**led\_strip\_handle\_t**](#typedef-led_strip_handle_t)
_LED strip handle._ | @@ -328,34 +373,24 @@ enum led_model_t { Different led model may have different timing parameters, so we need to distinguish them. -### enum `led_pixel_format_t` - -_LED strip pixel format._ - -```c -enum led_pixel_format_t { - LED_PIXEL_FORMAT_GRB, - LED_PIXEL_FORMAT_GRBW, - LED_PIXEL_FORMAT_INVALID -}; -``` - ### struct `led_strip_config_t` _LED Strip Configuration._ Variables: -- struct led\_strip\_config\_t::@2 flags
Extra driver flags +- uint8\_t bytes_per_pixel
bytes per LED pixel. Should be 3 or 4 + +- struct led\_strip\_config\_t::@2 flags
The order of the pixel color. Use help macro LED\_STRIP\_SET\_RGB\_ORDER or LED\_STRIP\_SET\_RGBW\_ORDER to set. Not set or set to 0 if the default order is used. Extra driver flags - uint32\_t invert_out
Invert output signal - [**led\_model\_t**](#enum-led_model_t) led_model
LED model -- [**led\_pixel\_format\_t**](#enum-led_pixel_format_t) led_pixel_format
LED pixel format - - uint32\_t max_leds
Maximum LEDs in a single strip +- uint8\_t pixel_order + - int strip_gpio_num
GPIO number that used by LED strip ### typedef `led_strip_handle_t` diff --git a/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c b/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c index 5cae3f079c..863e7d63b0 100644 --- a/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c +++ b/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -11,9 +11,9 @@ #include "esp_err.h" // GPIO assignment -#define LED_STRIP_BLINK_GPIO 2 +#define LED_STRIP_GPIO_PIN 2 // Numbers of the LED in the strip -#define LED_STRIP_LED_NUMBERS 24 +#define LED_STRIP_LED_COUNT 24 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) #define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000) @@ -23,11 +23,13 @@ led_strip_handle_t configure_led(void) { // LED strip general initialization, according to your led board design led_strip_config_t strip_config = { - .strip_gpio_num = LED_STRIP_BLINK_GPIO, // The GPIO that connected to the LED strip's data line - .max_leds = LED_STRIP_LED_NUMBERS, // The number of LEDs in the strip, - .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 + .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line + .max_leds = LED_STRIP_LED_COUNT, // The number of LEDs in the strip, + .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip + .led_model = LED_MODEL_WS2812, // LED strip model + .flags.invert_out = false, // whether to invert the output signal + .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. + Here set to the default GRB order to demonstrate usage */ }; // LED strip backend configuration: RMT @@ -57,7 +59,7 @@ void app_main(void) while (1) { 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++) { + for (int i = 0; i < LED_STRIP_LED_COUNT; i++) { ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 5, 5, 5)); } /* Refresh the strip to send data */ diff --git a/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c b/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c index 69b780c5aa..54a1b54c74 100644 --- a/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c +++ b/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -11,9 +11,9 @@ #include "esp_err.h" // GPIO assignment -#define LED_STRIP_BLINK_GPIO 2 +#define LED_STRIP_GPIO_PIN 2 // Numbers of the LED in the strip -#define LED_STRIP_LED_NUMBERS 24 +#define LED_STRIP_LED_COUNT 24 static const char *TAG = "example"; @@ -21,11 +21,13 @@ led_strip_handle_t configure_led(void) { // LED strip general initialization, according to your led board design led_strip_config_t strip_config = { - .strip_gpio_num = LED_STRIP_BLINK_GPIO, // The GPIO that connected to the LED strip's data line - .max_leds = LED_STRIP_LED_NUMBERS, // The number of LEDs in the strip, - .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 + .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line + .max_leds = LED_STRIP_LED_COUNT, // The number of LEDs in the strip, + .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip + .led_model = LED_MODEL_WS2812, // LED strip model + .flags.invert_out = false, // whether to invert the output signal + .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. + Here set to the default GRB order to demonstrate usage */ }; // LED strip backend configuration: SPI @@ -51,7 +53,7 @@ void app_main(void) while (1) { 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++) { + for (int i = 0; i < LED_STRIP_LED_COUNT; i++) { ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, i, 5, 5, 5)); } /* Refresh the strip to send data */ diff --git a/led_strip/idf_component.yml b/led_strip/idf_component.yml index 4928449549..ae2e6031bc 100644 --- a/led_strip/idf_component.yml +++ b/led_strip/idf_component.yml @@ -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: diff --git a/led_strip/include/led_strip.h b/led_strip/include/led_strip.h index a4e994675e..3c4758009c 100644 --- a/led_strip/include/led_strip.h +++ b/led_strip/include/led_strip.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,29 @@ extern "C" { #endif +/** + * @brief Help macro to set pixel RGB color order + * The default order of the three-color LED strips is GRB. If you have a different order, you can use the macro to set `pixel_order` in led_strip_config_t. + * The positions are counted from the least significant bit (LSB). + * @param R The position of the red channel in the color order. + * @param G The position of the green channel in the color order. + * @param B The position of the blue channel in the color order. + * @note The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. + */ +#define LED_STRIP_SET_RGB_ORDER(R, G, B) (R << 0 | G << 2 | B << 4) + +/** + * @brief Help macro to set pixel RGBW color order + * The default order of the four-color LED strips is GRBW. If you have a different order, you can use the macro to set `pixel_order` in led_strip_config_t. + * The positions are counted from the least significant bit (LSB). + * @param R The position of the red channel in the color order. + * @param G The position of the green channel in the color order. + * @param B The position of the blue channel in the color order. + * @param W The position of the white channel in the color order. + * @note The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. + */ +#define LED_STRIP_SET_RGBW_ORDER(R, G, B, W) (R << 0 | G << 2 | B << 4 | W << 6) + /** * @brief Set RGB for a specific pixel * diff --git a/led_strip/include/led_strip_types.h b/led_strip/include/led_strip_types.h index 691f0bc394..47aea74d8a 100644 --- a/led_strip/include/led_strip_types.h +++ b/led_strip/include/led_strip_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,15 +11,6 @@ extern "C" { #endif -/** - * @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_t; - /** * @brief LED strip model * @note Different led model may have different timing parameters, so we need to distinguish them. @@ -41,9 +32,11 @@ typedef struct led_strip_t *led_strip_handle_t; typedef struct { int strip_gpio_num; /*!< GPIO number that used by LED strip */ uint32_t max_leds; /*!< Maximum LEDs in a single strip */ - led_pixel_format_t led_pixel_format; /*!< LED pixel format */ + uint8_t bytes_per_pixel; /*!< bytes per LED pixel. Should be 3 or 4 */ led_model_t led_model; /*!< LED model */ - + uint8_t pixel_order; /*! The order of the pixel color. + Use help macro LED_STRIP_SET_RGB_ORDER or LED_STRIP_SET_RGBW_ORDER to set. + Not set or set to 0 if the default order is used. */ struct { uint32_t invert_out: 1; /*!< Invert output signal */ } flags; /*!< Extra driver flags */ diff --git a/led_strip/src/led_strip_common.c b/led_strip/src/led_strip_common.c new file mode 100644 index 0000000000..6338e9ffed --- /dev/null +++ b/led_strip/src/led_strip_common.c @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include "esp_log.h" +#include "esp_check.h" +#include "esp_bit_defs.h" +#include "led_strip_common.h" + +static const char *TAG = "led_strip_common"; + +esp_err_t led_strip_set_color_order(uint8_t *led_pixel_offset, const uint8_t pixel_order, const uint8_t bytes_per_pixel) +{ + if (pixel_order) { + uint8_t r_order = (pixel_order >> 0) & 0x03; + uint8_t g_order = (pixel_order >> 2) & 0x03; + uint8_t b_order = (pixel_order >> 4) & 0x03; + uint8_t w_order = (pixel_order >> 6) & 0x03; + uint8_t mask = bytes_per_pixel == 3 ? BIT(r_order) | BIT(g_order) | BIT(b_order) : BIT(r_order) | BIT(g_order) | BIT(b_order) | BIT(w_order); + // Check for invalid values + ESP_RETURN_ON_FALSE(__builtin_popcount(mask) == bytes_per_pixel && r_order < bytes_per_pixel && g_order < bytes_per_pixel && b_order < bytes_per_pixel && w_order < bytes_per_pixel, + ESP_ERR_INVALID_ARG, TAG, "invalid order argument"); + led_pixel_offset[LED_PIXEL_INDEX_RED] = r_order; + led_pixel_offset[LED_PIXEL_INDEX_GREEN] = g_order; + led_pixel_offset[LED_PIXEL_INDEX_BLUE] = b_order; + led_pixel_offset[LED_PIXEL_INDEX_WHITE] = w_order; + } else { + // If pixel_order is not set, set default GRB(GRBW) order as fallback path + led_pixel_offset[LED_PIXEL_INDEX_RED] = 1; + led_pixel_offset[LED_PIXEL_INDEX_GREEN] = 0; + led_pixel_offset[LED_PIXEL_INDEX_BLUE] = 2; + led_pixel_offset[LED_PIXEL_INDEX_WHITE] = 3; + } + return ESP_OK; +} diff --git a/led_strip/src/led_strip_common.h b/led_strip/src/led_strip_common.h new file mode 100644 index 0000000000..e4ca2811f3 --- /dev/null +++ b/led_strip/src/led_strip_common.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include "esp_err.h" +#include "led_strip_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @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 Set LED color order + * + * @param led_pixel_offset Each pixel's offset + * @param pixel_order `pixel_order` parameter in LED strip configuration + * @param bytes_per_pixel bytes per pixel + * @return + * - ESP_OK: Set LED color order successfully + * - ESP_ERR_INVALID_ARG: Set LED color order failed because of invalid argument + */ +esp_err_t led_strip_set_color_order(uint8_t *led_pixel_offset, const uint8_t pixel_order, const uint8_t bytes_per_pixel); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/led_strip/src/led_strip_rmt_dev.c b/led_strip/src/led_strip_rmt_dev.c index 1cbf0e45ae..15a2ef4a48 100644 --- a/led_strip/src/led_strip_rmt_dev.c +++ b/led_strip/src/led_strip_rmt_dev.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,7 @@ #include "led_strip.h" #include "led_strip_interface.h" #include "led_strip_rmt_encoder.h" +#include "led_strip_common.h" #define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution #define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4 @@ -30,6 +31,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; @@ -38,12 +40,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; } @@ -53,12 +58,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; } @@ -99,15 +106,8 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l led_strip_rmt_obj *rmt_strip = NULL; esp_err_t ret = ESP_OK; 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) { - bytes_per_pixel = 3; - } else { - assert(false); - } + ESP_GOTO_ON_FALSE(led_config->bytes_per_pixel == 3 || led_config->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel bytes"); + uint8_t bytes_per_pixel = led_config->bytes_per_pixel; rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel); ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip"); uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION; @@ -138,7 +138,7 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l .led_model = led_config->led_model }; ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed"); - + ESP_GOTO_ON_ERROR(led_strip_set_color_order(rmt_strip->led_pixel_offset, led_config->pixel_order, bytes_per_pixel), err, TAG, "adjust color order failed"); rmt_strip->bytes_per_pixel = bytes_per_pixel; rmt_strip->strip_len = led_config->max_leds; diff --git a/led_strip/src/led_strip_rmt_dev_idf4.c b/led_strip/src/led_strip_rmt_dev_idf4.c index a1067cd7c4..091ccf8106 100644 --- a/led_strip/src/led_strip_rmt_dev_idf4.c +++ b/led_strip/src/led_strip_rmt_dev_idf4.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -11,6 +11,7 @@ #include "driver/rmt.h" #include "led_strip.h" #include "led_strip_interface.h" +#include "led_strip_common.h" static const char *TAG = "led_strip_rmt"; @@ -43,6 +44,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; @@ -83,12 +85,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; } @@ -123,17 +127,9 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l led_strip_rmt_obj *rmt_strip = NULL; esp_err_t ret = ESP_OK; ESP_RETURN_ON_FALSE(led_config && dev_config && ret_strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, TAG, "invalid led_pixel_format"); 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) { - bytes_per_pixel = 3; - } else { - assert(false); - } + ESP_RETURN_ON_FALSE(led_config->bytes_per_pixel == 3 || led_config->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "invalid led_pixel bytes"); + uint8_t bytes_per_pixel = led_config->bytes_per_pixel; // allocate memory for led_strip object rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel); @@ -174,6 +170,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); + ESP_GOTO_ON_ERROR(led_strip_set_color_order(rmt_strip->led_pixel_offset, led_config->pixel_order, bytes_per_pixel), err, TAG, "adjust color order failed"); rmt_strip->bytes_per_pixel = bytes_per_pixel; rmt_strip->rmt_channel = (rmt_channel_t)dev_config->rmt_channel; diff --git a/led_strip/src/led_strip_spi_dev.c b/led_strip/src/led_strip_spi_dev.c index 6c66d7e375..248c474cf5 100644 --- a/led_strip/src/led_strip_spi_dev.c +++ b/led_strip/src/led_strip_spi_dev.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,9 +10,10 @@ #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" +#include "led_strip_common.h" #define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000) // 2.5MHz resolution #define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4 @@ -28,6 +29,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; @@ -51,14 +53,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); + __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; } @@ -70,12 +74,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); + __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; } @@ -124,15 +130,8 @@ esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const l led_strip_spi_obj *spi_strip = NULL; esp_err_t ret = ESP_OK; 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) { - bytes_per_pixel = 3; - } else { - assert(false); - } + ESP_GOTO_ON_FALSE(led_config->bytes_per_pixel == 3 || led_config->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel bytes"); + uint8_t bytes_per_pixel = led_config->bytes_per_pixel; uint32_t mem_caps = MALLOC_CAP_DEFAULT; if (spi_config->flags.with_dma) { // DMA buffer must be placed in internal SRAM @@ -186,6 +185,7 @@ esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const l // clock_resolution between 2.2MHz to 2.8MHz is supported 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); + ESP_GOTO_ON_ERROR(led_strip_set_color_order(spi_strip->led_pixel_offset, led_config->pixel_order, bytes_per_pixel), err, TAG, "adjust color order failed"); spi_strip->bytes_per_pixel = bytes_per_pixel; spi_strip->strip_len = led_config->max_leds; From 31585c8c97b5a403e1550270fb9fad58879cc2dd Mon Sep 17 00:00:00 2001 From: morris Date: Thu, 24 Oct 2024 11:25:53 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat(led=5Fstrip):=20discontinue=20esp-idf?= =?UTF-8?q?=20v4=20and=20bump=20major=20version=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- led_strip/CHANGELOG.md | 7 +- led_strip/CMakeLists.txt | 11 +- led_strip/README.md | 63 +++--- led_strip/api.md | 153 ++++++++------ .../led_strip_rmt_ws2812/CMakeLists.txt | 6 +- .../main/idf_component.yml | 2 +- .../main/led_strip_rmt_ws2812_main.c | 23 +-- .../led_strip_spi_ws2812/CMakeLists.txt | 6 +- .../main/idf_component.yml | 2 +- .../main/led_strip_spi_ws2812_main.c | 26 ++- led_strip/idf_component.yml | 6 +- led_strip/include/led_strip.h | 27 --- led_strip/include/led_strip_rmt.h | 12 +- led_strip/include/led_strip_spi.h | 3 +- led_strip/include/led_strip_types.h | 46 +++-- led_strip/src/led_strip_common.c | 37 ---- led_strip/src/led_strip_common.h | 41 ---- led_strip/src/led_strip_rmt_dev.c | 60 ++++-- led_strip/src/led_strip_rmt_dev_idf4.c | 191 ------------------ led_strip/src/led_strip_spi_dev.c | 57 ++++-- 20 files changed, 289 insertions(+), 490 deletions(-) delete mode 100644 led_strip/src/led_strip_common.c delete mode 100644 led_strip/src/led_strip_common.h delete mode 100644 led_strip/src/led_strip_rmt_dev_idf4.c diff --git a/led_strip/CHANGELOG.md b/led_strip/CHANGELOG.md index bfbb0c7315..d7b130a24f 100644 --- a/led_strip/CHANGELOG.md +++ b/led_strip/CHANGELOG.md @@ -1,7 +1,8 @@ -## 2.6.0 +## 3.0.0 + +- Discontinued support for ESP-IDF v4.x +- Added configuration for user-defined color component format -- Add pixel order configuration 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. diff --git a/led_strip/CMakeLists.txt b/led_strip/CMakeLists.txt index 13c35ec3d3..9e82ccaceb 100644 --- a/led_strip/CMakeLists.txt +++ b/led_strip/CMakeLists.txt @@ -1,15 +1,10 @@ include($ENV{IDF_PATH}/tools/cmake/version.cmake) -set(srcs "src/led_strip_api.c" "src/led_strip_common.c") +set(srcs "src/led_strip_api.c") set(public_requires) -# Starting from esp-idf v5.x, the RMT driver is rewritten -if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") - if(CONFIG_SOC_RMT_SUPPORTED) - list(APPEND srcs "src/led_strip_rmt_dev.c" "src/led_strip_rmt_encoder.c") - endif() -else() - list(APPEND srcs "src/led_strip_rmt_dev_idf4.c") +if(CONFIG_SOC_RMT_SUPPORTED) + list(APPEND srcs "src/led_strip_rmt_dev.c" "src/led_strip_rmt_encoder.c") endif() # the SPI backend driver relies on some feature that was available in IDF 5.1 diff --git a/led_strip/README.md b/led_strip/README.md index 6634b4f7cf..ca3cac20e9 100644 --- a/led_strip/README.md +++ b/led_strip/README.md @@ -15,28 +15,29 @@ This is the most economical way to drive the LEDs because it only consumes one R ```c #define BLINK_GPIO 0 -led_strip_handle_t led_strip; - -/* LED strip initialization with the GPIO and pixels number*/ +/// LED strip common configuration led_strip_config_t strip_config = { - .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line - .max_leds = 1, // The number of LEDs in the strip, - .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip - .led_model = LED_MODEL_WS2812, // LED strip model - .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) - .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. - Here set to the default GRB order to demonstrate usage */ + .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line + .max_leds = 1, // The number of LEDs in the strip, + .led_model = LED_MODEL_WS2812, // LED strip model, it determines the bit timing + .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, // The color component format is G-R-B + .flags = { + .invert_out = false, // don't invert the output signal + } }; +/// RMT backend specific configuration led_strip_rmt_config_t rmt_config = { -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) - .rmt_channel = 0, -#else - .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption - .resolution_hz = 10 * 1000 * 1000, // 10MHz - .flags.with_dma = false, // whether to enable the DMA feature -#endif + .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption + .resolution_hz = 10 * 1000 * 1000, // RMT counter clock frequency: 10MHz + .mem_block_symbols = 64, // the memory size of each RMT channel, in words (4 bytes) + .flags = { + .with_dma = false, // DMA feature is available on chips like ESP32-S3/P4 + } }; + +/// Create the LED strip object +led_strip_handle_t led_strip; ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); ``` @@ -53,24 +54,28 @@ Please note, the SPI backend has a dependency of **ESP-IDF >= 5.1** ```c #define BLINK_GPIO 0 -led_strip_handle_t led_strip; - -/* LED strip initialization with the GPIO and pixels number*/ +/// LED strip common configuration led_strip_config_t strip_config = { - .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line - .max_leds = 1, // The number of LEDs in the strip, - .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip - .led_model = LED_MODEL_WS2812, // LED strip model - .flags.invert_out = false, // whether to invert the output signal (useful when your hardware has a level inverter) - .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. - Here set to the default GRB order to demonstrate usage */ + .strip_gpio_num = BLINK_GPIO, // The GPIO that connected to the LED strip's data line + .max_leds = 1, // The number of LEDs in the strip, + .led_model = LED_MODEL_WS2812, // LED strip model, it determines the bit timing + .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, // The color component format is G-R-B + .flags = { + .invert_out = false, // don't invert the output signal + } }; +/// SPI backend specific configuration led_strip_spi_config_t spi_config = { .clk_src = SPI_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption - .flags.with_dma = true, // Using DMA can improve performance and help drive more LEDs - .spi_bus = SPI2_HOST, // SPI bus ID + .spi_bus = SPI2_HOST, // SPI bus ID + .flags = { + .with_dma = true, // Using DMA can improve performance and help drive more LEDs + } }; + +/// Create the LED strip object +led_strip_handle_t led_strip; ESP_ERROR_CHECK(led_strip_new_spi_device(&strip_config, &spi_config, &led_strip)); ``` diff --git a/led_strip/api.md b/led_strip/api.md index 1f589c75bf..abe7f76763 100644 --- a/led_strip/api.md +++ b/led_strip/api.md @@ -21,13 +21,6 @@ | esp\_err\_t | [**led\_strip\_set\_pixel\_hsv**](#function-led_strip_set_pixel_hsv) ([**led\_strip\_handle\_t**](#typedef-led_strip_handle_t) strip, uint32\_t index, uint16\_t hue, uint8\_t saturation, uint8\_t value)
_Set HSV for a specific pixel._ | | esp\_err\_t | [**led\_strip\_set\_pixel\_rgbw**](#function-led_strip_set_pixel_rgbw) ([**led\_strip\_handle\_t**](#typedef-led_strip_handle_t) strip, uint32\_t index, uint32\_t red, uint32\_t green, uint32\_t blue, uint32\_t white)
_Set RGBW for a specific pixel._ | -## Macros - -| Type | Name | -| ---: | :--- | -| define | [**LED\_STRIP\_SET\_RGBW\_ORDER**](#define-led_strip_set_rgbw_order) (R, G, B, W) (R << 0 \| G << 2 \| B << 4 \| W << 6)
_Help macro to set pixel RGBW color order The default order of the four-color LED strips is GRBW. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ | -| define | [**LED\_STRIP\_SET\_RGB\_ORDER**](#define-led_strip_set_rgb_order) (R, G, B) (R << 0 \| G << 2 \| B << 4)
_Help macro to set pixel RGB color order The default order of the three-color LED strips is GRB. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ | - ## Functions Documentation ### function `led_strip_clear` @@ -185,45 +178,6 @@ Also see `led_strip_set_pixel` if you only want to specify the RGB part of the c - ESP\_ERR\_INVALID\_ARG: Set RGBW color for a specific pixel failed because of an invalid argument - ESP\_FAIL: Set RGBW color for a specific pixel failed because other error occurred -## Macros Documentation - -### define `LED_STRIP_SET_RGBW_ORDER` - -_Help macro to set pixel RGBW color order The default order of the four-color LED strips is GRBW. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ - -```c -#define LED_STRIP_SET_RGBW_ORDER (R, G, B, W) (R << 0 | G << 2 | B << 4 | W << 6) -``` - -**Parameters:** - -- `R` The position of the red channel in the color order. -- `G` The position of the green channel in the color order. -- `B` The position of the blue channel in the color order. -- `W` The position of the white channel in the color order. - -**Note:** - -The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. - -### define `LED_STRIP_SET_RGB_ORDER` - -_Help macro to set pixel RGB color order The default order of the three-color LED strips is GRB. If you have a different order, you can use the macro to set_ `pixel_order`_in_[_**led\_strip\_config\_t**_](#struct-led_strip_config_t)_. The positions are counted from the least significant bit (LSB)._ - -```c -#define LED_STRIP_SET_RGB_ORDER (R, G, B) (R << 0 | G << 2 | B << 4) -``` - -**Parameters:** - -- `R` The position of the red channel in the color order. -- `G` The position of the green channel in the color order. -- `B` The position of the blue channel in the color order. - -**Note:** - -The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. - ## File include/led_strip_rmt.h ## Structures and Types @@ -231,6 +185,7 @@ The order starts from 0. And the user needs to make sure that all the numbers ap | Type | Name | | ---: | :--- | | struct | [**led\_strip\_rmt\_config\_t**](#struct-led_strip_rmt_config_t)
_LED Strip RMT specific configuration._ | +| struct | [**led\_strip\_rmt\_extra\_config**](#struct-led_strip_rmt_config_tled_strip_rmt_extra_config)
| ## Functions @@ -248,12 +203,16 @@ Variables: - rmt\_clock\_source\_t clk_src
RMT clock source -- struct led\_strip\_rmt\_config\_t::@0 flags
Extra driver flags +- struct [**led\_strip\_rmt\_config\_t::led\_strip\_rmt\_extra\_config**](#struct-led_strip_rmt_config_tled_strip_rmt_extra_config) flags
Extra driver flags -- size\_t mem_block_symbols
How many RMT symbols can one RMT channel hold at one time. Set to 0 will fallback to use the default size. +- size\_t mem_block_symbols
How many RMT symbols can one RMT channel hold at one time. Set to 0 will fallback to use the default size. Extra RMT specific driver flags - uint32\_t resolution_hz
RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied +### struct `led_strip_rmt_config_t::led_strip_rmt_extra_config` + +Variables: + - uint32\_t with_dma
Use DMA to transmit data ## Functions Documentation @@ -307,7 +266,7 @@ Variables: - spi\_clock\_source\_t clk_src
SPI clock source -- struct led\_strip\_spi\_config\_t::@1 flags
Extra driver flags +- struct [**led\_strip\_spi\_config\_t**](#struct-led_strip_spi_config_t) flags
Extra driver flags - spi\_host\_device\_t spi_bus
SPI bus ID. Which buses are available depends on the specific chip @@ -351,12 +310,54 @@ Although only the MOSI line is used for generating the signal, the whole SPI bus | Type | Name | | ---: | :--- | +| union | [**led\_color\_component\_format\_t**](#union-led_color_component_format_t)
_LED color component format._ | +| struct | [**format\_layout**](#struct-led_color_component_format_tformat_layout)
| | enum | [**led\_model\_t**](#enum-led_model_t)
_LED strip model._ | -| struct | [**led\_strip\_config\_t**](#struct-led_strip_config_t)
_LED Strip Configuration._ | -| typedef struct [**led\_strip\_t**](#struct-led_strip_t) \* | [**led\_strip\_handle\_t**](#typedef-led_strip_handle_t)
_LED strip handle._ | +| struct | [**led\_strip\_config\_t**](#struct-led_strip_config_t)
_LED Strip common configurations The common configurations are not specific to any backend peripheral._ | +| struct | [**led\_strip\_extra\_flags**](#struct-led_strip_config_tled_strip_extra_flags)
| +| typedef struct [**led\_strip\_t**](#struct-led_strip_t) \* | [**led\_strip\_handle\_t**](#typedef-led_strip_handle_t)
_Type of LED strip handle._ | + +## Macros + +| Type | Name | +| ---: | :--- | +| define | [**LED\_STRIP\_COLOR\_COMPONENT\_FMT\_GRB**](#define-led_strip_color_component_fmt_grb) ([**led\_color\_component\_format\_t**](#union-led_color_component_format_t)){.format = {.r\_pos = 1, .g\_pos = 0, .b\_pos = 2, .w\_pos = 3, .reserved = 0, .num\_components = 3}}
_Helper macros to set the color component format._ | +| define | [**LED\_STRIP\_COLOR\_COMPONENT\_FMT\_GRBW**](#define-led_strip_color_component_fmt_grbw) ([**led\_color\_component\_format\_t**](#union-led_color_component_format_t)){.format = {.r\_pos = 1, .g\_pos = 0, .b\_pos = 2, .w\_pos = 3, .reserved = 0, .num\_components = 4}}
| +| define | [**LED\_STRIP\_COLOR\_COMPONENT\_FMT\_RGB**](#define-led_strip_color_component_fmt_rgb) ([**led\_color\_component\_format\_t**](#union-led_color_component_format_t)){.format = {.r\_pos = 0, .g\_pos = 1, .b\_pos = 2, .w\_pos = 3, .reserved = 0, .num\_components = 3}}
| +| define | [**LED\_STRIP\_COLOR\_COMPONENT\_FMT\_RGBW**](#define-led_strip_color_component_fmt_rgbw) ([**led\_color\_component\_format\_t**](#union-led_color_component_format_t)){.format = {.r\_pos = 0, .g\_pos = 1, .b\_pos = 2, .w\_pos = 3, .reserved = 0, .num\_components = 4}}
| ## Structures and Types Documentation +### union `led_color_component_format_t` + +_LED color component format._ + +**Note:** + +The format is used to specify the order of color components in each pixel, also the number of color components. + +Variables: + +- struct [**led\_color\_component\_format\_t::format\_layout**](#struct-led_color_component_format_tformat_layout) format
Format layout + +- uint32\_t format_id
Format ID + +### struct `led_color_component_format_t::format_layout` + +Variables: + +- uint32\_t b_pos
Position of the blue channel in the color order: 0~3 + +- uint32\_t g_pos
Position of the green channel in the color order: 0~3 + +- uint32\_t num_components
Number of color components per pixel: 3 or 4. If set to 0, it will fallback to 3 + +- uint32\_t r_pos
Position of the red channel in the color order: 0~3 + +- uint32\_t reserved
Reserved + +- uint32\_t w_pos
Position of the white channel in the color order: 0~3 + ### enum `led_model_t` _LED strip model._ @@ -375,32 +376,62 @@ Different led model may have different timing parameters, so we need to distingu ### struct `led_strip_config_t` -_LED Strip Configuration._ +_LED Strip common configurations The common configurations are not specific to any backend peripheral._ Variables: -- uint8\_t bytes_per_pixel
bytes per LED pixel. Should be 3 or 4 +- [**led\_color\_component\_format\_t**](#union-led_color_component_format_t) color_component_format
Specifies the order of color components in each pixel. Use helper macros like `LED_STRIP_COLOR_COMPONENT_FMT_GRB` to set the format LED strip extra driver flags -- struct led\_strip\_config\_t::@2 flags
The order of the pixel color. Use help macro LED\_STRIP\_SET\_RGB\_ORDER or LED\_STRIP\_SET\_RGBW\_ORDER to set. Not set or set to 0 if the default order is used. Extra driver flags +- struct [**led\_strip\_config\_t::led\_strip\_extra\_flags**](#struct-led_strip_config_tled_strip_extra_flags) flags
Extra driver flags -- uint32\_t invert_out
Invert output signal +- [**led\_model\_t**](#enum-led_model_t) led_model
Specifies the LED strip model (e.g., WS2812, SK6812) -- [**led\_model\_t**](#enum-led_model_t) led_model
LED model +- uint32\_t max_leds
Maximum number of LEDs that can be controlled in a single strip -- uint32\_t max_leds
Maximum LEDs in a single strip +- int strip_gpio_num
GPIO number that used by LED strip -- uint8\_t pixel_order +### struct `led_strip_config_t::led_strip_extra_flags` -- int strip_gpio_num
GPIO number that used by LED strip +Variables: + +- uint32\_t invert_out
Invert output signal ### typedef `led_strip_handle_t` -_LED strip handle._ +_Type of LED strip handle._ ```c typedef struct led_strip_t* led_strip_handle_t; ``` +## Macros Documentation + +### define `LED_STRIP_COLOR_COMPONENT_FMT_GRB` + +_Helper macros to set the color component format._ + +```c +#define LED_STRIP_COLOR_COMPONENT_FMT_GRB ( led_color_component_format_t ){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 3}} +``` + +### define `LED_STRIP_COLOR_COMPONENT_FMT_GRBW` + +```c +#define LED_STRIP_COLOR_COMPONENT_FMT_GRBW ( led_color_component_format_t ){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 4}} +``` + +### define `LED_STRIP_COLOR_COMPONENT_FMT_RGB` + +```c +#define LED_STRIP_COLOR_COMPONENT_FMT_RGB ( led_color_component_format_t ){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 3}} +``` + +### define `LED_STRIP_COLOR_COMPONENT_FMT_RGBW` + +```c +#define LED_STRIP_COLOR_COMPONENT_FMT_RGBW ( led_color_component_format_t ){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 4}} +``` + ## File interface/led_strip_interface.h ## Structures and Types @@ -408,7 +439,7 @@ typedef struct led_strip_t* led_strip_handle_t; | Type | Name | | ---: | :--- | | struct | [**led\_strip\_t**](#struct-led_strip_t)
_LED strip interface definition._ | -| typedef struct [**led\_strip\_t**](#struct-led_strip_t) | [**led\_strip\_t**](#typedef-led_strip_t)
| +| typedef struct led\_strip\_t | [**led\_strip\_t**](#typedef-led_strip_t)
| ## Structures and Types Documentation diff --git a/led_strip/examples/led_strip_rmt_ws2812/CMakeLists.txt b/led_strip/examples/led_strip_rmt_ws2812/CMakeLists.txt index fc2dfc7a0e..ff10c822c7 100644 --- a/led_strip/examples/led_strip_rmt_ws2812/CMakeLists.txt +++ b/led_strip/examples/led_strip_rmt_ws2812/CMakeLists.txt @@ -1,8 +1,6 @@ -# For more information about build system see -# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html -# The following five lines of boilerplate have to be in your project's -# CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(led_strip_rmt_ws2812) diff --git a/led_strip/examples/led_strip_rmt_ws2812/main/idf_component.yml b/led_strip/examples/led_strip_rmt_ws2812/main/idf_component.yml index 916c366c79..67a577507b 100644 --- a/led_strip/examples/led_strip_rmt_ws2812/main/idf_component.yml +++ b/led_strip/examples/led_strip_rmt_ws2812/main/idf_component.yml @@ -1,5 +1,5 @@ ## IDF Component Manager Manifest File dependencies: espressif/led_strip: - version: '^2' + version: '^3' override_path: '../../../' diff --git a/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c b/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c index 863e7d63b0..0fd88b30a8 100644 --- a/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c +++ b/led_strip/examples/led_strip_rmt_ws2812/main/led_strip_rmt_ws2812_main.c @@ -23,24 +23,23 @@ led_strip_handle_t configure_led(void) { // LED strip general initialization, according to your led board design led_strip_config_t strip_config = { - .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line - .max_leds = LED_STRIP_LED_COUNT, // The number of LEDs in the strip, - .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip - .led_model = LED_MODEL_WS2812, // LED strip model - .flags.invert_out = false, // whether to invert the output signal - .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. - Here set to the default GRB order to demonstrate usage */ + .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line + .max_leds = LED_STRIP_LED_COUNT, // The number of LEDs in the strip, + .led_model = LED_MODEL_WS2812, // LED strip model + .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, // The color order of the strip: GRB + .flags = { + .invert_out = false, // don't invert the output signal + } }; // LED strip backend configuration: RMT led_strip_rmt_config_t rmt_config = { -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) - .rmt_channel = 0, -#else .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption .resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency - .flags.with_dma = false, // DMA feature is available on ESP target like ESP32-S3 -#endif + .mem_block_symbols = 64, // the memory size of each RMT channel, in words (4 bytes) + .flags = { + .with_dma = false, // DMA feature is available on chips like ESP32-S3/P4 + } }; // LED Strip object handle diff --git a/led_strip/examples/led_strip_spi_ws2812/CMakeLists.txt b/led_strip/examples/led_strip_spi_ws2812/CMakeLists.txt index 7d3af2dfae..822cf2bbad 100644 --- a/led_strip/examples/led_strip_spi_ws2812/CMakeLists.txt +++ b/led_strip/examples/led_strip_spi_ws2812/CMakeLists.txt @@ -1,8 +1,6 @@ -# For more information about build system see -# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html -# The following five lines of boilerplate have to be in your project's -# CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.16) +set(COMPONENTS main) + include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(led_strip_spi_ws2812) diff --git a/led_strip/examples/led_strip_spi_ws2812/main/idf_component.yml b/led_strip/examples/led_strip_spi_ws2812/main/idf_component.yml index 050d8d269f..ed00d7eb3c 100644 --- a/led_strip/examples/led_strip_spi_ws2812/main/idf_component.yml +++ b/led_strip/examples/led_strip_spi_ws2812/main/idf_component.yml @@ -1,6 +1,6 @@ ## IDF Component Manager Manifest File dependencies: espressif/led_strip: - version: '^2.4' + version: '^3' override_path: '../../../' idf: ">=5.1" diff --git a/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c b/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c index 54a1b54c74..1ccd626646 100644 --- a/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c +++ b/led_strip/examples/led_strip_spi_ws2812/main/led_strip_spi_ws2812_main.c @@ -21,20 +21,30 @@ led_strip_handle_t configure_led(void) { // LED strip general initialization, according to your led board design led_strip_config_t strip_config = { - .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line - .max_leds = LED_STRIP_LED_COUNT, // The number of LEDs in the strip, - .bytes_per_pixel = 3, // 3 bytes per pixel of the LED strip - .led_model = LED_MODEL_WS2812, // LED strip model - .flags.invert_out = false, // whether to invert the output signal - .pixel_order = LED_STRIP_SET_RGB_ORDER(1, 0, 2), /* The order of the pixel color. Not set or set to 0 if the default order is used. - Here set to the default GRB order to demonstrate usage */ + .strip_gpio_num = LED_STRIP_GPIO_PIN, // The GPIO that connected to the LED strip's data line + .max_leds = LED_STRIP_LED_COUNT, // The number of LEDs in the strip, + .led_model = LED_MODEL_WS2812, // LED strip model + // set the color order of the strip: GRB + .color_component_format = { + .format = { + .r_pos = 1, // red is the second byte in the color data + .g_pos = 0, // green is the first byte in the color data + .b_pos = 2, // blue is the third byte in the color data + .num_components = 3, // total 3 color components + }, + }, + .flags = { + .invert_out = false, // don't invert the output signal + } }; // LED strip backend configuration: SPI led_strip_spi_config_t spi_config = { .clk_src = SPI_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption - .flags.with_dma = true, // Using DMA can improve performance and help drive more LEDs .spi_bus = SPI2_HOST, // SPI bus ID + .flags = { + .with_dma = true, // Using DMA can improve performance and help drive more LEDs + } }; // LED Strip object handle diff --git a/led_strip/idf_component.yml b/led_strip/idf_component.yml index ae2e6031bc..eb75f1ed1a 100644 --- a/led_strip/idf_component.yml +++ b/led_strip/idf_component.yml @@ -1,5 +1,7 @@ -version: "2.5.6" +version: "3.0.0" description: Driver for Addressable LED Strip (WS2812, etc) url: https://github.com/espressif/idf-extra-components/tree/master/led_strip +issues: https://github.com/espressif/idf-extra-components/issues +repository: https://github.com/espressif/idf-extra-components.git dependencies: - idf: ">=4.4" + idf: ">=5.0" diff --git a/led_strip/include/led_strip.h b/led_strip/include/led_strip.h index 3c4758009c..36fe5fefff 100644 --- a/led_strip/include/led_strip.h +++ b/led_strip/include/led_strip.h @@ -8,39 +8,12 @@ #include #include "esp_err.h" #include "led_strip_rmt.h" -#include "esp_idf_version.h" - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 1, 0) #include "led_strip_spi.h" -#endif #ifdef __cplusplus extern "C" { #endif -/** - * @brief Help macro to set pixel RGB color order - * The default order of the three-color LED strips is GRB. If you have a different order, you can use the macro to set `pixel_order` in led_strip_config_t. - * The positions are counted from the least significant bit (LSB). - * @param R The position of the red channel in the color order. - * @param G The position of the green channel in the color order. - * @param B The position of the blue channel in the color order. - * @note The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. - */ -#define LED_STRIP_SET_RGB_ORDER(R, G, B) (R << 0 | G << 2 | B << 4) - -/** - * @brief Help macro to set pixel RGBW color order - * The default order of the four-color LED strips is GRBW. If you have a different order, you can use the macro to set `pixel_order` in led_strip_config_t. - * The positions are counted from the least significant bit (LSB). - * @param R The position of the red channel in the color order. - * @param G The position of the green channel in the color order. - * @param B The position of the blue channel in the color order. - * @param W The position of the white channel in the color order. - * @note The order starts from 0. And the user needs to make sure that all the numbers appear exactly once and are all less than the number of colors per pixel. - */ -#define LED_STRIP_SET_RGBW_ORDER(R, G, B, W) (R << 0 | G << 2 | B << 4 | W << 6) - /** * @brief Set RGB for a specific pixel * diff --git a/led_strip/include/led_strip_rmt.h b/led_strip/include/led_strip_rmt.h index b575aeaba1..3b58276b14 100644 --- a/led_strip/include/led_strip_rmt.h +++ b/led_strip/include/led_strip_rmt.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -9,10 +9,7 @@ #include "esp_err.h" #include "led_strip_types.h" #include "esp_idf_version.h" - -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) #include "driver/rmt_types.h" -#endif #ifdef __cplusplus extern "C" { @@ -22,14 +19,11 @@ extern "C" { * @brief LED Strip RMT specific configuration */ typedef struct { -#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) - uint8_t rmt_channel; /*!< Specify the channel number, the legacy RMT driver doesn't support channel allocator */ -#else // new driver supports specify the clock source and clock resolution rmt_clock_source_t clk_src; /*!< RMT clock source */ uint32_t resolution_hz; /*!< RMT tick resolution, if set to zero, a default resolution (10MHz) will be applied */ -#endif size_t mem_block_symbols; /*!< How many RMT symbols can one RMT channel hold at one time. Set to 0 will fallback to use the default size. */ - struct { + /*!< Extra RMT specific driver flags */ + struct led_strip_rmt_extra_config { uint32_t with_dma: 1; /*!< Use DMA to transmit data */ } flags; /*!< Extra driver flags */ } led_strip_rmt_config_t; diff --git a/led_strip/include/led_strip_spi.h b/led_strip/include/led_strip_spi.h index eb35249360..cd66e7a8f1 100644 --- a/led_strip/include/led_strip_spi.h +++ b/led_strip/include/led_strip_spi.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -27,6 +27,7 @@ typedef struct { /** * @brief Create LED strip based on SPI MOSI channel + * * @note Although only the MOSI line is used for generating the signal, the whole SPI bus can't be used for other purposes. * * @param led_config LED strip configuration diff --git a/led_strip/include/led_strip_types.h b/led_strip/include/led_strip_types.h index 47aea74d8a..3c290d5b96 100644 --- a/led_strip/include/led_strip_types.h +++ b/led_strip/include/led_strip_types.h @@ -11,6 +11,11 @@ extern "C" { #endif +/** + * @brief Type of LED strip handle + */ +typedef struct led_strip_t *led_strip_handle_t; + /** * @brief LED strip model * @note Different led model may have different timing parameters, so we need to distinguish them. @@ -22,24 +27,41 @@ typedef enum { } led_model_t; /** - * @brief LED strip handle + * @brief LED color component format + * @note The format is used to specify the order of color components in each pixel, also the number of color components. */ -typedef struct led_strip_t *led_strip_handle_t; +typedef union { + struct format_layout { + uint32_t r_pos: 2; /*!< Position of the red channel in the color order: 0~3 */ + uint32_t g_pos: 2; /*!< Position of the green channel in the color order: 0~3 */ + uint32_t b_pos: 2; /*!< Position of the blue channel in the color order: 0~3 */ + uint32_t w_pos: 2; /*!< Position of the white channel in the color order: 0~3 */ + uint32_t reserved: 21; /*!< Reserved */ + uint32_t num_components: 3; /*!< Number of color components per pixel: 3 or 4. If set to 0, it will fallback to 3 */ + } format; /*!< Format layout */ + uint32_t format_id; /*!< Format ID */ +} led_color_component_format_t; + +/// Helper macros to set the color component format +#define LED_STRIP_COLOR_COMPONENT_FMT_GRB (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 3}} +#define LED_STRIP_COLOR_COMPONENT_FMT_GRBW (led_color_component_format_t){.format = {.r_pos = 1, .g_pos = 0, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 4}} +#define LED_STRIP_COLOR_COMPONENT_FMT_RGB (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 3}} +#define LED_STRIP_COLOR_COMPONENT_FMT_RGBW (led_color_component_format_t){.format = {.r_pos = 0, .g_pos = 1, .b_pos = 2, .w_pos = 3, .reserved = 0, .num_components = 4}} /** - * @brief LED Strip Configuration + * @brief LED Strip common configurations + * The common configurations are not specific to any backend peripheral. */ typedef struct { - int strip_gpio_num; /*!< GPIO number that used by LED strip */ - uint32_t max_leds; /*!< Maximum LEDs in a single strip */ - uint8_t bytes_per_pixel; /*!< bytes per LED pixel. Should be 3 or 4 */ - led_model_t led_model; /*!< LED model */ - uint8_t pixel_order; /*! The order of the pixel color. - Use help macro LED_STRIP_SET_RGB_ORDER or LED_STRIP_SET_RGBW_ORDER to set. - Not set or set to 0 if the default order is used. */ - struct { + int strip_gpio_num; /*!< GPIO number that used by LED strip */ + uint32_t max_leds; /*!< Maximum number of LEDs that can be controlled in a single strip */ + led_model_t led_model; /*!< Specifies the LED strip model (e.g., WS2812, SK6812) */ + led_color_component_format_t color_component_format; /*!< Specifies the order of color components in each pixel. + Use helper macros like `LED_STRIP_COLOR_COMPONENT_FMT_GRB` to set the format */ + /*!< LED strip extra driver flags */ + struct led_strip_extra_flags { uint32_t invert_out: 1; /*!< Invert output signal */ - } flags; /*!< Extra driver flags */ + } flags; /*!< Extra driver flags */ } led_strip_config_t; #ifdef __cplusplus diff --git a/led_strip/src/led_strip_common.c b/led_strip/src/led_strip_common.c deleted file mode 100644 index 6338e9ffed..0000000000 --- a/led_strip/src/led_strip_common.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include "esp_log.h" -#include "esp_check.h" -#include "esp_bit_defs.h" -#include "led_strip_common.h" - -static const char *TAG = "led_strip_common"; - -esp_err_t led_strip_set_color_order(uint8_t *led_pixel_offset, const uint8_t pixel_order, const uint8_t bytes_per_pixel) -{ - if (pixel_order) { - uint8_t r_order = (pixel_order >> 0) & 0x03; - uint8_t g_order = (pixel_order >> 2) & 0x03; - uint8_t b_order = (pixel_order >> 4) & 0x03; - uint8_t w_order = (pixel_order >> 6) & 0x03; - uint8_t mask = bytes_per_pixel == 3 ? BIT(r_order) | BIT(g_order) | BIT(b_order) : BIT(r_order) | BIT(g_order) | BIT(b_order) | BIT(w_order); - // Check for invalid values - ESP_RETURN_ON_FALSE(__builtin_popcount(mask) == bytes_per_pixel && r_order < bytes_per_pixel && g_order < bytes_per_pixel && b_order < bytes_per_pixel && w_order < bytes_per_pixel, - ESP_ERR_INVALID_ARG, TAG, "invalid order argument"); - led_pixel_offset[LED_PIXEL_INDEX_RED] = r_order; - led_pixel_offset[LED_PIXEL_INDEX_GREEN] = g_order; - led_pixel_offset[LED_PIXEL_INDEX_BLUE] = b_order; - led_pixel_offset[LED_PIXEL_INDEX_WHITE] = w_order; - } else { - // If pixel_order is not set, set default GRB(GRBW) order as fallback path - led_pixel_offset[LED_PIXEL_INDEX_RED] = 1; - led_pixel_offset[LED_PIXEL_INDEX_GREEN] = 0; - led_pixel_offset[LED_PIXEL_INDEX_BLUE] = 2; - led_pixel_offset[LED_PIXEL_INDEX_WHITE] = 3; - } - return ESP_OK; -} diff --git a/led_strip/src/led_strip_common.h b/led_strip/src/led_strip_common.h deleted file mode 100644 index e4ca2811f3..0000000000 --- a/led_strip/src/led_strip_common.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include -#include "esp_err.h" -#include "led_strip_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @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 Set LED color order - * - * @param led_pixel_offset Each pixel's offset - * @param pixel_order `pixel_order` parameter in LED strip configuration - * @param bytes_per_pixel bytes per pixel - * @return - * - ESP_OK: Set LED color order successfully - * - ESP_ERR_INVALID_ARG: Set LED color order failed because of invalid argument - */ -esp_err_t led_strip_set_color_order(uint8_t *led_pixel_offset, const uint8_t pixel_order, const uint8_t bytes_per_pixel); - -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/led_strip/src/led_strip_rmt_dev.c b/led_strip/src/led_strip_rmt_dev.c index 15a2ef4a48..4a38f4eee7 100644 --- a/led_strip/src/led_strip_rmt_dev.c +++ b/led_strip/src/led_strip_rmt_dev.c @@ -12,7 +12,6 @@ #include "led_strip.h" #include "led_strip_interface.h" #include "led_strip_rmt_encoder.h" -#include "led_strip_common.h" #define LED_STRIP_RMT_DEFAULT_RESOLUTION 10000000 // 10MHz resolution #define LED_STRIP_RMT_DEFAULT_TRANS_QUEUE_SIZE 4 @@ -31,7 +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]; + led_color_component_format_t component_fmt; uint8_t pixel_buf[]; } led_strip_rmt_obj; @@ -39,33 +38,36 @@ 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"); + + led_color_component_format_t component_fmt = rmt_strip->component_fmt; 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; - // 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) { - pixel_buf[start + offset[LED_PIXEL_INDEX_WHITE]] = 0; + + pixel_buf[start + component_fmt.format.r_pos] = red & 0xFF; + pixel_buf[start + component_fmt.format.g_pos] = green & 0xFF; + pixel_buf[start + component_fmt.format.b_pos] = blue & 0xFF; + if (component_fmt.format.num_components > 3) { + pixel_buf[start + component_fmt.format.w_pos] = 0; } + return ESP_OK; } static esp_err_t led_strip_rmt_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) { led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); + led_color_component_format_t component_fmt = rmt_strip->component_fmt; 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"); + ESP_RETURN_ON_FALSE(component_fmt.format.num_components == 4, ESP_ERR_INVALID_ARG, TAG, "led doesn't have 4 components"); + 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 - 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; + + pixel_buf[start + component_fmt.format.r_pos] = red & 0xFF; + pixel_buf[start + component_fmt.format.g_pos] = green & 0xFF; + pixel_buf[start + component_fmt.format.b_pos] = blue & 0xFF; + pixel_buf[start + component_fmt.format.w_pos] = white & 0xFF; + return ESP_OK; } @@ -106,8 +108,26 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l led_strip_rmt_obj *rmt_strip = NULL; esp_err_t ret = ESP_OK; ESP_GOTO_ON_FALSE(led_config && rmt_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - ESP_GOTO_ON_FALSE(led_config->bytes_per_pixel == 3 || led_config->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel bytes"); - uint8_t bytes_per_pixel = led_config->bytes_per_pixel; + led_color_component_format_t component_fmt = led_config->color_component_format; + // If R/G/B order is not specified, set default GRB order as fallback + if (component_fmt.format_id == 0) { + component_fmt = LED_STRIP_COLOR_COMPONENT_FMT_GRB; + } + // check the validation of the color component format + uint8_t mask = 0; + if (component_fmt.format.num_components == 3) { + mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos); + // Check for invalid values + ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG, "invalid order argument"); + } else if (component_fmt.format.num_components == 4) { + mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos) | BIT(component_fmt.format.w_pos); + // Check for invalid values + ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG, "invalid order argument"); + } else { + ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid number of color components: %d", component_fmt.format.num_components); + } + // TODO: we assume each color component is 8 bits, may need to support other configurations in the future, e.g. 10bits per color component? + uint8_t bytes_per_pixel = component_fmt.format.num_components; rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel); ESP_GOTO_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for rmt strip"); uint32_t resolution = rmt_config->resolution_hz ? rmt_config->resolution_hz : LED_STRIP_RMT_DEFAULT_RESOLUTION; @@ -138,8 +158,8 @@ esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const l .led_model = led_config->led_model }; ESP_GOTO_ON_ERROR(rmt_new_led_strip_encoder(&strip_encoder_conf, &rmt_strip->strip_encoder), err, TAG, "create LED strip encoder failed"); - ESP_GOTO_ON_ERROR(led_strip_set_color_order(rmt_strip->led_pixel_offset, led_config->pixel_order, bytes_per_pixel), err, TAG, "adjust color order failed"); + rmt_strip->component_fmt = component_fmt; 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; diff --git a/led_strip/src/led_strip_rmt_dev_idf4.c b/led_strip/src/led_strip_rmt_dev_idf4.c deleted file mode 100644 index 091ccf8106..0000000000 --- a/led_strip/src/led_strip_rmt_dev_idf4.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include -#include -#include -#include "esp_log.h" -#include "esp_check.h" -#include "driver/rmt.h" -#include "led_strip.h" -#include "led_strip_interface.h" -#include "led_strip_common.h" - -static const char *TAG = "led_strip_rmt"; - -#define WS2812_T0H_NS (300) -#define WS2812_T0L_NS (900) -#define WS2812_T1H_NS (900) -#define WS2812_T1L_NS (300) - -#define SK6812_T0H_NS (300) -#define SK6812_T0L_NS (900) -#define SK6812_T1H_NS (600) -#define SK6812_T1L_NS (600) - -#define LED_STRIP_RESET_MS (10) - -// the memory size of each RMT channel, in words (4 bytes) -#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 -#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 64 -#else -#define LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS 48 -#endif - -static uint32_t led_t0h_ticks = 0; -static uint32_t led_t1h_ticks = 0; -static uint32_t led_t0l_ticks = 0; -static uint32_t led_t1l_ticks = 0; - -typedef struct { - led_strip_t base; - 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; - -static void IRAM_ATTR ws2812_rmt_adapter(const void *src, rmt_item32_t *dest, size_t src_size, - size_t wanted_num, size_t *translated_size, size_t *item_num) -{ - if (src == NULL || dest == NULL) { - *translated_size = 0; - *item_num = 0; - return; - } - const rmt_item32_t bit0 = {{{ led_t0h_ticks, 1, led_t0l_ticks, 0 }}}; //Logical 0 - const rmt_item32_t bit1 = {{{ led_t1h_ticks, 1, led_t1l_ticks, 0 }}}; //Logical 1 - size_t size = 0; - size_t num = 0; - uint8_t *psrc = (uint8_t *)src; - rmt_item32_t *pdest = dest; - while (size < src_size && num < wanted_num) { - for (int i = 0; i < 8; i++) { - // MSB first - if (*psrc & (1 << (7 - i))) { - pdest->val = bit1.val; - } else { - pdest->val = bit0.val; - } - num++; - pdest++; - } - size++; - psrc++; - } - *translated_size = size; - *item_num = num; -} - -static esp_err_t led_strip_rmt_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) -{ - 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; - 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 + offset[LED_PIXEL_INDEX_WHITE]] = 0; - } - return ESP_OK; -} - -static esp_err_t led_strip_rmt_refresh(led_strip_t *strip) -{ - led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); - ESP_RETURN_ON_ERROR(rmt_write_sample(rmt_strip->rmt_channel, rmt_strip->buffer, rmt_strip->strip_len * rmt_strip->bytes_per_pixel, true), TAG, - "transmit RMT samples failed"); - vTaskDelay(pdMS_TO_TICKS(LED_STRIP_RESET_MS)); - return ESP_OK; -} - -static esp_err_t led_strip_rmt_clear(led_strip_t *strip) -{ - led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); - // Write zero to turn off all LEDs - memset(rmt_strip->buffer, 0, rmt_strip->strip_len * rmt_strip->bytes_per_pixel); - return led_strip_rmt_refresh(strip); -} - -static esp_err_t led_strip_rmt_del(led_strip_t *strip) -{ - led_strip_rmt_obj *rmt_strip = __containerof(strip, led_strip_rmt_obj, base); - ESP_RETURN_ON_ERROR(rmt_driver_uninstall(rmt_strip->rmt_channel), TAG, "uninstall RMT driver failed"); - free(rmt_strip); - return ESP_OK; -} - -esp_err_t led_strip_new_rmt_device(const led_strip_config_t *led_config, const led_strip_rmt_config_t *dev_config, led_strip_handle_t *ret_strip) -{ - led_strip_rmt_obj *rmt_strip = NULL; - esp_err_t ret = ESP_OK; - ESP_RETURN_ON_FALSE(led_config && dev_config && ret_strip, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(dev_config->flags.with_dma == 0, ESP_ERR_NOT_SUPPORTED, TAG, "DMA is not supported"); - ESP_RETURN_ON_FALSE(led_config->bytes_per_pixel == 3 || led_config->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "invalid led_pixel bytes"); - uint8_t bytes_per_pixel = led_config->bytes_per_pixel; - - // allocate memory for led_strip object - rmt_strip = calloc(1, sizeof(led_strip_rmt_obj) + led_config->max_leds * bytes_per_pixel); - ESP_RETURN_ON_FALSE(rmt_strip, ESP_ERR_NO_MEM, TAG, "request memory for les_strip failed"); - - // install RMT channel driver - rmt_config_t config = RMT_DEFAULT_CONFIG_TX(led_config->strip_gpio_num, dev_config->rmt_channel); - // set the minimal clock division because the LED strip needs a high clock resolution - config.clk_div = 2; - - uint8_t mem_block_num = 2; - // override the default value if the user specify the mem block size - if (dev_config->mem_block_symbols) { - mem_block_num = (dev_config->mem_block_symbols + LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS / 2) / LED_STRIP_RMT_DEFAULT_MEM_BLOCK_SYMBOLS; - } - config.mem_block_num = mem_block_num; - - ESP_GOTO_ON_ERROR(rmt_config(&config), err, TAG, "RMT config failed"); - ESP_GOTO_ON_ERROR(rmt_driver_install(config.channel, 0, 0), err, TAG, "RMT install failed"); - - uint32_t counter_clk_hz = 0; - rmt_get_counter_clock((rmt_channel_t)dev_config->rmt_channel, &counter_clk_hz); - // ns -> ticks - float ratio = (float)counter_clk_hz / 1e9; - if (led_config->led_model == LED_MODEL_WS2812) { - led_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS); - led_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS); - led_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS); - led_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS); - } else if (led_config->led_model == LED_MODEL_SK6812) { - led_t0h_ticks = (uint32_t)(ratio * SK6812_T0H_NS); - led_t0l_ticks = (uint32_t)(ratio * SK6812_T0L_NS); - led_t1h_ticks = (uint32_t)(ratio * SK6812_T1H_NS); - led_t1l_ticks = (uint32_t)(ratio * SK6812_T1L_NS); - } else { - assert(false); - } - - // adapter to translates the LES strip date frame into RMT symbols - rmt_translator_init((rmt_channel_t)dev_config->rmt_channel, ws2812_rmt_adapter); - ESP_GOTO_ON_ERROR(led_strip_set_color_order(rmt_strip->led_pixel_offset, led_config->pixel_order, bytes_per_pixel), err, TAG, "adjust color order failed"); - - 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; - rmt_strip->base.set_pixel = led_strip_rmt_set_pixel; - rmt_strip->base.refresh = led_strip_rmt_refresh; - rmt_strip->base.clear = led_strip_rmt_clear; - rmt_strip->base.del = led_strip_rmt_del; - - *ret_strip = &rmt_strip->base; - return ESP_OK; - -err: - if (rmt_strip) { - free(rmt_strip); - } - return ret; -} diff --git a/led_strip/src/led_strip_spi_dev.c b/led_strip/src/led_strip_spi_dev.c index 248c474cf5..81e0259ceb 100644 --- a/led_strip/src/led_strip_spi_dev.c +++ b/led_strip/src/led_strip_spi_dev.c @@ -10,10 +10,8 @@ #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 "led_strip_common.h" #define LED_STRIP_SPI_DEFAULT_RESOLUTION (2.5 * 1000 * 1000) // 2.5MHz resolution #define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4 @@ -29,7 +27,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]; + led_color_component_format_t component_fmt; uint8_t pixel_buf[]; } led_strip_spi_obj; @@ -56,32 +54,35 @@ static esp_err_t led_strip_spi_set_pixel(led_strip_t *strip, uint32_t index, uin // 3 pixels take 72bits(9bytes) 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; + led_color_component_format_t component_fmt = spi_strip->component_fmt; memset(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); - __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, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * LED_PIXEL_INDEX_WHITE]); + + __led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.r_pos]); + __led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.g_pos]); + __led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.b_pos]); + if (component_fmt.format.num_components > 3) { + __led_strip_spi_bit(0, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.w_pos]); } + return ESP_OK; } static esp_err_t led_strip_spi_set_pixel_rgbw(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) { led_strip_spi_obj *spi_strip = __containerof(strip, led_strip_spi_obj, base); + led_color_component_format_t component_fmt = spi_strip->component_fmt; ESP_RETURN_ON_FALSE(index < spi_strip->strip_len, ESP_ERR_INVALID_ARG, TAG, "index out of maximum number of LEDs"); - ESP_RETURN_ON_FALSE(spi_strip->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, TAG, "wrong LED pixel format, expected 4 bytes per pixel"); + ESP_RETURN_ON_FALSE(component_fmt.format.num_components == 4, ESP_ERR_INVALID_ARG, TAG, "led doesn't have 4 components"); + // 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(pixel_buf + start, 0, spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); - __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]]); + + __led_strip_spi_bit(red, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.r_pos]); + __led_strip_spi_bit(green, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.g_pos]); + __led_strip_spi_bit(blue, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.b_pos]); + __led_strip_spi_bit(white, &pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * component_fmt.format.w_pos]); return ESP_OK; } @@ -130,8 +131,26 @@ esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const l led_strip_spi_obj *spi_strip = NULL; esp_err_t ret = ESP_OK; ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - ESP_GOTO_ON_FALSE(led_config->bytes_per_pixel == 3 || led_config->bytes_per_pixel == 4, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel bytes"); - uint8_t bytes_per_pixel = led_config->bytes_per_pixel; + led_color_component_format_t component_fmt = led_config->color_component_format; + // If R/G/B order is not specified, set default GRB order as fallback + if (component_fmt.format_id == 0) { + component_fmt = LED_STRIP_COLOR_COMPONENT_FMT_GRB; + } + // check the validation of the color component format + uint8_t mask = 0; + if (component_fmt.format.num_components == 3) { + mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos); + // Check for invalid values + ESP_RETURN_ON_FALSE(mask == 0x07, ESP_ERR_INVALID_ARG, TAG, "invalid order argument"); + } else if (component_fmt.format.num_components == 4) { + mask = BIT(component_fmt.format.r_pos) | BIT(component_fmt.format.g_pos) | BIT(component_fmt.format.b_pos) | BIT(component_fmt.format.w_pos); + // Check for invalid values + ESP_RETURN_ON_FALSE(mask == 0x0F, ESP_ERR_INVALID_ARG, TAG, "invalid order argument"); + } else { + ESP_RETURN_ON_FALSE(false, ESP_ERR_INVALID_ARG, TAG, "invalid number of color components: %d", component_fmt.format.num_components); + } + // TODO: we assume each color component is 8 bits, may need to support other configurations in the future, e.g. 10bits per color component? + uint8_t bytes_per_pixel = component_fmt.format.num_components; uint32_t mem_caps = MALLOC_CAP_DEFAULT; if (spi_config->flags.with_dma) { // DMA buffer must be placed in internal SRAM @@ -185,8 +204,8 @@ esp_err_t led_strip_new_spi_device(const led_strip_config_t *led_config, const l // clock_resolution between 2.2MHz to 2.8MHz is supported 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); - ESP_GOTO_ON_ERROR(led_strip_set_color_order(spi_strip->led_pixel_offset, led_config->pixel_order, bytes_per_pixel), err, TAG, "adjust color order failed"); + spi_strip->component_fmt = component_fmt; 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;