diff --git a/examples/ESP32/DotStarTest_Esp32Advanced/DotStarTest_Esp32Advanced.ino b/examples/ESP32/DotStarTest_Esp32Advanced/DotStarTest_Esp32Advanced.ino index cd31da2b..2d0de4ea 100644 --- a/examples/ESP32/DotStarTest_Esp32Advanced/DotStarTest_Esp32Advanced.ino +++ b/examples/ESP32/DotStarTest_Esp32Advanced/DotStarTest_Esp32Advanced.ino @@ -21,6 +21,7 @@ // If you set useSpiAlternatePins true, then these pins will be used instead. Any output-capable GPIO can be used. const uint8_t DotClockPin = 18; const uint8_t DotDataPin = 23; + const uint8_t MisoUnusedPin = -1; const int8_t DotChipSelectPin = -1; // -1 means the chip select signal won't be output, freeing up one pin compared to useSpiAlternatePins=false // for software bit bang (only use if neither SPI peripheral is available) @@ -76,7 +77,7 @@ void setup() #if (USE_DEFAULT_SPI_PORT == 1) if (useSpiAlternatePins) { - strip.Begin(DotClockPin, DotDataPin, DotDataPin, DotChipSelectPin); + strip.Begin(DotClockPin, MisoUnusedPin, DotDataPin, DotChipSelectPin); } else { @@ -90,7 +91,7 @@ void setup() #if (USE_ALTERNATE_SPI_PORT == 1) if (useSpiAlternatePins2) { - strip2.Begin(DotClockPin2, DotDataPin2, DotDataPin2, DotChipSelectPin2); + strip2.Begin(DotClockPin2, MisoUnusedPin, DotDataPin2, DotChipSelectPin2); } else { diff --git a/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino b/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino index 41ffdbac..b370d88c 100644 --- a/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino +++ b/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino @@ -38,6 +38,7 @@ // If you set useSpiAlternatePins true, then these pins will be used instead. Any output-capable GPIO can be used. const uint8_t DotClockPin = 18; const uint8_t DotDataPin = 23; + const uint8_t MisoUnusedPin = -1; const int8_t DotChipSelectPin = -1; // -1 means the chip select signal won't be output, freeing up one pin compared to useSpiAlternatePins=false // for software bit bang (only use if neither SPI peripheral is available) @@ -89,7 +90,7 @@ void setup() #if (USE_DEFAULT_SPI_PORT == 1) if (useSpiAlternatePins) { - strip.Begin(DotClockPin, DotDataPin, DotDataPin, DotChipSelectPin); + strip.Begin(DotClockPin, MisoUnusedPin, DotDataPin, DotChipSelectPin); } else { @@ -103,7 +104,7 @@ void setup() #if (USE_ALTERNATE_SPI_PORT == 1) if (useSpiAlternatePins2) { - strip2.Begin(DotClockPin2, DotDataPin2, DotDataPin2, DotChipSelectPin2); + strip2.Begin(DotClockPin2, MisoUnusedPin, DotDataPin2, DotChipSelectPin2); } else { diff --git a/library.json b/library.json index 51b14b33..dd4dd34c 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/Makuna/NeoPixelBus" }, - "version": "2.8.3", + "version": "2.9.0", "frameworks": "arduino", "platforms": "*", "dependencies": [ diff --git a/library.properties b/library.properties index e2e07949..65d122c6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=NeoPixelBus by Makuna -version=2.8.3 +version=2.9.0 author=Michael C. Miller (makuna@live.com) maintainer=Michael C. Miller (makuna@live.com) sentence=A library that makes controlling NeoPixels (WS2812x and many others) and DotStars (SK6812 and many others) easy. diff --git a/src/internal/NeoMethods.h b/src/internal/NeoMethods.h index cc241306..19fcaf3b 100644 --- a/src/internal/NeoMethods.h +++ b/src/internal/NeoMethods.h @@ -50,39 +50,56 @@ License along with NeoPixel. If not, see // #if defined(ARDUINO_ARCH_ESP8266) -#include "methods/NeoEsp8266DmaMethod.h" -#include "methods/NeoEsp8266I2sDmx512Method.h" -#include "methods/NeoEsp8266UartMethod.h" -#include "methods/NeoEspBitBangMethod.h" +#include "methods/ESP/ESP8266/NeoEsp8266DmaMethod.h" +#include "methods/ESP/ESP8266/NeoEsp8266I2sDmx512Method.h" +#include "methods/ESP/ESP8266/NeoEsp8266UartMethod.h" +#include "methods/ESP/NeoEspBitBangMethod.h" #elif defined(ARDUINO_ARCH_ESP32) -#if !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) -#include "methods/NeoEsp32I2sMethod.h" -#include "methods/NeoEsp32RmtMethod.h" -#include "methods/DotStarEsp32DmaSpiMethod.h" -#include "methods/NeoEsp32I2sXMethod.h" -#include "methods/NeoEsp32LcdXMethod.h" +#if ESP_IDF_VERSION_MAJOR < 5 +#include "methods/ESP/ESP32/Core_2_x/NeoEsp32RmtMethod.h" +#else // ESP_IDF_VERSION_MAJOR < 5 + +#define NEOPIXEL_ESP32_RMT_DEFAULT // core3 will have RMT default, maybe change after an updated i2s + +#if !defined(CONFIG_IDF_TARGET_ESP32C2) +#include "methods/ESP/ESP32/NeoEsp32RmtXMethod.h" // every other SOC +#else //CONFIG_IDF_TARGET_ESP32C2 +#include "methods/ESP/ESP32/NeoEsp32SpiMethod.h" // ESP32C2 +#endif //CONFIG_IDF_TARGET_ESP32C2 + +#endif // ESP_IDF_VERSION_MAJOR < 5 + +// once we have a core3 i2s, then fix this +#if !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#include "methods/ESP/ESP32/Core_2_x/NeoEsp32I2sMethod.h" +#include "methods/ESP/ESP32/Core_2_x/NeoEsp32I2sXMethod.h" #endif -#include "methods/NeoEspBitBangMethod.h" + +#include "methods/ESP/ESP32/DotStarEsp32DmaSpiMethod.h" +#include "methods/ESP/ESP32/NeoEsp32LcdXMethod.h" + + +#include "methods/ESP/NeoEspBitBangMethod.h" #elif defined(ARDUINO_ARCH_NRF52840) // must be before __arm__ -#include "methods/NeoNrf52xMethod.h" +#include "methods/ARM/NeoNrf52xMethod.h" #elif defined(ARDUINO_ARCH_RP2040) // must be before __arm__ -#include "methods/Rp2040/NeoRp2040x4Method.h" +#include "methods/RP2040/NeoRp2040x4Method.h" #elif defined(__arm__) // must be before ARDUINO_ARCH_AVR due to Teensy incorrectly having it set -#include "methods/NeoArmMethod.h" +#include "methods/ARM/NeoArmMethod.h" #elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) -#include "methods/NeoAvrMethod.h" +#include "methods/AVR/NeoAvrMethod.h" #else #error "Platform Currently Not Supported, please add an Issue at Github/Makuna/NeoPixelBus" diff --git a/src/internal/XMethods.h b/src/internal/XMethods.h index 361a44d1..48ba7b4a 100644 --- a/src/internal/XMethods.h +++ b/src/internal/XMethods.h @@ -27,7 +27,7 @@ License along with NeoPixel. If not, see #pragma once -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#if defined(ARDUINO_ARCH_ESP32) //---------------------------------------------------------- #if defined(CONFIG_IDF_TARGET_ESP32S3) @@ -68,26 +68,24 @@ typedef NeoEsp32LcdX16Ws2816Method X16Ws2816Method; typedef NeoEsp32LcdX16Ws2812Method X16Ws2812Method; typedef NeoEsp32LcdX16Lc8812Method X16Lc8812Method; -#elif defined(CONFIG_IDF_TARGET_ESP32C3) + +#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) + //---------------------------------------------------------- -/* RMT doesnt have a X method yet -typedef NeoEsp32Rmtx8Ws2812xMethod X8Ws2812xMethod; -typedef NeoEsp32Rmtx8Ws2805Method X8Ws2805Method; -typedef NeoEsp32Rmtx8Sk6812Method X8Sk6812Method; -typedef NeoEsp32Rmtx8Tm1814Method X8Tm1814Method; -typedef NeoEsp32Rmtx8Tm1829Method X8Tm1829Method; -typedef NeoEsp32Rmtx8Tm1914Method X8Tm1914Method; -typedef NeoEsp32Rmtx8800KbpsMethod X8800KbpsMethod; -typedef NeoEsp32Rmtx8400KbpsMethod X8400KbpsMethod; -typedef NeoEsp32Rmtx8Apa106Method X8Apa106Method; -typedef NeoEsp32Rmtx8Ws2814Method X8Ws2814Method; -typedef NeoEsp32Rmtx8Ws2813Method X8Ws2813Method; -typedef NeoEsp32Rmtx8Ws2812dMethod X8Ws2812dMethod; -typedef NeoEsp32Rmtx8Ws2811Method X8Ws2811Method; -typedef NeoEsp32Rmtx8Ws2816Method X8Ws2816Method; -typedef NeoEsp32Rmtx8Ws2812Method X8Ws2812Method; -typedef NeoEsp32Rmtx8Lc8812Method X8Lc8812Method; -*/ +typedef NeoEsp32RmtXWs2812xMethod XWs2812xMethod; +typedef NeoEsp32RmtXWs2805Method XWs2805Method; +typedef NeoEsp32RmtXSk6812Method XSk6812Method; +typedef NeoEsp32RmtXTm1814Method XTm1814Method; +typedef NeoEsp32RmtXTm1829Method XTm1829Method; +typedef NeoEsp32RmtXTm1914Method XTm1914Method; +typedef NeoEsp32RmtX800KbpsMethod X800KbpsMethod; +typedef NeoEsp32RmtX400KbpsMethod X400KbpsMethod; +typedef NeoEsp32RmtXApa106Method XApa106Method; +typedef NeoEsp32RmtXWs2814Method XWs2814Method; +typedef NeoEsp32RmtXWs2813Method XWs2813Method; +typedef NeoEsp32RmtXWs2811Method XWs2811Method; +typedef NeoEsp32RmtXWs2816Method XWs2816Method; +typedef NeoEsp32RmtXLc8812Method XLc8812Method; #elif defined(CONFIG_IDF_TARGET_ESP32S2) //---------------------------------------------------------- @@ -127,6 +125,7 @@ typedef NeoEsp32I2s0X16Ws2816Method X16Ws2816Method; typedef NeoEsp32I2s0X16Ws2812Method X16Ws2812Method; typedef NeoEsp32I2s0X16Lc8812Method X16Lc8812Method; + #else // plain old ESP32 //---------------------------------------------------------- #define NEO_X4_ALIAS @@ -192,7 +191,7 @@ typedef Rp2040x4Pio1Ws2812xMethod X4Ws2812xMethod; typedef Rp2040x4Pio1400KbpsMethod X4400KbpsMethod; #endif -// some plafforms do not have a native x4, so alias it to x8 +// some platforms do not have a native x4, so alias it to x8 // #if defined(NEO_X4_ALIAS) typedef X8Ws2812xMethod X4Ws2813Method; diff --git a/src/internal/methods/NeoArmMethod.h b/src/internal/methods/ARM/NeoArmMethod.h similarity index 100% rename from src/internal/methods/NeoArmMethod.h rename to src/internal/methods/ARM/NeoArmMethod.h diff --git a/src/internal/methods/NeoNrf52xMethod.h b/src/internal/methods/ARM/NeoNrf52xMethod.h similarity index 100% rename from src/internal/methods/NeoNrf52xMethod.h rename to src/internal/methods/ARM/NeoNrf52xMethod.h diff --git a/src/internal/methods/NeoAvrMethod.h b/src/internal/methods/AVR/NeoAvrMethod.h similarity index 100% rename from src/internal/methods/NeoAvrMethod.h rename to src/internal/methods/AVR/NeoAvrMethod.h diff --git a/src/internal/methods/NeoPixelAvr.c b/src/internal/methods/AVR/NeoPixelAvr.c similarity index 100% rename from src/internal/methods/NeoPixelAvr.c rename to src/internal/methods/AVR/NeoPixelAvr.c diff --git a/src/internal/methods/TwoWireBitBangImpleAvr.h b/src/internal/methods/AVR/TwoWireBitBangImpleAvr.h similarity index 100% rename from src/internal/methods/TwoWireBitBangImpleAvr.h rename to src/internal/methods/AVR/TwoWireBitBangImpleAvr.h diff --git a/src/internal/methods/DotStarGenericMethod.h b/src/internal/methods/DotStarGenericMethod.h index 3f2f1c31..714fdced 100644 --- a/src/internal/methods/DotStarGenericMethod.h +++ b/src/internal/methods/DotStarGenericMethod.h @@ -167,7 +167,7 @@ typedef DotStarMethodBase> DotStarEsp32VspiHzMethod; typedef DotStarSpi10MhzMethod DotStarEsp32VspiMethod; -#include "TwoWireHspiImple.h" +#include "ESP/ESP32/TwoWireHspiImple.h" typedef DotStarMethodBase> DotStarEsp32Hspi40MhzMethod; typedef DotStarMethodBase> DotStarEsp32Hspi20MhzMethod; typedef DotStarMethodBase> DotStarEsp32Hspi10MhzMethod; diff --git a/src/internal/methods/Esp32_i2s.c b/src/internal/methods/ESP/ESP32/Core_2_x/Esp32_i2s.c similarity index 98% rename from src/internal/methods/Esp32_i2s.c rename to src/internal/methods/ESP/ESP32/Core_2_x/Esp32_i2s.c index 119cbc7a..6b8281d5 100644 --- a/src/internal/methods/Esp32_i2s.c +++ b/src/internal/methods/ESP/ESP32/Core_2_x/Esp32_i2s.c @@ -22,14 +22,14 @@ #include #include "stdlib.h" -// ESP32 C3, S3, C6, and H2 I2S is not supported yet due to significant changes to interface -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +// ESP32 C3, S3, C6, H2, and P4 I2S is not supported yet due to significant changes to interface +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/queue.h" -#include "FractionClk.h" +#include "../../../FractionClk.h" #if ESP_IDF_VERSION_MAJOR>=4 #include "esp_intr_alloc.h" @@ -516,7 +516,9 @@ void i2sInit(uint8_t bus_num, // conf1.rx_pcm_bypass = 1; conf1.tx_stop_en = 0; +#if SOC_I2S_SUPPORTS_PCM_BYPASS conf1.tx_pcm_bypass = 1; +#endif i2s->conf1.val = conf1.val; } @@ -950,6 +952,6 @@ bool i2sGetClks(uint8_t bus_num, } #endif -#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32H2) -#endif // defined(ARDUINO_ARCH_ESP32) \ No newline at end of file +#endif // defined(ARDUINO_ARCH_ESP32) diff --git a/src/internal/methods/Esp32_i2s.h b/src/internal/methods/ESP/ESP32/Core_2_x/Esp32_i2s.h similarity index 100% rename from src/internal/methods/Esp32_i2s.h rename to src/internal/methods/ESP/ESP32/Core_2_x/Esp32_i2s.h diff --git a/src/internal/methods/NeoEsp32I2sMethod.h b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32I2sMethod.h similarity index 98% rename from src/internal/methods/NeoEsp32I2sMethod.h rename to src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32I2sMethod.h index 85aae16d..fb9021c8 100644 --- a/src/internal/methods/NeoEsp32I2sMethod.h +++ b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32I2sMethod.h @@ -26,8 +26,9 @@ License along with NeoPixel. If not, see #pragma once -// ESP32 C3 & S3 I2S is not supported yet due to significant changes to interface -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) +// ESP32 beyond C3 & S3 I2S is not supported yet +// due to significant changes to interface +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) extern "C" diff --git a/src/internal/methods/NeoEsp32I2sXMethod.h b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32I2sXMethod.h similarity index 99% rename from src/internal/methods/NeoEsp32I2sXMethod.h rename to src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32I2sXMethod.h index ecc304aa..f099620c 100644 --- a/src/internal/methods/NeoEsp32I2sXMethod.h +++ b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32I2sXMethod.h @@ -26,8 +26,9 @@ License along with NeoPixel. If not, see . -------------------------------------------------------------------------*/ -// ESP32C3/S3 I2S is not supported yet due to significant changes to interface -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) +// ESP32 beyond C3 & S3 I2S is not supported yet +// due to significant changes to interface +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) extern "C" { diff --git a/src/internal/methods/NeoEsp32RmtMethod.cpp b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32RmtMethod.cpp similarity index 97% rename from src/internal/methods/NeoEsp32RmtMethod.cpp rename to src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32RmtMethod.cpp index 09feb344..32b2fce0 100644 --- a/src/internal/methods/NeoEsp32RmtMethod.cpp +++ b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32RmtMethod.cpp @@ -29,10 +29,12 @@ License along with NeoPixel. If not, see #include -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) +#if ESP_IDF_VERSION_MAJOR < 5 -#include "../NeoSettings.h" -#include "../NeoBusChannel.h" +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32H2) + +#include "../../../../NeoSettings.h" +#include "../../../../NeoBusChannel.h" #include "NeoEsp32RmtMethod.h" // translate NeoPixelBuffer into RMT buffer @@ -40,7 +42,7 @@ License along with NeoPixel. If not, see // which would be 32x larger than the primary buffer // // NOTE: This was moved from the template below to here to workaround a GCC bug -// That bug is that the IRAM_ATTR attribute (any attributes) is lost on template classes. +// That bug is that the IRAM_ATTR attribute (any attributes) is lost on template classes. // // Further, it was removed from the header to support current Esp32 release // which will need to be removed when the latest GitHub branchis released @@ -373,4 +375,5 @@ void NeoEsp32RmtInvertedSpeedGs1903::Translate(const void* src, RmtBit0, RmtBit1, RmtDurationReset); } -#endif \ No newline at end of file +#endif +#endif diff --git a/src/internal/methods/NeoEsp32RmtMethod.h b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32RmtMethod.h similarity index 99% rename from src/internal/methods/NeoEsp32RmtMethod.h rename to src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32RmtMethod.h index 208b1ac4..6ef2ae96 100644 --- a/src/internal/methods/NeoEsp32RmtMethod.h +++ b/src/internal/methods/ESP/ESP32/Core_2_x/NeoEsp32RmtMethod.h @@ -982,7 +982,7 @@ typedef NeoEsp32Rmt7Ws2805InvertedMethod NeoEsp32Rmt7Ws2814InvertedMethod; // Normally I2s method is the default, defining NEOPIXEL_ESP32_RMT_DEFAULT // will switch to use RMT as the default method -// The ESP32S2, ESP32S3, and ESP32C3 will always defualt to RMT +// The ESP32S2, ESP32S3, and ESP32C3 will always default to RMT #if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) @@ -1070,4 +1070,4 @@ typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod; #endif // defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) -#endif +#endif \ No newline at end of file diff --git a/src/internal/methods/DotStarEsp32DmaSpiMethod.h b/src/internal/methods/ESP/ESP32/DotStarEsp32DmaSpiMethod.h similarity index 96% rename from src/internal/methods/DotStarEsp32DmaSpiMethod.h rename to src/internal/methods/ESP/ESP32/DotStarEsp32DmaSpiMethod.h index f44e3cc9..a105e43d 100644 --- a/src/internal/methods/DotStarEsp32DmaSpiMethod.h +++ b/src/internal/methods/ESP/ESP32/DotStarEsp32DmaSpiMethod.h @@ -134,8 +134,8 @@ template class DotStarEsp32DmaSpiMethodB // If pins aren't specified, initialize bus with just the default SCK and MOSI pins for the SPI peripheral (no SS, no >1-bit pins) void Initialize() { -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) - if (T_SPIBUS::SpiHostDevice == VSPI_HOST) +#if SOC_SPI_PERIPH_NUM > 2 + if (T_SPIBUS::SpiHostDevice == SPI3_HOST) { Initialize(SCK, -1, MOSI, -1, -1, -1); } @@ -309,19 +309,20 @@ typedef DotStarEsp32DmaSpiMethodBase DotStarEsp // SPI3 -#if (defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)) +#if SOC_SPI_PERIPH_NUM > 2 + typedef Esp32SpiBus Esp32Spi3Bus; +typedef DotStarEsp32DmaSpiMethodBase DotStarEsp32DmaSpi3Method; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) + typedef Esp32SpiBus Esp32Spi32BitBus; typedef Esp32SpiBus Esp32Spi34BitBus; -typedef DotStarEsp32DmaSpiMethodBase DotStarEsp32DmaSpi3Method; typedef DotStarEsp32DmaSpiMethodBase DotStarEsp32DmaSpi32BitMethod; typedef DotStarEsp32DmaSpiMethodBase DotStarEsp32DmaSpi34BitMethod; -#endif -#if defined(CONFIG_IDF_TARGET_ESP32S2) -typedef Esp32SpiBus Esp32Spi3Bus; -typedef DotStarEsp32DmaSpiMethodBase DotStarEsp32DmaSpi3Method; +#endif #endif // Default SpiDma methods if we don't care about bus. It's nice that every single ESP32 out there diff --git a/src/internal/methods/NeoEsp32LcdXMethod.h b/src/internal/methods/ESP/ESP32/NeoEsp32LcdXMethod.h similarity index 98% rename from src/internal/methods/NeoEsp32LcdXMethod.h rename to src/internal/methods/ESP/ESP32/NeoEsp32LcdXMethod.h index e6e98ac1..b224331c 100644 --- a/src/internal/methods/NeoEsp32LcdXMethod.h +++ b/src/internal/methods/ESP/ESP32/NeoEsp32LcdXMethod.h @@ -30,7 +30,11 @@ License along with NeoPixel. If not, see extern "C" { +#if ESP_IDF_VERSION_MAJOR < 5 #include +#else +#include +#endif #include #include //#include @@ -38,7 +42,7 @@ extern "C" #include #include #include -#include "FractionClk.h" +#include "../../FractionClk.h" } // @@ -433,7 +437,13 @@ class NeoEspLcdMonoBuffContext .sibling_chan = NULL, .direction = GDMA_CHANNEL_DIRECTION_TX, .flags = {.reserve_sibling = 0}}; +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 + gdma_new_ahb_channel(&dma_chan_config, &_dmaChannel); +#elif CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 + gdma_new_axi_channel(&dma_chan_config, &_dmaChannel); +#else gdma_new_channel(&dma_chan_config, &_dmaChannel); +#endif gdma_connect(_dmaChannel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0)); gdma_strategy_config_t strategy_config = {.owner_check = false, .auto_update_desc = false}; @@ -542,7 +552,7 @@ class NeoEsp32LcdMuxBus uint8_t muxIdx = LCD_DATA_OUT0_IDX + _muxId; esp_rom_gpio_connect_out_signal(pin, muxIdx, invert, false); - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[pin], PIN_FUNC_GPIO); + PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[pin], PIN_FUNC_GPIO); gpio_set_drive_capability((gpio_num_t)pin, (gpio_drive_cap_t)3); } diff --git a/src/internal/methods/ESP/ESP32/NeoEsp32RmtSpeed.h b/src/internal/methods/ESP/ESP32/NeoEsp32RmtSpeed.h new file mode 100644 index 00000000..6a4d98ce --- /dev/null +++ b/src/internal/methods/ESP/ESP32/NeoEsp32RmtSpeed.h @@ -0,0 +1,165 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by donating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +class NeoEsp32RmtSpeedBase +{ +public: + // + // ClkDiv of 2 provides for good resolution and plenty of reset resolution; but + // a ClkDiv of 1 will provide enough space for the longest reset and does show + // little better pulse accuracy + const static uint8_t RmtClockDivider = 2; + const static uint32_t RmtCpu = 80000000L; // 80 mhz RMT clock + const static uint32_t NsPerSecond = 1000000000L; + const static uint32_t RmtTicksPerSecond = (RmtCpu / RmtClockDivider); + const static uint32_t NsPerRmtTick = (NsPerSecond / RmtTicksPerSecond); // about 25 + + inline constexpr static uint32_t FromNs(uint32_t ns) + { + return ns / NsPerRmtTick; + } + // this is used rather than the rmt_symbol_word_t as you can't correctly initialize + // it as a static constexpr within the template + inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) + { + return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh)); + } +}; + + +class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(300, 950); + const static uint32_t RmtBit1 = Item32Val(900, 350); + const static uint16_t RmtDurationReset = FromNs(300000); // 300us +}; + +class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(400, 850); + const static uint32_t RmtBit1 = Item32Val(800, 450); + const static uint16_t RmtDurationReset = FromNs(300000); // 300us +}; + +class NeoEsp32RmtSpeedWs2805 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(300, 790); + const static uint32_t RmtBit1 = Item32Val(790, 300); + const static uint16_t RmtDurationReset = FromNs(300000); // spec is 280, intentionally longer for compatiblity use +}; + +class NeoEsp32RmtSpeedSk6812 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(400, 850); + const static uint32_t RmtBit1 = Item32Val(800, 450); + const static uint16_t RmtDurationReset = FromNs(80000); // 80us +}; + +// normal is inverted signal +class NeoEsp32RmtSpeedTm1814 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(360, 890); + const static uint32_t RmtBit1 = Item32Val(720, 530); + const static uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +// normal is inverted signal +class NeoEsp32RmtSpeedTm1829 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(300, 900); + const static uint32_t RmtBit1 = Item32Val(800, 400); + const static uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +// normal is inverted signal +class NeoEsp32RmtSpeedTm1914 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(360, 890); + const static uint32_t RmtBit1 = Item32Val(720, 530); + const static uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +class NeoEsp32RmtSpeed800Kbps : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(400, 850); + const static uint32_t RmtBit1 = Item32Val(800, 450); + const static uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtSpeed400Kbps : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(800, 1700); + const static uint32_t RmtBit1 = Item32Val(1600, 900); + const static uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtSpeedApa106 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(350, 1350); + const static uint32_t RmtBit1 = Item32Val(1350, 350); + const static uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtSpeedTx1812 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(300, 600); + const static uint32_t RmtBit1 = Item32Val(600, 300); + const static uint16_t RmtDurationReset = FromNs(80000); // 80us +}; + +class NeoEsp32RmtSpeedGs1903 : public NeoEsp32RmtSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(300, 900); + const static uint32_t RmtBit1 = Item32Val(900, 300); + const static uint16_t RmtDurationReset = FromNs(40000); // 40us +}; + + +class NeoEsp32RmtNotInverted +{ +public: + const static bool Inverted = false; +}; + +class NeoEsp32RmtInverted +{ +public: + const static bool Inverted = true; +}; diff --git a/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h b/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h new file mode 100644 index 00000000..387946da --- /dev/null +++ b/src/internal/methods/ESP/ESP32/NeoEsp32RmtXMethod.h @@ -0,0 +1,404 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by donating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C2) + +#include +#include "NeoEsp32RmtSpeed.h" + +extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); + +extern "C" +{ +#include +#include "driver/rmt_tx.h" +#include "driver/rmt_encoder.h" +#include "esp_check.h" +} + +static const char *TAG = "led_strip_rmt"; // TODO: Remove all TAG log stuff + +struct led_strip_encoder_config_t +{ + uint32_t resolution; /*!< Encoder resolution, in Hz */ +}; + +struct rmt_led_strip_encoder_t +{ + rmt_encoder_t base; + rmt_encoder_t* bytes_encoder; + rmt_encoder_t* copy_encoder; + int state; + rmt_symbol_word_t reset_code; +}; + +#define NEOPIXELBUS_RMT_INT_FLAGS (ESP_INTR_FLAG_LOWMED) + + +template class NeoEsp32RmtMethodBase +{ +public: + typedef NeoNoSettings SettingsObject; + + NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel = NeoBusChannel_0) : + _sizeData(pixelCount* elementSize + settingsSize), + _pin(pin), + _channel(NULL) + { + construct(); + } + + ~NeoEsp32RmtMethodBase() + { + // wait until the last send finishes before destructing everything + // arbitrary time out of 10 seconds + + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_tx_wait_all_done(_channel, 10000 / portTICK_PERIOD_MS)); + ESP_ERROR_CHECK(rmt_disable(_channel)); + ESP_ERROR_CHECK(rmt_del_channel(_channel)); + + gpio_matrix_out(_pin, 0x100, false, false); + pinMode(_pin, INPUT); + + free(_dataEditing); + free(_dataSending); + } + + + bool IsReadyToUpdate() const + { + return (ESP_OK == rmt_tx_wait_all_done(_channel, 0)); + } + + void Initialize() + { + esp_err_t ret = ESP_OK; + rmt_tx_channel_config_t config = {}; + config.clk_src = RMT_CLK_SRC_DEFAULT; + config.gpio_num = static_cast(_pin); + // PARLA PATCH: was 192 — that's the ENTIRE RMT symbol pool on ESP32-C3/C6 + // (SOC_RMT_CHANNELS_PER_GROUP=4 * SOC_RMT_MEM_WORDS_PER_CHANNEL=48 = 192 total), + // so a single bus starved every other bus of memory and rmt_new_tx_channel() + // silently failed for the 2nd pin. 48 = one channel's native block (2 pixels + // of buffer before a refill IRQ), leaving room for a 2nd TX channel (48+48=96/192). + config.mem_block_symbols = 48; + config.resolution_hz = T_SPEED::RmtTicksPerSecond; // 1 MHz tick resolution, i.e., 1 tick = 1 µs + config.trans_queue_depth = 4; // set the number of transactions that can pend in the background + config.flags.invert_out = T_INVERTED::Inverted; // do not invert output signal + config.flags.with_dma = false; // do not need DMA backend + + ret += rmt_new_tx_channel(&config, &_channel); + led_strip_encoder_config_t encoder_config = {}; + encoder_config.resolution = T_SPEED::RmtTicksPerSecond; + + _tx_config.loop_count = 0; //no loop + + ret += rmt_new_led_strip_encoder(&encoder_config, &_led_encoder, T_SPEED::RmtBit0, T_SPEED::RmtBit1); + + // ESP_LOGI(TAG, "Enable RMT TX channel"); + ret += rmt_enable(_channel); + // PARLA PATCH: this used to be silently swallowed — make failures visible on Serial + // instead of the bus just not lighting up / misbehaving with no explanation. + if (ret != ESP_OK) { + Serial.printf("RMT init FAILED (err=%d) on pin %u\n", (int)ret, (unsigned)_pin); + } + } + + void Update(bool maintainBufferConsistency) + { + // AddLog(2,".."); + // wait for not actively sending data + // this will time out at 10 seconds, an arbitrarily long period of time + // and do nothing if this happens + + if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_tx_wait_all_done(_channel, 10000 / portTICK_PERIOD_MS))) + { + // AddLog(2,"__ %u", _sizeData); + // now start the RMT transmit with the editing buffer before we swap + // esp_err_t ret = + rmt_transmit(_channel, _led_encoder, _dataEditing, _sizeData, &_tx_config); // 3 for _sizeData + // AddLog(2,"rmt_transmit: %u", ret); + if (maintainBufferConsistency) + { + // copy editing to sending, + // this maintains the contract that "colors present before will + // be the same after", otherwise GetPixelColor will be inconsistent + memcpy(_dataSending, _dataEditing, _sizeData); + } + + // swap so the user can modify without affecting the async operation + std::swap(_dataSending, _dataEditing); + } + } + + bool AlwaysUpdate() + { + // this method requires update to be called only if changes to buffer + return false; + } + + bool SwapBuffers() + { + std::swap(_dataSending, _dataEditing); + return true; + } + + uint8_t* getData() const + { + return _dataEditing; + }; + + size_t getDataSize() const + { + return _sizeData; + } + + void applySettings(const SettingsObject& settings) + {} + +private: + const size_t _sizeData; // Size of '_data*' buffers + const uint8_t _pin; // output pin rmt_channel_handle_t + + rmt_transmit_config_t _tx_config = {}; + rmt_encoder_handle_t _led_encoder = nullptr; + rmt_channel_handle_t _channel = nullptr; // holds dynamic instance for multi channel support + + // Holds data stream which include LED color values and other settings as needed + uint8_t* _dataEditing; // exposed for get and set + uint8_t* _dataSending; // used for async send using RMT + + + void construct() + { + // AddLog(2,"RMT:construct"); + _dataEditing = static_cast(malloc(_sizeData)); + // data cleared later in Begin() + + _dataSending = static_cast(malloc(_sizeData)); + // no need to initialize it, it gets overwritten on every send + } + + + static size_t rmt_encode_led_strip(rmt_encoder_t* encoder, rmt_channel_handle_t channel, const void* primary_data, size_t data_size, rmt_encode_state_t* ret_state) + { + rmt_led_strip_encoder_t* led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = RMT_ENCODING_RESET; + rmt_encode_state_t state = RMT_ENCODING_RESET; + size_t encoded_symbols = 0; + + switch (led_encoder->state) + { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); + if (session_state & RMT_ENCODING_COMPLETE) + { + led_encoder->state = 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) + { + // static_cast(static_cast(a) | static_cast(b)); + state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_MEM_FULL)); + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + case 1: // send reset code + encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state); + if (session_state & RMT_ENCODING_COMPLETE) + { + led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session + state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_COMPLETE)); + } + if (session_state & RMT_ENCODING_MEM_FULL) + { + state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_MEM_FULL)); + goto out; // yield if there's no free space for encoding artifacts + } + } + + out: + *ret_state = state; + return encoded_symbols; + } + + static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t* encoder) + { + rmt_led_strip_encoder_t* led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + delete led_encoder; + return ESP_OK; + } + + static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t* encoder) + { + rmt_led_strip_encoder_t* led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = RMT_ENCODING_RESET; + return ESP_OK; + } + + static esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t* config, rmt_encoder_handle_t* ret_encoder, uint32_t bit0, uint32_t bit1) + { + esp_err_t ret = ESP_OK; + rmt_led_strip_encoder_t* led_encoder = NULL; + uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us + rmt_bytes_encoder_config_t bytes_encoder_config; + rmt_copy_encoder_config_t copy_encoder_config = {}; + rmt_symbol_word_t reset_code_config; + + + ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + led_encoder = new rmt_led_strip_encoder_t(); + ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder"); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + + bytes_encoder_config.bit0.val = bit0; + bytes_encoder_config.bit1.val = bit1; + + bytes_encoder_config.flags.msb_first = 1; // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - TODO: more checks +\ + ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, "TEST_RMT", "create bytes encoder failed"); + ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, "TEST_RMT", "create copy encoder failed"); + + reset_code_config.level0 = 0; + reset_code_config.duration0 = reset_ticks; + reset_code_config.level1 = 0; + reset_code_config.duration1 = reset_ticks; + led_encoder->reset_code = reset_code_config; + *ret_encoder = &led_encoder->base; + return ret; + + err: + // AddLog(2,"RMT:could not init led decoder"); + if (led_encoder) + { + if (led_encoder->bytes_encoder) + { + rmt_del_encoder(led_encoder->bytes_encoder); + } + if (led_encoder->copy_encoder) + { + rmt_del_encoder(led_encoder->copy_encoder); + } + delete led_encoder; + } + + return ret; + } + +}; + +// NOTE: While these are multi-instance auto channel selecting, there are limits +// to the number of times based on the specific ESP32 model it is compiled for +// ESP32 - 8x (beyond 4x may experience issues) +// ESP32S2 - 4x +// ESP32C3 - 2x +// ESP32S3 - 4x + +// normal +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXWs2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXWs2812xMethod; +typedef NeoEsp32RmtXWs2812xMethod NeoEsp32RmtXWs2816Method; +typedef NeoEsp32RmtXWs2812xMethod NeoEsp32RmtXWs2813Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXWs2805Method; +typedef NeoEsp32RmtXWs2805Method NeoEsp32RmtXWs2814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXSk6812Method; +typedef NeoEsp32RmtXSk6812Method NeoEsp32RmtXLc8812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXApa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXGs1903Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtX800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtX400KbpsMethod; + + +// inverted +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXWs2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXWs2812xInvertedMethod; +typedef NeoEsp32RmtXWs2812xInvertedMethod NeoEsp32RmtXWs2816InvertedMethod; +typedef NeoEsp32RmtXWs2812xInvertedMethod NeoEsp32RmtXWs2813InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXWs2805InvertedMethod; +typedef NeoEsp32RmtXWs2805InvertedMethod NeoEsp32RmtXWs2814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXSk6812InvertedMethod; +typedef NeoEsp32RmtXSk6812InvertedMethod NeoEsp32RmtXLc8812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXApa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXTx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtXGs1903InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtX800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtX400KbpsInvertedMethod; + +#if defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32S3) + +// Normally I2s method is the default, defining NEOPIXEL_ESP32_RMT_DEFAULT +// will switch to use RMT as the default method +// The ESP32S2, ESP32S3, ESP32C3, ESP32C6 will always default to RMT + +typedef NeoEsp32RmtXWs2805Method NeoWs2805Method; +typedef NeoEsp32RmtXWs2811Method NeoWs2811Method; +typedef NeoEsp32RmtXWs2812xMethod NeoWs2812xMethod; +typedef NeoEsp32RmtXWs2816Method NeoWs2816Method; +typedef NeoEsp32RmtXSk6812Method NeoSk6812Method; +typedef NeoEsp32RmtXLc8812Method NeoLc8812Method; +typedef NeoEsp32RmtXTm1814Method NeoTm1814Method; +typedef NeoEsp32RmtXTm1829Method NeoTm1829Method; +typedef NeoEsp32RmtXTm1914Method NeoTm1914Method; +typedef NeoEsp32RmtXApa106Method NeoApa106Method; +typedef NeoEsp32RmtXTx1812Method NeoTx1812Method; +typedef NeoEsp32RmtXWs2812xMethod Neo800KbpsMethod; +typedef NeoEsp32RmtX400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32RmtXWs2805InvertedMethod NeoWs2805InvertedMethod; +typedef NeoEsp32RmtXWs2811InvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32RmtXWs2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32RmtXWs2816InvertedMethod NeoWs2816InvertedMethod; +typedef NeoEsp32RmtXSk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32RmtXLc8812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32RmtXTm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32RmtXTm1829InvertedMethod NeoTm1829InvertedMethod; +typedef NeoEsp32RmtXTm1914InvertedMethod NeoTm1914InvertedMethod; +typedef NeoEsp32RmtXApa106InvertedMethod NeoApa106InvertedMethod; +typedef NeoEsp32RmtXTx1812InvertedMethod NeoTx1812InvertedMethod; +typedef NeoEsp32RmtXWs2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32RmtX400KbpsInvertedMethod Neo400KbpsInvertedMethod; + + +#endif // defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) + +#endif diff --git a/src/internal/methods/ESP/ESP32/NeoEsp32SpiMethod.h b/src/internal/methods/ESP/ESP32/NeoEsp32SpiMethod.h new file mode 100644 index 00000000..be621a04 --- /dev/null +++ b/src/internal/methods/ESP/ESP32/NeoEsp32SpiMethod.h @@ -0,0 +1,514 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +Adaption of Espressif's component library code by Christian Baars + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by donating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is not yet part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_ESP32) + +#include + +extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); // TODO: Remove all Addlogs + +extern "C" +{ +#include +#include "esp_rom_gpio.h" +#include "driver/spi_master.h" +#include "esp_check.h" +} + +#define LED_STRIP_SPI_DEFAULT_RESOLUTION (25 * 100 * 1000) // 2.5MHz resolution +#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4 + +#define SPI_BYTES_PER_COLOR_BYTE 3 +#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8) + +static const char *TAG = "led_strip_spi"; // TODO: Remove all TAG log stuff + +typedef enum { + LED_MODEL_WS2812, /*!< LED strip model: WS2812 */ + LED_MODEL_SK6812, /*!< LED strip model: SK6812 */ + LED_MODEL_INVALID /*!< Invalid LED strip model */ +} led_model_t; + +typedef enum { + LED_PIXEL_FORMAT_GRB, /*!< Pixel format: GRB */ + LED_PIXEL_FORMAT_GRBW, /*!< Pixel format: GRBW */ + LED_PIXEL_FORMAT_INVALID /*!< Invalid pixel format */ +} led_pixel_format_t; + +typedef struct { + spi_host_device_t spi_host; + spi_device_handle_t spi_device; + uint32_t strip_len; + uint8_t bytes_per_pixel; + uint8_t pixel_buf[]; +} led_strip_spi_obj; + +/** + * @brief LED Strip Configuration + */ +typedef struct { + int strip_gpio_num; /*!< GPIO number that used by LED strip */ + uint32_t max_leds; /*!< Maximum LEDs in a single strip */ + led_pixel_format_t led_pixel_format; /*!< LED pixel format */ + led_model_t led_model; /*!< LED model */ + + struct { + uint32_t invert_out: 1; /*!< Invert output signal */ + } flags; +} led_strip_config_t; + +typedef struct { + spi_clock_source_t clk_src; /*!< SPI clock source */ + spi_host_device_t spi_bus; /*!< SPI bus ID. Which buses are available depends on the specific chip */ + struct { + uint32_t with_dma: 1; /*!< Use DMA to transmit data */ + } flags; +} led_strip_spi_config_t; + + +class NeoEsp32SpiSpeed +{ +public: + + +protected: + +// end of deprecated section + +}; + +class NeoEsp32SpiSpeedBase : public NeoEsp32SpiSpeed +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedBase : public NeoEsp32SpiSpeed +{ +public: + +}; + +class NeoEsp32SpiSpeedWs2811 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedWs2812x : public NeoEsp32SpiSpeedBase +{ +public: + static const uint8_t bytes_per_pixel = 3; + +}; + +class NeoEsp32SpiSpeedSk6812 : public NeoEsp32SpiSpeedBase +{ +public: + static const uint8_t bytes_per_pixel = 4; + +}; + +class NeoEsp32SpiSpeed400Kbps : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedApa106 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedTx1812 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedWs2811 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedWs2812x : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedSk6812 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeed800Kbps : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeed400Kbps : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedApa106 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedTx1812 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiChannel +{ +public: + +}; + + +template class NeoEsp32SpiMethodBase +{ +public: + typedef NeoNoSettings SettingsObject; + + NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + // _pixelCount(pixelCount), + _pin(pin) + { + _pixelCount = pixelCount; + construct(); + } + + NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : + _sizeData(pixelCount* elementSize + settingsSize), + // _pixelCount(pixelCount), + _pin(pin) + // _channel(channel) // TODO: Refactor this somehow + { + _pixelCount = pixelCount; + construct(); + } + + ~NeoEsp32SpiMethodBase() + { + // wait until the last send finishes before destructing everything + // arbitrary time out of 10 seconds + + gpio_matrix_out(_pin, 0x100, false, false); + pinMode(_pin, INPUT); + + spi_bus_remove_device(_spi_strip->spi_device); + spi_bus_free(_spi_strip->spi_host); + free(_spi_strip); + + free(_dataEditing); + free(_dataSending); + } + + + bool IsReadyToUpdate() const + { + return true; // TODO + } + + void Initialize() + { + esp_err_t ret = ESP_OK; + uint8_t bytes_per_pixel = T_SPEED::bytes_per_pixel; + uint32_t mem_caps = MALLOC_CAP_DEFAULT; + spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT; + spi_bus_config_t spi_bus_cfg; + spi_device_interface_config_t spi_dev_cfg; + bool with_dma = true; /// TODO: pass value or compute based on pixelcount + int clock_resolution_khz = 0; + + // ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + // ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format"); + + // if ( LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRBW) { // TODO + // bytes_per_pixel = 4; + // } else if (LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRB) { + // bytes_per_pixel = 3; + // } else { + // assert(false); + // } + + if (with_dma) { // TODO + // DMA buffer must be placed in internal SRAM + mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; + } + _spi_strip = (led_strip_spi_obj *)heap_caps_calloc(1, sizeof(led_strip_spi_obj) + _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps); + + ESP_GOTO_ON_FALSE(_spi_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for spi strip"); + + _spi_strip->spi_host = SPI2_HOST; + + // for backward compatibility, if the user does not set the clk_src, use the default value + // if (clk_src) { + // clk_src = spi_config->clk_src; + // } + + spi_bus_cfg = { + .mosi_io_num = _pin, + //Only use MOSI to generate the signal, set -1 when other pins are not used. + .miso_io_num = -1, + .sclk_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, + }; + ESP_GOTO_ON_ERROR(spi_bus_initialize(_spi_strip->spi_host, &spi_bus_cfg, with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG, "create SPI bus failed"); + + // if (led_config->flags.invert_out == true) { + // esp_rom_gpio_connect_out_signal(_pin, spi_periph_signal[_spi_strip->spi_host].spid_out, true, false); + // } + + spi_dev_cfg = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = 0, + //set -1 when CS is not used + .clock_source = clk_src, + .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION, + .spics_io_num = -1, + .queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE, + }; + + ESP_GOTO_ON_ERROR(spi_bus_add_device(_spi_strip->spi_host, &spi_dev_cfg, &_spi_strip->spi_device), err, TAG, "Failed to add spi device"); + + spi_device_get_actual_freq(_spi_strip->spi_device, &clock_resolution_khz); + // TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution + // But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION + ESP_GOTO_ON_FALSE(clock_resolution_khz == LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000, ESP_ERR_NOT_SUPPORTED, err, + TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz); + + _spi_strip->bytes_per_pixel = bytes_per_pixel; + _spi_strip->strip_len = _pixelCount; + // if (ret) { + // AddLog(2,"SPI: initialized with error code: %u on pin: %u",ret, _pin); + // } + return; + err: + if (_spi_strip) { + if (_spi_strip->spi_device) { + spi_bus_remove_device(_spi_strip->spi_device); + } + if (_spi_strip->spi_host) { + spi_bus_free(_spi_strip->spi_host); + } + free(_spi_strip); + } + // if (ret) { + // AddLog(2,"SPI-Error:initialized with error code: %u on pin: %u",ret, _pin); + // } + return; + } + + void Update(bool maintainBufferConsistency) + { + // AddLog(2,".."); + // wait for not actively sending data + // this will time out at 10 seconds, an arbitrarily long period of time + // and do nothing if this happens + + // if READY + { + // AddLog(2,"__ %u", _sizeData); + // now start the SPI transmit with the editing buffer before we swap + led_strip_transmit_RGB_buffer(_dataEditing, _sizeData, T_SPEED::bytes_per_pixel); + + if (maintainBufferConsistency) + { + // copy editing to sending, + // this maintains the contract that "colors present before will + // be the same after", otherwise GetPixelColor will be inconsistent + memcpy(_dataSending, _dataEditing, _sizeData); + } + + // swap so the user can modify without affecting the async operation + std::swap(_dataSending, _dataEditing); + } + } + + bool AlwaysUpdate() + { + // this method requires update to be called only if changes to buffer + return false; + } + + bool SwapBuffers() + { + std::swap(_dataSending, _dataEditing); + return true; + } + + uint8_t* getData() const + { + return _dataEditing; + }; + + size_t getDataSize() const + { + return _sizeData; + } + + void applySettings(const SettingsObject& settings) + { + } + +private: + const size_t _sizeData; // Size of '_data*' buffers + int16_t _pixelCount; + const uint8_t _pin; // output pin number + T_CHANNEL _channel; // not really used here + + led_strip_spi_obj *_spi_strip; + + + // Holds data stream which include LED color values and other settings as needed + uint8_t* _dataEditing; // exposed for get and set + uint8_t* _dataSending; // used for async send using RMT - TODO: Check if this useful for SPI + + + void construct() + { + _dataEditing = static_cast(malloc(_sizeData)); + // data cleared later in Begin() + + _dataSending = static_cast(malloc(_sizeData)); + // no need to initialize it, it gets overwritten on every send + } + + // please make sure to zero-initialize the buf before calling this function + + void __led_strip_spi_bit(uint8_t data, uint8_t *buf) + { + // Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110 + // So a color byte occupies 3 bytes of SPI. + *(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2); + *(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5); + *(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00; + *(buf + 1) |= BIT(0); + *(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3); + *(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6); + *(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1); + *(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4); + *(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7); + } + + esp_err_t led_strip_spi_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) + { + if(index >= _spi_strip->strip_len) return ESP_FAIL; + // LED_PIXEL_FORMAT_GRB takes 72bits(9bytes) + uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + if (_spi_strip->bytes_per_pixel > 3) { + __led_strip_spi_bit(0, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + } + return ESP_OK; + } + + esp_err_t led_strip_spi_set_pixel_rgbw(uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) + { + // LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes) + uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + // SK6812 component order is GRBW + memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + __led_strip_spi_bit(white, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + + return ESP_OK; + } + + esp_err_t led_strip_spi_clear() + { + //Write zero to turn off all leds + memset(_spi_strip->pixel_buf, 0, _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + uint8_t *buf = _spi_strip->pixel_buf; + for (int index = 0; index < _spi_strip->strip_len * _spi_strip->bytes_per_pixel; index++) { + __led_strip_spi_bit(0, buf); + buf += SPI_BYTES_PER_COLOR_BYTE; + } + return led_strip_spi_refresh(); + } + + esp_err_t led_strip_spi_refresh() + { + spi_transaction_t tx_conf; + memset(&tx_conf, 0, sizeof(tx_conf)); + + tx_conf.length = _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE; + tx_conf.tx_buffer = _spi_strip->pixel_buf; + tx_conf.rx_buffer = NULL; + spi_device_transmit(_spi_strip->spi_device, &tx_conf); // TODO -check + return ESP_OK; + } + + void led_strip_transmit_RGB_buffer(uint8_t * buffer, size_t size, uint8_t bytes_per_pixel) + { + for (int i = 0; i < size; i+=bytes_per_pixel) { + led_strip_spi_set_pixel(i/bytes_per_pixel, buffer[i+1], buffer[i], buffer[i+2]); //GRB -> RGB + } + /* Refresh the strip to send data */ + led_strip_spi_refresh(); + } +}; + +// normal +typedef NeoEsp32SpiMethodBase NeoEsp32SpiN800KbpsMethod; +typedef NeoEsp32SpiMethodBase NeoEsp32SpiNSk6812Method; + + +// SPI channel method is the default method for Esp32C2 +#ifdef CONFIG_IDF_TARGET_ESP32C2 +typedef NeoEsp32SpiSpeedWs2812x NeoWs2813Method; +typedef NeoEsp32SpiSpeedWs2812x NeoWs2812xMethod; +typedef NeoEsp32SpiSpeedSk6812 NeoSk6812Method; + +#endif //CONFIG_IDF_TARGET_ESP32C2 + +#endif diff --git a/src/internal/methods/TwoWireHspiImple.h b/src/internal/methods/ESP/ESP32/TwoWireHspiImple.h similarity index 100% rename from src/internal/methods/TwoWireHspiImple.h rename to src/internal/methods/ESP/ESP32/TwoWireHspiImple.h diff --git a/src/internal/methods/NeoEsp8266DmaMethod.h b/src/internal/methods/ESP/ESP8266/NeoEsp8266DmaMethod.h similarity index 100% rename from src/internal/methods/NeoEsp8266DmaMethod.h rename to src/internal/methods/ESP/ESP8266/NeoEsp8266DmaMethod.h diff --git a/src/internal/methods/NeoEsp8266I2sDmx512Method.h b/src/internal/methods/ESP/ESP8266/NeoEsp8266I2sDmx512Method.h similarity index 100% rename from src/internal/methods/NeoEsp8266I2sDmx512Method.h rename to src/internal/methods/ESP/ESP8266/NeoEsp8266I2sDmx512Method.h diff --git a/src/internal/methods/NeoEsp8266I2sMethodCore.cpp b/src/internal/methods/ESP/ESP8266/NeoEsp8266I2sMethodCore.cpp similarity index 97% rename from src/internal/methods/NeoEsp8266I2sMethodCore.cpp rename to src/internal/methods/ESP/ESP8266/NeoEsp8266I2sMethodCore.cpp index 9f56db6c..042e3db8 100644 --- a/src/internal/methods/NeoEsp8266I2sMethodCore.cpp +++ b/src/internal/methods/ESP/ESP8266/NeoEsp8266I2sMethodCore.cpp @@ -25,7 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include -#include "../NeoUtil.h" +#include "../../../NeoUtil.h" #include "NeoEsp8266I2sMethodCore.h" #ifdef ARDUINO_ARCH_ESP8266 diff --git a/src/internal/methods/NeoEsp8266I2sMethodCore.h b/src/internal/methods/ESP/ESP8266/NeoEsp8266I2sMethodCore.h similarity index 99% rename from src/internal/methods/NeoEsp8266I2sMethodCore.h rename to src/internal/methods/ESP/ESP8266/NeoEsp8266I2sMethodCore.h index 3d64059a..39d75b7a 100644 --- a/src/internal/methods/NeoEsp8266I2sMethodCore.h +++ b/src/internal/methods/ESP/ESP8266/NeoEsp8266I2sMethodCore.h @@ -291,7 +291,7 @@ class NeoEsp8266I2sMethodCore // the last item will loop to the first item _i2sBufDesc[indexDesc - 1].next_link_ptr = reinterpret_cast(&(_i2sBufDesc[0])); - // the last state block will loop to the first state block by defualt + // the last state block will loop to the first state block by default _i2sBufDesc[c_StateBlockCount - 1].next_link_ptr = reinterpret_cast(&(_i2sBufDesc[0])); // setup the rest of i2s DMA diff --git a/src/internal/methods/NeoEsp8266UartMethod.cpp b/src/internal/methods/ESP/ESP8266/NeoEsp8266UartMethod.cpp similarity index 99% rename from src/internal/methods/NeoEsp8266UartMethod.cpp rename to src/internal/methods/ESP/ESP8266/NeoEsp8266UartMethod.cpp index 09213ac2..121366a7 100644 --- a/src/internal/methods/NeoEsp8266UartMethod.cpp +++ b/src/internal/methods/ESP/ESP8266/NeoEsp8266UartMethod.cpp @@ -27,7 +27,7 @@ License along with NeoPixel. If not, see #ifdef ARDUINO_ARCH_ESP8266 #include -#include "../NeoSettings.h" +#include "../../../NeoSettings.h" #include "NeoEsp8266UartMethod.h" #include extern "C" diff --git a/src/internal/methods/NeoEsp8266UartMethod.h b/src/internal/methods/ESP/ESP8266/NeoEsp8266UartMethod.h similarity index 100% rename from src/internal/methods/NeoEsp8266UartMethod.h rename to src/internal/methods/ESP/ESP8266/NeoEsp8266UartMethod.h diff --git a/src/internal/methods/NeoEspBitBangMethod.cpp b/src/internal/methods/ESP/NeoEspBitBangMethod.cpp similarity index 93% rename from src/internal/methods/NeoEspBitBangMethod.cpp rename to src/internal/methods/ESP/NeoEspBitBangMethod.cpp index 910d2dca..2deeefe2 100644 --- a/src/internal/methods/NeoEspBitBangMethod.cpp +++ b/src/internal/methods/ESP/NeoEspBitBangMethod.cpp @@ -36,7 +36,7 @@ static inline uint32_t getCycleCount(void) { uint32_t ccount; -#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) +#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) __asm__ __volatile__("csrr %0,0x7e2":"=r" (ccount)); //ccount = esp_cpu_get_ccount(); #else @@ -46,7 +46,8 @@ static inline uint32_t getCycleCount(void) } // Interrupt lock class, used for RAII interrupt disabling -class InterruptLock { +class InterruptLock +{ #if defined(ARDUINO_ARCH_ESP32) portMUX_TYPE updateMux; #endif @@ -61,7 +62,7 @@ class InterruptLock { } inline void unlock() - { + { #if defined(ARDUINO_ARCH_ESP32) portEXIT_CRITICAL(&updateMux); #else @@ -76,12 +77,12 @@ class InterruptLock { unlock(); lock(); } - + inline InterruptLock() #if defined(ARDUINO_ARCH_ESP32) : updateMux(portMUX_INITIALIZER_UNLOCKED) #endif - { + { lock(); } @@ -114,13 +115,13 @@ bool IRAM_ATTR neoEspBitBangWriteSpacingPixels(const uint8_t* pixels, volatile uint32_t* setRegister; volatile uint32_t* clearRegister; -#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) +#if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) if (pin < 32) { setRegister = &GPIO.out_w1ts.val; clearRegister = &GPIO.out_w1tc.val; } -#if !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32H2) else { setRegister = &GPIO.out1_w1ts.val; @@ -138,7 +139,7 @@ bool IRAM_ATTR neoEspBitBangWriteSpacingPixels(const uint8_t* pixels, setRegister = &GPIO.out1_w1ts.val; clearRegister = &GPIO.out1_w1tc.val; } -#endif // defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) +#endif // defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32H2) #else // just ESP8266 uint32_t setRegister = PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS; diff --git a/src/internal/methods/NeoEspBitBangMethod.h b/src/internal/methods/ESP/NeoEspBitBangMethod.h similarity index 91% rename from src/internal/methods/NeoEspBitBangMethod.h rename to src/internal/methods/ESP/NeoEspBitBangMethod.h index c8758919..01acd5d5 100644 --- a/src/internal/methods/NeoEspBitBangMethod.h +++ b/src/internal/methods/ESP/NeoEspBitBangMethod.h @@ -365,45 +365,6 @@ typedef NeoEsp32BitBangWs2805InvertedMethod NeoEsp32BitBangWs2814InvertedNoIntrM typedef NeoEsp32BitBangTm1814InvertedMethod NeoEsp32BitBangTm1914InvertedNoIntrMethod; typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedNoIntrMethod; -#if defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) -// -// Esp32 C6 && H2 currently use BitBang as the default until other support -// is created, as they are not compatible with older generation chips -typedef NeoEsp32BitBangWs2812xMethod NeoWs2813Method; -typedef NeoEsp32BitBangWs2812xMethod NeoWs2812xMethod; -typedef NeoEsp32BitBang800KbpsMethod NeoWs2812Method; -typedef NeoEsp32BitBangWs2812xMethod NeoWs2811Method; -typedef NeoEsp32BitBangWs2812xMethod NeoWs2816Method; -typedef NeoEsp32BitBangWs2805Method NeoWs2805Method; -typedef NeoEsp32BitBangWs2814Method NeoWs2814Method; -typedef NeoEsp32BitBangSk6812Method NeoSk6812Method; -typedef NeoEsp32BitBangTm1814Method NeoTm1814Method; -typedef NeoEsp32BitBangTm1829Method NeoTm1829Method; -typedef NeoEsp32BitBangTm1914Method NeoTm1914Method; -typedef NeoEsp32BitBangSk6812Method NeoLc8812Method; -typedef NeoEsp32BitBangApa106Method NeoApa106Method; - -typedef NeoEsp32BitBangWs2812xMethod Neo800KbpsMethod; -typedef NeoEsp32BitBang400KbpsMethod Neo400KbpsMethod; - -typedef NeoEsp32BitBangWs2812xInvertedMethod NeoWs2813InvertedMethod; -typedef NeoEsp32BitBangWs2812xInvertedMethod NeoWs2812xInvertedMethod; -typedef NeoEsp32BitBangWs2812xInvertedMethod NeoWs2811InvertedMethod; -typedef NeoEsp32BitBangWs2812xInvertedMethod NeoWs2816InvertedMethod; -typedef NeoEsp32BitBangWs2805InvertedMethod NeoWs2805InvertedMethod; -typedef NeoEsp32BitBangWs2814InvertedMethod NeoWs2814InvertedMethod; -typedef NeoEsp32BitBang800KbpsInvertedMethod NeoWs2812InvertedMethod; -typedef NeoEsp32BitBangSk6812InvertedMethod NeoSk6812InvertedMethod; -typedef NeoEsp32BitBangTm1814InvertedMethod NeoTm1814InvertedMethod; -typedef NeoEsp32BitBangTm1829InvertedMethod NeoTm1829InvertedMethod; -typedef NeoEsp32BitBangTm1914InvertedMethod NeoTm1914InvertedMethod; -typedef NeoEsp32BitBangSk6812InvertedMethod NeoLc8812InvertedMethod; -typedef NeoEsp32BitBangApa106InvertedMethod NeoApa106InvertedMethod; - -typedef NeoEsp32BitBangWs2812xInvertedMethod Neo800KbpsInvertedMethod; -typedef NeoEsp32BitBang400KbpsInvertedMethod Neo400KbpsInvertedMethod; -#endif - #else // defined(ARDUINO_ARCH_ESP8266) typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2811Method; diff --git a/src/internal/methods/Hd108GenericMethod.h b/src/internal/methods/Hd108GenericMethod.h index 6b9cbe5c..223b2a99 100644 --- a/src/internal/methods/Hd108GenericMethod.h +++ b/src/internal/methods/Hd108GenericMethod.h @@ -157,7 +157,7 @@ typedef Hd108MethodBase> Hd108Esp32VspiHzMethod; typedef Hd108Spi10MhzMethod Hd108Esp32VspiMethod; -#include "TwoWireHspiImple.h" +#include "ESP/ESP32/TwoWireHspiImple.h" typedef Hd108MethodBase> Hd108Esp32Hspi40MhzMethod; typedef Hd108MethodBase> Hd108Esp32Hspi20MhzMethod; typedef Hd108MethodBase> Hd108Esp32Hspi10MhzMethod; diff --git a/src/internal/methods/Mbi6033GenericMethod.h b/src/internal/methods/Mbi6033GenericMethod.h index 5f66729b..fdbf8ad5 100644 --- a/src/internal/methods/Mbi6033GenericMethod.h +++ b/src/internal/methods/Mbi6033GenericMethod.h @@ -197,7 +197,7 @@ typedef Mbi6033MethodBase> Mbi6033Esp32VspiHzMethod; typedef Mbi6033Spi10MhzMethod Mbi6033Esp32VspiMethod; -#include "TwoWireHspiImple.h" +#include "ESP/ESP32/TwoWireHspiImple.h" typedef Mbi6033MethodBase> Mbi6033Esp32Hspi40MhzMethod; typedef Mbi6033MethodBase> Mbi6033Esp32Hspi20MhzMethod; typedef Mbi6033MethodBase> Mbi6033Esp32Hspi10MhzMethod; diff --git a/src/internal/methods/Rp2040/NeoRp2040PioInstance.h b/src/internal/methods/Rp2040/NeoRp2040PioInstance.h index d51323b6..5fbb12ad 100644 --- a/src/internal/methods/Rp2040/NeoRp2040PioInstance.h +++ b/src/internal/methods/Rp2040/NeoRp2040PioInstance.h @@ -50,12 +50,28 @@ class NeoRp2040PioInstance1 const PIO Instance; }; +#if NUM_PIOS == 3 +class NeoRp2040PioInstance2 +{ +public: + NeoRp2040PioInstance2() : + Instance(pio2) + {}; + + const PIO Instance; +}; +#endif + // dynamic channel support class NeoRp2040PioInstanceN { public: NeoRp2040PioInstanceN(NeoBusChannel channel) : +#if NUM_PIOS == 2 Instance(channel == NeoBusChannel_0 ? pio0 : pio1) +#elif NUM_PIOS == 3 + Instance(channel == NeoBusChannel_0 ? pio0 : (channel == NeoBusChannel_1 ? pio1 : pio2)) +#endif { } NeoRp2040PioInstanceN() = delete; // no default constructor diff --git a/src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.h b/src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.h index 6ac3fc0b..bcd6bfc2 100644 --- a/src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.h +++ b/src/internal/methods/Rp2040/NeoRp2040PioMonoProgram.h @@ -164,7 +164,12 @@ class NeoRp2040PioMonoProgram public: static inline uint add(PIO pio_instance) { - size_t index = (pio_instance == pio0) ? 0 : 1; + size_t index = +#if NUM_PIOS == 2 + (pio_instance == pio0) ? 0 : 1; +#elif NUM_PIOS == 3 + (pio_instance == pio0) ? 0 : (pio_instance == pio1 ? 1 : 2); +#endif if (s_loadedOffset[index] == c_ProgramNotLoaded) { assert(pio_can_add_program(pio_instance, &T_CADENCE::program)); @@ -203,10 +208,16 @@ class NeoRp2040PioMonoProgram } private: - static uint s_loadedOffset[2]; // singlet instance of loaded program, one for each PIO hardware unit + static uint s_loadedOffset[NUM_PIOS]; // singlet instance of loaded program, one for each PIO hardware unit }; template -uint NeoRp2040PioMonoProgram::s_loadedOffset[] = {c_ProgramNotLoaded, c_ProgramNotLoaded}; +uint NeoRp2040PioMonoProgram::s_loadedOffset[] = +#if NUM_PIOS == 2 + {c_ProgramNotLoaded, c_ProgramNotLoaded}; +#elif NUM_PIOS == 3 + {c_ProgramNotLoaded, c_ProgramNotLoaded, c_ProgramNotLoaded}; +#endif + #endif diff --git a/src/internal/methods/Rp2040/NeoRp2040x4Method.h b/src/internal/methods/Rp2040/NeoRp2040x4Method.h index 8ba02fe8..6969ade2 100644 --- a/src/internal/methods/Rp2040/NeoRp2040x4Method.h +++ b/src/internal/methods/Rp2040/NeoRp2040x4Method.h @@ -118,13 +118,13 @@ class NeoRp2040x4MethodBase if (_sizeData % 4 == 0) { // data is 4 byte aligned in size, - // use a 32 bit fifo word for effeciency + // use a 32 bit fifo word for efficiency fifoWordBits = 32; } else if (_sizeData % 2 == 0) { // data is 2 byte aligned in size, - // use a 16 bit fifo word for effeciency + // use a 16 bit fifo word for efficiency fifoWordBits = 16; } @@ -364,6 +364,23 @@ typedef NeoRp2040x4MethodBase R typedef NeoRp2040x4MethodBase Rp2040x4Pio1400KbpsMethod; typedef Rp2040x4Pio1Ws2805Method Rp2040x4Pio1Ws2814Method; +#if NUM_PIOS == 3 +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2811Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2812xMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2816Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2805Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Sk6812Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tm1814Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tm1829Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tm1914Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Apa106Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tx1812Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Gs1903Method; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2800KbpsMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2400KbpsMethod; +typedef Rp2040x4Pio2Ws2805Method Rp2040x4Pio2Ws2814Method; +#endif + // inverted typedef NeoRp2040x4MethodBase Rp2040x4NWs2811InvertedMethod; typedef NeoRp2040x4MethodBase Rp2040x4NWs2812xInvertedMethod; @@ -410,6 +427,23 @@ typedef NeoRp2040x4MethodBase Rp2040x4Pio1400KbpsInvertedMethod; typedef Rp2040x4Pio1Ws2805InvertedMethod Rp2040x4Pio1Ws2814InvertedMethod; +#if NUM_PIOS == 3 +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2811InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2812xInvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2816InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Ws2805InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Sk6812InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tm1814InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tm1829InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tm1914InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Apa106InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Tx1812InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2Gs1903InvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2800KbpsInvertedMethod; +typedef NeoRp2040x4MethodBase Rp2040x4Pio2400KbpsInvertedMethod; +typedef Rp2040x4Pio2Ws2805InvertedMethod Rp2040x4Pio2Ws2814InvertedMethod; +#endif + // PIO 1 method is the default method, and still x4 instances typedef Rp2040x4Pio1Ws2812xMethod NeoWs2813Method; typedef Rp2040x4Pio1Ws2812xMethod NeoWs2812xMethod; diff --git a/src/internal/methods/Tlc59711GenericMethod.h b/src/internal/methods/Tlc59711GenericMethod.h index 68bde4be..8ad58105 100644 --- a/src/internal/methods/Tlc59711GenericMethod.h +++ b/src/internal/methods/Tlc59711GenericMethod.h @@ -214,7 +214,7 @@ typedef Tlc59711MethodBase> Tlc59711Esp32VspiHzMetho typedef Tlc59711MethodBase> Tlc59711Esp32VspiMethod; -#include "TwoWireHspiImple.h" +#include "ESP/ESP32/TwoWireHspiImple.h" typedef Tlc59711MethodBase> Tlc59711Esp32Hspi40MhzMethod; typedef Tlc59711MethodBase> Tlc59711Esp32Hspi20MhzMethod; typedef Tlc59711MethodBase> Tlc59711Esp32Hspi10MhzMethod;