Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--library.json1
-rw-r--r--src/lib8tion.h10
-rw-r--r--src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h10
-rw-r--r--src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h2
-rw-r--r--src/platforms/arm/mxrt1062/octows2811_controller.h64
-rw-r--r--src/platforms/esp/32/clockless_block_esp32.h5
-rw-r--r--src/platforms/esp/32/clockless_i2s_esp32.h4
-rw-r--r--src/platforms/esp/32/clockless_rmt_esp32.cpp114
-rw-r--r--src/platforms/esp/32/clockless_rmt_esp32.h48
-rw-r--r--src/platforms/esp/32/fastpin_esp32.h167
-rw-r--r--src/platforms/esp/32/fastspi_esp32.h4
-rw-r--r--src/platforms/esp/32/led_sysdefs_esp32.h19
-rw-r--r--src/platforms/esp/8266/clockless_esp8266.h44
-rw-r--r--src/platforms/esp/8266/led_sysdefs_esp8266.h2
14 files changed, 379 insertions, 115 deletions
diff --git a/library.json b/library.json
index 9e330204..fdcde146 100644
--- a/library.json
+++ b/library.json
@@ -38,6 +38,7 @@
"homepage": "http://fastled.io",
"frameworks": "arduino",
"platforms": "atmelavr, atmelsam, freescalekinetis, nordicnrf51, nxplpc, ststm32, teensy, espressif8266, espressif32, nordicnrf52",
+ "headers": "FastLED.h",
"export": {
"exclude": [
"docs",
diff --git a/src/lib8tion.h b/src/lib8tion.h
index 0cc3baa4..80e27100 100644
--- a/src/lib8tion.h
+++ b/src/lib8tion.h
@@ -834,10 +834,7 @@ public:
uint16_t operator*(uint16_t v) { return (v*i) + ((v*f)>>F); }
int32_t operator*(int32_t v) { return (v*i) + ((v*f)>>F); }
int16_t operator*(int16_t v) { return (v*i) + ((v*f)>>F); }
-#ifdef FASTLED_ARM
- int operator*(int v) { return (v*i) + ((v*f)>>F); }
-#endif
-#ifdef FASTLED_APOLLO3
+#if defined(FASTLED_ARM) | defined(FASTLED_RISCV) | defined(FASTLED_APOLLO3)
int operator*(int v) { return (v*i) + ((v*f)>>F); }
#endif
};
@@ -846,10 +843,7 @@ template<class T, int F, int I> static uint32_t operator*(uint32_t v, q<T,F,I> &
template<class T, int F, int I> static uint16_t operator*(uint16_t v, q<T,F,I> & q) { return q * v; }
template<class T, int F, int I> static int32_t operator*(int32_t v, q<T,F,I> & q) { return q * v; }
template<class T, int F, int I> static int16_t operator*(int16_t v, q<T,F,I> & q) { return q * v; }
-#ifdef FASTLED_ARM
-template<class T, int F, int I> static int operator*(int v, q<T,F,I> & q) { return q * v; }
-#endif
-#ifdef FASTLED_APOLLO3
+#if defined(FASTLED_ARM) | defined(FASTLED_RISCV) | defined(FASTLED_APOLLO3)
template<class T, int F, int I> static int operator*(int v, q<T,F,I> & q) { return q * v; }
#endif
diff --git a/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
index ed3be816..1dd0021d 100644
--- a/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
@@ -56,24 +56,24 @@ protected:
next_mark = ARM_DWT_CYCCNT + off[0];
FastPin<DATA_PIN>::hi();
if(b&0x80) {
- while((next_mark - ARM_DWT_CYCCNT) > off[1]);
+ while((next_mark - ARM_DWT_CYCCNT) > off[2]);
FastPin<DATA_PIN>::lo();
} else {
- while((next_mark - ARM_DWT_CYCCNT) > off[2]);
+ while((next_mark - ARM_DWT_CYCCNT) > off[1]);
FastPin<DATA_PIN>::lo();
}
b <<= 1;
}
while(ARM_DWT_CYCCNT < next_mark);
- next_mark = ARM_DWT_CYCCNT + off[1];
+ next_mark = ARM_DWT_CYCCNT + off[0];
FastPin<DATA_PIN>::hi();
if(b&0x80) {
while((next_mark - ARM_DWT_CYCCNT) > off[2]);
FastPin<DATA_PIN>::lo();
} else {
- while((next_mark - ARM_DWT_CYCCNT) > off[2]);
+ while((next_mark - ARM_DWT_CYCCNT) > off[1]);
FastPin<DATA_PIN>::lo();
}
}
@@ -91,7 +91,7 @@ protected:
off[1] = _FASTLED_NS_TO_DWT(T2+T3);
off[2] = _FASTLED_NS_TO_DWT(T3);
- uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD));
+ uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD)*1000);
uint32_t next_mark = ARM_DWT_CYCCNT + off[0];
diff --git a/src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h
index 5098af33..0cd53602 100644
--- a/src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h
@@ -3,7 +3,7 @@
#include "fastpin_arm_mxrt1062.h"
#include "fastspi_arm_mxrt1062.h"
-#include "../k20/octows2811_controller.h"
+#include "octows2811_controller.h"
#include "../k20/ws2812serial_controller.h"
#include "../k20/smartmatrix_t3.h"
#include "clockless_arm_mxrt1062.h"
diff --git a/src/platforms/arm/mxrt1062/octows2811_controller.h b/src/platforms/arm/mxrt1062/octows2811_controller.h
new file mode 100644
index 00000000..d0000a40
--- /dev/null
+++ b/src/platforms/arm/mxrt1062/octows2811_controller.h
@@ -0,0 +1,64 @@
+#ifndef __INC_OCTOWS2811_CONTROLLER_H
+#define __INC_OCTOWS2811_CONTROLLER_H
+
+#ifdef USE_OCTOWS2811
+
+// #include "OctoWS2811.h"
+
+FASTLED_NAMESPACE_BEGIN
+
+template<EOrder RGB_ORDER = GRB, uint8_t CHIP = WS2811_800kHz>
+class COctoWS2811Controller : public CPixelLEDController<RGB_ORDER, 8, 0xFF> {
+ OctoWS2811 *pocto;
+ uint8_t *drawbuffer,*framebuffer;
+
+ void _init(int nLeds) {
+ if(pocto == NULL) {
+ drawbuffer = (uint8_t*)malloc(nLeds * 8 * 3);
+ framebuffer = (uint8_t*)malloc(nLeds * 8 * 3);
+
+ // byte ordering is handled in show by the pixel controller
+ int config = WS2811_RGB;
+ config |= CHIP;
+
+ pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, config);
+
+ pocto->begin();
+ }
+ }
+public:
+ COctoWS2811Controller() { pocto = NULL; }
+ virtual int size() { return CLEDController::size() * 8; }
+
+ virtual void init() { /* do nothing yet */ }
+
+ virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> &pixels) {
+ uint32_t size = pixels.size();
+ uint32_t sizeTimes8 = 8U * size;
+ _init(size);
+
+ uint32_t index = 0;
+ while (pixels.has(1)) {
+ for (uint32_t i = 0; i < 8; i++) {
+ uint8_t r = pixels.loadAndScale0(i);
+ uint8_t g = pixels.loadAndScale1(i);
+ uint8_t b = pixels.loadAndScale2(i);
+ pocto->setPixel(index, r, g, b);
+ index += size;
+ }
+ index -= sizeTimes8;
+ index++;
+ pixels.stepDithering();
+ pixels.advanceData();
+ }
+
+ pocto->show();
+ }
+
+};
+
+FASTLED_NAMESPACE_END
+
+#endif
+
+#endif
diff --git a/src/platforms/esp/32/clockless_block_esp32.h b/src/platforms/esp/32/clockless_block_esp32.h
index 45b7671c..3e3c139e 100644
--- a/src/platforms/esp/32/clockless_block_esp32.h
+++ b/src/platforms/esp/32/clockless_block_esp32.h
@@ -21,7 +21,10 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<FIRST_PIN>::port_t data_t;
- data_t mPinMask;
+ // Verify that the pin is valid
+ static_assert(FastPin<FIRST_PIN>::validpin(), "Invalid pin specified");
+
+ data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
diff --git a/src/platforms/esp/32/clockless_i2s_esp32.h b/src/platforms/esp/32/clockless_i2s_esp32.h
index 6306ccd2..845d625b 100644
--- a/src/platforms/esp/32/clockless_i2s_esp32.h
+++ b/src/platforms/esp/32/clockless_i2s_esp32.h
@@ -201,8 +201,8 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER>
// -- Store the GPIO pin
gpio_num_t mPin;
- // -- This instantiation forces a check on the pin choice
- FastPin<DATA_PIN> mFastPin;
+ // -- Verify that the pin is valid
+ static_assert(FastPin<DATA_PIN>::validpin(), "Invalid pin specified");
// -- Save the pixel controller
PixelController<RGB_ORDER> * mPixels;
diff --git a/src/platforms/esp/32/clockless_rmt_esp32.cpp b/src/platforms/esp/32/clockless_rmt_esp32.cpp
index 90ca046f..0f8ad9b3 100644
--- a/src/platforms/esp/32/clockless_rmt_esp32.cpp
+++ b/src/platforms/esp/32/clockless_rmt_esp32.cpp
@@ -108,12 +108,14 @@ uint8_t * ESP32RMTController::getPixelBuffer(int size_in_bytes)
void ESP32RMTController::init(gpio_num_t pin)
{
if (gInitialized) return;
+ esp_err_t espErr = ESP_OK;
for (int i = 0; i < gMaxChannel; i += gMemBlocks) {
gOnChannel[i] = NULL;
// -- RMT configuration for transmission
rmt_config_t rmt_tx;
+ memset(&rmt_tx, 0, sizeof(rmt_config_t));
rmt_tx.channel = rmt_channel_t(i);
rmt_tx.rmt_mode = RMT_MODE_TX;
rmt_tx.gpio_num = pin;
@@ -126,7 +128,8 @@ void ESP32RMTController::init(gpio_num_t pin)
rmt_tx.tx_config.idle_output_en = true;
// -- Apply the configuration
- rmt_config(&rmt_tx);
+ espErr = rmt_config(&rmt_tx);
+ FASTLED_DEBUG("rmt_config result: %d", espErr);
if (FASTLED_RMT_BUILTIN_DRIVER) {
rmt_driver_install(rmt_channel_t(i), 0, 0);
@@ -134,7 +137,8 @@ void ESP32RMTController::init(gpio_num_t pin)
// -- Set up the RMT to send 32 bits of the pulse buffer and then
// generate an interrupt. When we get this interrupt we
// fill the other part in preparation (like double-buffering)
- rmt_set_tx_thr_intr_en(rmt_channel_t(i), true, PULSES_PER_FILL);
+ espErr = rmt_set_tx_thr_intr_en(rmt_channel_t(i), true, PULSES_PER_FILL);
+ FASTLED_DEBUG("rmt_set_tx_thr_intr_en result: %d", espErr);
}
}
@@ -232,6 +236,7 @@ void IRAM_ATTR ESP32RMTController::startNext(int channel)
// for it to finish.
void IRAM_ATTR ESP32RMTController::startOnChannel(int channel)
{
+ esp_err_t espErr = ESP_OK;
// -- Assign this channel and configure the RMT
mRMT_channel = rmt_channel_t(channel);
@@ -240,7 +245,13 @@ void IRAM_ATTR ESP32RMTController::startOnChannel(int channel)
gOnChannel[channel] = this;
// -- Assign the pin to this channel
- rmt_set_pin(mRMT_channel, RMT_MODE_TX, mPin);
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
+ espErr = rmt_set_gpio(mRMT_channel, RMT_MODE_TX, mPin, false);
+ FASTLED_DEBUG("rmt_set_gpio result: %d", espErr);
+#else
+ espErr = rmt_set_pin(mRMT_channel, RMT_MODE_TX, mPin);
+ FASTLED_DEBUG("rrmt_set_pin result: %d", espErr);
+#endif
if (FASTLED_RMT_BUILTIN_DRIVER) {
// -- Use the built-in RMT driver to send all the data in one shot
@@ -262,7 +273,8 @@ void IRAM_ATTR ESP32RMTController::startOnChannel(int channel)
fillNext(false);
// -- Turn on the interrupts
- rmt_set_tx_intr_en(mRMT_channel, true);
+ espErr = rmt_set_tx_intr_en(mRMT_channel, true);
+ FASTLED_DEBUG("rmt_set_tx_intr_en result: %d", espErr);
// -- Kick off the transmission
tx_start();
@@ -275,11 +287,46 @@ void IRAM_ATTR ESP32RMTController::tx_start()
{
// rmt_tx_start(mRMT_channel, true);
// Inline the code for rmt_tx_start, so it can be placed in IRAM
+#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
+ // rmt_ll_tx_reset_pointer(&RMT, mRMT_channel)
+ RMT.tx_conf[mRMT_channel].mem_rd_rst = 1;
+ RMT.tx_conf[mRMT_channel].mem_rd_rst = 0;
+ RMT.tx_conf[mRMT_channel].mem_rst = 1;
+ RMT.tx_conf[mRMT_channel].mem_rst = 0;
+ // rmt_ll_clear_tx_end_interrupt(&RMT, mRMT_channel)
+ RMT.int_clr.val = (1 << (mRMT_channel));
+ // rmt_ll_enable_tx_end_interrupt(&RMT, mRMT_channel, true)
+ RMT.int_ena.val |= (1 << mRMT_channel);
+ // rmt_ll_tx_start(&RMT, mRMT_channel)
+ RMT.tx_conf[mRMT_channel].conf_update = 1;
+ RMT.tx_conf[mRMT_channel].tx_start = 1;
+#elif CONFIG_IDF_TARGET_ESP32S3
+ // rmt_ll_tx_reset_pointer(&RMT, mRMT_channel)
+ RMT.chnconf0[mRMT_channel].mem_rd_rst_n = 1;
+ RMT.chnconf0[mRMT_channel].mem_rd_rst_n = 0;
+ RMT.chnconf0[mRMT_channel].apb_mem_rst_n = 1;
+ RMT.chnconf0[mRMT_channel].apb_mem_rst_n = 0;
+ // rmt_ll_clear_tx_end_interrupt(&RMT, mRMT_channel)
+ RMT.int_clr.val = (1 << (mRMT_channel));
+ // rmt_ll_enable_tx_end_interrupt(&RMT, mRMT_channel, true)
+ RMT.int_ena.val |= (1 << mRMT_channel);
+ // rmt_ll_tx_start(&RMT, mRMT_channel)
+ RMT.chnconf0[mRMT_channel].conf_update_n = 1;
+ RMT.chnconf0[mRMT_channel].tx_start_n = 1;
+#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32
+ // rmt_ll_tx_reset_pointer(&RMT, mRMT_channel)
RMT.conf_ch[mRMT_channel].conf1.mem_rd_rst = 1;
RMT.conf_ch[mRMT_channel].conf1.mem_rd_rst = 0;
+ // rmt_ll_clear_tx_end_interrupt(&RMT, mRMT_channel)
+ RMT.int_clr.val = (1 << (mRMT_channel * 3));
+ // rmt_ll_enable_tx_end_interrupt(&RMT, mRMT_channel, true)
RMT.int_ena.val &= ~(1 << (mRMT_channel * 3));
RMT.int_ena.val |= (1 << (mRMT_channel * 3));
+ // rmt_ll_tx_start(&RMT, mRMT_channel)
RMT.conf_ch[mRMT_channel].conf1.tx_start = 1;
+#else
+ #error Not yet implemented for unknown ESP32 target
+#endif
mLastFill = __clock_cycles();
}
@@ -299,10 +346,51 @@ void IRAM_ATTR ESP32RMTController::doneOnChannel(rmt_channel_t channel, void * a
// -- Turn off the interrupts
// rmt_set_tx_intr_en(channel, false);
- // Inline the code for rmt_tx_stop, so it can be placed in IRAM
+
+ // Inline the code for rmt_set_tx_intr_en(channel, false) and rmt_tx_stop, so it can be placed in IRAM
+#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
+ // rmt_ll_enable_tx_end_interrupt(&RMT, channel)
+ RMT.int_ena.val &= ~(1 << channel);
+ // rmt_ll_tx_stop(&RMT, channel)
+ RMT.tx_conf[channel].tx_stop = 1;
+ RMT.tx_conf[channel].conf_update = 1;
+ // rmt_ll_tx_reset_pointer(&RMT, channel)
+ RMT.tx_conf[channel].mem_rd_rst = 1;
+ RMT.tx_conf[channel].mem_rd_rst = 0;
+ RMT.tx_conf[channel].mem_rst = 1;
+ RMT.tx_conf[channel].mem_rst = 0;
+#elif CONFIG_IDF_TARGET_ESP32S3
+ // rmt_ll_enable_tx_end_interrupt(&RMT, channel)
+ RMT.int_ena.val &= ~(1 << channel);
+ // rmt_ll_tx_stop(&RMT, channel)
+ RMT.chnconf0[channel].tx_stop_n = 1;
+ RMT.chnconf0[channel].conf_update_n = 1;
+ // rmt_ll_tx_reset_pointer(&RMT, channel)
+ RMT.chnconf0[channel].mem_rd_rst_n = 1;
+ RMT.chnconf0[channel].mem_rd_rst_n = 0;
+ RMT.chnconf0[channel].apb_mem_rst_n = 1;
+ RMT.chnconf0[channel].apb_mem_rst_n = 0;
+#elif CONFIG_IDF_TARGET_ESP32S2
+ // rmt_ll_enable_tx_end_interrupt(&RMT, channel)
+ RMT.int_ena.val &= ~(1 << (channel * 3));
+ // rmt_ll_tx_stop(&RMT, channel)
+ RMT.conf_ch[channel].conf1.tx_stop = 1;
+ // rmt_ll_tx_reset_pointer(&RMT, channel)
+ RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
+ RMT.conf_ch[channel].conf1.mem_rd_rst = 0;
+#elif CONFIG_IDF_TARGET_ESP32
+ // rmt_ll_enable_tx_end_interrupt(&RMT, channel)
RMT.int_ena.val &= ~(1 << (channel * 3));
+ // rmt_ll_tx_stop(&RMT, channel)
+ RMT.conf_ch[channel].conf1.tx_start = 0;
RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
RMT.conf_ch[channel].conf1.mem_rd_rst = 0;
+ // rmt_ll_tx_reset_pointer(&RMT, channel)
+ // RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
+ // RMT.conf_ch[channel].conf1.mem_rd_rst = 0;
+#else
+ #error Not yet implemented for unknown ESP32 target
+#endif
gOnChannel[channel] = NULL;
gNumDone++;
@@ -337,11 +425,17 @@ void IRAM_ATTR ESP32RMTController::interruptHandler(void *arg)
uint8_t channel;
for (channel = 0; channel < gMaxChannel; channel++) {
+ #if CONFIG_IDF_TARGET_ESP32S2
int tx_done_bit = channel * 3;
- #ifdef CONFIG_IDF_TARGET_ESP32S2
int tx_next_bit = channel + 12;
- #else
+ #elif CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
+ int tx_done_bit = channel;
+ int tx_next_bit = channel + 8;
+ #elif CONFIG_IDF_TARGET_ESP32
+ int tx_done_bit = channel * 3;
int tx_next_bit = channel + 24;
+ #else
+ #error Not yet implemented for unknown ESP32 target
#endif
ESP32RMTController * pController = gOnChannel[channel];
@@ -369,9 +463,9 @@ void IRAM_ATTR ESP32RMTController::fillNext(bool check_time)
{
uint32_t now = __clock_cycles();
if (check_time) {
- if (mLastFill != 0 and now > mLastFill) {
- uint32_t delta = (now - mLastFill);
- if (delta > mMaxCyclesPerFill) {
+ if (mLastFill != 0) {
+ int32_t delta = (now - mLastFill);
+ if (delta > (int32_t)mMaxCyclesPerFill) {
// Serial.print(delta);
// Serial.print(" BAIL ");
// Serial.println(mCur);
diff --git a/src/platforms/esp/32/clockless_rmt_esp32.h b/src/platforms/esp/32/clockless_rmt_esp32.h
index 8f5690bb..66b04928 100644
--- a/src/platforms/esp/32/clockless_rmt_esp32.h
+++ b/src/platforms/esp/32/clockless_rmt_esp32.h
@@ -80,6 +80,13 @@
* send the data while the program continues to prepare the next
* frame of data.
*
+ * #define FASTLED_RMT_SERIAL_DEBUG 1
+ *
+ * NEW (Oct 2021): If set enabled (Set to 1), output errorcodes to
+ * Serial for debugging if not ESP_OK. Might be useful to find
+ * bugs or problems with GPIO PINS.
+ *
+ *
* Based on public domain code created 19 Nov 2016 by Chris Osborn <fozztexx@fozztexx.com>
* http://insentricity.com *
*
@@ -136,7 +143,11 @@ extern void spi_flash_op_unlock(void);
__attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
uint32_t cyc;
+#ifdef FASTLED_XTENSA
__asm__ __volatile__ ("rsr %0,ccount":"=a" (cyc));
+#else
+ cyc = cpu_hal_get_cycle_count();
+#endif
return cyc;
}
@@ -151,6 +162,16 @@ __attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
//#define FASTLED_RMT_SHOW_TIMER false
//#endif
+#ifndef FASTLED_RMT_SERIAL_DEBUG
+#define FASTLED_RMT_SERIAL_DEBUG 0
+#endif
+
+#if FASTLED_RMT_SERIAL_DEBUG == 1
+#define FASTLED_DEBUG(format, errcode, ...) if (errcode != ESP_OK) { Serial.printf(PSTR("FASTLED: " format "\n"), errcode, ##__VA_ARGS__); }
+#else
+#define FASTLED_DEBUG(format, ...)
+#endif
+
// -- Configuration constants
#define DIVIDER 2 /* 4, 8 still seem to work, but timings become marginal */
@@ -164,11 +185,23 @@ __attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
#define FASTLED_RMT_MEM_BLOCKS 2
#endif
-#define MAX_PULSES (64 * FASTLED_RMT_MEM_BLOCKS) /* One block has a 64 "pulse" buffer */
+// 64 for ESP32, ESP32S2
+// 48 for ESP32S3, ESP32C3, ESP32H2
+#ifndef FASTLED_RMT_MEM_WORDS_PER_CHANNEL
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
+#define FASTLED_RMT_MEM_WORDS_PER_CHANNEL SOC_RMT_MEM_WORDS_PER_CHANNEL
+#else
+// ESP32 value (only chip variant supported on older IDF)
+#define FASTLED_RMT_MEM_WORDS_PER_CHANNEL 64
+#endif
+#endif
+
+#define MAX_PULSES (FASTLED_RMT_MEM_WORDS_PER_CHANNEL * FASTLED_RMT_MEM_BLOCKS)
#define PULSES_PER_FILL (MAX_PULSES / 2) /* Half of the channel buffer */
// -- Convert ESP32 CPU cycles to RMT device cycles, taking into account the divider
-#define F_CPU_RMT ( 80000000L)
+// RMT Clock is typically APB CLK, which is 80MHz on most devices, but 40MHz on ESP32-H2
+#define F_CPU_RMT ( APB_CLK_FREQ )
#define RMT_CYCLES_PER_SEC (F_CPU_RMT/DIVIDER)
#define RMT_CYCLES_PER_ESP_CYCLE (F_CPU / RMT_CYCLES_PER_SEC)
#define ESP_TO_RMT_CYCLES(n) ((n) / (RMT_CYCLES_PER_ESP_CYCLE))
@@ -188,14 +221,19 @@ __attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
#define FASTLED_RMT_MAX_CONTROLLERS 32
#endif
-// -- Max RMT channel (default to 8 on ESP32 and 4 on ESP32-S2)
+// -- Max RMT TX channel
#ifndef FASTLED_RMT_MAX_CHANNELS
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
+// 8 for (ESP32) 4 for (ESP32S2, ESP32S3) 2 for (ESP32C3, ESP32H2)
+#define FASTLED_RMT_MAX_CHANNELS SOC_RMT_TX_CANDIDATES_PER_GROUP
+#else
#ifdef CONFIG_IDF_TARGET_ESP32S2
#define FASTLED_RMT_MAX_CHANNELS 4
#else
#define FASTLED_RMT_MAX_CHANNELS 8
#endif
#endif
+#endif
class ESP32RMTController
{
@@ -316,8 +354,8 @@ private:
// -- The actual controller object for ESP32
ESP32RMTController mRMTController;
- // -- This instantiation forces a check on the pin choice
- FastPin<DATA_PIN> mFastPin;
+ // -- Verify that the pin is valid
+ static_assert(FastPin<DATA_PIN>::validpin(), "Invalid pin specified");
public:
diff --git a/src/platforms/esp/32/fastpin_esp32.h b/src/platforms/esp/32/fastpin_esp32.h
index 7876b281..7c77a738 100644
--- a/src/platforms/esp/32/fastpin_esp32.h
+++ b/src/platforms/esp/32/fastpin_esp32.h
@@ -2,34 +2,45 @@
FASTLED_NAMESPACE_BEGIN
-template<uint8_t PIN, uint32_t MASK> class _ESPPIN {
+template<uint8_t PIN, uint32_t MASK, bool VALIDPIN> class _ESPPIN {
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
- inline static void setOutput() { pinMode(PIN, OUTPUT); }
+ static constexpr bool validpin() { return VALIDPIN; }
+
+#ifndef GPIO_OUT1_REG
+ static constexpr uint32_t GPIO_REG = GPIO_OUT_REG;
+ static constexpr uint32_t GPIO_BIT_SET_REG = GPIO_OUT_W1TS_REG;
+ static constexpr uint32_t GPIO_BIT_CLEAR_REG = GPIO_OUT_W1TC_REG;
+ #else
+ static constexpr uint32_t GPIO_REG = PIN < 32 ? GPIO_OUT_REG : GPIO_OUT1_REG;
+ static constexpr uint32_t GPIO_BIT_SET_REG = PIN < 32 ? GPIO_OUT_W1TS_REG : GPIO_OUT1_W1TS_REG;
+ static constexpr uint32_t GPIO_BIT_CLEAR_REG = PIN < 32 ? GPIO_OUT_W1TC_REG : GPIO_OUT1_W1TC_REG;
+ #endif
+
+ inline static void setOutput() {
+ static_assert(validpin(), "Invalid pin specified");
+ pinMode(PIN, OUTPUT);
+ }
inline static void setInput() { pinMode(PIN, INPUT); }
inline static void hi() __attribute__ ((always_inline)) {
- if (PIN < 32) GPIO.out_w1ts = MASK;
- else GPIO.out1_w1ts.val = MASK;
+ *sport() = MASK;
}
inline static void lo() __attribute__ ((always_inline)) {
- if (PIN < 32) GPIO.out_w1tc = MASK;
- else GPIO.out1_w1tc.val = MASK;
+ *cport() = MASK;
}
inline static void set(register port_t val) __attribute__ ((always_inline)) {
- if (PIN < 32) GPIO.out = val;
- else GPIO.out1.val = val;
+ *port() = val;
}
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
inline static void toggle() __attribute__ ((always_inline)) {
- if(PIN < 32) { GPIO.out ^= MASK; }
- else { GPIO.out1.val ^=MASK; }
+ *port() ^= MASK;
}
inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
@@ -37,77 +48,111 @@ public:
inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
inline static port_t hival() __attribute__ ((always_inline)) {
- if (PIN < 32) return GPIO.out | MASK;
- else return GPIO.out1.val | MASK;
+ return (*port()) | MASK;
}
inline static port_t loval() __attribute__ ((always_inline)) {
- if (PIN < 32) return GPIO.out & ~MASK;
- else return GPIO.out1.val & ~MASK;
+ return (*port()) & ~MASK;
}
inline static port_ptr_t port() __attribute__ ((always_inline)) {
- if (PIN < 32) return &GPIO.out;
- else return &GPIO.out1.val;
+ return (port_ptr_t)GPIO_REG;
}
inline static port_ptr_t sport() __attribute__ ((always_inline)) {
- if (PIN < 32) return &GPIO.out_w1ts;
- else return &GPIO.out1_w1ts.val;
+ return (port_ptr_t)GPIO_BIT_SET_REG;
}
inline static port_ptr_t cport() __attribute__ ((always_inline)) {
- if (PIN < 32) return &GPIO.out_w1tc;
- else return &GPIO.out1_w1tc.val;
+ return (port_ptr_t)GPIO_BIT_CLEAR_REG;
}
inline static port_t mask() __attribute__ ((always_inline)) { return MASK; }
inline static bool isset() __attribute__ ((always_inline)) {
- if (PIN < 32) return GPIO.out & MASK;
- else return GPIO.out1.val & MASK;
+ return (*port()) & MASK;
}
};
-#define _FL_DEFPIN(PIN) template<> class FastPin<PIN> : public _ESPPIN<PIN, ((PIN<32)?((uint32_t)1 << PIN):((uint32_t)1 << (PIN-32)))> {};
-
-_FL_DEFPIN(0);
-_FL_DEFPIN(1); // WARNING: Using TX causes flashiness when uploading
-_FL_DEFPIN(2);
-_FL_DEFPIN(3); // WARNING: Using RX causes flashiness when uploading
-_FL_DEFPIN(4);
-_FL_DEFPIN(5);
-
-// -- These pins are not safe to use:
-// _FL_DEFPIN(6,6); _FL_DEFPIN(7,7); _FL_DEFPIN(8,8);
-// _FL_DEFPIN(9,9); _FL_DEFPIN(10,10); _FL_DEFPIN(11,11);
-
-_FL_DEFPIN(12);
-_FL_DEFPIN(13);
-_FL_DEFPIN(14);
-_FL_DEFPIN(15);
-_FL_DEFPIN(16);
-_FL_DEFPIN(17);
-_FL_DEFPIN(18);
-_FL_DEFPIN(19);
-
-// No pin 20 : _FL_DEFPIN(20,20);
-
-_FL_DEFPIN(21); // Works, but note that GPIO21 is I2C SDA
-_FL_DEFPIN(22); // Works, but note that GPIO22 is I2C SCL
-_FL_DEFPIN(23);
-
-// No pin 24 : _FL_DEFPIN(24,24);
-
-_FL_DEFPIN(25);
-_FL_DEFPIN(26);
-_FL_DEFPIN(27);
-
-// No pin 28-31: _FL_DEFPIN(28,28); _FL_DEFPIN(29,29); _FL_DEFPIN(30,30); _FL_DEFPIN(31,31);
-
-// Need special handling for pins > 31
-_FL_DEFPIN(32);
-_FL_DEFPIN(33);
+#ifndef FASTLED_UNUSABLE_PIN_MASK
+
+#define _FL_BIT(B) (1ULL << B)
+
+#if CONFIG_IDF_TARGET_ESP32
+// 40 GPIO pins. ESPIDF defined 24, 28-31 as invalid and 34-39 as readonly
+// GPIO 6-11 used by default for SPI flash. GPIO 20 is invalid.
+// NOTE: GPIO 1 & 3 commonly used for UART and may cause flashes when uploading.
+#define FASTLED_UNUSABLE_PIN_MASK (0ULL | _FL_BIT(6) | _FL_BIT(7) | _FL_BIT(8) | _FL_BIT(9) | _FL_BIT(10) | _FL_BIT(20))
+
+#elif CONFIG_IDF_TARGET_ESP32C3
+// 22 GPIO pins. ESPIDF defines all pins as valid
+// GPIO 11-17 used by default for SPI flash
+// NOTE: GPIO 20-21 commonly used for UART and may cause flashes when uploading.
+#define FASTLED_UNUSABLE_PIN_MASK (0ULL | _FL_BIT(11) | _FL_BIT(12) | _FL_BIT(13) | _FL_BIT(14) | _FL_BIT(15) | _FL_BIT(16) | _FL_BIT(17))
+
+#elif CONFIG_IDF_TARGET_ESP32S2
+// 48 GPIO pins. ESPIDF defines 22-25, 47 as invalid and 46-47 as readonly.s
+// GPIO 27-32 used by default for SPI flash.
+// NOTE: GPIO 37 & 38 commonly used for UART and may cause flashes when uploading.
+#define FASTLED_UNUSABLE_PIN_MASK (0ULL | _FL_BIT(27) | _FL_BIT(28) | _FL_BIT(29) | _FL_BIT(30) | _FL_BIT(31) | _FL_BIT(32))
+
+#elif CONFIG_IDF_TARGET_ESP32S3
+// 49 GPIO pins. ESPIDF defineds 22-25 as invalid.
+// GPIO 27-32 used by default for SPI flash.
+// NOTE: GPIO 43 & 44 commonly used for UART and may cause flashes when uploading.
+#define FASTLED_UNUSABLE_PIN_MASK (0ULL | _FL_BIT(27) | _FL_BIT(28) | _FL_BIT(29) | _FL_BIT(30) | _FL_BIT(31) | _FL_BIT(32))
+
+#elif CONFIG_IDF_TARGET_ESP32H2
+// 22 GPIO pins. ESPIDF defines all pins as valid.
+// ESP32-H2 datasheet not yet available, when it is, mask the pins commonly used by SPI flash.
+#warning ESP32-H2 chip flash configuration not yet known. Only pins defined by ESP-IDF will be masked.
+#define FASTLED_UNUSABLE_PIN_MASK (0ULL)
+
+#else
+#warning Unknown ESP32 chip variant. Only pins defined by ESP-IDF will be masked.
+#define FASTLED_UNUSABLE_PIN_MASK (0ULL)
+#endif
+
+#endif
+
+
+
+// SOC GPIO mask was not added until version IDF version 4.3. Prior to this only ESP32 chip was supported, so only
+// the value for ESP32
+#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 3, 0) && !defined(SOC_GPIO_VALID_OUTPUT_GPIO_MASK)
+// 0~39 except from 24, 28~31 are valid
+#define SOC_GPIO_VALID_GPIO_MASK (0xFFFFFFFFFFULL & ~(0ULL | _FL_BIT(24) | _FL_BIT(28) | _FL_BIT(29) | _FL_BIT(30) | _FL_BIT(31)))
+// GPIO >= 34 are input only
+#define SOC_GPIO_VALID_OUTPUT_GPIO_MASK (SOC_GPIO_VALID_GPIO_MASK & ~(0ULL | _FL_BIT(34) | _FL_BIT(35) | _FL_BIT(36) | _FL_BIT(37) | _FL_BIT(38) | _FL_BIT(39)))
+
+#endif
+
+
+// Define mask of valid pins. Start with the list of valid output pins from ESPIDF and remove unusable pins
+#define _FL_VALID_PIN_MASK (uint64_t(SOC_GPIO_VALID_OUTPUT_GPIO_MASK) & ~FASTLED_UNUSABLE_PIN_MASK)
+
+#define _FL_PIN_VALID(PIN) ((_FL_VALID_PIN_MASK & (1ULL << PIN)) != 0)
+
+#define _FL_DEFPIN(PIN) template <> class FastPin<PIN> : public _ESPPIN<PIN, ((uint32_t)1 << (PIN % 32)), _FL_PIN_VALID(PIN)> {};
+
+// Define all possible pins. If the pin is not valid for a particular ESP32 variant, the pin number
+// will be shifted into the 192-255 range, in effect rendering it unusable.
+_FL_DEFPIN( 0); _FL_DEFPIN( 1); _FL_DEFPIN( 2); _FL_DEFPIN( 3);
+_FL_DEFPIN( 4); _FL_DEFPIN( 5); _FL_DEFPIN( 6); _FL_DEFPIN( 7);
+_FL_DEFPIN( 8); _FL_DEFPIN( 9); _FL_DEFPIN(10); _FL_DEFPIN(11);
+_FL_DEFPIN(12); _FL_DEFPIN(13); _FL_DEFPIN(14); _FL_DEFPIN(15);
+_FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
+_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23);
+_FL_DEFPIN(24); _FL_DEFPIN(25); _FL_DEFPIN(26); _FL_DEFPIN(27);
+_FL_DEFPIN(28); _FL_DEFPIN(29); _FL_DEFPIN(30); _FL_DEFPIN(31);
+_FL_DEFPIN(32); _FL_DEFPIN(33); _FL_DEFPIN(34); _FL_DEFPIN(35);
+_FL_DEFPIN(36); _FL_DEFPIN(37); _FL_DEFPIN(38); _FL_DEFPIN(39);
+_FL_DEFPIN(40); _FL_DEFPIN(41); _FL_DEFPIN(42); _FL_DEFPIN(43);
+_FL_DEFPIN(44); _FL_DEFPIN(45); _FL_DEFPIN(46); _FL_DEFPIN(47);
+_FL_DEFPIN(48); _FL_DEFPIN(49); _FL_DEFPIN(50); _FL_DEFPIN(51);
+_FL_DEFPIN(52); _FL_DEFPIN(53); _FL_DEFPIN(54); _FL_DEFPIN(55);
+_FL_DEFPIN(56); _FL_DEFPIN(57); _FL_DEFPIN(58); _FL_DEFPIN(59);
+_FL_DEFPIN(60); _FL_DEFPIN(61); _FL_DEFPIN(62); _FL_DEFPIN(63);
#define HAS_HARDWARE_PIN_SUPPORT
diff --git a/src/platforms/esp/32/fastspi_esp32.h b/src/platforms/esp/32/fastspi_esp32.h
index 33d620fd..d69bc523 100644
--- a/src/platforms/esp/32/fastspi_esp32.h
+++ b/src/platforms/esp/32/fastspi_esp32.h
@@ -68,6 +68,10 @@ class ESP32SPIOutput {
Selectable *m_pSelect;
public:
+ // Verify that the pins are valid
+ static_assert(FastPin<DATA_PIN>::validpin(), "Invalid data pin specified");
+ static_assert(FastPin<CLOCK_PIN>::validpin(), "Invalid clock pin specified");
+
ESP32SPIOutput() { m_pSelect = NULL; }
ESP32SPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
diff --git a/src/platforms/esp/32/led_sysdefs_esp32.h b/src/platforms/esp/32/led_sysdefs_esp32.h
index 5cd374e2..cf1aa4dc 100644
--- a/src/platforms/esp/32/led_sysdefs_esp32.h
+++ b/src/platforms/esp/32/led_sysdefs_esp32.h
@@ -1,11 +1,26 @@
#pragma once
-
+#include "esp32-hal.h"
#ifndef ESP32
#define ESP32
#endif
#define FASTLED_ESP32
+#if CONFIG_IDF_TARGET_ARCH_RISCV
+#define FASTLED_RISCV
+#else
+#define FASTLED_XTENSA
+#endif
+
+// Handling for older versions of ESP32 Arduino core
+#if !defined(ESP_IDF_VERSION)
+// Older versions of ESP_IDF only supported ESP32
+#define CONFIG_IDF_TARGET_ESP32 1
+// Define missing version macros. Hard code older version 3.0 since actual version is unknown
+#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
+#define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(3, 0, 0)
+#endif
+
// Use system millis timer
#define FASTLED_HAS_MILLIS
@@ -29,5 +44,3 @@ typedef unsigned long prog_uint32_t;
// These can be overridden
# define FASTLED_ESP32_RAW_PIN_ORDER
-// #define cli() os_intr_lock();
-// #define sei() os_intr_lock();
diff --git a/src/platforms/esp/8266/clockless_esp8266.h b/src/platforms/esp/8266/clockless_esp8266.h
index cf6690c6..ca2a6067 100644
--- a/src/platforms/esp/8266/clockless_esp8266.h
+++ b/src/platforms/esp/8266/clockless_esp8266.h
@@ -42,9 +42,7 @@ protected:
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
++_retry_cnt;
#endif
- os_intr_unlock();
delayMicroseconds(WAIT_TIME);
- os_intr_lock();
}
mWait.mark();
}
@@ -78,23 +76,35 @@ protected:
return false;
}
- // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
- // gcc will use register Y for the this pointer.
+
static uint32_t ICACHE_RAM_ATTR showRGBInternal(PixelController<RGB_ORDER> pixels) {
// Setup the pixel controller and load/scale the first byte
pixels.preStepFirstByteDithering();
register uint32_t b = pixels.loadAndScale0();
- pixels.preStepFirstByteDithering();
+ pixels.preStepFirstByteDithering();
uint32_t start;
- {
- struct Lock {
- Lock() {
- os_intr_lock();
- }
- ~Lock() {
- os_intr_unlock();
- }
- };
+
+ // This function has multiple exits, so we'll use an object
+ // with a destructor that releases the interrupt lock, regardless
+ // of how we exit the function. It also has methods for manually
+ // unlocking and relocking interrupts temporarily.
+ struct InterruptLock {
+ InterruptLock() {
+ os_intr_lock();
+ }
+ ~InterruptLock() {
+ os_intr_unlock();
+ }
+ void Unlock() {
+ os_intr_unlock();
+ }
+ void Lock() {
+ os_intr_lock();
+ }
+ };
+
+ { // Start of interrupt-locked block
+ InterruptLock intlock;
start = __clock_cycles();
uint32_t last_mark = start;
@@ -117,14 +127,14 @@ protected:
}
#if (FASTLED_ALLOW_INTERRUPTS == 1)
- os_intr_unlock();
+ intlock.Unlock();
#endif
b = pixels.advanceAndLoadAndScale0();
pixels.stepDithering();
#if (FASTLED_ALLOW_INTERRUPTS == 1)
- os_intr_lock();
+ intlock.Lock();
// if interrupts took longer than 45µs, punt on the current frame
if((int32_t)(__clock_cycles()-last_mark) > 0) {
if((int32_t)(__clock_cycles()-last_mark) > (T1+T2+T3+((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US))) {
@@ -133,7 +143,7 @@ protected:
}
#endif
};
- }
+ } // End of interrupt-locked block
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
++_frame_cnt;
diff --git a/src/platforms/esp/8266/led_sysdefs_esp8266.h b/src/platforms/esp/8266/led_sysdefs_esp8266.h
index 26dffdcf..668a006b 100644
--- a/src/platforms/esp/8266/led_sysdefs_esp8266.h
+++ b/src/platforms/esp/8266/led_sysdefs_esp8266.h
@@ -35,5 +35,3 @@ typedef uint32_t prog_uint32_t;
# endif
#endif
-// #define cli() os_intr_lock();
-// #define sei() os_intr_lock();