From f808038694ec18aea61cce8a60ee540e0e8f4f29 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Wed, 10 Mar 2021 20:38:19 +0100 Subject: [PATCH] ESP32 support for WS2812 hardware driver via RMT or I2S --- CHANGELOG.md | 1 + .../src/esp8266toEsp32.h | 4 - tasmota/my_user_config.h | 4 +- tasmota/xlgt_01_ws2812.ino | 153 ++++++++++-------- 4 files changed, 93 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ded922bad..b2dc87a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ All notable changes to this project will be documented in this file. - Crash protection in ext_vnsprintf_P (#11202) - Extent compile time SetOptions support (#11204) - ESP32 Extent BLE (#11212) +- ESP32 support for WS2812 hardware driver via RMT or I2S ### Changed - ESP32 core library from v1.0.5-rc6 to v1.0.5 diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index 6a45d6632..25f6f539b 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -114,10 +114,6 @@ typedef int SerConfu8; typedef int SerialConfig; //#define analogWrite(a, b) -// -// WS2812 -// -#define NeoEsp8266BitBang800KbpsMethod NeoEsp32BitBang800KbpsMethod // // UDP // diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index a89fd65eb..3275e76cf 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -494,7 +494,9 @@ // -- Optional light modules ---------------------- #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // -// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow +// #define USE_WS2812_DMA // ESP8266 only, DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow + #define USE_WS2812_RMT 0 // ESP32 only, hardware RMT support (default). Specify the RMT channel 0..7. This should be preferred to software bit bang. +// #define USE_WS2812_I2S 0 // ESP32 only, hardware I2S support. Specify the I2S channel 0..2. This is exclusive from RMT. By default, prefer RMT support // #define USE_WS2812_INVERTED // Use inverted data signal #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106, NEO_HW_P9813) #define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW) diff --git a/tasmota/xlgt_01_ws2812.ino b/tasmota/xlgt_01_ws2812.ino index fcd685931..b41884a22 100644 --- a/tasmota/xlgt_01_ws2812.ino +++ b/tasmota/xlgt_01_ws2812.ino @@ -47,81 +47,106 @@ void (* const Ws2812Command[])(void) PROGMEM = { #include -#if (USE_WS2812_HARDWARE == NEO_HW_P9813) - typedef P9813BgrFeature selectedNeoFeatureType; - #undef USE_WS2812_DMA - #undef USE_WS2812_INVERTED -#elif (USE_WS2812_CTYPE == NEO_GRB) - typedef NeoGrbFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_BRG) - typedef NeoBrgFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_RBG) - typedef NeoRbgFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_RGBW) - typedef NeoRgbwFeature selectedNeoFeatureType; -#elif (USE_WS2812_CTYPE == NEO_GRBW) - typedef NeoGrbwFeature selectedNeoFeatureType; -#else // USE_WS2812_CTYPE - typedef NeoRgbFeature selectedNeoFeatureType; -#endif // USE_WS2812_CTYPE - -#ifdef USE_WS2812_DMA - -#ifdef USE_WS2812_INVERTED // See NeoEspDmaMethod.h for available options - -#if (USE_WS2812_HARDWARE == NEO_HW_WS2812X) - typedef NeoEsp8266DmaInvertedWs2812xMethod selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_SK6812) - typedef NeoEsp8266DmaInvertedSk6812Method selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_APA106) - typedef NeoEsp8266DmaInvertedApa106Method selectedNeoSpeedType; -#else // USE_WS2812_HARDWARE - typedef NeoEsp8266DmaInverted800KbpsMethod selectedNeoSpeedType; -#endif // USE_WS2812_HARDWARE - -#else // No USE_WS2812_INVERTED - -#if (USE_WS2812_HARDWARE == NEO_HW_WS2812X) - typedef NeoEsp8266DmaWs2812xMethod selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_SK6812) - typedef NeoEsp8266DmaSk6812Method selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_APA106) - typedef NeoEsp8266DmaApa106Method selectedNeoSpeedType; -#else // USE_WS2812_HARDWARE - typedef NeoEsp8266Dma800KbpsMethod selectedNeoSpeedType; -#endif // USE_WS2812_HARDWARE - -#endif // No USE_WS2812_INVERTED - -#else // No USE_WS2812_DMA - -#ifdef USE_WS2812_INVERTED // See NeoEspBitBangMethod.h for available options +// Build `selectedNeoFeatureType` as Neo-Rgb-Feature +// parametrized as: NEO_FEATURE_NEO+NEO_FEATURE_TYPE+NEO_FEATURE_FEATURE +#define CONCAT2(A,B) CONCAT2_(A,B) // ensures expansion first, see https://stackoverflow.com/questions/3221896/how-can-i-guarantee-full-macro-expansion-of-a-parameter-before-paste +#define CONCAT2_(A,B) A ## B +#define CONCAT3(A,B,C) CONCAT3_(A,B,C) // ensures expansion first, see https://stackoverflow.com/questions/3221896/how-can-i-guarantee-full-macro-expansion-of-a-parameter-before-paste +#define CONCAT3_(A,B,C) A ## B ## C + +#define NEO_FEATURE_NEO Neo +#define NEO_FEATURE_FEATURE Feature + +// select the right Neo feature based on USE_WS2812_CTYPE +// NEO_FEATURE_TYPE can be one of: Rgb (default), Grb, Brg, Rgb, Rgbw, Grbw +#if (USE_WS2812_CTYPE == NEO_GRB) + #define NEO_FEATURE_TYPE Grb +#elif (USE_WS2812_CTYPE == NEO_BRG) + #define NEO_FEATURE_TYPE Brg +#elif (USE_WS2812_CTYPE == NEO_RBG) + #define NEO_FEATURE_TYPE Rbg +#elif (USE_WS2812_CTYPE == NEO_RGBW) + #define NEO_FEATURE_TYPE Rbgw +#elif (USE_WS2812_CTYPE == NEO_GRBW) + #define NEO_FEATURE_TYPE Grbw +#else + #define NEO_FEATURE_TYPE Rgb +#endif + +// Exception for NEO_HW_P9813 +#if (USE_WS2812_HARDWARE == NEO_HW_P9813) + #undef NEO_FEATURE_NEO + #undef NEO_FEATURE_TYPE + #define NEO_FEATURE_NEO P9813 // P9813BgrFeature + #define NEO_FEATURE_TYPE Bgr + #undef USE_WS2812_DMA + #undef USE_WS2812_INVERTED +#endif // USE_WS2812_CTYPE + +typedef CONCAT3(NEO_FEATURE_NEO,NEO_FEATURE_TYPE,NEO_FEATURE_FEATURE) selectedNeoFeatureType; + +// selectedNeoSpeedType is built as Neo+Esp8266+Dma+Inverted+Ws2812x+Method +// Or NEO_NEO+NEO_CHIP+NEO_PROTO+NEO_INV+NEO_HW+Method +#define CONCAT6(A,B,C,D,E,F) CONCAT6_(A,B,C,D,E,F) // ensures expansion first, see https://stackoverflow.com/questions/3221896/how-can-i-guarantee-full-macro-expansion-of-a-parameter-before-paste +#define CONCAT6_(A,B,C,D,E,F) A ## B ## C ## D ## E ## F + +#define NEO_NEO Neo + +#ifdef ESP32 + #define NEO_CHIP Esp32 +#else + #define NEO_CHIP Esp8266 +#endif + +// Proto = DMA or BigBang +#if defined(USE_WS2812_DMA) && defined(ESP8266) + #define NEO_PROTO Dma +#elif defined(USE_WS2812_RMT) && defined(ESP32) + #define NEO_PROTO CONCAT2(Rmt,USE_WS2812_RMT) +#elif defined(USE_WS2812_I2S) && defined(ESP32) + #define NEO_PROTO CONCAT2(I2s,USE_WS2812_I2S) +#else + #define NEO_PROTO BitBang +#endif + +#ifdef USE_WS2812_INVERTED + #define NEO_INV Inverted +#else + #define NEO_INV +#endif + #if (USE_WS2812_HARDWARE == NEO_HW_WS2812X) - typedef NeoEsp8266BitBangWs2812xInvertedMethod selectedNeoSpeedType; + #define NEO_HW Ws2812x #elif (USE_WS2812_HARDWARE == NEO_HW_SK6812) - typedef NeoEsp8266BitBangSk6812InvertedMethod selectedNeoSpeedType; + #define NEO_HW Sk6812 +#elif (USE_WS2812_HARDWARE == NEO_HW_APA106) + #define NEO_HW Apa106 #else // USE_WS2812_HARDWARE - typedef NeoEsp8266BitBang400KbpsInvertedMethod selectedNeoSpeedType; + #define NEO_HW 800Kbps #endif // USE_WS2812_HARDWARE -#else // No USE_WS2812_INVERTED #if (USE_WS2812_HARDWARE == NEO_HW_P9813) - typedef P9813Method selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_WS2812X) - typedef NeoEsp8266BitBangWs2812xMethod selectedNeoSpeedType; -#elif (USE_WS2812_HARDWARE == NEO_HW_SK6812) - typedef NeoEsp8266BitBangSk6812Method selectedNeoSpeedType; -#else // USE_WS2812_HARDWARE - typedef NeoEsp8266BitBang800KbpsMethod selectedNeoSpeedType; -#endif // USE_WS2812_HARDWARE + #undef NEO_NEO + #define NEO_NEO + #undef NEO_CHIP + #define NEO_CHIP + #undef NEO_PROTO + #define NEO_PROTO + #undef NEO_INV + #define NEO_INV + #undef NEO_HW + #define NEO_HW P9813 // complete driver is P9813Method +#endif -#endif // No USE_WS2812_INVERTED - -#endif // No USE_WS2812_DMA +#if defined(ESP8266) && defined(USE_WS2812_DMA) +typedef CONCAT6(NEO_NEO,NEO_CHIP,NEO_PROTO,NEO_INV,NEO_HW,Method) selectedNeoSpeedType; +#else // Dma : different naming scheme +typedef CONCAT6(NEO_NEO,NEO_CHIP,NEO_PROTO,NEO_HW,NEO_INV,Method) selectedNeoSpeedType; +#endif NeoPixelBus *strip = nullptr;