From f60914c7d09a7bca8b603d7940c677e9bdd95f32 Mon Sep 17 00:00:00 2001 From: moon2 <moon2protonmail@protonmail.com> Date: Thu, 18 May 2023 23:52:19 +0200 Subject: [PATCH] added led support kinda --- components/badge23/CMakeLists.txt | 1 + components/badge23/espan.c | 2 +- components/badge23/include/badge23/leds.h | 1 - components/badge23/leds.c | 274 ++++++------------ .../espressif__led_strip/CMakeLists.txt | 4 + components/espressif__led_strip/README.md | 16 + .../espressif__led_strip/idf_component.yml | 7 + .../espressif__led_strip/include/led_strip.h | 147 ++++++++++ .../led_strip_rmt_ws2812.c | 208 +++++++++++++ components/espressif__led_strip/license.txt | 202 +++++++++++++ 10 files changed, 676 insertions(+), 186 deletions(-) create mode 100644 components/espressif__led_strip/CMakeLists.txt create mode 100644 components/espressif__led_strip/README.md create mode 100644 components/espressif__led_strip/idf_component.yml create mode 100644 components/espressif__led_strip/include/led_strip.h create mode 100644 components/espressif__led_strip/led_strip_rmt_ws2812.c create mode 100644 components/espressif__led_strip/license.txt diff --git a/components/badge23/CMakeLists.txt b/components/badge23/CMakeLists.txt index 31354d5922..60c1009dc4 100644 --- a/components/badge23/CMakeLists.txt +++ b/components/badge23/CMakeLists.txt @@ -12,4 +12,5 @@ idf_component_register( include REQUIRES gc9a01 + espressif__led_strip ) diff --git a/components/badge23/espan.c b/components/badge23/espan.c index d510579826..7d7afcf889 100644 --- a/components/badge23/espan.c +++ b/components/badge23/espan.c @@ -57,7 +57,7 @@ void os_app_main(void) set_global_vol_dB(-90); audio_init(); - //leds_init(); + leds_init(); captouch_init(); vTaskDelay(2000 / portTICK_PERIOD_MS); diff --git a/components/badge23/include/badge23/leds.h b/components/badge23/include/badge23/leds.h index f86056cb74..361f4ab1ae 100644 --- a/components/badge23/include/badge23/leds.h +++ b/components/badge23/include/badge23/leds.h @@ -2,7 +2,6 @@ #include <stdint.h> void leds_init(); -void leds_animate(int leaf); void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue); void leds_set_single_hsv(uint8_t index, float hue, float sat, float value); void leds_update(); diff --git a/components/badge23/leds.c b/components/badge23/leds.c index 5148e44c67..7f8d09ea15 100644 --- a/components/badge23/leds.c +++ b/components/badge23/leds.c @@ -1,15 +1,20 @@ -#include "badge23/leds.h" - -#include "driver/spi_master.h" - #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <freertos/queue.h> #include <stdio.h> #include <string.h> #include <math.h> - #include "esp_system.h" +#include "badge23/leds.h" +#include "../../../revision_config.h" + +#ifdef HARDWARE_REVISION_01 +#define LED_SPI_PORT +#endif + +#ifdef HARDWARE_REVISION_04 +#define LED_ASYNC_PORT +#endif typedef struct leds_cfg { int leaf; @@ -19,25 +24,7 @@ typedef struct leds_cfg { int timer; } leds_cfg_t; -static QueueHandle_t leds_queue = NULL; static leds_cfg_t active_leds[11]; -static void leds_task(void* arg); - -#include "badge23/apa102LEDStrip.h" -static struct apa102LEDStrip leds; - -//SPI Vars -static spi_device_handle_t spi_led; -static spi_transaction_t spiTransObject; -static esp_err_t ret; -static spi_bus_config_t buscfg; -static spi_device_interface_config_t devcfg; - -#define totalPixels 40 -#define bytesPerPixel 4 -#define maxValuePerColour 255 -#define maxSPIFrameInBytes 8000 -#define maxSPIFrequency 10000000 struct RGB { @@ -128,6 +115,23 @@ struct RGB HSVToRGB(struct HSV hsv) { return rgb; } +#ifdef LED_SPI_PORT +#include "driver/spi_master.h" +#include "badge23/apa102LEDStrip.h" + +#define totalPixels 40 +#define bytesPerPixel 4 + +static struct apa102LEDStrip leds; +static spi_device_handle_t spi_led; +static spi_transaction_t spiTransObject; +static esp_err_t ret; +static spi_bus_config_t buscfg; +static spi_device_interface_config_t devcfg; + +#define maxSPIFrameInBytes 8000 +#define maxSPIFrequency 10000000 + void renderLEDs() { spi_device_queue_trans(spi_led, &spiTransObject, portMAX_DELAY); @@ -158,75 +162,9 @@ static int setupSPI() return ret; } -static uint8_t black[] = {0,0,0}; - -static const uint8_t pl[][9] = { - {39, 0, 1, 2, 3, 4, 5, 6, 7}, - {3, 4, 5, 6, 7, 8, 9, 10, 11}, - {7, 8, 9, 10, 11, 12, 13, 14, 15}, - {11, 12, 13, 14, 15, 16, 17, 18, 19}, - {15, 16, 17, 18, 19, 20, 21, 22, 23}, - {19, 20, 21, 22, 23, 24, 25, 26, 27}, - {23, 24, 25, 26, 27, 28, 29, 30, 31}, - {27, 28, 29, 30, 31, 32, 33, 34, 35}, - {31, 32, 33, 34, 35, 36, 37, 38, 39}, - {35, 36, 37, 38, 39, 0, 1, 2, 3} - }; - -static const int8_t pan_leds[][11][2] = { - { - {pl[0][4], pl[0][4]}, {pl[0][3], pl[0][5]}, {pl[0][2], pl[0][6]}, {pl[0][1], pl[0][7]}, {pl[0][0], pl[0][8]}, - {pl[4][0], pl[6][8]}, {pl[4][1], pl[6][7]}, {pl[4][2], pl[6][6]}, {pl[4][3], pl[6][5]}, {pl[4][4], pl[6][4]} - ,{-1, -1} - }, - { - {pl[2][4], pl[0][4]}, {pl[2][3], pl[0][5]}, {pl[2][2], pl[0][6]}, {pl[2][1], pl[0][7]}, {pl[2][0], pl[0][8]}, - {pl[6][8], pl[6][0]}, {pl[6][6], pl[6][1]}, {pl[6][6], pl[6][2]}, {pl[6][5], pl[6][3]}, {pl[6][4], pl[6][4]} - ,{-1, -1} - }, - { - {pl[2][4], pl[2][4]}, {pl[2][3], pl[2][5]}, {pl[2][2], pl[2][6]}, {pl[2][1], pl[2][7]}, {pl[2][0], pl[2][8]}, - {pl[6][0], pl[8][8]}, {pl[6][1], pl[8][7]}, {pl[6][2], pl[8][6]}, {pl[6][3], pl[8][5]}, {pl[6][4], pl[8][4]} - ,{-1, -1} - }, - { - {pl[4][4], pl[2][4]}, {pl[4][3], pl[2][5]}, {pl[4][2], pl[2][6]}, {pl[4][1], pl[2][7]}, {pl[4][0], pl[2][8]}, - {pl[8][8], pl[8][0]}, {pl[8][6], pl[8][1]}, {pl[8][6], pl[8][2]}, {pl[8][5], pl[8][3]}, {pl[8][4], pl[8][4]} - ,{-1, -1} - }, - { - {pl[4][4], pl[4][4]}, {pl[4][3], pl[4][5]}, {pl[4][2], pl[4][6]}, {pl[4][1], pl[4][7]}, {pl[4][0], pl[4][8]}, - {pl[8][0], pl[0][8]}, {pl[8][1], pl[0][7]}, {pl[8][2], pl[0][6]}, {pl[8][3], pl[0][5]}, {pl[8][4], pl[0][4]} - ,{-1, -1} - }, - { - {pl[6][4], pl[4][4]}, {pl[6][3], pl[4][5]}, {pl[6][2], pl[4][6]}, {pl[6][1], pl[4][7]}, {pl[6][0], pl[4][8]}, - {pl[0][8], pl[0][0]}, {pl[0][6], pl[0][1]}, {pl[0][6], pl[0][2]}, {pl[0][5], pl[0][3]}, {pl[0][4], pl[0][4]} - ,{-1, -1} - }, - { - {pl[6][4], pl[6][4]}, {pl[6][3], pl[6][5]}, {pl[6][2], pl[6][6]}, {pl[6][1], pl[6][7]}, {pl[6][0], pl[6][8]}, - {pl[0][0], pl[6][2]}, {pl[0][1], pl[2][7]}, {pl[0][2], pl[2][6]}, {pl[0][3], pl[2][5]}, {pl[0][4], pl[2][4]} - ,{-1, -1} - }, - { - {pl[8][4], pl[6][4]}, {pl[8][3], pl[6][5]}, {pl[8][2], pl[6][6]}, {pl[8][1], pl[6][7]}, {pl[8][0], pl[6][8]}, - {pl[2][8], pl[2][0]}, {pl[2][6], pl[2][1]}, {pl[2][6], pl[2][2]}, {pl[2][5], pl[2][3]}, {pl[2][4], pl[2][4]} - ,{-1, -1} - }, - { - {pl[8][4], pl[8][4]}, {pl[8][3], pl[8][5]}, {pl[8][2], pl[8][6]}, {pl[8][1], pl[8][7]}, {pl[8][0], pl[8][8]}, - {pl[2][0], pl[4][4]}, {pl[2][1], pl[4][7]}, {pl[2][2], pl[4][6]}, {pl[2][3], pl[4][5]}, {pl[2][4], pl[4][4]} - ,{-1, -1} - }, - { - {pl[0][4], pl[8][4]}, {pl[0][3], pl[8][5]}, {pl[0][2], pl[8][6]}, {pl[0][1], pl[8][7]}, {pl[0][0], pl[8][8]}, - {pl[4][8], pl[4][0]}, {pl[4][6], pl[4][1]}, {pl[4][6], pl[4][2]}, {pl[4][5], pl[4][3]}, {pl[4][4], pl[4][4]} - ,{-1, -1} - }, - - }; - +static void set_single_led(uint8_t index, uint8_t[3] c){ + setPixel(&leds, index, c); +} static void _leds_init() { leds_queue = xQueueCreate(10, sizeof(leds_cfg_t)); @@ -244,105 +182,82 @@ static void _leds_init() { TaskHandle_t handle; //xTaskCreate(&leds_task, "LEDs player", 4096, NULL, configMAX_PRIORITIES - 2, &handle); } +#endif + +#ifdef LED_ASYNC_PORT +#include "../../espressif__led_strip/include/led_strip.h" +led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num); + +#define LED_GPIO_NUM 14 +#define LED_RMT_CHAN 0 + +#if 0 +//ESP-IDF 5.0 for reference +led_strip_handle_t led_strip; + +/* LED strip initialization with the GPIO and pixels number*/ +led_strip_config_t strip_config = { + .strip_gpio_num = 14, // The GPIO that connected to the LED strip's data line + .max_leds = 40, // 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 (useful when your hardware has a level inverter) +}; -static bool leds_active(void) -{ - for(size_t i=0; i<sizeof(active_leds) / sizeof(active_leds[0]); i++) { - if(active_leds[i].size != active_leds[i].position) { - return true; - } - } - return false; -} - - -static void leds_task(void* arg) { - leds_cfg_t leds_; - - static int timer = 0; - - while(true) { - if(xQueueReceive(leds_queue, &leds_, 1)) { - leds_.position = 0; - active_leds[leds_.slot] = leds_; - } - - if(leds_active()) { - for(int i=0; i<40; i++) { - setPixel(&leds, i, black); - } - - for(size_t i=0; i<sizeof(active_leds) / sizeof(active_leds[0]); i++) { - if(active_leds[i].size == active_leds[i].position) continue; - - int leaf = active_leds[i].leaf; - int position = active_leds[i].position; - - uint8_t c[] = {0,0,0}; - if(leaf % 2 == 0) - c[0] = 32; - else - c[2] = 32; - - struct RGB rgb = HSVToRGB((struct HSV){leaf/9.*360,1,1}); - c[0] = rgb.R / 4; - c[1] = rgb.G / 4; - c[2] = rgb.B / 4; - - if(pan_leds[leaf][position][0] >= 0) - setPixel(&leds, pan_leds[leaf][position][0], c); - if(pan_leds[leaf][position][1] >= 0) - setPixel(&leds, pan_leds[leaf][position][1], c); +led_strip_rmt_config_t rmt_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, // different clock source can lead to different power consumption + .resolution_hz = 10 * 1000 * 1000, // 10MHz + .flags.with_dma = true, // whether to enable the DMA feature +}; - if(active_leds[i].timer-- == 0) { - active_leds[i].timer = 2; - active_leds[i].position += 1; - } +static void renderLEDs() +{ + ESP_ERROR_CHECK(led_strip_refresh(led_strip)); - } +} - renderLEDs(); - timer = 30; - } +void set_single_led(int led, uint8_t c[3]) +{ + led = ((39-led) + 1 + 32)%40; + ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, led, c[0], c[1], c[2])); +} - static int phase = 0; +static void _leds_init() { + memset(active_leds, 0 , sizeof(active_leds)); - if(!leds_active()) { - // background anim + ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); - if(timer-- == 0) { - timer = 60; - for(int i=0; i<40; i++) { - setPixel(&leds, i, black); - } + TaskHandle_t handle; + xTaskCreate(&leds_task, "LEDs player", 4096, NULL, configMAX_PRIORITIES - 2, &handle); +} +#endif - if(phase++ == 360) { - phase = 0; - } +led_strip_t * led_strip; - uint8_t c[] = {0,0,0}; +static void _leds_init(){ + memset(active_leds, 0 , sizeof(active_leds)); + led_strip = led_strip_init(LED_RMT_CHAN, LED_GPIO_NUM, 40); +} - for(int i=0; i<40; i++) { - struct RGB rgb = HSVToRGB((struct HSV){(phase+i*3) % 360,1,0.125}); - c[0] = rgb.R / 1; - c[1] = rgb.G / 1; - c[2] = rgb.B / 1; - setPixel(&leds, i, c); - } +void set_single_led(uint8_t index, uint8_t c[3]){ + index = ((39-index) + 1 + 32)%40; + led_strip->set_pixel(led_strip, index, c[0], c[1], c[2]); +} - renderLEDs(); - } - } - } +static void renderLEDs(){ + led_strip->refresh(led_strip, 1000); } +#endif + void leds_set_single_rgb(uint8_t index, uint8_t red, uint8_t green, uint8_t blue){ uint8_t c[3]; c[0] = red; c[1] = green; c[2] = blue; - setPixel(&leds, index, c); + set_single_led(index, c); } + void leds_set_single_hsv(uint8_t index, float hue, float sat, float val){ struct RGB rgb; struct HSV hsv; @@ -356,22 +271,13 @@ void leds_set_single_hsv(uint8_t index, float hue, float sat, float val){ c[0] = rgb.R; c[1] = rgb.G; c[2] = rgb.B; - setPixel(&leds, index, c); + set_single_led(index, c); } void leds_update(){ - vTaskDelay(10 / portTICK_PERIOD_MS); + vTaskDelay(10 / portTICK_PERIOD_MS); //do we... renderLEDs(); - vTaskDelay(10 / portTICK_PERIOD_MS); + vTaskDelay(10 / portTICK_PERIOD_MS); //...need these? } void leds_init() { _leds_init(); } - -void leds_animate(int leaf) { - leds_cfg_t leds = {0,}; - - leds.leaf = leaf; - leds.slot = leaf; - leds.size = 11; - xQueueSend(leds_queue, &leds, 0); -} diff --git a/components/espressif__led_strip/CMakeLists.txt b/components/espressif__led_strip/CMakeLists.txt new file mode 100644 index 0000000000..fe4ca413a2 --- /dev/null +++ b/components/espressif__led_strip/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "led_strip_rmt_ws2812.c" + INCLUDE_DIRS "include" + PRIV_REQUIRES "driver" + ) diff --git a/components/espressif__led_strip/README.md b/components/espressif__led_strip/README.md new file mode 100644 index 0000000000..abf07898a5 --- /dev/null +++ b/components/espressif__led_strip/README.md @@ -0,0 +1,16 @@ +# LED Strip Component + +This directory contains an implementation for addressable LEDs using the RMT peripheral. + +It's compatible with: + +* [WS2812](http://www.world-semi.com/Certifications/WS2812B.html) +* SK68XX + +This component is used as part of the following ESP-IDF examples: +- [Blink Example](../../get-started/blink). +- [LED Strip Example](../../peripherals/rmt/led_strip). + +To learn more about how to use this component, please check API Documentation from header file [led_strip.h](./include/led_strip.h). + +Please note that this component is not considered to be a part of ESP-IDF stable API. It may change and it may be removed in the future releases. diff --git a/components/espressif__led_strip/idf_component.yml b/components/espressif__led_strip/idf_component.yml new file mode 100644 index 0000000000..8d2fc65337 --- /dev/null +++ b/components/espressif__led_strip/idf_component.yml @@ -0,0 +1,7 @@ +version: "1.1.0-alpha" +description: C driver, based on RMT peripheral, for WS2812 and SK6812 smart RGB diodes + +dependencies: + # Required IDF version + idf: + version: ">=4.0" diff --git a/components/espressif__led_strip/include/led_strip.h b/components/espressif__led_strip/include/led_strip.h new file mode 100644 index 0000000000..dcf7a62f8a --- /dev/null +++ b/components/espressif__led_strip/include/led_strip.h @@ -0,0 +1,147 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" + +/** +* @brief LED Strip Type +* +*/ +typedef struct led_strip_s led_strip_t; + +/** +* @brief LED Strip Device Type +* +*/ +typedef void *led_strip_dev_t; + +/** +* @brief Declare of LED Strip Type +* +*/ +struct led_strip_s { + /** + * @brief Set RGB for a specific pixel + * + * @param strip: LED strip + * @param index: index of pixel to set + * @param red: red part of color + * @param green: green part of color + * @param blue: blue part of color + * + * @return + * - ESP_OK: Set RGB for a specific pixel successfully + * - ESP_ERR_INVALID_ARG: Set RGB for a specific pixel failed because of invalid parameters + * - ESP_FAIL: Set RGB for a specific pixel failed because other error occurred + */ + esp_err_t (*set_pixel)(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue); + + /** + * @brief Refresh memory colors to LEDs + * + * @param strip: LED strip + * @param timeout_ms: timeout value for refreshing task + * + * @return + * - ESP_OK: Refresh successfully + * - ESP_ERR_TIMEOUT: Refresh failed because of timeout + * - ESP_FAIL: Refresh failed because some other error occurred + * + * @note: + * After updating the LED colors in the memory, a following invocation of this API is needed to flush colors to strip. + */ + esp_err_t (*refresh)(led_strip_t *strip, uint32_t timeout_ms); + + /** + * @brief Clear LED strip (turn off all LEDs) + * + * @param strip: LED strip + * @param timeout_ms: timeout value for clearing task + * + * @return + * - ESP_OK: Clear LEDs successfully + * - ESP_ERR_TIMEOUT: Clear LEDs failed because of timeout + * - ESP_FAIL: Clear LEDs failed because some other error occurred + */ + esp_err_t (*clear)(led_strip_t *strip, uint32_t timeout_ms); + + /** + * @brief Free LED strip resources + * + * @param strip: LED strip + * + * @return + * - ESP_OK: Free resources successfully + * - ESP_FAIL: Free resources failed because error occurred + */ + esp_err_t (*del)(led_strip_t *strip); +}; + +/** +* @brief LED Strip Configuration Type +* +*/ +typedef struct { + uint32_t max_leds; /*!< Maximum LEDs in a single strip */ + led_strip_dev_t dev; /*!< LED strip device (e.g. RMT channel, PWM channel, etc) */ +} led_strip_config_t; + +/** + * @brief Default configuration for LED strip + * + */ +#define LED_STRIP_DEFAULT_CONFIG(number, dev_hdl) \ + { \ + .max_leds = number, \ + .dev = dev_hdl, \ + } + +/** +* @brief Install a new ws2812 driver (based on RMT peripheral) +* +* @param config: LED strip configuration +* @return +* LED strip instance or NULL +*/ +led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config); + +/** + * @brief Init the RMT peripheral and LED strip configuration. + * + * @param[in] channel: RMT peripheral channel number. + * @param[in] gpio: GPIO number for the RMT data output. + * @param[in] led_num: number of addressable LEDs. + * @return + * LED strip instance or NULL + */ +led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num); + +/** + * @brief Denit the RMT peripheral. + * + * @param[in] strip: LED strip + * @return + * - ESP_OK + * - ESP_FAIL + */ +esp_err_t led_strip_denit(led_strip_t *strip); + +#ifdef __cplusplus +} +#endif diff --git a/components/espressif__led_strip/led_strip_rmt_ws2812.c b/components/espressif__led_strip/led_strip_rmt_ws2812.c new file mode 100644 index 0000000000..08c3dab499 --- /dev/null +++ b/components/espressif__led_strip/led_strip_rmt_ws2812.c @@ -0,0 +1,208 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include <stdlib.h> +#include <string.h> +#include <sys/cdefs.h> +#include "esp_log.h" +#include "esp_attr.h" +#include "led_strip.h" +#include "driver/rmt.h" + +#define RMT_TX_CHANNEL RMT_CHANNEL_0 + +static const char *TAG = "ws2812"; +#define STRIP_CHECK(a, str, goto_tag, ret_value, ...) \ + do \ + { \ + if (!(a)) \ + { \ + ESP_LOGE(TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + ret = ret_value; \ + goto goto_tag; \ + } \ + } while (0) + +#define WS2812_T0H_NS (350) +#define WS2812_T0L_NS (1000) +#define WS2812_T1H_NS (1000) +#define WS2812_T1L_NS (350) +#define WS2812_RESET_US (280) + +static uint32_t ws2812_t0h_ticks = 0; +static uint32_t ws2812_t1h_ticks = 0; +static uint32_t ws2812_t0l_ticks = 0; +static uint32_t ws2812_t1l_ticks = 0; + +typedef struct { + led_strip_t parent; + rmt_channel_t rmt_channel; + uint32_t strip_len; + uint8_t buffer[0]; +} ws2812_t; + +/** + * @brief Conver RGB data to RMT format. + * + * @note For WS2812, R,G,B each contains 256 different choices (i.e. uint8_t) + * + * @param[in] src: source data, to converted to RMT format + * @param[in] dest: place where to store the convert result + * @param[in] src_size: size of source data + * @param[in] wanted_num: number of RMT items that want to get + * @param[out] translated_size: number of source data that got converted + * @param[out] item_num: number of RMT items which are converted from source data + */ +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 = {{{ ws2812_t0h_ticks, 1, ws2812_t0l_ticks, 0 }}}; //Logical 0 + const rmt_item32_t bit1 = {{{ ws2812_t1h_ticks, 1, ws2812_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 ws2812_set_pixel(led_strip_t *strip, uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + esp_err_t ret = ESP_OK; + ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent); + STRIP_CHECK(index < ws2812->strip_len, "index out of the maximum number of leds", err, ESP_ERR_INVALID_ARG); + uint32_t start = index * 3; + // In thr order of GRB + ws2812->buffer[start + 0] = green & 0xFF; + ws2812->buffer[start + 1] = red & 0xFF; + ws2812->buffer[start + 2] = blue & 0xFF; + return ESP_OK; +err: + return ret; +} + +static esp_err_t ws2812_refresh(led_strip_t *strip, uint32_t timeout_ms) +{ + esp_err_t ret = ESP_OK; + ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent); + STRIP_CHECK(rmt_write_sample(ws2812->rmt_channel, ws2812->buffer, ws2812->strip_len * 3, true) == ESP_OK, + "transmit RMT samples failed", err, ESP_FAIL); + return rmt_wait_tx_done(ws2812->rmt_channel, pdMS_TO_TICKS(timeout_ms)); +err: + return ret; +} + +static esp_err_t ws2812_clear(led_strip_t *strip, uint32_t timeout_ms) +{ + ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent); + // Write zero to turn off all leds + memset(ws2812->buffer, 0, ws2812->strip_len * 3); + return ws2812_refresh(strip, timeout_ms); +} + +static esp_err_t ws2812_del(led_strip_t *strip) +{ + ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent); + free(ws2812); + return ESP_OK; +} + +led_strip_t *led_strip_new_rmt_ws2812(const led_strip_config_t *config) +{ + led_strip_t *ret = NULL; + STRIP_CHECK(config, "configuration can't be null", err, NULL); + + // 24 bits per led + uint32_t ws2812_size = sizeof(ws2812_t) + config->max_leds * 3; + ws2812_t *ws2812 = calloc(1, ws2812_size); + STRIP_CHECK(ws2812, "request memory for ws2812 failed", err, NULL); + + uint32_t counter_clk_hz = 0; + STRIP_CHECK(rmt_get_counter_clock((rmt_channel_t)config->dev, &counter_clk_hz) == ESP_OK, + "get rmt counter clock failed", err, NULL); + // ns -> ticks + float ratio = (float)counter_clk_hz / 1e9; + ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS); + ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS); + ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS); + ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS); + + // set ws2812 to rmt adapter + rmt_translator_init((rmt_channel_t)config->dev, ws2812_rmt_adapter); + + ws2812->rmt_channel = (rmt_channel_t)config->dev; + ws2812->strip_len = config->max_leds; + + ws2812->parent.set_pixel = ws2812_set_pixel; + ws2812->parent.refresh = ws2812_refresh; + ws2812->parent.clear = ws2812_clear; + ws2812->parent.del = ws2812_del; + + return &ws2812->parent; +err: + return ret; +} + +led_strip_t *led_strip_init(uint8_t channel, uint8_t gpio, uint16_t led_num) +{ + static led_strip_t *pStrip; + + rmt_config_t config = RMT_DEFAULT_CONFIG_TX(gpio, channel); + // set counter clock to 40MHz + config.clk_div = 2; + + ESP_ERROR_CHECK(rmt_config(&config)); + ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0)); + + // install ws2812 driver + led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(led_num, (led_strip_dev_t)config.channel); + + pStrip = led_strip_new_rmt_ws2812(&strip_config); + + if ( !pStrip ) { + ESP_LOGE(TAG, "install WS2812 driver failed"); + return NULL; + } + + // Clear LED strip (turn off all LEDs) + // This will fail for inverted output + //ESP_ERROR_CHECK(pStrip->clear(pStrip, 100)); + + return pStrip; +} + +esp_err_t led_strip_denit(led_strip_t *strip) +{ + ws2812_t *ws2812 = __containerof(strip, ws2812_t, parent); + ESP_ERROR_CHECK(rmt_driver_uninstall(ws2812->rmt_channel)); + return strip->del(strip); +} diff --git a/components/espressif__led_strip/license.txt b/components/espressif__led_strip/license.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/components/espressif__led_strip/license.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. -- GitLab