From 580a51bef4510eb3d47ae4bd387cb20ed7190487 Mon Sep 17 00:00:00 2001 From: Benoit Anastay <45088785+BenoitAnastay@users.noreply.github.com> Date: Mon, 28 Mar 2022 01:07:23 +0200 Subject: An attempt to update ESP8266 SPI integration --- src/fastspi.h | 7 +- src/platforms/esp/8266/fastled_esp8266.h | 5 ++ src/platforms/esp/8266/fastspi_esp8266.h | 122 +++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/platforms/esp/8266/fastspi_esp8266.h diff --git a/src/fastspi.h b/src/fastspi.h index 3eabce13..603e755a 100644 --- a/src/fastspi.h +++ b/src/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) || (defined(ESP32) && defined(FASTLED_ALL_PINS_HARDWARE_SPI)) +#elif defined(FASTLED_TEENSY4) || (defined(ESP32) && defined(FASTLED_ALL_PINS_HARDWARE_SPI)) || (defined(ESP8266) && defined(FASTLED_ALL_PINS_HARDWARE_SPI)) // just use clocks #define DATA_RATE_MHZ(X) (1000000 * (X)) #define DATA_RATE_KHZ(X) (1000 * (X)) @@ -59,6 +59,11 @@ template class SPIOutput : public ESP32SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; #endif +#if defined(ESP8266) && defined(FASTLED_ALL_PINS_HARDWARE_SPI) +template +class SPIOutput : public ESP8266SPIOutput<_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/src/platforms/esp/8266/fastled_esp8266.h b/src/platforms/esp/8266/fastled_esp8266.h index 8c4048db..cb444336 100644 --- a/src/platforms/esp/8266/fastled_esp8266.h +++ b/src/platforms/esp/8266/fastled_esp8266.h @@ -1,5 +1,10 @@ #pragma once #include "fastpin_esp8266.h" + +#ifdef FASTLED_ALL_PINS_HARDWARE_SPI +#include "fastspi_esp8266.h" +#endif + #include "clockless_esp8266.h" #include "clockless_block_esp8266.h" diff --git a/src/platforms/esp/8266/fastspi_esp8266.h b/src/platforms/esp/8266/fastspi_esp8266.h new file mode 100644 index 00000000..be659eff --- /dev/null +++ b/src/platforms/esp/8266/fastspi_esp8266.h @@ -0,0 +1,122 @@ +#ifndef __INC_FASTSPI_ESP8266_H +#define __INC_FASTSPI_ESP8266_H + +#include "FastLED.h" + +#include "fastled_delay.h" + +#include + +FASTLED_NAMESPACE_BEGIN + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// An attempt to use harware spi on ESP8266 +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ESP8266SPIOutput { + Selectable *m_pSelect; + +public: + ESP8266SPIOutput() { m_pSelect = NULL; } + ESP8266SPIOutput(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) + SPI.begin(); + 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) { + SPI.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() { + SPI.beginTransaction(SPISettings(3200000, MSBFIRST, SPI_MODE0)); + if(m_pSelect != NULL) { m_pSelect->select(); } + } + + // release the SPI line + void release() { + if(m_pSelect != NULL) { m_pSelect->release(); } + SPI.endTransaction(); + } + + // Write out len bytes of the given value out over SPI. 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--) { + SPI.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) { + SPI.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 + +#endif \ No newline at end of file -- cgit v1.2.3