From fc97aefe3f41a74e904fa64f2a567b84f28c711b Mon Sep 17 00:00:00 2001 From: Nick Wallace Date: Wed, 1 Jul 2020 13:16:34 -0400 Subject: Add hardware SPI support on ESP32 --- .DS_Store | Bin 0 -> 8196 bytes fastspi.h | 7 ++- platforms/.DS_Store | Bin 0 -> 8196 bytes platforms/esp/.DS_Store | Bin 0 -> 8196 bytes platforms/esp/32/fastled_esp32.h | 4 ++ platforms/esp/32/fastspi_esp32.h | 132 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 .DS_Store create mode 100644 platforms/.DS_Store create mode 100644 platforms/esp/.DS_Store mode change 100644 => 100755 platforms/esp/32/fastled_esp32.h create mode 100644 platforms/esp/32/fastspi_esp32.h diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..cf681fa9 Binary files /dev/null and b/.DS_Store differ diff --git a/fastspi.h b/fastspi.h index 2245ffe9..3996de47 100644 --- a/fastspi.h +++ b/fastspi.h @@ -13,7 +13,7 @@ FASTLED_NAMESPACE_BEGIN #if defined(FASTLED_TEENSY3) && (F_CPU > 48000000) #define DATA_RATE_MHZ(X) (((48000000L / 1000000L) / X)) #define DATA_RATE_KHZ(X) (((48000000L / 1000L) / X)) -#elif defined(FASTLED_TEENSY4) // && (ARM_HARDWARE_SPI) +#elif defined(FASTLED_TEENSY4) || (defined(ESP32) && defined(FASTLED_ALL_PINS_HARDWARE_SPI)) // just use clocks #define DATA_RATE_MHZ(X) (1000000 * (X)) #define DATA_RATE_KHZ(X) (1000 * (X)) @@ -54,6 +54,11 @@ template class SPIOutput : public APOLLO3HardwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; #endif +#if defined(ESP32) && defined(FASTLED_ALL_PINS_HARDWARE_SPI) +template +class SPIOutput : public ESP32SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; +#endif + #if defined(SPI_DATA) && defined(SPI_CLOCK) #if defined(FASTLED_TEENSY3) && defined(ARM_HARDWARE_SPI) diff --git a/platforms/.DS_Store b/platforms/.DS_Store new file mode 100644 index 00000000..ea4c6d40 Binary files /dev/null and b/platforms/.DS_Store differ diff --git a/platforms/esp/.DS_Store b/platforms/esp/.DS_Store new file mode 100644 index 00000000..821fadec Binary files /dev/null and b/platforms/esp/.DS_Store differ diff --git a/platforms/esp/32/fastled_esp32.h b/platforms/esp/32/fastled_esp32.h old mode 100644 new mode 100755 index edf27e7d..6e9a1c59 --- a/platforms/esp/32/fastled_esp32.h +++ b/platforms/esp/32/fastled_esp32.h @@ -2,6 +2,10 @@ #include "fastpin_esp32.h" +#ifdef FASTLED_ALL_PINS_HARDWARE_SPI +#include "fastspi_esp32.h" +#endif + #ifdef FASTLED_ESP32_I2S #include "clockless_i2s_esp32.h" #else diff --git a/platforms/esp/32/fastspi_esp32.h b/platforms/esp/32/fastspi_esp32.h new file mode 100644 index 00000000..b1f41783 --- /dev/null +++ b/platforms/esp/32/fastspi_esp32.h @@ -0,0 +1,132 @@ +#pragma once +#pragma message "ESP32 Hardware SPI support added" + +FASTLED_NAMESPACE_BEGIN + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// An attempt to use harware spi on ESP32 +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifndef FASTLED_ESP32_SPI_BUS + #define FASTLED_ESP32_SPI_BUS VSPI +#endif + +SPIClass ledSPI(FASTLED_ESP32_SPI_BUS); + +#if FASTLED_ESP32_SPI_BUS == VSPI + static uint8_t spiClk = 18; + static uint8_t spiMiso = 19; + static uint8_t spiMosi = 23; + static uint8_t spiCs = 5; +#elif FASTLED_ESP32_SPI_BUS == HSPI + static uint8_t spiClk = 14; + static uint8_t spiMiso = 12; + static uint8_t spiMosi = 13; + static uint8_t spiCs = 15; +#endif + +template +class ESP32SPIOutput { + Selectable *m_pSelect; + +public: + ESP32SPIOutput() { m_pSelect = NULL; } + ESP32SPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } + + void init() { + // set the pins to output and make sure the select is released (which apparently means hi? This is a bit + // confusing to me) + ledSPI.begin(spiClk, spiMiso, spiMosi, spiCs); + release(); + } + + // stop the SPI output. Pretty much a NOP with software, as there's no registers to kick + static void stop() { } + + // wait until the SPI subsystem is ready for more data to write. A NOP when bitbanging + static void wait() __attribute__((always_inline)) { } + static void waitFully() __attribute__((always_inline)) { wait(); } + + static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { writeByte(b); } + static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { writeByte(b); wait(); } + + static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); } + + // naive writeByte implelentation, simply calls writeBit on the 8 bits in the byte. + static void writeByte(uint8_t b) { + ledSPI.transfer(b); + } + +public: + + // select the SPI output (TODO: research whether this really means hi or lo. Alt TODO: move select responsibility out of the SPI classes + // entirely, make it up to the caller to remember to lock/select the line?) + void select() { + ledSPI.beginTransaction(SPISettings(SPI_SPEED, MSBFIRST, SPI_MODE0)); + if(m_pSelect != NULL) { m_pSelect->select(); } + } + + // release the SPI line + void release() { + if(m_pSelect != NULL) { m_pSelect->release(); } + ledSPI.endTransaction(); + } + + // Write out len bytes of the given value out over ledSPI. Useful for quickly flushing, say, a line of 0's down the line. + void writeBytesValue(uint8_t value, int len) { + select(); + writeBytesValueRaw(value, len); + release(); + } + + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { + ledSPI.transfer(value); + } + } + + // write a block of len uint8_ts out. Need to type this better so that explicit casts into the call aren't required. + // note that this template version takes a class parameter for a per-byte modifier to the data. + template void writeBytes(register uint8_t *data, int len) { + select(); + uint8_t *end = data + len; + while(data != end) { + writeByte(D::adjust(*data++)); + } + D::postBlock(len); + release(); + } + + // default version of writing a block of data out to the SPI port, with no data modifications being made + void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } + + // write a single bit out, which bit from the passed in byte is determined by template parameter + template inline void writeBit(uint8_t b) { + ledSPI.transfer(b); + } + + // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template + // parameters indicate how many uint8_ts to skip at the beginning of each grouping, as well as a class specifying a per + // byte of data modification to be made. (See DATA_NOP above) + template __attribute__((noinline)) void writePixels(PixelController pixels) { + select(); + int len = pixels.mLen; + while(pixels.has(1)) { + if(FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + } + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + pixels.advanceData(); + pixels.stepDithering(); + } + D::postBlock(len); + release(); + } +}; + +FASTLED_NAMESPACE_END \ No newline at end of file -- cgit v1.2.3 From 18f3692c105ddb801635cfd46fa118dd5cf1fae9 Mon Sep 17 00:00:00 2001 From: Nick Wallace Date: Wed, 1 Jul 2020 13:19:40 -0400 Subject: Add hardware SPI support on ESP32 --- .DS_Store | Bin 8196 -> 0 bytes platforms/.DS_Store | Bin 8196 -> 0 bytes platforms/esp/.DS_Store | Bin 8196 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 platforms/.DS_Store delete mode 100644 platforms/esp/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index cf681fa9..00000000 Binary files a/.DS_Store and /dev/null differ diff --git a/platforms/.DS_Store b/platforms/.DS_Store deleted file mode 100644 index ea4c6d40..00000000 Binary files a/platforms/.DS_Store and /dev/null differ diff --git a/platforms/esp/.DS_Store b/platforms/esp/.DS_Store deleted file mode 100644 index 821fadec..00000000 Binary files a/platforms/esp/.DS_Store and /dev/null differ -- cgit v1.2.3 From 91584ddb99ed9c8dad134305a4462778bcefdb36 Mon Sep 17 00:00:00 2001 From: Nick Wallace Date: Wed, 1 Jul 2020 13:24:32 -0400 Subject: Add comments to driver --- platforms/esp/32/fastspi_esp32.h | 46 +++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/platforms/esp/32/fastspi_esp32.h b/platforms/esp/32/fastspi_esp32.h index b1f41783..639b71da 100644 --- a/platforms/esp/32/fastspi_esp32.h +++ b/platforms/esp/32/fastspi_esp32.h @@ -3,11 +3,47 @@ FASTLED_NAMESPACE_BEGIN -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// An attempt to use harware spi on ESP32 -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * ESP32 Hardware SPI Driver + * + * Copyright (c) 2020 Nick Wallace + * Derived from code for ESP8266 hardware SPI by Benoit Anastay and . + * + * This hardware SPI implementation can drive clocked LEDs from either the + * VSPI or HSPI bus (aka SPI2 & SPI3). No support is provided for SPI1, because it is + * shared among devices and the cache for data (code) in the Flash as well as the PSRAM. + * + * To enable the hardware SPI driver, add the following line *before* including + * FastLED.h: + * + * #define FASTLED_ALL_PINS_HARDWARE_SPI + * + * This driver uses the VSPI bus by default (GPIO 18, 19, 23, & 5). To use the + * HSPI bus (GPIO 14, 12, 13, & 15) add the following line *before* including + * FastLED.h: + * + * #define FASTLED_ESP32_SPI_BUS HSPI + * + */ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ #ifndef FASTLED_ESP32_SPI_BUS #define FASTLED_ESP32_SPI_BUS VSPI -- cgit v1.2.3 From 70942f170a96b93638025dbd73e0b810bcb2839f Mon Sep 17 00:00:00 2001 From: Nick Wallace Date: Wed, 1 Jul 2020 13:24:59 -0400 Subject: Add comments to driver --- platforms/esp/32/fastspi_esp32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/esp/32/fastspi_esp32.h b/platforms/esp/32/fastspi_esp32.h index 639b71da..33d620fd 100644 --- a/platforms/esp/32/fastspi_esp32.h +++ b/platforms/esp/32/fastspi_esp32.h @@ -7,7 +7,7 @@ FASTLED_NAMESPACE_BEGIN * ESP32 Hardware SPI Driver * * Copyright (c) 2020 Nick Wallace - * Derived from code for ESP8266 hardware SPI by Benoit Anastay and . + * Derived from code for ESP8266 hardware SPI by Benoit Anastay. * * This hardware SPI implementation can drive clocked LEDs from either the * VSPI or HSPI bus (aka SPI2 & SPI3). No support is provided for SPI1, because it is -- cgit v1.2.3