From d2199451c112e7b3f79e06fc7c237879f04e512c Mon Sep 17 00:00:00 2001 From: Shlomo Zippel Date: Sun, 8 Jan 2023 13:51:17 -0800 Subject: [PATCH] Revamp ESP32 SPI DMA support (#608) * Renamed all of the SPI buses and provided classes for all of the valid combinations of bus and bit width * Updated dotstar dma spi example to use new names and to work on all 4 supported esp32 variants --- .../DotStarTest_Esp32DmaSpi.ino | 24 +- src/internal/DotStarEsp32DmaSpiMethod.h | 230 ++++++------------ 2 files changed, 98 insertions(+), 156 deletions(-) diff --git a/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino b/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino index 9805ac4..41ffdba 100644 --- a/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino +++ b/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino @@ -6,10 +6,28 @@ // There is serial output of the current state so you can confirm and follow along // +// +// ESP32 SPI Buses and up to how many bits they support: +// ESP32: Spi1 (4 bit) | Spi2 (4 bit) | Spi3 (4 bit) +// ESP32-S2: | Spi2 (8 bit) | Spi3 +// ESP32-S3: | Spi2 (8 bit) | Spi3 (4 bit) +// ESP32-C3: | Spi2 (4 bit) | +// +// If a DotStarEsp32DmaSpi method is used without specifying the bus number +// then Spi2 will be used by default +// +// In this demo if an alternate SPI bus is chosen then Spi3 will be used + #include #define USE_DEFAULT_SPI_PORT 1 + +// C3 only has a single Spi bus +#if CONFIG_IDF_TARGET_ESP32C3 +#define USE_ALTERNATE_SPI_PORT 0 +#else #define USE_ALTERNATE_SPI_PORT 1 +#endif #if (USE_DEFAULT_SPI_PORT == 1) const uint16_t PixelCount = 4; // this example assumes 4 pixels, making it smaller will cause a failure @@ -26,7 +44,7 @@ //NeoPixelBus strip(PixelCount, DotClockPin, DotDataPin); // for hardware SPI (best performance) with default SPI peripheral - NeoPixelBus strip(PixelCount); + NeoPixelBus strip(PixelCount); // DotStarEsp32DmaVspiMethod defaults to 10MHz clock speed. For other speeds, replace "DotStarSpiMethod" with another method specifying speed, e.g. "DotStarSpi2MhzMethod" (see wiki for more details) // See DotStarTest_Esp32Advanced example for how to set clock speed at runtime @@ -44,14 +62,14 @@ const int8_t DotChipSelectPin2 = -1; // -1 means the chip select signal won't be output, freeing up one pin compared to useSpiAlternatePins2=false // for hardware SPI (best performance) with alternate SPI peripheral - NeoPixelBus strip2(PixelCount2); + NeoPixelBus strip2(PixelCount2); // DotStarEsp32DmaHspiMethod defaults to 10MHz clock speed. For other speeds, replace "DotStarSpiMethod" with another method specifying speed, e.g. "DotStarHspi2MhzMethod" (see wiki for more details) #endif #define colorSaturation 128 -// Note that both DotStarEsp32DmaVspiMethod and DotStarEsp32DmaHspiMethod can be used with DotStarLbgrFeature and DotStarWbgrFeature but to keep things simple those are excluded from this example, see DotStarTest for more details +// Note that both DotStarEsp32DmaSpiMethod and DotStarEsp32DmaSpi1Method can be used with DotStarLbgrFeature and DotStarWbgrFeature but to keep things simple those are excluded from this example, see DotStarTest for more details RgbColor red(colorSaturation, 0, 0); RgbColor green(0, colorSaturation, 0); diff --git a/src/internal/DotStarEsp32DmaSpiMethod.h b/src/internal/DotStarEsp32DmaSpiMethod.h index 992e25c..37b2098 100644 --- a/src/internal/DotStarEsp32DmaSpiMethod.h +++ b/src/internal/DotStarEsp32DmaSpiMethod.h @@ -29,75 +29,13 @@ License along with NeoPixel. If not, see #include "driver/spi_master.h" -#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)) && !defined(HSPI_HOST) -// HSPI_HOST depreciated in C3 & S3 -#define HSPI_HOST SPI2_HOST -#endif - -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) -class Esp32VspiBus -{ -public: - const static spi_host_device_t SpiHostDevice = VSPI_HOST; - const static int ParallelBits = 1; -}; -#endif - -class Esp32HspiBus -{ -public: - const static spi_host_device_t SpiHostDevice = HSPI_HOST; - const static int ParallelBits = 1; -}; - -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) -class Esp32Vspi2BitBus -{ -public: - const static spi_host_device_t SpiHostDevice = VSPI_HOST; - const static int ParallelBits = 2; -}; -#endif - -class Esp32Hspi2BitBus -{ -public: - const static spi_host_device_t SpiHostDevice = HSPI_HOST; - const static int ParallelBits = 2; -}; - -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) -class Esp32Vspi4BitBus -{ -public: - const static spi_host_device_t SpiHostDevice = VSPI_HOST; - const static int ParallelBits = 4; -}; -#endif - -class Esp32Hspi4BitBus -{ -public: - const static spi_host_device_t SpiHostDevice = HSPI_HOST; - const static int ParallelBits = 4; -}; - -#if defined(CONFIG_IDF_TARGET_ESP32S3) -class Esp32Hspi8BitBus -{ -public: - const static spi_host_device_t SpiHostDevice = HSPI_HOST; - const static int ParallelBits = 8; -}; -#endif - -template class DotStarEsp32DmaSpiMethod +template class _DotStarEsp32DmaSpiMethod { public: typedef typename T_SPISPEED::SettingsObject SettingsObject; - DotStarEsp32DmaSpiMethod(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _DotStarEsp32DmaSpiMethod(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : _sizePixelData(pixelCount * elementSize + settingsSize), _sizeEndFrame((pixelCount + 15) / 16) // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes) { @@ -117,12 +55,12 @@ public: } // Support constructor specifying pins by ignoring pins - DotStarEsp32DmaSpiMethod(uint8_t, uint8_t, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : - DotStarEsp32DmaSpiMethod(pixelCount, elementSize, settingsSize) + _DotStarEsp32DmaSpiMethod(uint8_t, uint8_t, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _DotStarEsp32DmaSpiMethod(pixelCount, elementSize, settingsSize) { } - ~DotStarEsp32DmaSpiMethod() + ~_DotStarEsp32DmaSpiMethod() { if (_spiHandle) { @@ -302,94 +240,80 @@ private: int8_t _ssPin; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) -// Clock Speed and Default Definitions for DotStarEsp32DmaVspi -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi40MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi20MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi10MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi5MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi1MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi500KhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspiHzMethod; -typedef DotStarEsp32DmaVspi10MhzMethod DotStarEsp32DmaVspiMethod; +// Unfortunately we have a bit of a mess with SPI bus names across different version of the ESP32 +// e.g ESP32 has SPI, HSPI, and VSPI (1, 2, and 3), ESP32-S2 has SPI, FSPI, and HSPI (1, 2, and 3) +// and the S3 and C3 dropped the silly names entirely and just uses SPI1, SPI2, and SPI3. +// +// SPI1 can be only be used by ESP32 and supports up to 4 bit +// SPI2 supports up to 4 bit output across all of those devices (!) and supports 8 bit on S2 and S3 +// SPI3 supports up to 4 bit output on ESP32 and S3, and 1 bit only on the S2 + +enum spi_bus_width_t { + WIDTH1 = 1, + WIDTH2 = 2, + WIDTH4 = 4, + WIDTH8 = 8, +}; + +template +struct Esp32SpiBus +{ + const static spi_host_device_t SpiHostDevice = bus; + const static int ParallelBits = bits; +}; + +// Define all valid ESP32 SPI Buses with a default speed + +// SPI1 -- ESP32 Only +#if defined(CONFIG_IDF_TARGET_ESP32) +typedef Esp32SpiBus Esp32Spi1Bus; +typedef Esp32SpiBus Esp32Spi12BitBus; +typedef Esp32SpiBus Esp32Spi14BitBus; + +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi1Method; +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi12BitMethod; +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi14BitMethod; #endif -// Clock Speed and Default Definitions for DotStarEsp32DmaHspi -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi40MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi20MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi10MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi5MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi1MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi500KhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspiHzMethod; - -typedef DotStarEsp32DmaHspi10MhzMethod DotStarEsp32DmaHspiMethod; - -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) -// Clock Speed and Default Definitions for DotStarEsp32DmaVspi2Bit -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit40MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit20MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit10MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit5MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit2MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit1MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit500KhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2BitHzMethod; - -typedef DotStarEsp32DmaVspi2Bit10MhzMethod DotStarEsp32DmaVspi2BitMethod; -#endif - -// Clock Speed and Default Definitions for DotStarEsp32DmaHspi2Bit -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2Bit40MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2Bit20MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2Bit10MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2Bit5MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2Bit2MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2Bit1MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2Bit500KhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi2BitHzMethod; - -typedef DotStarEsp32DmaHspi2Bit10MhzMethod DotStarEsp32DmaHspi2BitMethod; - -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) -// Clock Speed and Default Definitions for DotStarEsp32DmaVspi4Bit -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit40MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit20MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit10MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit5MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit2MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit1MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit500KhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4BitHzMethod; - -typedef DotStarEsp32DmaVspi4Bit10MhzMethod DotStarEsp32DmaVspi4BitMethod; -#endif - -// Clock Speed and Default Definitions for DotStarEsp32DmaHspi4Bit -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4Bit40MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4Bit20MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4Bit10MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4Bit5MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4Bit2MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4Bit1MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4Bit500KhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi4BitHzMethod; - -typedef DotStarEsp32DmaHspi4Bit10MhzMethod DotStarEsp32DmaHspi4BitMethod; - +// SPI2 +typedef Esp32SpiBus Esp32Spi2Bus; +typedef Esp32SpiBus Esp32Spi22BitBus; +typedef Esp32SpiBus Esp32Spi24BitBus; #if SOC_SPI_SUPPORT_OCT -// Clock Speed and Default Definitions for DotStarEsp32DmaHspi8Bit -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8Bit40MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8Bit20MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8Bit10MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8Bit5MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8Bit2MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8Bit1MhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8Bit500KhzMethod; -typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspi8BitHzMethod; +typedef Esp32SpiBus Esp32Spi28BitBus; +#endif -typedef DotStarEsp32DmaHspi8Bit10MhzMethod DotStarEsp32DmaHspi8BitMethod; -#endif \ No newline at end of file +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi2Method; +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi22BitMethod; +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi24BitMethod; +#if SOC_SPI_SUPPORT_OCT +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi28BitMethod; +#endif + + +// SPI3 +#if (defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)) +typedef Esp32SpiBus Esp32Spi3Bus; +typedef Esp32SpiBus Esp32Spi32BitBus; +typedef Esp32SpiBus Esp32Spi34BitBus; + +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi3Method; +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi32BitMethod; +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi34BitMethod; +#endif + +#if defined(CONFIG_IDF_TARGET_ESP32S2) +typedef Esp32SpiBus Esp32Spi3Bus; +typedef _DotStarEsp32DmaSpiMethod DotStarEsp32DmaSpi3Method; +#endif + +// Default SpiDma methods if we don't care about bus. It's nice that every single ESP32 out there +// supports up to 4 bits on SPI2 + +typedef DotStarEsp32DmaSpi2Method DotStarEsp32DmaSpiMethod; +typedef DotStarEsp32DmaSpi22BitMethod DotStarEsp32DmaSpi2BitMethod; +typedef DotStarEsp32DmaSpi24BitMethod DotStarEsp32DmaSpi4BitMethod; +#if SOC_SPI_SUPPORT_OCT +typedef DotStarEsp32DmaSpi28BitMethod DotStarEsp32DmaSpi8BitMethod; +#endif