From 6a9f9718821138ca0f667246406444bc957c2424 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 7 Apr 2020 13:42:48 +0700 Subject: add saola button pin support, esp32 build with board_test --- examples/device/board_test/src/CMakeLists.txt | 19 +++++++++++++++++++ examples/device/board_test/src/main.c | 7 +++++++ examples/device/board_test/src/tusb_config.h | 5 ++++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 examples/device/board_test/src/CMakeLists.txt (limited to 'examples/device/board_test/src') diff --git a/examples/device/board_test/src/CMakeLists.txt b/examples/device/board_test/src/CMakeLists.txt new file mode 100644 index 000000000..66746502c --- /dev/null +++ b/examples/device/board_test/src/CMakeLists.txt @@ -0,0 +1,19 @@ +idf_component_register(SRCS "main.c" + INCLUDE_DIRS "." + REQUIRES freertos soc) + +target_compile_options(${COMPONENT_TARGET} PUBLIC + "-DCFG_TUSB_MCU=OPT_MCU_ESP32S2" + "-DCFG_TUSB_OS=OPT_OS_FREERTOS" +) + +idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH) +target_include_directories(${COMPONENT_TARGET} PUBLIC + "${FREERTOS_ORIG_INCLUDE_PATH}" + "${TOP}/hw" + "${TOP}/src" +) + +target_sources(${COMPONENT_TARGET} PUBLIC + "${TOP}/hw/bsp/esp32s2_saola/esp32s2_saola.c" +) diff --git a/examples/device/board_test/src/main.c b/examples/device/board_test/src/main.c index 584ff799d..71665550f 100644 --- a/examples/device/board_test/src/main.c +++ b/examples/device/board_test/src/main.c @@ -73,3 +73,10 @@ int main(void) return 0; } + +#if CFG_TUSB_MCU == OPT_MCU_ESP32S2 +void app_main(void) +{ + main(); +} +#endif diff --git a/examples/device/board_test/src/tusb_config.h b/examples/device/board_test/src/tusb_config.h index 1a52cc348..0587d48e3 100644 --- a/examples/device/board_test/src/tusb_config.h +++ b/examples/device/board_test/src/tusb_config.h @@ -39,8 +39,11 @@ #error CFG_TUSB_MCU must be defined #endif +#ifndef CFG_TUSB_OS + #define CFG_TUSB_OS OPT_OS_NONE +#endif + #define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE -#define CFG_TUSB_OS OPT_OS_NONE // CFG_TUSB_DEBUG is defined by compiler in DEBUG build // #define CFG_TUSB_DEBUG 0 -- cgit v1.3.1 From a2dee7fb5041d19ace9078d295a2e4c95574d869 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 7 Apr 2020 23:07:25 +0700 Subject: rename saola to saola_1 --- examples/device/board_test/src/CMakeLists.txt | 2 +- .../device/cdc_msc_freertos/src/CMakeLists.txt | 2 +- .../hid_composite_freertos/src/CMakeLists.txt | 2 +- hw/bsp/esp32s2_saola/board.mk | 2 - hw/bsp/esp32s2_saola/esp32s2_saola.c | 85 ---------------------- hw/bsp/esp32s2_saola_1/board.mk | 2 + hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c | 85 ++++++++++++++++++++++ 7 files changed, 90 insertions(+), 90 deletions(-) delete mode 100644 hw/bsp/esp32s2_saola/board.mk delete mode 100644 hw/bsp/esp32s2_saola/esp32s2_saola.c create mode 100644 hw/bsp/esp32s2_saola_1/board.mk create mode 100644 hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c (limited to 'examples/device/board_test/src') diff --git a/examples/device/board_test/src/CMakeLists.txt b/examples/device/board_test/src/CMakeLists.txt index 66746502c..676159ac9 100644 --- a/examples/device/board_test/src/CMakeLists.txt +++ b/examples/device/board_test/src/CMakeLists.txt @@ -15,5 +15,5 @@ target_include_directories(${COMPONENT_TARGET} PUBLIC ) target_sources(${COMPONENT_TARGET} PUBLIC - "${TOP}/hw/bsp/esp32s2_saola/esp32s2_saola.c" + "${TOP}/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c" ) diff --git a/examples/device/cdc_msc_freertos/src/CMakeLists.txt b/examples/device/cdc_msc_freertos/src/CMakeLists.txt index ab4c1aa6d..7f8eeca17 100644 --- a/examples/device/cdc_msc_freertos/src/CMakeLists.txt +++ b/examples/device/cdc_msc_freertos/src/CMakeLists.txt @@ -14,7 +14,7 @@ target_include_directories(${COMPONENT_TARGET} PUBLIC ) target_sources(${COMPONENT_TARGET} PUBLIC - "${TOP}/hw/bsp/esp32s2_saola/esp32s2_saola.c" + "${TOP}/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c" "${TOP}/src/tusb.c" "${TOP}/src/common/tusb_fifo.c" "${TOP}/src/device/usbd.c" diff --git a/examples/device/hid_composite_freertos/src/CMakeLists.txt b/examples/device/hid_composite_freertos/src/CMakeLists.txt index fbe5f6389..c674873b2 100644 --- a/examples/device/hid_composite_freertos/src/CMakeLists.txt +++ b/examples/device/hid_composite_freertos/src/CMakeLists.txt @@ -14,7 +14,7 @@ target_include_directories(${COMPONENT_TARGET} PUBLIC ) target_sources(${COMPONENT_TARGET} PUBLIC - "${TOP}/hw/bsp/esp32s2_saola/esp32s2_saola.c" + "${TOP}/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c" "${TOP}/src/tusb.c" "${TOP}/src/common/tusb_fifo.c" "${TOP}/src/device/usbd.c" diff --git a/hw/bsp/esp32s2_saola/board.mk b/hw/bsp/esp32s2_saola/board.mk deleted file mode 100644 index 167ef6226..000000000 --- a/hw/bsp/esp32s2_saola/board.mk +++ /dev/null @@ -1,2 +0,0 @@ -# Cross Compiler for ESP32 -CROSS_COMPILE = xtensa-esp32s2-elf- diff --git a/hw/bsp/esp32s2_saola/esp32s2_saola.c b/hw/bsp/esp32s2_saola/esp32s2_saola.c deleted file mode 100644 index 16d054f75..000000000 --- a/hw/bsp/esp32s2_saola/esp32s2_saola.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020, Ha Thach (tinyusb.org) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This file is part of the TinyUSB stack. - */ - -#include "bsp/board.h" -#include "driver/gpio.h" -#include "hal/usb_hal.h" - -//--------------------------------------------------------------------+ -// MACRO TYPEDEF CONSTANT ENUM DECLARATION -//--------------------------------------------------------------------+ - -#define LED_PIN 21 - -#define BUTTON_PIN 0 -#define BUTTON_STATE_ACTIVE 0 - -// Initialize on-board peripherals : led, button, uart and USB -void board_init(void) -{ - // LED - gpio_pad_select_gpio(LED_PIN); - gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT); - - // Button - gpio_pad_select_gpio(BUTTON_PIN); - gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT); - gpio_set_pull_mode(BUTTON_PIN, BUTTON_STATE_ACTIVE ? GPIO_PULLDOWN_ONLY : GPIO_PULLUP_ONLY); - - // USB Controller Hal init - usb_hal_context_t hal = { - .use_external_phy = false // use built-in PHY - }; - usb_hal_init(&hal); -} - -// Turn LED on or off -void board_led_write(bool state) -{ - gpio_set_level(LED_PIN, state); -} - -// Get the current state of button -// a '1' means active (pressed), a '0' means inactive. -uint32_t board_button_read(void) -{ - return gpio_get_level(BUTTON_PIN) == BUTTON_STATE_ACTIVE; -} - -// Get characters from UART -int board_uart_read(uint8_t* buf, int len) -{ - (void) buf; (void) len; - return 0; -} - -// Send characters to UART -int board_uart_write(void const * buf, int len) -{ - (void) buf; (void) len; - return 0; -} - diff --git a/hw/bsp/esp32s2_saola_1/board.mk b/hw/bsp/esp32s2_saola_1/board.mk new file mode 100644 index 000000000..167ef6226 --- /dev/null +++ b/hw/bsp/esp32s2_saola_1/board.mk @@ -0,0 +1,2 @@ +# Cross Compiler for ESP32 +CROSS_COMPILE = xtensa-esp32s2-elf- diff --git a/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c b/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c new file mode 100644 index 000000000..16d054f75 --- /dev/null +++ b/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c @@ -0,0 +1,85 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "bsp/board.h" +#include "driver/gpio.h" +#include "hal/usb_hal.h" + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +#define LED_PIN 21 + +#define BUTTON_PIN 0 +#define BUTTON_STATE_ACTIVE 0 + +// Initialize on-board peripherals : led, button, uart and USB +void board_init(void) +{ + // LED + gpio_pad_select_gpio(LED_PIN); + gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT); + + // Button + gpio_pad_select_gpio(BUTTON_PIN); + gpio_set_direction(BUTTON_PIN, GPIO_MODE_INPUT); + gpio_set_pull_mode(BUTTON_PIN, BUTTON_STATE_ACTIVE ? GPIO_PULLDOWN_ONLY : GPIO_PULLUP_ONLY); + + // USB Controller Hal init + usb_hal_context_t hal = { + .use_external_phy = false // use built-in PHY + }; + usb_hal_init(&hal); +} + +// Turn LED on or off +void board_led_write(bool state) +{ + gpio_set_level(LED_PIN, state); +} + +// Get the current state of button +// a '1' means active (pressed), a '0' means inactive. +uint32_t board_button_read(void) +{ + return gpio_get_level(BUTTON_PIN) == BUTTON_STATE_ACTIVE; +} + +// Get characters from UART +int board_uart_read(uint8_t* buf, int len) +{ + (void) buf; (void) len; + return 0; +} + +// Send characters to UART +int board_uart_write(void const * buf, int len) +{ + (void) buf; (void) len; + return 0; +} + -- cgit v1.3.1 From cefbd9579c7fb5a16a253d5d0f7c582142933c46 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 9 Apr 2020 00:06:18 +0700 Subject: add neopixel led strip driver for saola, make saola as an component --- examples/device/board_test/CMakeLists.txt | 7 +- examples/device/board_test/src/CMakeLists.txt | 4 - hw/bsp/esp32s2_saola_1/CMakeLists.txt | 16 ++ hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c | 30 +++- .../esp32s2_saola_1/led_strip/include/led_strip.h | 126 +++++++++++++++ .../led_strip/src/led_strip_rmt_ws2812.c | 171 +++++++++++++++++++++ 6 files changed, 340 insertions(+), 14 deletions(-) create mode 100644 hw/bsp/esp32s2_saola_1/CMakeLists.txt create mode 100644 hw/bsp/esp32s2_saola_1/led_strip/include/led_strip.h create mode 100644 hw/bsp/esp32s2_saola_1/led_strip/src/led_strip_rmt_ws2812.c (limited to 'examples/device/board_test/src') diff --git a/examples/device/board_test/CMakeLists.txt b/examples/device/board_test/CMakeLists.txt index 1d8f2fe32..27f737d88 100644 --- a/examples/device/board_test/CMakeLists.txt +++ b/examples/device/board_test/CMakeLists.txt @@ -2,13 +2,14 @@ # CMakeLists in this exact order for cmake to work correctly cmake_minimum_required(VERSION 3.5) -# example src directory -set(EXTRA_COMPONENT_DIRS "src") - # TOP is absolute path to root directory of TinyUSB git repo set(TOP "../../..") get_filename_component(TOP "${TOP}" REALPATH) +# Add example src and bsp directories +set(EXTRA_COMPONENT_DIRS "src" "${TOP}/hw/bsp/esp32s2_saola_1") + include($ENV{IDF_PATH}/tools/cmake/project.cmake) +set(SUPPORTED_TARGETS esp32s2) project(board_test) diff --git a/examples/device/board_test/src/CMakeLists.txt b/examples/device/board_test/src/CMakeLists.txt index 676159ac9..29ae46a33 100644 --- a/examples/device/board_test/src/CMakeLists.txt +++ b/examples/device/board_test/src/CMakeLists.txt @@ -13,7 +13,3 @@ target_include_directories(${COMPONENT_TARGET} PUBLIC "${TOP}/hw" "${TOP}/src" ) - -target_sources(${COMPONENT_TARGET} PUBLIC - "${TOP}/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c" -) diff --git a/hw/bsp/esp32s2_saola_1/CMakeLists.txt b/hw/bsp/esp32s2_saola_1/CMakeLists.txt new file mode 100644 index 000000000..379b2e3d0 --- /dev/null +++ b/hw/bsp/esp32s2_saola_1/CMakeLists.txt @@ -0,0 +1,16 @@ +idf_component_register(SRCS "esp32s2_saola_1.c" "led_strip/src/led_strip_rmt_ws2812.c" + INCLUDE_DIRS "led_strip/include" + PRIV_REQUIRES "driver" + REQUIRES freertos src) + +target_compile_options(${COMPONENT_TARGET} PUBLIC + "-DCFG_TUSB_MCU=OPT_MCU_ESP32S2" + "-DCFG_TUSB_OS=OPT_OS_FREERTOS" +) + +idf_component_get_property( FREERTOS_ORIG_INCLUDE_PATH freertos ORIG_INCLUDE_PATH) +target_include_directories(${COMPONENT_TARGET} PUBLIC + "${FREERTOS_ORIG_INCLUDE_PATH}" + "${TOP}/hw" + "${TOP}/src" +) diff --git a/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c b/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c index ed855f727..ef70f1ee2 100644 --- a/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c +++ b/hw/bsp/esp32s2_saola_1/esp32s2_saola_1.c @@ -24,26 +24,41 @@ * This file is part of the TinyUSB stack. */ -#include "bsp/board.h" +#include "../board.h" #include "driver/gpio.h" #include "hal/usb_hal.h" +#include "driver/rmt.h" +#include "led_strip/include/led_strip.h" + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ -// TODO use saola-1 on-board neopixel (WS2812) -#define LED_PIN 21 +// Note: On the production version (v1.2) WS2812 is connected to GPIO 18, +// however earlier revision v1.1 WS2812 is connected to GPIO 17 +//#define LED_PIN 18 // v1.2 and later +#define LED_PIN 17 // v1.1 #define BUTTON_PIN 0 #define BUTTON_STATE_ACTIVE 0 + +static led_strip_t *strip; + // Initialize on-board peripherals : led, button, uart and USB void board_init(void) { - // LED - gpio_pad_select_gpio(LED_PIN); - gpio_set_direction(LED_PIN, GPIO_MODE_OUTPUT); + // WS2812 Neopixel driver with RMT peripheral + rmt_config_t config = RMT_DEFAULT_CONFIG_TX(LED_PIN, RMT_CHANNEL_0); + config.clk_div = 2; // set counter clock to 40MHz + + rmt_config(&config); + rmt_driver_install(config.channel, 0, 0); + + led_strip_config_t strip_config = LED_STRIP_DEFAULT_CONFIG(1, (led_strip_dev_t) config.channel); + strip = led_strip_new_rmt_ws2812(&strip_config); + strip->clear(strip, 100); // off led // Button gpio_pad_select_gpio(BUTTON_PIN); @@ -60,7 +75,8 @@ void board_init(void) // Turn LED on or off void board_led_write(bool state) { - gpio_set_level(LED_PIN, state); + strip->set_pixel(strip, 0, (state ? 0x88 : 0x00), 0x00, 0x00); + strip->refresh(strip, 100); } // Get the current state of button diff --git a/hw/bsp/esp32s2_saola_1/led_strip/include/led_strip.h b/hw/bsp/esp32s2_saola_1/led_strip/include/led_strip.h new file mode 100644 index 000000000..a9dffc325 --- /dev/null +++ b/hw/bsp/esp32s2_saola_1/led_strip/include/led_strip.h @@ -0,0 +1,126 @@ +// 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); + +#ifdef __cplusplus +} +#endif diff --git a/hw/bsp/esp32s2_saola_1/led_strip/src/led_strip_rmt_ws2812.c b/hw/bsp/esp32s2_saola_1/led_strip/src/led_strip_rmt_ws2812.c new file mode 100644 index 000000000..025d3c590 --- /dev/null +++ b/hw/bsp/esp32s2_saola_1/led_strip/src/led_strip_rmt_ws2812.c @@ -0,0 +1,171 @@ +// 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 +#include +#include +#include "esp_log.h" +#include "esp_attr.h" +#include "led_strip.h" +#include "driver/rmt.h" + +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; +} -- cgit v1.3.1