diff --git a/examples/ESP32/DotStarTest_Esp32Advanced/DotStarTest_Esp32Advanced.ino b/examples/ESP32/DotStarTest_Esp32Advanced/DotStarTest_Esp32Advanced.ino new file mode 100644 index 0000000..cd31da2 --- /dev/null +++ b/examples/ESP32/DotStarTest_Esp32Advanced/DotStarTest_Esp32Advanced.ino @@ -0,0 +1,159 @@ +// DotStarTest_Esp32Advanced - This example only works on the ESP32 +// This example will cycle between showing four pixels as Red, Green, Blue, White +// and then showing those pixels as Black. This example uses Hardware SPI on the ESP32 +// with options to use alternate pins for SPI and drive two SPI ports using the alternate +// additional SPI hardware available on the ESP32. +// +// There is serial output of the current state so you can confirm and follow along +// + +#include + +#define USE_DEFAULT_SPI_PORT 1 +#define USE_ALTERNATE_SPI_PORT 1 + +#if (USE_DEFAULT_SPI_PORT == 1) + const uint16_t PixelCount = 4; // this example assumes 4 pixels, making it smaller will cause a failure + + // It's usually better to use alternate pins. If set to false, strip will use GPIO 18 for Clock, GPIO 23 for Data, and pin 5 will output a chip select signal + const bool useSpiAlternatePins = true; + + // 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 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) + //NeoPixelBus strip(PixelCount, DotClockPin, DotDataPin); + + // for hardware SPI (best performance) with default SPI peripheral + NeoPixelBus strip(PixelCount); + + // DotStarSpiMethod defaults to 10MHz clock speed. For other speeds, replace "DotStarSpiMethod" with another method specifying speed, e.g. "DotStarSpi2MhzMethod" (see wiki for more details) + + // to change the SPI clock speed during runtime, use the "Hz" clock setting, e.g. DotStarSpiHzMethod, which default to 10MHz but supports updating during runtime + //NeoPixelBus strip(PixelCount); + //#define SET_CLOCK_SPEED_DURING_RUNTIME // only define if using "Hz" clock method + +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + const uint16_t PixelCount2 = 4; // this example assumes 4 pixels, making it smaller will cause a failure + + // It's usually better to use alternate pins. If set to false, strip2 will use GPIO 14 for Clock, GPIO 13 for Data, and pin 15 will output a chip select signal + const bool useSpiAlternatePins2 = true; + + // If you set useSpiAlternatePins2 true, then these pins will be used instead. Any output-capable GPIO can be used. + const uint8_t DotClockPin2 = 14; + const uint8_t DotDataPin2 = 13; + 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); + + // DotStarHspiMethod 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 DotStarSpiMethod and DotStarHspiMethod 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); +RgbColor blue(0, 0, colorSaturation); +RgbColor white(colorSaturation); +RgbColor black(0); + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + +#if (USE_DEFAULT_SPI_PORT == 1) + if (useSpiAlternatePins) + { + strip.Begin(DotClockPin, DotDataPin, DotDataPin, DotChipSelectPin); + } + else + { + strip.Begin(); + } + + strip.ClearTo(black); // this resets all the DotStars to an off state + strip.Show(); +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + if (useSpiAlternatePins2) + { + strip2.Begin(DotClockPin2, DotDataPin2, DotDataPin2, DotChipSelectPin2); + } + else + { + strip2.Begin(); + } + + strip2.ClearTo(black); // this resets all the DotStars to an off state + strip2.Show(); +#endif + + Serial.println(); + Serial.println("Running..."); +} + + +void loop() +{ + delay(5000); + +#if (USE_DEFAULT_SPI_PORT == 1) + Serial.println("Default SPI Colors R, G, B, W..."); + // set the colors, + strip.SetPixelColor(0, red); + strip.SetPixelColor(1, green); + strip.SetPixelColor(2, blue); + strip.SetPixelColor(3, white); + strip.Show(); +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + Serial.println("Alt SPI Colors W, B, G, R..."); + // set the colors, + strip2.SetPixelColor(0, white); + strip2.SetPixelColor(1, blue); + strip2.SetPixelColor(2, green); + strip2.SetPixelColor(3, red); + strip2.Show(); +#endif + + delay(5000); + + Serial.println("Off ..."); + +#if (USE_DEFAULT_SPI_PORT == 1) + #ifdef SET_CLOCK_SPEED_DURING_RUNTIME + uint32_t clockspeed = 5000000UL; + strip.SetMethodSettings(NeoSpiSettings(clockspeed)); + #endif + + // turn off the pixels + strip.SetPixelColor(0, black); + strip.SetPixelColor(1, black); + strip.SetPixelColor(2, black); + strip.SetPixelColor(3, black); + strip.Show(); +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + // turn off the pixels + strip2.SetPixelColor(0, black); + strip2.SetPixelColor(1, black); + strip2.SetPixelColor(2, black); + strip2.SetPixelColor(3, black); + strip2.Show(); +#endif +} diff --git a/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino b/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino new file mode 100644 index 0000000..9805ac4 --- /dev/null +++ b/examples/ESP32/DotStarTest_Esp32DmaSpi/DotStarTest_Esp32DmaSpi.ino @@ -0,0 +1,148 @@ +// DotStarTest_Esp32Advanced - This example only works on the ESP32 +// This example will cycle between showing four pixels as Red, Green, Blue, White +// and then showing those pixels as Black. This example uses DMA to drive Hardware SPI on the ESP32 +// with options to use alternate pins for SPI and drive two SPI ports +// +// There is serial output of the current state so you can confirm and follow along +// + +#include + +#define USE_DEFAULT_SPI_PORT 1 +#define USE_ALTERNATE_SPI_PORT 1 + +#if (USE_DEFAULT_SPI_PORT == 1) + const uint16_t PixelCount = 4; // this example assumes 4 pixels, making it smaller will cause a failure + + // It's usually better to use alternate pins. If set to false, strip will use GPIO 18 for Clock, GPIO 23 for Data, and pin 5 will output a chip select signal + const bool useSpiAlternatePins = true; + + // 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 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) + //NeoPixelBus strip(PixelCount, DotClockPin, DotDataPin); + + // for hardware SPI (best performance) with default SPI peripheral + 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 +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + const uint16_t PixelCount2 = 4; // this example assumes 4 pixels, making it smaller will cause a failure + + // It's usually better to use alternate pins. If set to false, strip2 will use GPIO 14 for Clock, GPIO 13 for Data, and pin 15 will output a chip select signal + const bool useSpiAlternatePins2 = true; + + // If you set useSpiAlternatePins2 true, then these pins will be used instead. Any output-capable GPIO can be used. + const uint8_t DotClockPin2 = 14; + const uint8_t DotDataPin2 = 13; + 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); + + // 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 + +RgbColor red(colorSaturation, 0, 0); +RgbColor green(0, colorSaturation, 0); +RgbColor blue(0, 0, colorSaturation); +RgbColor white(colorSaturation); +RgbColor black(0); + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + +#if (USE_DEFAULT_SPI_PORT == 1) + if (useSpiAlternatePins) + { + strip.Begin(DotClockPin, DotDataPin, DotDataPin, DotChipSelectPin); + } + else + { + strip.Begin(); + } + + strip.ClearTo(black); // this resets all the DotStars to an off state + strip.Show(); +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + if (useSpiAlternatePins2) + { + strip2.Begin(DotClockPin2, DotDataPin2, DotDataPin2, DotChipSelectPin2); + } + else + { + strip2.Begin(); + } + + strip2.ClearTo(black); // this resets all the DotStars to an off state + strip2.Show(); +#endif + + Serial.println(); + Serial.println("Running..."); +} + +void loop() +{ + delay(500); + +#if (USE_DEFAULT_SPI_PORT == 1) + Serial.println("Default SPI Colors R, G, B, W..."); + // set the colors, + strip.SetPixelColor(0, red); + strip.SetPixelColor(1, green); + strip.SetPixelColor(2, blue); + strip.SetPixelColor(3, white); + strip.Show(); +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + Serial.println("Alt SPI Colors W, B, G, R..."); + // set the colors, + strip2.SetPixelColor(0, white); + strip2.SetPixelColor(1, blue); + strip2.SetPixelColor(2, green); + strip2.SetPixelColor(3, red); + strip2.Show(); +#endif + + delay(500); + + Serial.println("Off ..."); + +#if (USE_DEFAULT_SPI_PORT == 1) + // turn off the pixels + strip.SetPixelColor(0, black); + strip.SetPixelColor(1, black); + strip.SetPixelColor(2, black); + strip.SetPixelColor(3, black); + strip.Show(); +#endif + +#if (USE_ALTERNATE_SPI_PORT == 1) + // turn off the pixels + strip2.SetPixelColor(0, black); + strip2.SetPixelColor(1, black); + strip2.SetPixelColor(2, black); + strip2.SetPixelColor(3, black); + strip2.Show(); +#endif +} diff --git a/src/NeoPixelBus.h b/src/NeoPixelBus.h index 990405e..2151567 100644 --- a/src/NeoPixelBus.h +++ b/src/NeoPixelBus.h @@ -104,6 +104,7 @@ License along with NeoPixel. If not, see #include "internal/NeoEsp32I2sMethod.h" #include "internal/NeoEsp32RmtMethod.h" #include "internal/NeoEspBitBangMethod.h" +#include "internal/DotStarEsp32DmaSpiMethod.h" #elif defined(ARDUINO_ARCH_NRF52840) // must be before __arm__ @@ -172,13 +173,20 @@ public: ClearTo(0); } - // used by DotStartSpiMethod if pins can be configured + // used by DotStarSpiMethod/DotStarEsp32DmaSpiMethod if pins can be configured void Begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) { _method.Initialize(sck, miso, mosi, ss); ClearTo(0); } + // used by DotStarEsp32DmaSpiMethod if pins can be configured - reordered and extended version supporting quad SPI + void Begin(int8_t sck, int8_t dat0, int8_t dat1, int8_t dat2, int8_t dat3, int8_t ss) + { + _method.Initialize(sck, dat0, dat1, dat2, dat3, ss); + ClearTo(0); + } + void Show(bool maintainBufferConsistency = true) { if (!IsDirty()) diff --git a/src/internal/DotStarEsp32DmaSpiMethod.h b/src/internal/DotStarEsp32DmaSpiMethod.h new file mode 100644 index 0000000..af2da7b --- /dev/null +++ b/src/internal/DotStarEsp32DmaSpiMethod.h @@ -0,0 +1,335 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using Esp32, DMA and SPI (APA102). + +Written by Michael C. Miller. +DotStarEsp32DmaSpiMethod written by Louis Beaudoin (Pixelvation) + +I invest time and resources providing this open source code, +please support me by dontating (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 + +#include "driver/spi_master.h" + +class Esp32VspiBus +{ +public: + static const spi_host_device_t SpiHostDevice = VSPI_HOST; + static const int dmaChannel = 1; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow + static const int parallelBits = 1; +}; + +class Esp32HspiBus +{ +public: + static const spi_host_device_t SpiHostDevice = HSPI_HOST; + static const int dmaChannel = 2; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow + static const int parallelBits = 1; +}; + +class Esp32Vspi2BitBus +{ +public: + static const spi_host_device_t SpiHostDevice = VSPI_HOST; + static const int dmaChannel = 1; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow + static const int parallelBits = 2; +}; + +class Esp32Hspi2BitBus +{ +public: + static const spi_host_device_t SpiHostDevice = HSPI_HOST; + static const int dmaChannel = 2; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow + static const int parallelBits = 2; +}; + +class Esp32Vspi4BitBus +{ +public: + static const spi_host_device_t SpiHostDevice = VSPI_HOST; + static const int dmaChannel = 1; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow + static const int parallelBits = 4; +}; + +class Esp32Hspi4BitBus +{ +public: + static const spi_host_device_t SpiHostDevice = HSPI_HOST; + static const int dmaChannel = 2; // arbitrary assignment, but based on the fact there are only two DMA channels and two available SPI ports, we need to split them somehow + static const int parallelBits = 4; +}; + +template class DotStarEsp32DmaSpiMethod +{ +public: + typedef typename T_SPISPEED::SettingsObject SettingsObject; + + 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) + { + _spiBufferSize = _sizeStartFrame + _sizePixelData + _sizeEndFrame; + + // must have a 4 byte aligned buffer for i2s + uint32_t alignment = _spiBufferSize % 4; + if (alignment) + { + _spiBufferSize += 4 - alignment; + } + + _data = static_cast(malloc(_spiBufferSize)); + _dmadata = static_cast(heap_caps_malloc(_spiBufferSize, MALLOC_CAP_DMA)); + + // data cleared later in NeoPixelBus::Begin() + } + + // 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() + { + if (_spiHandle) + { + DeInitSpiDevice(); + esp_err_t ret = spi_bus_free(T_SPIBUS::SpiHostDevice); + ESP_ERROR_CHECK(ret); + } + free(_data); + free(_dmadata); + _spiHandle = NULL; + } + + bool IsReadyToUpdate() const + { + spi_transaction_t t; + spi_transaction_t * tptr = &t; + esp_err_t ret = spi_device_get_trans_result(_spiHandle, &tptr, 0); + + // We know the previous transaction completed if we got ESP_OK, and we know there's no transactions queued if tptr is unmodified + return (ret == ESP_OK || tptr == &t); + } + + void Initialize(int8_t sck, int8_t dat0, int8_t dat1, int8_t dat2, int8_t dat3, int8_t ss) + { + memset(_data, 0x00, _sizeStartFrame); + memset(_data + _sizeStartFrame + _sizePixelData, 0x00, _spiBufferSize - (_sizeStartFrame + _sizePixelData)); + + _ssPin = ss; + + esp_err_t ret; + spi_bus_config_t buscfg; + memset(&buscfg, 0x00, sizeof(buscfg)); + + buscfg.miso_io_num = dat1; + buscfg.mosi_io_num = dat0; + buscfg.sclk_io_num = sck; + buscfg.quadwp_io_num = dat2; + buscfg.quadhd_io_num = dat3; + buscfg.max_transfer_sz = _spiBufferSize; + + //Initialize the SPI bus + ret=spi_bus_initialize(T_SPIBUS::SpiHostDevice, &buscfg, T_SPIBUS::dmaChannel); + ESP_ERROR_CHECK(ret); + + InitSpiDevice(); + } + + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + Initialize(sck, mosi, miso, -1, -1, ss); + } + + // 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 (T_SPIBUS::SpiHostDevice == VSPI_HOST) + { + Initialize(SCK, -1, MOSI, -1, -1, -1); + } + else + { + Initialize(14, -1, 13, -1, -1, -1); + } + } + + void Update(bool) + { + while(!IsReadyToUpdate()); + + memcpy(_dmadata, _data, _spiBufferSize); + + memset(&_spiTransaction, 0, sizeof(spi_transaction_t)); + _spiTransaction.length = (_spiBufferSize) * 8; // in bits not bytes! + if (T_SPIBUS::parallelBits == 1) + { + _spiTransaction.flags = 0; + } + if (T_SPIBUS::parallelBits == 2) + { + _spiTransaction.flags = SPI_TRANS_MODE_DIO; + } + if (T_SPIBUS::parallelBits == 4) + { + _spiTransaction.flags = SPI_TRANS_MODE_QIO; + } + _spiTransaction.tx_buffer = _dmadata; + + esp_err_t ret = spi_device_queue_trans(_spiHandle, &_spiTransaction, 0); //Transmit! + assert(ret == ESP_OK); //Should have had no issues. + } + + uint8_t* getData() const + { + return _data + _sizeStartFrame; + }; + + size_t getDataSize() const + { + return _sizePixelData; + }; + + void applySettings(const SettingsObject& settings) + { + _speed.applySettings(settings); + if (_spiHandle) + { + DeInitSpiDevice(); + InitSpiDevice(); + } + } + +private: + void InitSpiDevice() + { + spi_device_interface_config_t devcfg = {}; + + devcfg.clock_speed_hz = _speed.Clock; + devcfg.mode = 0; //SPI mode 0 + devcfg.spics_io_num = _ssPin; //CS pin + devcfg.queue_size = 1; + if (T_SPIBUS::parallelBits == 1) + { + devcfg.flags=0; + } + if (T_SPIBUS::parallelBits >= 2) + { + devcfg.flags=SPI_DEVICE_HALFDUPLEX; + } + + //Allocate the LEDs on the SPI bus + esp_err_t ret=spi_bus_add_device(T_SPIBUS::SpiHostDevice, &devcfg, &_spiHandle); + ESP_ERROR_CHECK(ret); + } + + void DeInitSpiDevice() + { + while(!IsReadyToUpdate()); + esp_err_t ret = spi_bus_remove_device(_spiHandle); + ESP_ERROR_CHECK(ret); + } + + const size_t _sizeStartFrame = 4; + const size_t _sizePixelData; // Size of '_data' buffer below, minus (_sizeStartFrame + _sizeEndFrame) + const size_t _sizeEndFrame; + + size_t _spiBufferSize; + uint8_t* _data; // Holds start/end frames and LED color values + uint8_t* _dmadata; // Holds start/end frames and LED color values + spi_device_handle_t _spiHandle = NULL; + spi_transaction_t _spiTransaction; + T_SPISPEED _speed; + int8_t _ssPin; +}; + +// 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; + +// 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; + +// 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; + +// 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; + +// 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; + +// 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; diff --git a/src/internal/DotStarGenericMethod.h b/src/internal/DotStarGenericMethod.h index 0896267..81a4527 100644 --- a/src/internal/DotStarGenericMethod.h +++ b/src/internal/DotStarGenericMethod.h @@ -134,14 +134,37 @@ typedef DotStarMethodBase DotStarMethod; typedef DotStarMethodBase> DotStarSpi40MhzMethod; typedef DotStarMethodBase> DotStarSpi20MhzMethod; typedef DotStarMethodBase> DotStarSpi10MhzMethod; +typedef DotStarMethodBase> DotStarSpi5MhzMethod; typedef DotStarMethodBase> DotStarSpi2MhzMethod; typedef DotStarMethodBase> DotStarSpi1MhzMethod; typedef DotStarMethodBase> DotStarSpi500KhzMethod; - typedef DotStarMethodBase> DotStarSpiHzMethod; typedef DotStarSpi10MhzMethod DotStarSpiMethod; #endif +#if defined(ARDUINO_ARCH_ESP32) +// Give option to use Vspi alias of Spi class if wanting to specify which SPI peripheral is used on the ESP32 +typedef DotStarMethodBase> DotStarVspi40MhzMethod; +typedef DotStarMethodBase> DotStarVspi20MhzMethod; +typedef DotStarMethodBase> DotStarVspi10MhzMethod; +typedef DotStarMethodBase> DotStarVspi5MhzMethod; +typedef DotStarMethodBase> DotStarVspi2MhzMethod; +typedef DotStarMethodBase> DotStarVspi1MhzMethod; +typedef DotStarMethodBase> DotStarVspi500KhzMethod; +typedef DotStarMethodBase> DotStarVspiHzMethod; +typedef DotStarSpi10MhzMethod DotStarVspiMethod; +#include "TwoWireHspiImple.h" +typedef DotStarMethodBase> DotStarHspi40MhzMethod; +typedef DotStarMethodBase> DotStarHspi20MhzMethod; +typedef DotStarMethodBase> DotStarHspi10MhzMethod; +typedef DotStarMethodBase> DotStarHspi5MhzMethod; +typedef DotStarMethodBase> DotStarHspi2MhzMethod; +typedef DotStarMethodBase> DotStarHspi1MhzMethod; +typedef DotStarMethodBase> DotStarHspi500KhzMethod; +typedef DotStarMethodBase> DotStarHspiHzMethod; + +typedef DotStarHspi10MhzMethod DotStarHspiMethod; +#endif diff --git a/src/internal/Lpd6803GenericMethod.h b/src/internal/Lpd6803GenericMethod.h index c3bc669..ecb7e49 100644 --- a/src/internal/Lpd6803GenericMethod.h +++ b/src/internal/Lpd6803GenericMethod.h @@ -129,6 +129,7 @@ typedef Lpd6803MethodBase Lpd6803Method; #include "TwoWireSpiImple.h" typedef Lpd6803MethodBase> Lpd6803Spi20MhzMethod; typedef Lpd6803MethodBase> Lpd6803Spi10MhzMethod; +typedef Lpd6803MethodBase> Lpd6803Spi5MhzMethod; typedef Lpd6803MethodBase> Lpd6803Spi2MhzMethod; typedef Lpd6803MethodBase> Lpd6803Spi1MhzMethod; typedef Lpd6803MethodBase> Lpd6803Spi500KhzMethod; diff --git a/src/internal/Lpd8806GenericMethod.h b/src/internal/Lpd8806GenericMethod.h index 08248de..c2372f2 100644 --- a/src/internal/Lpd8806GenericMethod.h +++ b/src/internal/Lpd8806GenericMethod.h @@ -129,6 +129,7 @@ typedef Lpd8806MethodBase Lpd8806Method; #include "TwoWireSpiImple.h" typedef Lpd8806MethodBase> Lpd8806Spi20MhzMethod; typedef Lpd8806MethodBase> Lpd8806Spi10MhzMethod; +typedef Lpd8806MethodBase> Lpd8806Spi5MhzMethod; typedef Lpd8806MethodBase> Lpd8806Spi2MhzMethod; typedef Lpd8806MethodBase> Lpd8806Spi1MhzMethod; typedef Lpd8806MethodBase> Lpd8806Spi500KhzMethod; diff --git a/src/internal/P9813GenericMethod.h b/src/internal/P9813GenericMethod.h index b2d77fa..2fd1d4b 100644 --- a/src/internal/P9813GenericMethod.h +++ b/src/internal/P9813GenericMethod.h @@ -125,6 +125,7 @@ typedef P9813MethodBase P9813Method; #include "TwoWireSpiImple.h" typedef P9813MethodBase> P9813Spi20MhzMethod; typedef P9813MethodBase> P9813Spi10MhzMethod; +typedef P9813MethodBase> P9813Spi5MhzMethod; typedef P9813MethodBase> P9813Spi2MhzMethod; typedef P9813MethodBase> P9813Spi1MhzMethod; typedef P9813MethodBase> P9813Spi500KhzMethod; diff --git a/src/internal/TwoWireHspiImple.h b/src/internal/TwoWireHspiImple.h new file mode 100644 index 0000000..5a96bd5 --- /dev/null +++ b/src/internal/TwoWireHspiImple.h @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using ESP32's alternate SPI (HSPI) (APA102/LPD8806). + +Written by Michael C. Miller. +Minor changes adapting TwoWireSpiImple to support HSPI by Louis Beaudoin (Pixelvation) + +I invest time and resources providing this open source code, +please support me by dontating (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 + +#include + +template class TwoWireHspiImple +{ +public: + typedef typename T_SPISPEED::SettingsObject SettingsObject; + + TwoWireHspiImple(uint8_t, uint8_t) // clock and data pins ignored for hardware SPI + { + _hspi = new SPIClass(HSPI); + } + + ~TwoWireHspiImple() + { + _hspi->end(); + delete _hspi; + } + +#if defined(ARDUINO_ARCH_ESP32) + // for cases where hardware SPI can have pins changed + void begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _hspi->begin(sck, miso, mosi, ss); + } +#endif + + void begin() + { + _hspi->begin(); + } + + void beginTransaction() + { + _hspi->beginTransaction(SPISettings(_speed.Clock, MSBFIRST, SPI_MODE0)); + } + + void endTransaction() + { + _hspi->endTransaction(); + } + + void transmitByte(uint8_t data) + { + _hspi->transfer(data); + } + + void transmitBytes(const uint8_t* data, size_t dataSize) + { + // ESPs have a method to write without inplace overwriting the send buffer + // since we don't care what gets received, use it for performance + // FIX: but for what ever reason on Esp32, its not const + _hspi->writeBytes(const_cast(data), dataSize); + } + + void applySettings(const SettingsObject& settings) + { + _speed.applySettings(settings); + } + +private: + SPIClass * _hspi = NULL; + T_SPISPEED _speed; +}; diff --git a/src/internal/TwoWireSpiImple.h b/src/internal/TwoWireSpiImple.h index abea45b..906d86b 100644 --- a/src/internal/TwoWireSpiImple.h +++ b/src/internal/TwoWireSpiImple.h @@ -1,5 +1,5 @@ /*------------------------------------------------------------------------- -NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). +NeoPixel library helper functions for DotStars using SPI (APA102/LPD8806). Written by Michael C. Miller. @@ -61,6 +61,17 @@ public: static const uint32_t Clock = 10000000L; }; +class SpiSpeed5Mhz +{ +public: + typedef NeoNoSettings SettingsObject; + SpiSpeed5Mhz() {}; + + static void applySettings(const SettingsObject& settings) {} + + static const uint32_t Clock = 5000000L; +}; + class SpiSpeed2Mhz { public: diff --git a/src/internal/Ws2801GenericMethod.h b/src/internal/Ws2801GenericMethod.h index 7e63f6b..24521c6 100644 --- a/src/internal/Ws2801GenericMethod.h +++ b/src/internal/Ws2801GenericMethod.h @@ -131,6 +131,7 @@ typedef Ws2801MethodBase NeoWs2801Method; #include "TwoWireSpiImple.h" typedef Ws2801MethodBase> NeoWs2801Spi20MhzMethod; typedef Ws2801MethodBase> NeoWs2801Spi10MhzMethod; +typedef Ws2801MethodBase> NeoWs2801Spi5MhzMethod; typedef Ws2801MethodBase> NeoWs2801Spi2MhzMethod; typedef Ws2801MethodBase> NeoWs2801Spi1MhzMethod; typedef Ws2801MethodBase> NeoWs2801Spi500KhzMethod;