forked from bbulkow/FastLED-idf
Change default to I2S driver, explain how to use RMT if you really want to
This commit is contained in:
1 parent
8f0da6ff4a
commit
89a419b1c9
5 files changed
+261
-55
No files matched your search
@@ -14,7 +14,7 @@ set(srcs
|
||||
"hal/esp32-hal-misc.c"
|
||||
"hal/esp32-hal-gpio.c"
|
||||
# remove the following if you want I2S instead of RMT hardware, just put a pound in front
|
||||
"platforms/esp/32/clockless_rmt_esp32.cpp"
|
||||
# "platforms/esp/32/clockless_rmt_esp32.cpp"
|
||||
)
|
||||
|
||||
# everything needs the ESP32 flag, not sure why this won't work
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
// prefer I2S? Comment this in.
|
||||
// Not the default because haven't tried it as much, does work
|
||||
// #define FASTLED_ESP32_I2S
|
||||
#define FASTLED_ESP32_I2S
|
||||
|
||||
#include "esp32-hal.h"
|
||||
|
||||
|
||||
@@ -519,7 +519,9 @@ protected:
|
||||
// -- Allocate i2s interrupt
|
||||
SET_PERI_REG_BITS(I2S_INT_ENA_REG(I2S_DEVICE), I2S_OUT_EOF_INT_ENA_V, 1, I2S_OUT_EOF_INT_ENA_S);
|
||||
ESP_ERROR_CHECK(
|
||||
esp_intr_alloc(interruptSource, 0 /* ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL3*/,
|
||||
// this seems to work great with the default 0 flag, but everything is in IRAM
|
||||
// so why not raise it a little? Because you'll get a panic, and I'm not sure why.
|
||||
esp_intr_alloc(interruptSource, 0 /* ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL2 */,
|
||||
&interruptHandler, 0, &gI2S_intr_handle)
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
#pragma message "ESP32 Hardware SPI support added"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
/*
|
||||
* ESP32 Hardware SPI Driver
|
||||
*
|
||||
* Copyright (c) 2020 Nick Wallace
|
||||
* 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
|
||||
* 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
|
||||
#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 <uint8_t DATA_PIN, uint8_t CLOCK_PIN, uint32_t SPI_SPEED>
|
||||
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 <class D> 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_NOP>(data, len); }
|
||||
|
||||
// write a single bit out, which bit from the passed in byte is determined by template parameter
|
||||
template <uint8_t BIT> 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 <uint8_t FLAGS, class D, EOrder RGB_ORDER> __attribute__((noinline)) void writePixels(PixelController<RGB_ORDER> 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
|
||||
Reference in new issue
Block a user