diff --git a/components/badge23/CMakeLists.txt b/components/badge23/CMakeLists.txt index 84f8a3084eab6174be7641dd9bd74b6580868f96..ad46a42657c98be4b317a9e471730ff4582a302b 100644 --- a/components/badge23/CMakeLists.txt +++ b/components/badge23/CMakeLists.txt @@ -1,15 +1,13 @@ idf_component_register( SRCS - apa102LEDStrip.c captouch.c espan.c - leds.c spio.c + leds.c INCLUDE_DIRS include REQUIRES flow3r_bsp st3m - espressif__led_strip bl00mbox ) diff --git a/components/badge23/apa102LEDStrip.c b/components/badge23/apa102LEDStrip.c deleted file mode 100644 index dceba6a6417b25f10428b21dd3b89ea99ee875dd..0000000000000000000000000000000000000000 --- a/components/badge23/apa102LEDStrip.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "badge23/apa102LEDStrip.h" -#include <math.h> -#include <stdio.h> -#include <stdlib.h> - -void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness) -{ - ledObject->_numLEDs = numLEDs; - ledObject->_bytesPerLED = bytesPerLED; - ledObject->_endFrameLength = 1;//round( (numLEDs/2)/8 ); - ledObject->_frameLength = (1+numLEDs+ledObject->_endFrameLength)*bytesPerLED; - ledObject->_globalBrightness = globalBrightness; - ledObject->LEDs = (unsigned char *)malloc(ledObject->_frameLength*sizeof(unsigned char)); - - //Start Frame - ledObject->LEDs[0] = 0; - ledObject->LEDs[1] = 0; - ledObject->LEDs[2] = 0; - ledObject->LEDs[3] = 0; - //Driver frame+PIXEL frames - for(ledObject->_counter=ledObject->_bytesPerLED; ledObject->_counter<ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter+=ledObject->_bytesPerLED) - { - ledObject->LEDs[ledObject->_counter] = ledObject->_globalBrightness; - ledObject->LEDs[ledObject->_counter+1] = 0; - ledObject->LEDs[ledObject->_counter+2] = 0; - ledObject->LEDs[ledObject->_counter+3] = 0; - } - //END frames - for(ledObject->_counter=ledObject->_frameLength-(ledObject->_endFrameLength*ledObject->_bytesPerLED); ledObject->_counter<ledObject->_frameLength; ledObject->_counter+=ledObject->_bytesPerLED) - { - ledObject->LEDs[ledObject->_counter] = 255; - ledObject->LEDs[ledObject->_counter+1] = 255; - ledObject->LEDs[ledObject->_counter+2] = 255; - ledObject->LEDs[ledObject->_counter+3] = 255; - } -} -void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour) -{ - ledObject->_counter = 4*(pixelIndex+1); - ledObject->LEDs[ ledObject->_counter + 1 ] = pixelColour[2]; - ledObject->LEDs[ ledObject->_counter + 2 ] = pixelColour[1]; - ledObject->LEDs[ ledObject->_counter + 3 ] = pixelColour[0]; -} -void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour) -{ - ledObject->_counter = 4*(pixelIndex+1); - pixelColour[2] = ledObject->LEDs[ ledObject->_counter + 1 ]; - pixelColour[1] = ledObject->LEDs[ ledObject->_counter + 2 ]; - pixelColour[0] = ledObject->LEDs[ ledObject->_counter + 3 ]; -} diff --git a/components/badge23/include/badge23/apa102LEDStrip.h b/components/badge23/include/badge23/apa102LEDStrip.h deleted file mode 100644 index da495abf628285dedd3197462267736473c1153e..0000000000000000000000000000000000000000 --- a/components/badge23/include/badge23/apa102LEDStrip.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef DEF_apa102LEDStrip -#define DEF_apa102LEDStrip - -struct apa102LEDStrip -{ - unsigned char *LEDs; - short int _frameLength; - short int _endFrameLength; - short int _numLEDs; - unsigned char _bytesPerLED; - short int _counter; - unsigned char _globalBrightness; -}; -void initLEDs(struct apa102LEDStrip *ledObject, short int numLEDs, unsigned char bytesPerLED, unsigned char globalBrightness); -void setPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour); -void getPixel(struct apa102LEDStrip *ledObject, short int pixelIndex, unsigned char *pixelColour); -#endif diff --git a/components/badge23/leds.c b/components/badge23/leds.c index 321910f719f3ba8b24eef8f6a7d30ca69f87ecfd..438f75ff84260cc4b0f74167698b13e6054de40f 100644 --- a/components/badge23/leds.c +++ b/components/badge23/leds.c @@ -8,6 +8,11 @@ #include "badge23/leds.h" #include "badge23/lock.h" +#include "flow3r_bsp.h" +#include "esp_log.h" + +static const char *TAG = "badge23-leds"; + static uint8_t leds_brightness = 69;; static uint8_t leds_slew_rate = 255; static bool leds_auto_update = 0; @@ -16,14 +21,6 @@ static uint8_t gamma_red[256]; static uint8_t gamma_green[256]; static uint8_t gamma_blue[256]; -#if defined(CONFIG_BADGE23_HW_GEN_P1) -#define LED_SPI_PORT -#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P6) -#define LED_ASYNC_PORT -#else -#error "leds not implemented for this badge generation" -#endif - typedef struct leds_cfg { int leaf; size_t size; @@ -127,99 +124,18 @@ 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); -} - -static int setupSPI() -{ - //Set up the Bus Config struct - buscfg.miso_io_num=-1; - buscfg.mosi_io_num=18; - buscfg.sclk_io_num=8; - buscfg.quadwp_io_num=-1; - buscfg.quadhd_io_num=-1; - buscfg.max_transfer_sz=maxSPIFrameInBytes; - - //Set up the SPI Device Configuration Struct - devcfg.clock_speed_hz=maxSPIFrequency; - devcfg.mode=0; - devcfg.spics_io_num=-1; - devcfg.queue_size=1; - - //Initialize the SPI driver - ret=spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO); - ESP_ERROR_CHECK(ret); - //Add SPI port to bus - ret=spi_bus_add_device(SPI2_HOST, &devcfg, &spi_led); - ESP_ERROR_CHECK(ret); - return ret; -} - -static void set_single_led(uint8_t index, uint8_t c[3]){ - setPixel(&leds, index, c); -} - -static void _leds_init() { - memset(active_leds, 0 , sizeof(active_leds)); - - setupSPI(); - initLEDs(&leds, totalPixels, bytesPerPixel, 255); - - //Set up SPI tx/rx storage Object - memset(&spiTransObject, 0, sizeof(spiTransObject)); - spiTransObject.length = leds._frameLength*8; - spiTransObject.tx_buffer = leds.LEDs; - - - //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 - -led_strip_t * led_strip; - -static void _leds_init(){ - memset(active_leds, 0 , sizeof(active_leds)); - led_strip = led_strip_init(LED_RMT_CHAN, LED_GPIO_NUM, 40); -} - 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]); + flow3r_bsp_leds_set_pixel(index, c[0], c[1], c[2]); } static void renderLEDs(){ - led_strip->refresh(led_strip, 1000); + esp_err_t ret = flow3r_bsp_leds_refresh(portMAX_DELAY); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "LED refresh failed: %s", esp_err_to_name(ret)); + } } -#endif - uint8_t led_get_slew(int16_t old, int16_t new, int16_t slew){ if(new > old + slew){ return old + slew; @@ -309,7 +225,14 @@ void leds_init(){ gamma_green[i] = i; gamma_blue[i] = i; } - _leds_init(); + + esp_err_t ret = flow3r_bsp_leds_init(); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "LED initialization failed: %s", esp_err_to_name(ret)); + abort(); + } + + ESP_LOGI(TAG, "LEDs initialized"); } void leds_set_brightness(uint8_t b){ diff --git a/components/espressif__led_strip/CMakeLists.txt b/components/espressif__led_strip/CMakeLists.txt deleted file mode 100644 index fe4ca413a21fb71e5db88c15f8958a1cb5756c78..0000000000000000000000000000000000000000 --- a/components/espressif__led_strip/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index abf07898a573224b1c692df8cbba9a67c954a580..0000000000000000000000000000000000000000 --- a/components/espressif__led_strip/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# 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 deleted file mode 100644 index 8d2fc6533719f36a7c4bcfa590c8d37bb63b9ba6..0000000000000000000000000000000000000000 --- a/components/espressif__led_strip/idf_component.yml +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index dcf7a62f8a9eaab4a5ccd092eda4a62647bf2636..0000000000000000000000000000000000000000 --- a/components/espressif__led_strip/include/led_strip.h +++ /dev/null @@ -1,147 +0,0 @@ -// 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 deleted file mode 100644 index 08c3dab499f59303bb584b1cfb4be127cd07e075..0000000000000000000000000000000000000000 --- a/components/espressif__led_strip/led_strip_rmt_ws2812.c +++ /dev/null @@ -1,208 +0,0 @@ -// 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 deleted file mode 100644 index d645695673349e3947e8e5ae42332d0ac3164cd7..0000000000000000000000000000000000000000 --- a/components/espressif__led_strip/license.txt +++ /dev/null @@ -1,202 +0,0 @@ - - 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. diff --git a/components/flow3r_bsp/CMakeLists.txt b/components/flow3r_bsp/CMakeLists.txt index fb597b10e5e6190bd9877177a99834701de6f01b..7d165308ddb41193fe16794ee21d2e6eaffe97a4 100644 --- a/components/flow3r_bsp/CMakeLists.txt +++ b/components/flow3r_bsp/CMakeLists.txt @@ -6,6 +6,9 @@ idf_component_register( flow3r_bsp_hwconfig.c flow3r_bsp_i2c.c flow3r_bsp_max98091.c + flow3r_bsp_leds.c + flow3r_bsp_rmtled.c + flow3r_bsp_spiled.c INCLUDE_DIRS . ) diff --git a/components/flow3r_bsp/flow3r_bsp.h b/components/flow3r_bsp/flow3r_bsp.h index 2d538189ce8a699dddc3a1d0ac334987f619452f..8fd857a7ecfd7901d2866b07abce050d6298eca0 100644 --- a/components/flow3r_bsp/flow3r_bsp.h +++ b/components/flow3r_bsp/flow3r_bsp.h @@ -121,4 +121,20 @@ esp_err_t flow3r_bsp_audio_read(void *dest, size_t size, size_t *bytes_read, Tic esp_err_t flow3r_bsp_audio_write(const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait); // Write audio codec register. Obviously very unsafe. Have fun. -void flow3r_bsp_audio_register_poke(uint8_t reg, uint8_t data); \ No newline at end of file +void flow3r_bsp_audio_register_poke(uint8_t reg, uint8_t data); + +#define FLOW3R_BSP_LED_COUNT 40 + +// Initialize LEDs. +esp_err_t flow3r_bsp_leds_init(void); + +// Set internal buffer for given LED to an RGB value. +// +// Index is a value in [0, FLOW3R_BSP_LED_COUNT). +// +// RGB values are in [0, 0xff]. +void flow3r_bsp_leds_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue); + +// Transmit from internal buffer into LEDs. This will block in case there +// already is a previous transmission happening. +esp_err_t flow3r_bsp_leds_refresh(TickType_t timeout_ms); \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_i2c.c b/components/flow3r_bsp/flow3r_bsp_i2c.c index f1695b81ec086f5953a8a0bc349f0113b7b53471..a704e31ff55d6144b9f7e2d3eca30542fa1982dd 100644 --- a/components/flow3r_bsp/flow3r_bsp_i2c.c +++ b/components/flow3r_bsp/flow3r_bsp_i2c.c @@ -3,6 +3,7 @@ #include "driver/i2c.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" +#include "esp_log.h" static SemaphoreHandle_t mutex; @@ -70,8 +71,10 @@ void flow3r_bsp_i2c_init(void) { mutex = xSemaphoreCreateMutex(); assert(mutex != NULL); - assert(i2c_param_config(0, &i2c_conf) == ESP_OK); - assert(i2c_driver_install(0, i2c_conf.mode, 0, 0, 0) == ESP_OK); + assert(i2c_param_config(I2C_NUM_0, &i2c_conf) == ESP_OK); + assert(i2c_driver_install(I2C_NUM_0, i2c_conf.mode, 0, 0, 0) == ESP_OK); + + flow3r_bsp_i2c_scan(); } // Take I2C bus lock. @@ -86,14 +89,30 @@ static void flow3r_bsp_i2c_put(void) { esp_err_t flow3r_bsp_i2c_write_to_device(uint8_t address, const uint8_t *buffer, size_t write_size, TickType_t ticks_to_wait) { flow3r_bsp_i2c_get(); - esp_err_t res = i2c_master_write_to_device(0, address, buffer, write_size, ticks_to_wait); + esp_err_t res = i2c_master_write_to_device(I2C_NUM_0, address, buffer, write_size, ticks_to_wait); flow3r_bsp_i2c_put(); return res; } esp_err_t flow3r_bsp_i2c_write_read_device(uint8_t address, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, TickType_t ticks_to_wait) { flow3r_bsp_i2c_get(); - esp_err_t res = i2c_master_write_read_device(0, address, write_buffer, write_size, read_buffer, read_size, ticks_to_wait); + esp_err_t res = i2c_master_write_read_device(I2C_NUM_0, address, write_buffer, write_size, read_buffer, read_size, ticks_to_wait); flow3r_bsp_i2c_put(); return res; +} + +void flow3r_bsp_i2c_scan(void) { + ESP_LOGI(TAG, "Scan: starting..."); + for (uint8_t i = 1; i < 127; i++) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, 1); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(I2C_NUM_0, cmd, 100 / portTICK_RATE_MS); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Scan: detected %02x", i); + } + } + ESP_LOGI(TAG, "Scan: done."); } \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_i2c.h b/components/flow3r_bsp/flow3r_bsp_i2c.h index f54ec6428e5cf89b267b8a2e8534015770e769ee..49a14fdbae4395ae7f10a671902245a2afb43663 100644 --- a/components/flow3r_bsp/flow3r_bsp_i2c.h +++ b/components/flow3r_bsp/flow3r_bsp_i2c.h @@ -35,4 +35,6 @@ esp_err_t flow3r_bsp_i2c_write_to_device(flow3r_i2c_address address, const uint8 // Perform a write-then read transaction on an I2C device. // // This can be called concurrently from different tassks. -esp_err_t flow3r_bsp_i2c_write_read_device(flow3r_i2c_address address, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, TickType_t ticks_to_wait); \ No newline at end of file +esp_err_t flow3r_bsp_i2c_write_read_device(flow3r_i2c_address address, const uint8_t *write_buffer, size_t write_size, uint8_t *read_buffer, size_t read_size, TickType_t ticks_to_wait); + +void flow3r_bsp_i2c_scan(void); \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_leds.c b/components/flow3r_bsp/flow3r_bsp_leds.c new file mode 100644 index 0000000000000000000000000000000000000000..55c3bad890a1b79cf2cac11df46d7501e2420514 --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_leds.c @@ -0,0 +1,37 @@ +#include "flow3r_bsp.h" + +#if defined(CONFIG_BADGE23_HW_GEN_P1) + +#include "flow3r_bsp_spiled.h" + +esp_err_t flow3r_bsp_leds_init(void) { + return flow3r_bsp_spiled_init(FLOW3R_BSP_LED_COUNT); +} + +void flow3r_bsp_leds_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) { + flow3r_bsp_spiled_set_pixel(index, red, green, blue); +} + +esp_err_t flow3r_bsp_leds_refresh(TickType_t timeout_ms) { + return flow3r_bsp_spiled_refresh(timeout_ms); +} + +#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P6) + +#include "flow3r_bsp_rmtled.h" + +esp_err_t flow3r_bsp_leds_init(void) { + return flow3r_bsp_rmtled_init(FLOW3R_BSP_LED_COUNT); +} + +void flow3r_bsp_leds_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) { + flow3r_bsp_rmtled_set_pixel(index, red, green, blue); +} + +esp_err_t flow3r_bsp_leds_refresh(TickType_t timeout_ms) { + return flow3r_bsp_rmtled_refresh(timeout_ms); +} + +#else +#error "leds not implemented for this badge generation" +#endif \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_rmtled.c b/components/flow3r_bsp/flow3r_bsp_rmtled.c new file mode 100644 index 0000000000000000000000000000000000000000..ae975403311d55ee8b723d66a430ad354e716f94 --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_rmtled.c @@ -0,0 +1,157 @@ +// Driver for WS2812-style LEDs, using RMT peripheral. +// +// Based on espressif__led_strip. +// +// 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 "flow3r_bsp_rmtled.h" + +static const char *TAG = "flow3r-rmtled"; + +#include "driver/rmt.h" +#include "esp_log.h" + +#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) + +typedef struct { + uint16_t num_leds; + rmt_channel_t chan; + uint8_t *buffer; + bool transmitting; + + uint32_t ws2812_t0h_ticks; + uint32_t ws2812_t0l_ticks; + uint32_t ws2812_t1h_ticks; + uint32_t ws2812_t1l_ticks; +} flow3r_bsp_rmtled_t; + +static flow3r_bsp_rmtled_t rmtled = {0}; + +static void IRAM_ATTR _rmtled_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 = {{{ rmtled.ws2812_t0h_ticks, 1, rmtled.ws2812_t0l_ticks, 0 }}}; //Logical 0 + const rmt_item32_t bit1 = {{{ rmtled.ws2812_t1h_ticks, 1, rmtled.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; +} + + +esp_err_t flow3r_bsp_rmtled_init(uint16_t num_leds) { + if (rmtled.buffer != NULL) { + return ESP_ERR_INVALID_STATE; + } + + rmt_config_t config = RMT_DEFAULT_CONFIG_TX(14, 0); + // set counter clock to 40MHz + config.clk_div = 2; + + esp_err_t ret; + if ((ret = rmt_config(&config)) != ESP_OK) { + ESP_LOGE(TAG, "rmt_config failed: %s", esp_err_to_name(ret)); + return ret; + } + if ((ret = rmt_driver_install(config.channel, 0, 0)) != ESP_OK) { + ESP_LOGE(TAG, "rmt_driver_install failed: %s", esp_err_to_name(ret)); + return ret; + } + + uint32_t counter_clk_hz = 0; + if ((ret = rmt_get_counter_clock(config.channel, &counter_clk_hz)) != ESP_OK) { + ESP_LOGE(TAG, "rmt_get_counter_clock failed: %s", esp_err_to_name(ret)); + return ret; + } + + // ns -> ticks + float ratio = (float)counter_clk_hz / 1e9; + rmtled.ws2812_t0h_ticks = (uint32_t)(ratio * WS2812_T0H_NS); + rmtled.ws2812_t0l_ticks = (uint32_t)(ratio * WS2812_T0L_NS); + rmtled.ws2812_t1h_ticks = (uint32_t)(ratio * WS2812_T1H_NS); + rmtled.ws2812_t1l_ticks = (uint32_t)(ratio * WS2812_T1L_NS); + rmtled.num_leds = num_leds; + rmtled.chan = config.channel; + rmtled.buffer = calloc(3, num_leds); + if (rmtled.buffer == NULL) { + ESP_LOGE(TAG, "buffer allocation failed"); + return ESP_ERR_NO_MEM; + } + rmtled.transmitting = false; + + if ((ret = rmt_translator_init(config.channel, _rmtled_adapter)) != ESP_OK) { + ESP_LOGE(TAG, "rmt_translator_init: %s", esp_err_to_name(ret)); + return ret; + } + + return ESP_OK; +} + +void flow3r_bsp_rmtled_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) +{ + if (rmtled.buffer == NULL) { + return; + } + if (index >= rmtled.num_leds) { + return; + } + uint32_t start = index * 3; + rmtled.buffer[start + 0] = green & 0xFF; + rmtled.buffer[start + 1] = red & 0xFF; + rmtled.buffer[start + 2] = blue & 0xFF; +} + +esp_err_t flow3r_bsp_rmtled_refresh(int32_t timeout_ms) { + if (rmtled.buffer == NULL) { + return ESP_ERR_INVALID_STATE; + } + + if (rmtled.transmitting) { + esp_err_t ret = rmt_wait_tx_done(rmtled.chan, pdMS_TO_TICKS(timeout_ms)); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "rmt_wait_tx_done: %s", esp_err_to_name(ret)); + } + rmtled.transmitting = false; + } + + esp_err_t ret = rmt_write_sample(rmtled.chan, rmtled.buffer, rmtled.num_leds * 3, true); + rmtled.transmitting = true; + return ret; +} \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_rmtled.h b/components/flow3r_bsp/flow3r_bsp_rmtled.h new file mode 100644 index 0000000000000000000000000000000000000000..569b8507afbf469afc168a93d7f0918df8f6c40e --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_rmtled.h @@ -0,0 +1,7 @@ +#pragma once + +#include "esp_err.h" + +esp_err_t flow3r_bsp_rmtled_init(uint16_t num_leds); +void flow3r_bsp_rmtled_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue); +esp_err_t flow3r_bsp_rmtled_refresh(int32_t timeout_ms); \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_spiled.c b/components/flow3r_bsp/flow3r_bsp_spiled.c new file mode 100644 index 0000000000000000000000000000000000000000..676c20d5e7b4accb0848040cd5d05d8e94c60c8d --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_spiled.c @@ -0,0 +1,96 @@ +// Driver for APA102-style LEDs, using SPI peripheral. + +#include "flow3r_bsp_spiled.h" + +#include <string.h> + +#include "driver/spi_master.h" +#include "esp_log.h" + +static const char *TAG = "flow3r-spiled"; + +static spi_bus_config_t buscfg; +static spi_device_interface_config_t devcfg; +static spi_device_handle_t spi_led; +static spi_transaction_t spi_trans_object; + +typedef struct { + uint16_t num_leds; + uint8_t *buffer; +} flow3r_bsp_spiled_t; + +static flow3r_bsp_spiled_t spiled; + + +esp_err_t flow3r_bsp_spiled_init(uint16_t num_leds) { + // Set up the Bus Config struct + buscfg.miso_io_num = -1; + buscfg.mosi_io_num = 18; + buscfg.sclk_io_num = 8; + buscfg.quadwp_io_num = -1; + buscfg.quadhd_io_num = -1; + buscfg.max_transfer_sz = 8000; + + // Set up the SPI Device Configuration Struct + devcfg.clock_speed_hz = 10000000; + devcfg.mode = 0; + devcfg.spics_io_num = -1; + devcfg.queue_size = 1; + + // Initialize the SPI driver + esp_err_t ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "spi_bus_initialize: %s", esp_err_to_name(ret)); + return ret; + } + // Add SPI port to bus + ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi_led); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "spi_bus_add_device: %s", esp_err_to_name(ret)); + return ret; + } + + spiled.num_leds = num_leds; + spiled.buffer = calloc(4, num_leds + 2); + if (spiled.buffer == NULL) { + ESP_LOGE(TAG, "buffer allocation failed"); + return ESP_ERR_NO_MEM; + } + // Start Frame + spiled.buffer[0] = 0; + spiled.buffer[1] = 0; + spiled.buffer[2] = 0; + spiled.buffer[3] = 0; + // Global brightness. + for (int i = 0; i < num_leds; i++) { + spiled.buffer[i * 4 + 4] = 255; + } + // End Frame (this only works with up to 64 LEDs, meh). + int i = num_leds * 4 + 8; + spiled.buffer[i + 0] = 255; + spiled.buffer[i + 1] = 255; + spiled.buffer[i + 2] = 255; + spiled.buffer[i + 3] = 255; + + memset(&spi_trans_object, 0, sizeof(spi_trans_object)); + spi_trans_object.length = (4 * (num_leds+2))* 8; + spi_trans_object.tx_buffer = spiled.buffer; + return ESP_OK; +} + +void flow3r_bsp_spiled_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) { + if (spiled.buffer == NULL) { + return; + } + if (index >= spiled.num_leds) { + return; + } + uint32_t start = index * 4 + 4; + spiled.buffer[start + 1] = blue & 0xFF; + spiled.buffer[start + 2] = green & 0xFF; + spiled.buffer[start + 3] = red & 0xFF; +} + +esp_err_t flow3r_bsp_spiled_refresh(int32_t timeout_ms) { + return spi_device_queue_trans(spi_led, &spi_trans_object, timeout_ms); +} \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_spiled.h b/components/flow3r_bsp/flow3r_bsp_spiled.h new file mode 100644 index 0000000000000000000000000000000000000000..501e718a5c25498be3a5a5417279c8f0913f6f21 --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_spiled.h @@ -0,0 +1,7 @@ +#pragma once + +#include "esp_err.h" + +esp_err_t flow3r_bsp_spiled_init(uint16_t num_leds); +void flow3r_bsp_spiled_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue); +esp_err_t flow3r_bsp_spiled_refresh(int32_t timeout_ms); \ No newline at end of file