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:
authorSam Guyer <sam.guyer@gmail.com>2020-11-16 19:34:20 +0300
committerGitHub <noreply@github.com>2020-11-16 19:34:20 +0300
commitd5ddf40d3f3731adb36c122abba29cbf80654be3 (patch)
treeb0f96294b16af89a5fbe9c82f3a3fdff9399661a
parent17e3b508953a0c6b3792d197b06027ab682b9ff5 (diff)
parent324d114bf70976a20dbcc2e400e09300db1003dd (diff)
Merge pull request #1108 from samguyer/master
Major updates to ESP32 support
-rw-r--r--.gitignore1
-rw-r--r--library.json3
-rw-r--r--platforms/esp/32/clockless_esp32.h.orig786
-rw-r--r--platforms/esp/32/clockless_rmt_esp32.h686
-rw-r--r--src/FastLED.cpp (renamed from FastLED.cpp)0
-rw-r--r--src/FastLED.h (renamed from FastLED.h)0
-rw-r--r--src/bitswap.cpp (renamed from bitswap.cpp)0
-rw-r--r--src/bitswap.h (renamed from bitswap.h)0
-rw-r--r--src/chipsets.h (renamed from chipsets.h)0
-rw-r--r--src/color.h (renamed from color.h)0
-rw-r--r--src/colorpalettes.cpp (renamed from colorpalettes.cpp)0
-rw-r--r--src/colorpalettes.h (renamed from colorpalettes.h)0
-rw-r--r--src/colorutils.cpp (renamed from colorutils.cpp)0
-rw-r--r--src/colorutils.h (renamed from colorutils.h)0
-rw-r--r--src/controller.h (renamed from controller.h)0
-rw-r--r--src/cpp_compat.h (renamed from cpp_compat.h)0
-rw-r--r--src/dmx.h (renamed from dmx.h)0
-rw-r--r--src/fastled_config.h (renamed from fastled_config.h)0
-rw-r--r--src/fastled_delay.h (renamed from fastled_delay.h)0
-rw-r--r--src/fastled_progmem.h (renamed from fastled_progmem.h)0
-rw-r--r--src/fastpin.h (renamed from fastpin.h)0
-rw-r--r--src/fastspi.h (renamed from fastspi.h)0
-rw-r--r--src/fastspi_bitbang.h (renamed from fastspi_bitbang.h)0
-rw-r--r--src/fastspi_dma.h (renamed from fastspi_dma.h)0
-rw-r--r--src/fastspi_nop.h (renamed from fastspi_nop.h)0
-rw-r--r--src/fastspi_ref.h (renamed from fastspi_ref.h)0
-rw-r--r--src/fastspi_types.h (renamed from fastspi_types.h)0
-rw-r--r--src/hsv2rgb.cpp (renamed from hsv2rgb.cpp)0
-rw-r--r--src/hsv2rgb.h (renamed from hsv2rgb.h)0
-rw-r--r--src/led_sysdefs.h (renamed from led_sysdefs.h)0
-rw-r--r--src/lib8tion.cpp (renamed from lib8tion.cpp)0
-rw-r--r--src/lib8tion.h (renamed from lib8tion.h)0
-rw-r--r--src/lib8tion/math8.h (renamed from lib8tion/math8.h)0
-rw-r--r--src/lib8tion/random8.h (renamed from lib8tion/random8.h)0
-rw-r--r--src/lib8tion/scale8.h (renamed from lib8tion/scale8.h)0
-rw-r--r--src/lib8tion/trig8.h (renamed from lib8tion/trig8.h)0
-rw-r--r--src/noise.cpp (renamed from noise.cpp)0
-rw-r--r--src/noise.h (renamed from noise.h)0
-rw-r--r--src/pixelset.h (renamed from pixelset.h)0
-rw-r--r--src/pixeltypes.h (renamed from pixeltypes.h)0
-rw-r--r--src/platforms.cpp (renamed from platforms.cpp)0
-rw-r--r--src/platforms.h (renamed from platforms.h)0
-rw-r--r--src/platforms/apollo3/clockless_apollo3.h (renamed from platforms/apollo3/clockless_apollo3.h)0
-rw-r--r--src/platforms/apollo3/fastled_apollo3.h (renamed from platforms/apollo3/fastled_apollo3.h)0
-rw-r--r--src/platforms/apollo3/fastpin_apollo3.h (renamed from platforms/apollo3/fastpin_apollo3.h)0
-rw-r--r--src/platforms/apollo3/fastspi_apollo3.h (renamed from platforms/apollo3/fastspi_apollo3.h)0
-rw-r--r--src/platforms/apollo3/led_sysdefs_apollo3.h (renamed from platforms/apollo3/led_sysdefs_apollo3.h)0
-rw-r--r--src/platforms/arm/common/m0clockless.h (renamed from platforms/arm/common/m0clockless.h)0
-rw-r--r--src/platforms/arm/d21/clockless_arm_d21.h (renamed from platforms/arm/d21/clockless_arm_d21.h)0
-rw-r--r--src/platforms/arm/d21/fastled_arm_d21.h (renamed from platforms/arm/d21/fastled_arm_d21.h)0
-rw-r--r--src/platforms/arm/d21/fastpin_arm_d21.h (renamed from platforms/arm/d21/fastpin_arm_d21.h)0
-rw-r--r--src/platforms/arm/d21/led_sysdefs_arm_d21.h (renamed from platforms/arm/d21/led_sysdefs_arm_d21.h)0
-rw-r--r--src/platforms/arm/d51/README.txt (renamed from platforms/arm/d51/README.txt)0
-rw-r--r--src/platforms/arm/d51/clockless_arm_d51.h (renamed from platforms/arm/d51/clockless_arm_d51.h)0
-rw-r--r--src/platforms/arm/d51/fastled_arm_d51.h (renamed from platforms/arm/d51/fastled_arm_d51.h)0
-rw-r--r--src/platforms/arm/d51/fastpin_arm_d51.h (renamed from platforms/arm/d51/fastpin_arm_d51.h)0
-rw-r--r--src/platforms/arm/d51/led_sysdefs_arm_d51.h (renamed from platforms/arm/d51/led_sysdefs_arm_d51.h)0
-rw-r--r--src/platforms/arm/k20/clockless_arm_k20.h (renamed from platforms/arm/k20/clockless_arm_k20.h)0
-rw-r--r--src/platforms/arm/k20/clockless_block_arm_k20.h (renamed from platforms/arm/k20/clockless_block_arm_k20.h)0
-rw-r--r--src/platforms/arm/k20/fastled_arm_k20.h (renamed from platforms/arm/k20/fastled_arm_k20.h)0
-rw-r--r--src/platforms/arm/k20/fastpin_arm_k20.h (renamed from platforms/arm/k20/fastpin_arm_k20.h)0
-rw-r--r--src/platforms/arm/k20/fastspi_arm_k20.h (renamed from platforms/arm/k20/fastspi_arm_k20.h)0
-rw-r--r--src/platforms/arm/k20/led_sysdefs_arm_k20.h (renamed from platforms/arm/k20/led_sysdefs_arm_k20.h)0
-rw-r--r--src/platforms/arm/k20/octows2811_controller.h (renamed from platforms/arm/k20/octows2811_controller.h)0
-rw-r--r--src/platforms/arm/k20/smartmatrix_t3.h (renamed from platforms/arm/k20/smartmatrix_t3.h)0
-rw-r--r--src/platforms/arm/k20/ws2812serial_controller.h (renamed from platforms/arm/k20/ws2812serial_controller.h)0
-rw-r--r--src/platforms/arm/k66/clockless_arm_k66.h (renamed from platforms/arm/k66/clockless_arm_k66.h)0
-rw-r--r--src/platforms/arm/k66/clockless_block_arm_k66.h (renamed from platforms/arm/k66/clockless_block_arm_k66.h)0
-rw-r--r--src/platforms/arm/k66/fastled_arm_k66.h (renamed from platforms/arm/k66/fastled_arm_k66.h)0
-rw-r--r--src/platforms/arm/k66/fastpin_arm_k66.h (renamed from platforms/arm/k66/fastpin_arm_k66.h)0
-rw-r--r--src/platforms/arm/k66/fastspi_arm_k66.h (renamed from platforms/arm/k66/fastspi_arm_k66.h)0
-rw-r--r--src/platforms/arm/k66/led_sysdefs_arm_k66.h (renamed from platforms/arm/k66/led_sysdefs_arm_k66.h)0
-rw-r--r--src/platforms/arm/kl26/clockless_arm_kl26.h (renamed from platforms/arm/kl26/clockless_arm_kl26.h)0
-rw-r--r--src/platforms/arm/kl26/fastled_arm_kl26.h (renamed from platforms/arm/kl26/fastled_arm_kl26.h)0
-rw-r--r--src/platforms/arm/kl26/fastpin_arm_kl26.h (renamed from platforms/arm/kl26/fastpin_arm_kl26.h)0
-rw-r--r--src/platforms/arm/kl26/fastspi_arm_kl26.h (renamed from platforms/arm/kl26/fastspi_arm_kl26.h)0
-rw-r--r--src/platforms/arm/kl26/led_sysdefs_arm_kl26.h (renamed from platforms/arm/kl26/led_sysdefs_arm_kl26.h)0
-rw-r--r--src/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h)0
-rw-r--r--src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/clockless_arm_mxrt1062.h)0
-rw-r--r--src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/fastled_arm_mxrt1062.h)0
-rw-r--r--src/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h)0
-rw-r--r--src/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h)0
-rw-r--r--src/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h)0
-rw-r--r--src/platforms/arm/nrf51/clockless_arm_nrf51.h (renamed from platforms/arm/nrf51/clockless_arm_nrf51.h)0
-rw-r--r--src/platforms/arm/nrf51/fastled_arm_nrf51.h (renamed from platforms/arm/nrf51/fastled_arm_nrf51.h)0
-rw-r--r--src/platforms/arm/nrf51/fastpin_arm_nrf51.h (renamed from platforms/arm/nrf51/fastpin_arm_nrf51.h)0
-rw-r--r--src/platforms/arm/nrf51/fastspi_arm_nrf51.h (renamed from platforms/arm/nrf51/fastspi_arm_nrf51.h)0
-rw-r--r--src/platforms/arm/nrf51/led_sysdefs_arm_nrf51.h (renamed from platforms/arm/nrf51/led_sysdefs_arm_nrf51.h)0
-rw-r--r--src/platforms/arm/nrf52/arbiter_nrf52.h (renamed from platforms/arm/nrf52/arbiter_nrf52.h)0
-rw-r--r--src/platforms/arm/nrf52/clockless_arm_nrf52.h (renamed from platforms/arm/nrf52/clockless_arm_nrf52.h)0
-rw-r--r--src/platforms/arm/nrf52/fastled_arm_nrf52.h (renamed from platforms/arm/nrf52/fastled_arm_nrf52.h)0
-rw-r--r--src/platforms/arm/nrf52/fastpin_arm_nrf52.h (renamed from platforms/arm/nrf52/fastpin_arm_nrf52.h)0
-rw-r--r--src/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h (renamed from platforms/arm/nrf52/fastpin_arm_nrf52_variants.h)0
-rw-r--r--src/platforms/arm/nrf52/fastspi_arm_nrf52.h (renamed from platforms/arm/nrf52/fastspi_arm_nrf52.h)0
-rw-r--r--src/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h (renamed from platforms/arm/nrf52/led_sysdefs_arm_nrf52.h)0
-rw-r--r--src/platforms/arm/sam/clockless_arm_sam.h (renamed from platforms/arm/sam/clockless_arm_sam.h)0
-rw-r--r--src/platforms/arm/sam/clockless_block_arm_sam.h (renamed from platforms/arm/sam/clockless_block_arm_sam.h)0
-rw-r--r--src/platforms/arm/sam/fastled_arm_sam.h (renamed from platforms/arm/sam/fastled_arm_sam.h)0
-rw-r--r--src/platforms/arm/sam/fastpin_arm_sam.h (renamed from platforms/arm/sam/fastpin_arm_sam.h)0
-rw-r--r--src/platforms/arm/sam/fastspi_arm_sam.h (renamed from platforms/arm/sam/fastspi_arm_sam.h)0
-rw-r--r--src/platforms/arm/sam/led_sysdefs_arm_sam.h (renamed from platforms/arm/sam/led_sysdefs_arm_sam.h)0
-rw-r--r--src/platforms/arm/stm32/clockless_arm_stm32.h (renamed from platforms/arm/stm32/clockless_arm_stm32.h)0
-rw-r--r--src/platforms/arm/stm32/cm3_regs.h (renamed from platforms/arm/stm32/cm3_regs.h)0
-rw-r--r--src/platforms/arm/stm32/fastled_arm_stm32.h (renamed from platforms/arm/stm32/fastled_arm_stm32.h)0
-rw-r--r--src/platforms/arm/stm32/fastpin_arm_stm32.h (renamed from platforms/arm/stm32/fastpin_arm_stm32.h)0
-rw-r--r--src/platforms/arm/stm32/led_sysdefs_arm_stm32.h (renamed from platforms/arm/stm32/led_sysdefs_arm_stm32.h)0
-rw-r--r--src/platforms/avr/clockless_trinket.h (renamed from platforms/avr/clockless_trinket.h)0
-rw-r--r--src/platforms/avr/fastled_avr.h (renamed from platforms/avr/fastled_avr.h)0
-rw-r--r--src/platforms/avr/fastpin_avr.h (renamed from platforms/avr/fastpin_avr.h)0
-rw-r--r--src/platforms/avr/fastspi_avr.h (renamed from platforms/avr/fastspi_avr.h)0
-rw-r--r--src/platforms/avr/led_sysdefs_avr.h (renamed from platforms/avr/led_sysdefs_avr.h)0
-rw-r--r--src/platforms/esp/32/clockless_block_esp32.h (renamed from platforms/esp/32/clockless_block_esp32.h)0
-rw-r--r--src/platforms/esp/32/clockless_i2s_esp32.h (renamed from platforms/esp/32/clockless_i2s_esp32.h)0
-rw-r--r--src/platforms/esp/32/clockless_rmt_esp32.cpp419
-rw-r--r--src/platforms/esp/32/clockless_rmt_esp32.h411
-rw-r--r--src/platforms/esp/32/fastled_esp32.h (renamed from platforms/esp/32/fastled_esp32.h)0
-rw-r--r--src/platforms/esp/32/fastpin_esp32.h (renamed from platforms/esp/32/fastpin_esp32.h)0
-rw-r--r--src/platforms/esp/32/led_sysdefs_esp32.h (renamed from platforms/esp/32/led_sysdefs_esp32.h)0
-rw-r--r--src/platforms/esp/8266/clockless_block_esp8266.h (renamed from platforms/esp/8266/clockless_block_esp8266.h)0
-rw-r--r--src/platforms/esp/8266/clockless_esp8266.h (renamed from platforms/esp/8266/clockless_esp8266.h)0
-rw-r--r--src/platforms/esp/8266/fastled_esp8266.h (renamed from platforms/esp/8266/fastled_esp8266.h)0
-rw-r--r--src/platforms/esp/8266/fastpin_esp8266.h (renamed from platforms/esp/8266/fastpin_esp8266.h)0
-rw-r--r--src/platforms/esp/8266/led_sysdefs_esp8266.h (renamed from platforms/esp/8266/led_sysdefs_esp8266.h)0
-rw-r--r--src/power_mgt.cpp (renamed from power_mgt.cpp)0
-rw-r--r--src/power_mgt.h (renamed from power_mgt.h)0
-rw-r--r--src/wiring.cpp (renamed from wiring.cpp)0
126 files changed, 833 insertions, 1473 deletions
diff --git a/.gitignore b/.gitignore
index 54cd17df..9321044f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.gch
+*~
/.vscode
/docs/html
/docs/latex
diff --git a/library.json b/library.json
index bcb24070..7b1dd471 100644
--- a/library.json
+++ b/library.json
@@ -48,7 +48,8 @@
"srcFilter": [
"+<*.c>",
"+<*.cpp>",
- "+<*.h>"
+ "+<*.h>",
+ "+<platforms/esp/32/*.cpp>"
],
"libArchive": false
}
diff --git a/platforms/esp/32/clockless_esp32.h.orig b/platforms/esp/32/clockless_esp32.h.orig
deleted file mode 100644
index bdc0bd7a..00000000
--- a/platforms/esp/32/clockless_esp32.h.orig
+++ /dev/null
@@ -1,786 +0,0 @@
-/*
- * Integration into FastLED ClocklessController 2017 Thomas Basler
- *
- * Modifications Copyright (c) 2017 Martin F. Falatic
- *
- * Modifications Copyright (c) 2018 Samuel Z. Guyer
- *
- * ESP32 support is provided using the RMT peripheral device -- a unit
- * on the chip designed specifically for generating (and receiving)
- * precisely-timed digital signals. Nominally for use in infrared
- * remote controls, we use it to generate the signals for clockless
- * LED strips. The main advantage of using the RMT device is that,
- * once programmed, it generates the signal asynchronously, allowing
- * the CPU to continue executing other code. It is also not vulnerable
- * to interrupts or other timing problems that could disrupt the signal.
- *
- * The implementation strategy is borrowed from previous work and from
- * the RMT support built into the ESP32 IDF. The RMT device has 8
- * channels, which can be programmed independently to send sequences
- * of high/low bits. Memory for each channel is limited, however, so
- * in order to send a long sequence of bits, we need to continuously
- * refill the buffer until all the data is sent. To do this, we fill
- * half the buffer and then set an interrupt to go off when that half
- * is sent. Then we refill that half while the second half is being
- * sent. This strategy effectively overlaps computation (by the CPU)
- * and communication (by the RMT).
- *
- * Since the RMT device only has 8 channels, we need a strategy to
- * allow more than 8 LED controllers. Our driver assigns controllers
- * to channels on the fly, queuing up controllers as necessary until a
- * channel is free. The main showPixels routine just fires off the
- * first 8 controllers; the interrupt handler starts new controllers
- * asynchronously as previous ones finish. So, for example, it can
- * send the data for 8 controllers simultaneously, but 16 controllers
- * would take approximately twice as much time.
- *
- * There is a #define that allows a program to control the total
- * number of channels that the driver is allowed to use. It defaults
- * to 8 -- use all the channels. Setting it to 1, for example, results
- * in fully serial output:
- *
- * #define FASTLED_RMT_MAX_CHANNELS 1
- *
- * OTHER RMT APPLICATIONS
- *
- * The default FastLED driver takes over control of the RMT interrupt
- * handler, making it hard to use the RMT device for other
- * (non-FastLED) purposes. You can change it's behavior to use the ESP
- * core driver instead, allowing other RMT applications to
- * co-exist. To switch to this mode, add the following directive
- * before you include FastLED.h:
- *
- * #define FASTLED_RMT_BUILTIN_DRIVER
- *
- * There may be a performance penalty for using this mode. We need to
- * compute the RMT signal for the entire LED strip ahead of time,
- * rather than overlapping it with communication. We also need a large
- * buffer to hold the signal specification. Each bit of pixel data is
- * represented by a 32-bit pulse specification, so it is a 32X blow-up
- * in memory use.
- *
- *
- * Based on public domain code created 19 Nov 2016 by Chris Osborn <fozztexx@fozztexx.com>
- * http://insentricity.com *
- *
- */
-/*
- * 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.
- */
-
-#pragma once
-
-FASTLED_NAMESPACE_BEGIN
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "esp32-hal.h"
-#include "esp_intr.h"
-#include "driver/gpio.h"
-#include "driver/rmt.h"
-#include "driver/periph_ctrl.h"
-#include "freertos/semphr.h"
-#include "soc/rmt_struct.h"
-
-#include "esp_log.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-__attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
- uint32_t cyc;
- __asm__ __volatile__ ("rsr %0,ccount":"=a" (cyc));
- return cyc;
-}
-
-#define FASTLED_HAS_CLOCKLESS 1
-
-// -- Configuration constants
-#define DIVIDER 2 /* 4, 8 still seem to work, but timings become marginal */
-#define MAX_PULSES 32 /* A channel has a 64 "pulse" buffer - we use half per pass */
-
-// -- Convert ESP32 cycles back into nanoseconds
-#define ESPCLKS_TO_NS(_CLKS) (((long)(_CLKS) * 1000L) / F_CPU_MHZ)
-
-// -- Convert nanoseconds into RMT cycles
-#define F_CPU_RMT ( 80000000L)
-#define NS_PER_SEC (1000000000L)
-#define CYCLES_PER_SEC (F_CPU_RMT/DIVIDER)
-#define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC )
-#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )
-
-// -- Convert ESP32 cycles to RMT cycles
-#define TO_RMT_CYCLES(_CLKS) NS_TO_CYCLES(ESPCLKS_TO_NS(_CLKS))
-
-// -- Number of cycles to signal the strip to latch
-#define RMT_RESET_DURATION NS_TO_CYCLES(50000)
-
-// -- Core or custom driver
-#ifndef FASTLED_RMT_BUILTIN_DRIVER
-#define FASTLED_RMT_BUILTIN_DRIVER false
-#endif
-
-// -- Max number of controllers we can support
-#ifndef FASTLED_RMT_MAX_CONTROLLERS
-#define FASTLED_RMT_MAX_CONTROLLERS 32
-#endif
-
-// -- Number of RMT channels to use (up to 8)
-// Redefine this value to 1 to force serial output
-#ifndef FASTLED_RMT_MAX_CHANNELS
-#define FASTLED_RMT_MAX_CHANNELS 8
-#endif
-
-// -- Array of all controllers
-static CLEDController * gControllers[FASTLED_RMT_MAX_CONTROLLERS];
-
-// -- Current set of active controllers, indexed by the RMT
-// channel assigned to them.
-static CLEDController * gOnChannel[FASTLED_RMT_MAX_CHANNELS];
-
-static int gNumControllers = 0;
-static int gNumStarted = 0;
-static int gNumDone = 0;
-static int gNext = 0;
-
-static intr_handle_t gRMT_intr_handle = NULL;
-
-// -- Global semaphore for the whole show process
-// Semaphore is not given until all data has been sent
-static xSemaphoreHandle gTX_sem = NULL;
-
-static bool gInitialized = false;
-
-template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
-class ClocklessController : public CPixelLEDController<RGB_ORDER>
-{
- // -- RMT has 8 channels, numbered 0 to 7
- rmt_channel_t mRMT_channel;
-
- // -- Store the GPIO pin
- gpio_num_t mPin;
-<<<<<<< HEAD
-
- // -- This instantiation forces a check on the pin choice
- FastPin<DATA_PIN> mFastPin;
-
- // -- Timing values for zero and one bits, derived from T1, T2, and T3
- rmt_item32_t mZero;
- rmt_item32_t mOne;
-
-=======
-
- // -- Timing values for zero and one bits, derived from T1, T2, and T3
- rmt_item32_t mZero;
- rmt_item32_t mOne;
-
->>>>>>> upstream/master
- // -- State information for keeping track of where we are in the pixel data
- PixelController<RGB_ORDER> * mPixels = NULL;
- void * mPixelSpace = NULL;
- uint8_t mRGB_channel;
- uint16_t mCurPulse;
-
- // -- Buffer to hold all of the pulses. For the version that uses
- // the RMT driver built into the ESP core.
- rmt_item32_t * mBuffer;
- uint16_t mBufferSize;
-
-public:
-
- virtual void init()
- {
- // -- Precompute rmt items corresponding to a zero bit and a one bit
- // according to the timing values given in the template instantiation
- // T1H
- mOne.level0 = 1;
- mOne.duration0 = TO_RMT_CYCLES(T1+T2);
- // T1L
- mOne.level1 = 0;
- mOne.duration1 = TO_RMT_CYCLES(T3);
-
- // T0H
- mZero.level0 = 1;
- mZero.duration0 = TO_RMT_CYCLES(T1);
- // T0L
- mZero.level1 = 0;
- mZero.duration1 = TO_RMT_CYCLES(T2 + T3);
-
-<<<<<<< HEAD
- gControllers[gNumControllers] = this;
- ++gNumControllers;
-
- mPin = gpio_num_t(DATA_PIN);
-=======
- gControllers[gNumControllers] = this;
- ++gNumControllers;
-
- mPin = gpio_num_t(DATA_PIN);
->>>>>>> upstream/master
- }
-
- virtual uint16_t getMaxRefreshRate() const { return 400; }
-
-protected:
-
- void initRMT()
- {
-<<<<<<< HEAD
- // -- Only need to do this once
- if (gInitialized) return;
-
- for (int i = 0; i < FASTLED_RMT_MAX_CHANNELS; ++i) {
- gOnChannel[i] = NULL;
-
- // -- RMT configuration for transmission
- rmt_config_t rmt_tx;
- rmt_tx.channel = rmt_channel_t(i);
- rmt_tx.rmt_mode = RMT_MODE_TX;
- rmt_tx.gpio_num = mPin; // The particular pin will be assigned later
- rmt_tx.mem_block_num = 1;
- rmt_tx.clk_div = DIVIDER;
- rmt_tx.tx_config.loop_en = false;
- rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
- rmt_tx.tx_config.carrier_en = false;
- rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
- rmt_tx.tx_config.idle_output_en = true;
-
- // -- Apply the configuration
- rmt_config(&rmt_tx);
-
- if (FASTLED_RMT_BUILTIN_DRIVER) {
- rmt_driver_install(rmt_channel_t(i), 0, 0);
- } else {
- // -- Set up the RMT to send 1/2 of the pulse buffer and then
- // generate an interrupt. When we get this interrupt we
- // fill the other half in preparation (kind of like double-buffering)
- rmt_set_tx_thr_intr_en(rmt_channel_t(i), true, MAX_PULSES);
- }
- }
-
- // -- Create a semaphore to block execution until all the controllers are done
- if (gTX_sem == NULL) {
- gTX_sem = xSemaphoreCreateBinary();
- xSemaphoreGive(gTX_sem);
- }
-
- if ( ! FASTLED_RMT_BUILTIN_DRIVER) {
- // -- Allocate the interrupt if we have not done so yet. This
- // interrupt handler must work for all different kinds of
- // strips, so it delegates to the refill function for each
- // specific instantiation of ClocklessController.
- if (gRMT_intr_handle == NULL)
- esp_intr_alloc(ETS_RMT_INTR_SOURCE, 0, interruptHandler, 0, &gRMT_intr_handle);
- }
-
- gInitialized = true;
- }
-
- virtual void showPixels(PixelController<RGB_ORDER> & pixels)
- {
- if (gNumStarted == 0) {
- // -- First controller: make sure everything is set up
- initRMT();
- xSemaphoreTake(gTX_sem, portMAX_DELAY);
- }
-
- // -- Initialize the local state, save a pointer to the pixel
- // data. We need to make a copy because pixels is a local
- // variable in the calling function, and this data structure
- // needs to outlive this call to showPixels.
-
- if (mPixels != NULL) delete mPixels;
- mPixels = new PixelController<RGB_ORDER>(pixels);
-
- // -- Keep track of the number of strips we've seen
- ++gNumStarted;
-
- // -- The last call to showPixels is the one responsible for doing
- // all of the actual worl
- if (gNumStarted == gNumControllers) {
- gNext = 0;
-
- // -- First, fill all the available channels
- int channel = 0;
- while (channel < FASTLED_RMT_MAX_CHANNELS && gNext < gNumControllers) {
- startNext(channel);
- ++channel;
- }
-
- // -- Wait here while the rest of the data is sent. The interrupt handler
- // will keep refilling the RMT buffers until it is all sent; then it
- // gives the semaphore back.
- xSemaphoreTake(gTX_sem, portMAX_DELAY);
- xSemaphoreGive(gTX_sem);
-
- // -- Reset the counters
- gNumStarted = 0;
- gNumDone = 0;
- gNext = 0;
- }
- }
-
- // -- Start up the next controller
- // This method is static so that it can dispatch to the appropriate
- // startOnChannel method of the given controller.
- static void startNext(int channel)
- {
- if (gNext < gNumControllers) {
- ClocklessController * pController = static_cast<ClocklessController*>(gControllers[gNext]);
- pController->startOnChannel(channel);
- ++gNext;
- }
- }
-
- virtual void startOnChannel(int channel)
- {
- // -- Assign this channel and configure the RMT
- mRMT_channel = rmt_channel_t(channel);
-
- // -- Store a reference to this controller, so we can get it
- // inside the interrupt handler
- gOnChannel[channel] = this;
-
- // -- Assign the pin to this channel
- rmt_set_pin(mRMT_channel, RMT_MODE_TX, mPin);
-
- if (FASTLED_RMT_BUILTIN_DRIVER) {
- // -- Use the built-in RMT driver to send all the data in one shot
- rmt_register_tx_end_callback(doneOnChannel, 0);
- writeAllRMTItems();
- } else {
- // -- Use our custom driver to send the data incrementally
-
- // -- Turn on the interrupts
- rmt_set_tx_intr_en(mRMT_channel, true);
-
- // -- Initialize the counters that keep track of where we are in
- // the pixel data.
- mCurPulse = 0;
- mRGB_channel = 0;
-
- // -- Fill both halves of the buffer
- fillHalfRMTBuffer();
- fillHalfRMTBuffer();
-
- // -- Turn on the interrupts
- rmt_set_tx_intr_en(mRMT_channel, true);
-
- // -- Start the RMT TX operation
- rmt_tx_start(mRMT_channel, true);
- }
- }
-
- static void doneOnChannel(rmt_channel_t channel, void * arg)
- {
- ClocklessController * controller = static_cast<ClocklessController*>(gOnChannel[channel]);
- portBASE_TYPE HPTaskAwoken = 0;
-
- // -- Turn off output on the pin
- gpio_matrix_out(controller->mPin, 0x100, 0, 0);
-
- gOnChannel[channel] = NULL;
- ++gNumDone;
-
- if (gNumDone == gNumControllers) {
- // -- If this is the last controller, signal that we are all done
- xSemaphoreGiveFromISR(gTX_sem, &HPTaskAwoken);
- if(HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
- } else {
- // -- Otherwise, if there are still controllers waiting, then
- // start the next one on this channel
- if (gNext < gNumControllers)
- startNext(channel);
- }
-=======
- // -- Only need to do this once
- if (gInitialized) return;
-
- for (int i = 0; i < FASTLED_RMT_MAX_CHANNELS; ++i) {
- gOnChannel[i] = NULL;
-
- // -- RMT configuration for transmission
- rmt_config_t rmt_tx;
- rmt_tx.channel = rmt_channel_t(i);
- rmt_tx.rmt_mode = RMT_MODE_TX;
- rmt_tx.gpio_num = mPin; // The particular pin will be assigned later
- rmt_tx.mem_block_num = 1;
- rmt_tx.clk_div = DIVIDER;
- rmt_tx.tx_config.loop_en = false;
- rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
- rmt_tx.tx_config.carrier_en = false;
- rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
- rmt_tx.tx_config.idle_output_en = true;
-
- // -- Apply the configuration
- rmt_config(&rmt_tx);
-
- if (FASTLED_RMT_BUILTIN_DRIVER) {
- rmt_driver_install(rmt_channel_t(i), 0, 0);
- } else {
- // -- Set up the RMT to send 1/2 of the pulse buffer and then
- // generate an interrupt. When we get this interrupt we
- // fill the other half in preparation (kind of like double-buffering)
- rmt_set_tx_thr_intr_en(rmt_channel_t(i), true, MAX_PULSES);
- }
- }
-
- // -- Create a semaphore to block execution until all the controllers are done
- if (gTX_sem == NULL) {
- gTX_sem = xSemaphoreCreateBinary();
- xSemaphoreGive(gTX_sem);
- }
-
- if ( ! FASTLED_RMT_BUILTIN_DRIVER) {
- // -- Allocate the interrupt if we have not done so yet. This
- // interrupt handler must work for all different kinds of
- // strips, so it delegates to the refill function for each
- // specific instantiation of ClocklessController.
- if (gRMT_intr_handle == NULL)
- esp_intr_alloc(ETS_RMT_INTR_SOURCE, 0, interruptHandler, 0, &gRMT_intr_handle);
- }
-
- gInitialized = true;
- }
-
- virtual void showPixels(PixelController<RGB_ORDER> & pixels)
- {
- if (gNumStarted == 0) {
- // -- First controller: make sure everything is set up
- initRMT();
- xSemaphoreTake(gTX_sem, portMAX_DELAY);
- }
-
- // -- Initialize the local state, save a pointer to the pixel
- // data. We need to make a copy because pixels is a local
- // variable in the calling function, and this data structure
- // needs to outlive this call to showPixels.
-
- if (mPixels != NULL) delete mPixels;
- mPixels = new PixelController<RGB_ORDER>(pixels);
-
- // -- Keep track of the number of strips we've seen
- ++gNumStarted;
-
- // -- The last call to showPixels is the one responsible for doing
- // all of the actual worl
- if (gNumStarted == gNumControllers) {
- gNext = 0;
-
- // -- First, fill all the available channels
- int channel = 0;
- while (channel < FASTLED_RMT_MAX_CHANNELS && gNext < gNumControllers) {
- startNext(channel);
- ++channel;
- }
-
- // -- Wait here while the rest of the data is sent. The interrupt handler
- // will keep refilling the RMT buffers until it is all sent; then it
- // gives the semaphore back.
- xSemaphoreTake(gTX_sem, portMAX_DELAY);
- xSemaphoreGive(gTX_sem);
-
- // -- Reset the counters
- gNumStarted = 0;
- gNumDone = 0;
- gNext = 0;
- }
- }
-
- // -- Start up the next controller
- // This method is static so that it can dispatch to the appropriate
- // startOnChannel method of the given controller.
- static void startNext(int channel)
- {
- if (gNext < gNumControllers) {
- ClocklessController * pController = static_cast<ClocklessController*>(gControllers[gNext]);
- pController->startOnChannel(channel);
- ++gNext;
- }
- }
-
- virtual void startOnChannel(int channel)
- {
- // -- Assign this channel and configure the RMT
- mRMT_channel = rmt_channel_t(channel);
-
- // -- Store a reference to this controller, so we can get it
- // inside the interrupt handler
- gOnChannel[channel] = this;
-
- // -- Assign the pin to this channel
- rmt_set_pin(mRMT_channel, RMT_MODE_TX, mPin);
-
- if (FASTLED_RMT_BUILTIN_DRIVER) {
- // -- Use the built-in RMT driver to send all the data in one shot
- rmt_register_tx_end_callback(doneOnChannel, 0);
- writeAllRMTItems();
- } else {
- // -- Use our custom driver to send the data incrementally
-
- // -- Turn on the interrupts
- rmt_set_tx_intr_en(mRMT_channel, true);
-
- // -- Initialize the counters that keep track of where we are in
- // the pixel data.
- mCurPulse = 0;
- mRGB_channel = 0;
-
- // -- Fill both halves of the buffer
- fillHalfRMTBuffer();
- fillHalfRMTBuffer();
-
- // -- Turn on the interrupts
- rmt_set_tx_intr_en(mRMT_channel, true);
-
- // -- Start the RMT TX operation
- rmt_tx_start(mRMT_channel, true);
- }
- }
-
- static void doneOnChannel(rmt_channel_t channel, void * arg)
- {
- ClocklessController * controller = static_cast<ClocklessController*>(gOnChannel[channel]);
- portBASE_TYPE HPTaskAwoken = 0;
-
- // -- Turn off output on the pin
- gpio_matrix_out(controller->mPin, 0x100, 0, 0);
-
- gOnChannel[channel] = NULL;
- ++gNumDone;
-
- if (gNumDone == gNumControllers) {
- // -- If this is the last controller, signal that we are all done
- xSemaphoreGiveFromISR(gTX_sem, &HPTaskAwoken);
- if(HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
- } else {
- // -- Otherwise, if there are still controllers waiting, then
- // start the next one on this channel
- if (gNext < gNumControllers)
- startNext(channel);
- }
->>>>>>> upstream/master
- }
-
- static IRAM_ATTR void interruptHandler(void *arg)
- {
- // -- The basic structure of this code is borrowed from the
- // interrupt handler in esp-idf/components/driver/rmt.c
- uint32_t intr_st = RMT.int_st.val;
- uint8_t channel;
-
- for (channel = 0; channel < FASTLED_RMT_MAX_CHANNELS; ++channel) {
- int tx_done_bit = channel * 3;
- int tx_next_bit = channel + 24;
-
- if (gOnChannel[channel] != NULL) {
-
-<<<<<<< HEAD
- ClocklessController * controller = static_cast<ClocklessController*>(gOnChannel[channel]);
-
- // -- More to send on this channel
- if (intr_st & BIT(tx_next_bit)) {
- RMT.int_clr.val |= BIT(tx_next_bit);
-
- // -- Refill the half of the buffer that we just finished,
- // allowing the other half to proceed.
- controller->fillHalfRMTBuffer();
- }
-
- // -- Transmission is complete on this channel
- if (intr_st & BIT(tx_done_bit)) {
- RMT.int_clr.val |= BIT(tx_done_bit);
- doneOnChannel(rmt_channel_t(channel), 0);
-=======
- ClocklessController * controller = static_cast<ClocklessController*>(gOnChannel[channel]);
-
- // -- More to send on this channel
- if (intr_st & BIT(tx_next_bit)) {
- RMT.int_clr.val |= BIT(tx_next_bit);
-
- // -- Refill the half of the buffer that we just finished,
- // allowing the other half to proceed.
- controller->fillHalfRMTBuffer();
- }
-
- // -- Transmission is complete on this channel
- if (intr_st & BIT(tx_done_bit)) {
- RMT.int_clr.val |= BIT(tx_done_bit);
- doneOnChannel(rmt_channel_t(channel), 0);
->>>>>>> upstream/master
- }
- }
- }
- }
-
- virtual void fillHalfRMTBuffer()
- {
- // -- Fill half of the RMT pulse buffer
-
- // The buffer holds 64 total pulse items, so this loop converts
- // as many pixels as can fit in half of the buffer (MAX_PULSES =
- // 32 items). In our case, each pixel consists of three bytes,
- // each bit turns into one pulse item -- 24 items per pixel. So,
- // each half of the buffer can hold 1 and 1/3 of a pixel.
-
- // The member variable mCurPulse keeps track of which of the 64
- // items we are writing. During the first call to this method it
- // fills 0-31; in the second call it fills 32-63, and then wraps
- // back around to zero.
-
- // When we run out of pixel data, just fill the remaining items
- // with zero pulses.
-
- uint16_t pulse_count = 0; // Ranges from 0-31 (half a buffer)
- uint32_t byteval = 0;
- uint32_t one_val = mOne.val;
- uint32_t zero_val = mZero.val;
- bool done_strip = false;
-
- while (pulse_count < MAX_PULSES) {
- if (! mPixels->has(1)) {
-<<<<<<< HEAD
- if (mCurPulse > 0) {
- // -- Extend the last pulse to force the strip to latch. Honestly, I'm not
- // sure if this is really necessary.
- // RMTMEM.chan[mRMT_channel].data32[mCurPulse-1].duration1 = RMT_RESET_DURATION;
- }
-=======
->>>>>>> upstream/master
- done_strip = true;
- break;
- }
-
- // -- Cycle through the R,G, and B values in the right order
- switch (mRGB_channel) {
- case 0:
- byteval = mPixels->loadAndScale0();
- mRGB_channel = 1;
- break;
- case 1:
- byteval = mPixels->loadAndScale1();
- mRGB_channel = 2;
- break;
- case 2:
- byteval = mPixels->loadAndScale2();
- mPixels->advanceData();
- mPixels->stepDithering();
- mRGB_channel = 0;
- break;
- default:
- break;
- }
-
- byteval <<= 24;
- // Shift bits out, MSB first, setting RMTMEM.chan[n].data32[x] to the
- // rmt_item32_t value corresponding to the buffered bit value
- for (register uint32_t j = 0; j < 8; ++j) {
- uint32_t val = (byteval & 0x80000000L) ? one_val : zero_val;
- RMTMEM.chan[mRMT_channel].data32[mCurPulse].val = val;
- byteval <<= 1;
- ++mCurPulse;
- ++pulse_count;
- }
-<<<<<<< HEAD
-=======
-
- if (done_strip)
- RMTMEM.chan[mRMT_channel].data32[mCurPulse-1].duration1 = RMT_RESET_DURATION;
->>>>>>> upstream/master
- }
-
- if (done_strip) {
- // -- And fill the remaining items with zero pulses. The zero values triggers
- // the tx_done interrupt.
- while (pulse_count < MAX_PULSES) {
- RMTMEM.chan[mRMT_channel].data32[mCurPulse].val = 0;
- ++mCurPulse;
- ++pulse_count;
- }
- }
-
- // -- When we have filled the back half the buffer, reset the position to the first half
- if (mCurPulse >= MAX_PULSES*2)
- mCurPulse = 0;
- }
-
- virtual void writeAllRMTItems()
- {
- // -- Compute the pulse values for the whole strip at once.
- // Requires a large buffer
-<<<<<<< HEAD
- mBufferSize = mPixels->size() * 3 * 8;
-=======
- mBufferSize = mPixels->size() * 3 * 8;
->>>>>>> upstream/master
-
- // TODO: need a specific number here
- if (mBuffer == NULL) {
- mBuffer = (rmt_item32_t *) calloc( mBufferSize, sizeof(rmt_item32_t));
- }
-
- mCurPulse = 0;
- mRGB_channel = 0;
- uint32_t byteval = 0;
- while (mPixels->has(1)) {
- // -- Cycle through the R,G, and B values in the right order
- switch (mRGB_channel) {
- case 0:
- byteval = mPixels->loadAndScale0();
- mRGB_channel = 1;
- break;
- case 1:
- byteval = mPixels->loadAndScale1();
- mRGB_channel = 2;
- break;
- case 2:
- byteval = mPixels->loadAndScale2();
- mPixels->advanceData();
- mPixels->stepDithering();
- mRGB_channel = 0;
- break;
- default:
- break;
- }
-
- byteval <<= 24;
- // Shift bits out, MSB first, setting RMTMEM.chan[n].data32[x] to the
- // rmt_item32_t value corresponding to the buffered bit value
- for (register uint32_t j = 0; j < 8; ++j) {
- mBuffer[mCurPulse] = (byteval & 0x80000000L) ? mOne : mZero;
- byteval <<= 1;
- ++mCurPulse;
- }
- }
-
- mBuffer[mCurPulse-1].duration1 = RMT_RESET_DURATION;
- assert(mCurPulse == mBufferSize);
-
-<<<<<<< HEAD
- rmt_write_items(mRMT_channel, mBuffer, mBufferSize, false);
-=======
- rmt_write_items(mRMT_channel, mBuffer, mBufferSize, false);
->>>>>>> upstream/master
- }
-};
-
-FASTLED_NAMESPACE_END
diff --git a/platforms/esp/32/clockless_rmt_esp32.h b/platforms/esp/32/clockless_rmt_esp32.h
deleted file mode 100644
index a53ff5f6..00000000
--- a/platforms/esp/32/clockless_rmt_esp32.h
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Integration into FastLED ClocklessController
- * Copyright (c) 2018 Samuel Z. Guyer
- * Copyright (c) 2017 Thomas Basler
- * Copyright (c) 2017 Martin F. Falatic
- *
- * ESP32 support is provided using the RMT peripheral device -- a unit
- * on the chip designed specifically for generating (and receiving)
- * precisely-timed digital signals. Nominally for use in infrared
- * remote controls, we use it to generate the signals for clockless
- * LED strips. The main advantage of using the RMT device is that,
- * once programmed, it generates the signal asynchronously, allowing
- * the CPU to continue executing other code. It is also not vulnerable
- * to interrupts or other timing problems that could disrupt the signal.
- *
- * The implementation strategy is borrowed from previous work and from
- * the RMT support built into the ESP32 IDF. The RMT device has 8
- * channels, which can be programmed independently to send sequences
- * of high/low bits. Memory for each channel is limited, however, so
- * in order to send a long sequence of bits, we need to continuously
- * refill the buffer until all the data is sent. To do this, we fill
- * half the buffer and then set an interrupt to go off when that half
- * is sent. Then we refill that half while the second half is being
- * sent. This strategy effectively overlaps computation (by the CPU)
- * and communication (by the RMT).
- *
- * Since the RMT device only has 8 channels, we need a strategy to
- * allow more than 8 LED controllers. Our driver assigns controllers
- * to channels on the fly, queuing up controllers as necessary until a
- * channel is free. The main showPixels routine just fires off the
- * first 8 controllers; the interrupt handler starts new controllers
- * asynchronously as previous ones finish. So, for example, it can
- * send the data for 8 controllers simultaneously, but 16 controllers
- * would take approximately twice as much time.
- *
- * There is a #define that allows a program to control the total
- * number of channels that the driver is allowed to use. It defaults
- * to 8 -- use all the channels. Setting it to 1, for example, results
- * in fully serial output:
- *
- * #define FASTLED_RMT_MAX_CHANNELS 1
- *
- * OTHER RMT APPLICATIONS
- *
- * The default FastLED driver takes over control of the RMT interrupt
- * handler, making it hard to use the RMT device for other
- * (non-FastLED) purposes. You can change it's behavior to use the ESP
- * core driver instead, allowing other RMT applications to
- * co-exist. To switch to this mode, add the following directive
- * before you include FastLED.h:
- *
- * #define FASTLED_RMT_BUILTIN_DRIVER 1
- *
- * There may be a performance penalty for using this mode. We need to
- * compute the RMT signal for the entire LED strip ahead of time,
- * rather than overlapping it with communication. We also need a large
- * buffer to hold the signal specification. Each bit of pixel data is
- * represented by a 32-bit pulse specification, so it is a 32X blow-up
- * in memory use.
- *
- * NEW: Use of Flash memory on the ESP32 can interfere with the timing
- * of pixel output. The ESP-IDF system code disables all other
- * code running on *either* core during these operation. To prevent
- * this from happening, define this flag. It will force flash
- * operations to wait until the show() is done.
- *
- * #define FASTLED_ESP32_FLASH_LOCK 1
- *
- * Based on public domain code created 19 Nov 2016 by Chris Osborn <fozztexx@fozztexx.com>
- * http://insentricity.com *
- *
- */
-/*
- * 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.
- */
-
-#pragma once
-
-FASTLED_NAMESPACE_BEGIN
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "esp32-hal.h"
-#include "esp_intr.h"
-#include "driver/gpio.h"
-#include "driver/rmt.h"
-#include "driver/periph_ctrl.h"
-#include "freertos/semphr.h"
-#include "soc/rmt_struct.h"
-
-#include "esp_log.h"
-
-extern void spi_flash_op_lock(void);
-extern void spi_flash_op_unlock(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-__attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
- uint32_t cyc;
- __asm__ __volatile__ ("rsr %0,ccount":"=a" (cyc));
- return cyc;
-}
-
-#define FASTLED_HAS_CLOCKLESS 1
-#define NUM_COLOR_CHANNELS 3
-
-// -- Set to true to print debugging information about timing
-// Useful for finding out if timing is being messed up by other things
-// on the processor (WiFi, for example)
-#ifndef FASTLED_RMT_SHOW_TIMER
-#define FASTLED_RMT_SHOW_TIMER false
-#endif
-
-// -- Configuration constants
-#define DIVIDER 2 /* 4, 8 still seem to work, but timings become marginal */
-#define MAX_PULSES 64 /* A channel has a 64 "pulse" buffer */
-#define PULSES_PER_FILL 24 /* One pixel's worth of pulses */
-
-// -- Convert ESP32 CPU cycles to RMT device cycles, taking into account the divider
-#define F_CPU_RMT ( 80000000L)
-#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))
-
-// -- Number of cycles to signal the strip to latch
-#define NS_PER_CYCLE ( 1000000000L / RMT_CYCLES_PER_SEC )
-#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )
-#define RMT_RESET_DURATION NS_TO_CYCLES(50000)
-
-// -- Core or custom driver
-#ifndef FASTLED_RMT_BUILTIN_DRIVER
-#define FASTLED_RMT_BUILTIN_DRIVER false
-#endif
-
-// -- Max number of controllers we can support
-#ifndef FASTLED_RMT_MAX_CONTROLLERS
-#define FASTLED_RMT_MAX_CONTROLLERS 32
-#endif
-
-// -- Number of RMT channels to use (up to 8)
-// Redefine this value to 1 to force serial output
-#ifndef FASTLED_RMT_MAX_CHANNELS
-#define FASTLED_RMT_MAX_CHANNELS 8
-#endif
-
-// -- Array of all controllers
-static CLEDController * gControllers[FASTLED_RMT_MAX_CONTROLLERS];
-
-// -- Current set of active controllers, indexed by the RMT
-// channel assigned to them.
-static CLEDController * gOnChannel[FASTLED_RMT_MAX_CHANNELS];
-
-static int gNumControllers = 0;
-static int gNumStarted = 0;
-static int gNumDone = 0;
-static int gNext = 0;
-
-static intr_handle_t gRMT_intr_handle = NULL;
-
-// -- Global semaphore for the whole show process
-// Semaphore is not given until all data has been sent
-static xSemaphoreHandle gTX_sem = NULL;
-
-static bool gInitialized = false;
-
-template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
-class ClocklessController : public CPixelLEDController<RGB_ORDER>
-{
- // -- RMT has 8 channels, numbered 0 to 7
- rmt_channel_t mRMT_channel;
-
- // -- Store the GPIO pin
- gpio_num_t mPin;
-
- // -- This instantiation forces a check on the pin choice
- FastPin<DATA_PIN> mFastPin;
-
- // -- Timing values for zero and one bits, derived from T1, T2, and T3
- rmt_item32_t mZero;
- rmt_item32_t mOne;
-
- // -- Save the pixel controller
- PixelController<RGB_ORDER> * mPixels;
- int mCurColor;
- uint16_t mCurPulse;
- volatile uint32_t * mRMT_mem_ptr;
-
- // -- Buffer to hold all of the pulses. For the version that uses
- // the RMT driver built into the ESP core.
- rmt_item32_t * mBuffer;
- uint16_t mBufferSize;
-
- // -- Make sure we can't call show() too quickly
- CMinWait<50> mWait;
-
-public:
- void init()
- {
- // -- Allocate space to save the pixel controller
- // during parallel output
- mPixels = (PixelController<RGB_ORDER> *) malloc(sizeof(PixelController<RGB_ORDER>));
-
- // -- Precompute rmt items corresponding to a zero bit and a one bit
- // according to the timing values given in the template instantiation
- // T1H
- mOne.level0 = 1;
- mOne.duration0 = ESP_TO_RMT_CYCLES(T1+T2); // TO_RMT_CYCLES(T1+T2);
- // T1L
- mOne.level1 = 0;
- mOne.duration1 = ESP_TO_RMT_CYCLES(T3); // TO_RMT_CYCLES(T3);
-
- // T0H
- mZero.level0 = 1;
- mZero.duration0 = ESP_TO_RMT_CYCLES(T1); // TO_RMT_CYCLES(T1);
- // T0L
- mZero.level1 = 0;
- mZero.duration1 = ESP_TO_RMT_CYCLES(T2+T3); // TO_RMT_CYCLES(T2 + T3);
-
- gControllers[gNumControllers] = this;
- ++gNumControllers;
-
- mPin = gpio_num_t(DATA_PIN);
- }
-
- virtual uint16_t getMaxRefreshRate() const { return 400; }
-
-protected:
- void initRMT()
- {
- for (int i = 0; i < FASTLED_RMT_MAX_CHANNELS; ++i) {
- gOnChannel[i] = NULL;
-
- // -- RMT configuration for transmission
- rmt_config_t rmt_tx;
- rmt_tx.channel = rmt_channel_t(i);
- rmt_tx.rmt_mode = RMT_MODE_TX;
- rmt_tx.gpio_num = mPin; // The particular pin will be assigned later
- rmt_tx.mem_block_num = 1;
- rmt_tx.clk_div = DIVIDER;
- rmt_tx.tx_config.loop_en = false;
- rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
- rmt_tx.tx_config.carrier_en = false;
- rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
- rmt_tx.tx_config.idle_output_en = true;
-
- // -- Apply the configuration
- rmt_config(&rmt_tx);
-
- if (FASTLED_RMT_BUILTIN_DRIVER) {
- rmt_driver_install(rmt_channel_t(i), 0, 0);
- } else {
- // -- Set up the RMT to send 1 pixel of the pulse buffer and then
- // generate an interrupt. When we get this interrupt we
- // fill the other part in preparation (kind of like double-buffering)
- rmt_set_tx_thr_intr_en(rmt_channel_t(i), true, PULSES_PER_FILL);
- }
- }
-
- // -- Create a semaphore to block execution until all the controllers are done
- if (gTX_sem == NULL) {
- gTX_sem = xSemaphoreCreateBinary();
- xSemaphoreGive(gTX_sem);
- }
-
- if ( ! FASTLED_RMT_BUILTIN_DRIVER) {
- // -- Allocate the interrupt if we have not done so yet. This
- // interrupt handler must work for all different kinds of
- // strips, so it delegates to the refill function for each
- // specific instantiation of ClocklessController.
- if (gRMT_intr_handle == NULL)
- esp_intr_alloc(ETS_RMT_INTR_SOURCE, ESP_INTR_FLAG_LEVEL3, interruptHandler, 0, &gRMT_intr_handle);
- }
-
- gInitialized = true;
- }
-
- // -- Show pixels
- // This is the main entry point for the controller.
- virtual void IRAM_ATTR showPixels(PixelController<RGB_ORDER> & pixels)
- {
- if (gNumStarted == 0) {
- // -- First controller: make sure everything is set up
- // -- Only need to do this once
- if ( ! gInitialized) {
- initRMT();
- }
- xSemaphoreTake(gTX_sem, portMAX_DELAY);
-
-#if FASTLED_ESP32_FLASH_LOCK == 1
- // -- Make sure no flash operations happen right now
- spi_flash_op_lock();
-#endif
- }
-
- if (FASTLED_RMT_BUILTIN_DRIVER)
- convertAllPixelData(pixels);
- else {
- // -- Initialize the local state, save a pointer to the pixel
- // data. We need to make a copy because pixels is a local
- // variable in the calling function, and this data structure
- // needs to outlive this call to showPixels.
- (*mPixels) = pixels;
- }
-
- // -- Keep track of the number of strips we've seen
- ++gNumStarted;
-
- // -- The last call to showPixels is the one responsible for doing
- // all of the actual worl
- if (gNumStarted == gNumControllers) {
- gNext = 0;
-
- // -- First, fill all the available channels
- int channel = 0;
- while (channel < FASTLED_RMT_MAX_CHANNELS && gNext < gNumControllers) {
- startNext(channel);
- ++channel;
- }
-
- // -- Make sure it's been at least 50ms since last show
- mWait.wait();
-
- // -- Start them all
- for (int i = 0; i < channel; ++i) {
- ClocklessController * pController = static_cast<ClocklessController*>(gControllers[i]);
- rmt_tx_start(pController->mRMT_channel, true);
- }
-
- // -- Wait here while the rest of the data is sent. The interrupt handler
- // will keep refilling the RMT buffers until it is all sent; then it
- // gives the semaphore back.
- xSemaphoreTake(gTX_sem, portMAX_DELAY);
- xSemaphoreGive(gTX_sem);
-
- mWait.mark();
-
- // -- Reset the counters
- gNumStarted = 0;
- gNumDone = 0;
- gNext = 0;
-
-#if FASTLED_ESP32_FLASH_LOCK == 1
- // -- Release the lock on flash operations
- spi_flash_op_unlock();
-#endif
- }
- }
-
- // -- Convert all pixels to RMT pulses
- // This function is only used when the user chooses to use the
- // built-in RMT driver, which needs all of the RMT pulses
- // up-front.
- void convertAllPixelData(PixelController<RGB_ORDER> & pixels)
- {
- // -- Compute the pulse values for the whole strip at once.
- // Requires a large buffer
- mBufferSize = pixels.size() * 3 * 8;
-
- if (mBuffer == NULL) {
- mBuffer = (rmt_item32_t *) calloc( mBufferSize, sizeof(rmt_item32_t));
- }
-
- // -- Cycle through the R,G, and B values in the right order,
- // storing the pulses in the big buffer
- mCurPulse = 0;
-
- uint32_t byteval;
- while (pixels.has(1)) {
- byteval = pixels.loadAndScale0();
- convertByte(byteval);
- byteval = pixels.loadAndScale1();
- convertByte(byteval);
- byteval = pixels.loadAndScale2();
- convertByte(byteval);
- pixels.advanceData();
- pixels.stepDithering();
- }
-
- mBuffer[mCurPulse-1].duration1 = RMT_RESET_DURATION;
- assert(mCurPulse == mBufferSize);
- }
-
- void convertByte(uint32_t byteval)
- {
- // -- Write one byte's worth of RMT pulses to the big buffer
- byteval <<= 24;
- for (register uint32_t j = 0; j < 8; ++j) {
- mBuffer[mCurPulse] = (byteval & 0x80000000L) ? mOne : mZero;
- byteval <<= 1;
- ++mCurPulse;
- }
- }
-
- // -- Start up the next controller
- // This method is static so that it can dispatch to the
- // appropriate startOnChannel method of the given controller.
- static void IRAM_ATTR startNext(int channel)
- {
- if (gNext < gNumControllers) {
- ClocklessController * pController = static_cast<ClocklessController*>(gControllers[gNext]);
- pController->startOnChannel(channel);
- ++gNext;
- }
- }
-
- // -- Start this controller on the given channel
- // This function just initiates the RMT write; it does not wait
- // for it to finish.
- void IRAM_ATTR startOnChannel(int channel)
- {
- // -- Assign this channel and configure the RMT
- mRMT_channel = rmt_channel_t(channel);
-
- // -- Store a reference to this controller, so we can get it
- // inside the interrupt handler
- gOnChannel[channel] = this;
-
- // -- Assign the pin to this channel
- rmt_set_pin(mRMT_channel, RMT_MODE_TX, mPin);
-
- if (FASTLED_RMT_BUILTIN_DRIVER) {
- // -- Use the built-in RMT driver to send all the data in one shot
- rmt_register_tx_end_callback(doneOnChannel, 0);
- rmt_write_items(mRMT_channel, mBuffer, mBufferSize, false);
- } else {
- // -- Use our custom driver to send the data incrementally
-
- // -- Initialize the counters that keep track of where we are in
- // the pixel data.
- mRMT_mem_ptr = & (RMTMEM.chan[mRMT_channel].data32[0].val);
- mCurPulse = 0;
- mCurColor = 0;
-
- // -- Store 2 pixels worth of data (two "buffers" full)
- fillNext();
- fillNext();
-
- // -- Turn on the interrupts
- rmt_set_tx_intr_en(mRMT_channel, true);
- }
- }
-
- // -- A controller is done
- // This function is called when a controller finishes writing
- // its data. It is called either by the custom interrupt
- // handler (below), or as a callback from the built-in
- // interrupt handler. It is static because we don't know which
- // controller is done until we look it up.
- static void IRAM_ATTR doneOnChannel(rmt_channel_t channel, void * arg)
- {
- ClocklessController * controller = static_cast<ClocklessController*>(gOnChannel[channel]);
- portBASE_TYPE HPTaskAwoken = 0;
-
- // -- Turn off output on the pin
- gpio_matrix_out(controller->mPin, 0x100, 0, 0);
-
- gOnChannel[channel] = NULL;
- ++gNumDone;
-
- if (gNumDone == gNumControllers) {
- // -- If this is the last controller, signal that we are all done
- if (FASTLED_RMT_BUILTIN_DRIVER) {
- xSemaphoreGive(gTX_sem);
- } else {
- xSemaphoreGiveFromISR(gTX_sem, &HPTaskAwoken);
- if (HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
- }
- } else {
- // -- Otherwise, if there are still controllers waiting, then
- // start the next one on this channel
- if (gNext < gNumControllers) {
- startNext(channel);
- // -- Start the RMT TX operation
- // (I'm not sure if this is necessary here)
- rmt_tx_start(controller->mRMT_channel, true);
- }
- }
- }
-
- // -- Custom interrupt handler
- // This interrupt handler handles two cases: a controller is
- // done writing its data, or a controller needs to fill the
- // next half of the RMT buffer with data.
- static void IRAM_ATTR interruptHandler(void *arg)
- {
- // -- The basic structure of this code is borrowed from the
- // interrupt handler in esp-idf/components/driver/rmt.c
- uint32_t intr_st = RMT.int_st.val;
- uint8_t channel;
-
- for (channel = 0; channel < FASTLED_RMT_MAX_CHANNELS; ++channel) {
- int tx_done_bit = channel * 3;
- int tx_next_bit = channel + 24;
-
- if (gOnChannel[channel] != NULL) {
-
- // -- More to send on this channel
- if (intr_st & BIT(tx_next_bit)) {
- RMT.int_clr.val |= BIT(tx_next_bit);
-
- // -- Refill the half of the buffer that we just finished,
- // allowing the other half to proceed.
- ClocklessController * controller = static_cast<ClocklessController*>(gOnChannel[channel]);
- controller->fillNext();
- } else {
- // -- Transmission is complete on this channel
- if (intr_st & BIT(tx_done_bit)) {
- RMT.int_clr.val |= BIT(tx_done_bit);
- doneOnChannel(rmt_channel_t(channel), 0);
- }
- }
- }
- }
- }
-
- // -- Fill RMT buffer
- // Puts one pixel's worth of data into the next 24 slots in the RMT memory
- void IRAM_ATTR fillNext()
- {
- if (mPixels->has(1)) {
- uint32_t one_val = mOne.val;
- uint32_t zero_val = mZero.val;
-
- // -- Get a pixel's worth of data
- uint8_t byte0 = mPixels->loadAndScale0();
- uint8_t byte1 = mPixels->loadAndScale1();
- uint8_t byte2 = mPixels->loadAndScale2();
- mPixels->advanceData();
- mPixels->stepDithering();
-
- // -- Fill 24 slots in the RMT memory
- register uint32_t pixel = byte0 << 24 | byte1 << 16 | byte2 << 8;
-
- // -- Use locals for speed
- volatile register uint32_t * pItem = mRMT_mem_ptr;
- register uint16_t curPulse = mCurPulse;
-
- // Shift bits out, MSB first, setting RMTMEM.chan[n].data32[x] to the
- // rmt_item32_t value corresponding to the buffered bit value
- for (register uint32_t j = 0; j < 24; ++j) {
- uint32_t val = (pixel & 0x80000000L) ? one_val : zero_val;
- *pItem++ = val;
- // Replaces: RMTMEM.chan[mRMT_channel].data32[mCurPulse].val = val;
-
- pixel <<= 1;
- ++curPulse;
-
- if (curPulse == MAX_PULSES) {
- pItem = & (RMTMEM.chan[mRMT_channel].data32[0].val);
- curPulse = 0;
- }
- }
-
- // -- Store the new values back into the object
- mCurPulse = curPulse;
- mRMT_mem_ptr = pItem;
- } else {
- // -- No more data; signal to the RMT we are done
- for (uint32_t j = 0; j < 8; ++j) {
- * mRMT_mem_ptr++ = 0;
- }
- }
- }
-
- // NO LONGER USED
- uint8_t IRAM_ATTR getNextByte() __attribute__ ((always_inline))
- {
- uint8_t byte;
-
- // -- Cycle through the color channels
- switch (mCurColor) {
- case 0:
- byte = mPixels->loadAndScale0();
- break;
- case 1:
- byte = mPixels->loadAndScale1();
- break;
- case 2:
- byte = mPixels->loadAndScale2();
- mPixels->advanceData();
- mPixels->stepDithering();
- break;
- default:
- // -- This is bad!
- byte = 0;
- }
-
- ++mCurColor;
- if (mCurColor == NUM_COLOR_CHANNELS) mCurColor = 0;
-
- return byte;
- }
-
-
- // NO LONGER USED
- // -- Fill the RMT buffer
- // This function fills the next 32 slots in the RMT write
- // buffer with pixel data. It also handles the case where the
- // pixel data is exhausted, so we need to fill the RMT buffer
- // with zeros to signal that it's done.
- virtual void IRAM_ATTR fillHalfRMTBuffer()
- {
- uint32_t one_val = mOne.val;
- uint32_t zero_val = mZero.val;
-
- // -- Convert (up to) 32 bits of the raw pixel data into
- // into RMT pulses that encode the zeros and ones.
- int pulses = 0;
- register uint32_t byteval;
- while (pulses < 32 && mPixels->has(1)) {
- // -- Get one byte
- // -- Cycle through the color channels
- switch (mCurColor) {
- case 0:
- byteval = mPixels->loadAndScale0();
- break;
- case 1:
- byteval = mPixels->loadAndScale1();
- break;
- case 2:
- byteval = mPixels->loadAndScale2();
- mPixels->advanceData();
- mPixels->stepDithering();
- break;
- default:
- // -- This is bad!
- byteval = 0;
- }
-
- ++mCurColor;
- if (mCurColor == NUM_COLOR_CHANNELS) mCurColor = 0;
-
- // byteval = getNextByte();
- byteval <<= 24;
- // Shift bits out, MSB first, setting RMTMEM.chan[n].data32[x] to the
- // rmt_item32_t value corresponding to the buffered bit value
- for (register uint32_t j = 0; j < 8; ++j) {
- uint32_t val = (byteval & 0x80000000L) ? one_val : zero_val;
- * mRMT_mem_ptr++ = val;
- // Replaces: RMTMEM.chan[mRMT_channel].data32[mCurPulse].val = val;
- byteval <<= 1;
- ++mCurPulse;
- }
- pulses += 8;
- }
-
- // -- When we reach the end of the pixel data, fill the rest of the
- // RMT buffer with 0's, which signals to the device that we're done.
- if ( ! mPixels->has(1) ) {
- while (pulses < 32) {
- * mRMT_mem_ptr++ = 0;
- // Replaces: RMTMEM.chan[mRMT_channel].data32[mCurPulse].val = 0;
- ++mCurPulse;
- ++pulses;
- }
- }
-
- // -- When we have filled the back half the buffer, reset the position to the first half
- if (mCurPulse == MAX_PULSES) {
- mRMT_mem_ptr = & (RMTMEM.chan[mRMT_channel].data32[0].val);
- mCurPulse = 0;
- }
- }
-};
-
-FASTLED_NAMESPACE_END
diff --git a/FastLED.cpp b/src/FastLED.cpp
index 255dcfa3..255dcfa3 100644
--- a/FastLED.cpp
+++ b/src/FastLED.cpp
diff --git a/FastLED.h b/src/FastLED.h
index 0cc1acc4..0cc1acc4 100644
--- a/FastLED.h
+++ b/src/FastLED.h
diff --git a/bitswap.cpp b/src/bitswap.cpp
index 5be71f02..5be71f02 100644
--- a/bitswap.cpp
+++ b/src/bitswap.cpp
diff --git a/bitswap.h b/src/bitswap.h
index 79eec540..79eec540 100644
--- a/bitswap.h
+++ b/src/bitswap.h
diff --git a/chipsets.h b/src/chipsets.h
index 60457254..60457254 100644
--- a/chipsets.h
+++ b/src/chipsets.h
diff --git a/color.h b/src/color.h
index 63687cb5..63687cb5 100644
--- a/color.h
+++ b/src/color.h
diff --git a/colorpalettes.cpp b/src/colorpalettes.cpp
index 68e42f03..68e42f03 100644
--- a/colorpalettes.cpp
+++ b/src/colorpalettes.cpp
diff --git a/colorpalettes.h b/src/colorpalettes.h
index 4458575e..4458575e 100644
--- a/colorpalettes.h
+++ b/src/colorpalettes.h
diff --git a/colorutils.cpp b/src/colorutils.cpp
index c40f4860..c40f4860 100644
--- a/colorutils.cpp
+++ b/src/colorutils.cpp
diff --git a/colorutils.h b/src/colorutils.h
index f09d525f..f09d525f 100644
--- a/colorutils.h
+++ b/src/colorutils.h
diff --git a/controller.h b/src/controller.h
index fe32d70d..fe32d70d 100644
--- a/controller.h
+++ b/src/controller.h
diff --git a/cpp_compat.h b/src/cpp_compat.h
index ab5b773a..ab5b773a 100644
--- a/cpp_compat.h
+++ b/src/cpp_compat.h
diff --git a/dmx.h b/src/dmx.h
index 04cb5de0..04cb5de0 100644
--- a/dmx.h
+++ b/src/dmx.h
diff --git a/fastled_config.h b/src/fastled_config.h
index 6e415274..6e415274 100644
--- a/fastled_config.h
+++ b/src/fastled_config.h
diff --git a/fastled_delay.h b/src/fastled_delay.h
index a14e8a29..a14e8a29 100644
--- a/fastled_delay.h
+++ b/src/fastled_delay.h
diff --git a/fastled_progmem.h b/src/fastled_progmem.h
index dfcb9eff..dfcb9eff 100644
--- a/fastled_progmem.h
+++ b/src/fastled_progmem.h
diff --git a/fastpin.h b/src/fastpin.h
index 085a7d1b..085a7d1b 100644
--- a/fastpin.h
+++ b/src/fastpin.h
diff --git a/fastspi.h b/src/fastspi.h
index 2245ffe9..2245ffe9 100644
--- a/fastspi.h
+++ b/src/fastspi.h
diff --git a/fastspi_bitbang.h b/src/fastspi_bitbang.h
index 86663f17..86663f17 100644
--- a/fastspi_bitbang.h
+++ b/src/fastspi_bitbang.h
diff --git a/fastspi_dma.h b/src/fastspi_dma.h
index e69de29b..e69de29b 100644
--- a/fastspi_dma.h
+++ b/src/fastspi_dma.h
diff --git a/fastspi_nop.h b/src/fastspi_nop.h
index 1dcd2961..1dcd2961 100644
--- a/fastspi_nop.h
+++ b/src/fastspi_nop.h
diff --git a/fastspi_ref.h b/src/fastspi_ref.h
index a12a962a..a12a962a 100644
--- a/fastspi_ref.h
+++ b/src/fastspi_ref.h
diff --git a/fastspi_types.h b/src/fastspi_types.h
index ea7d46ce..ea7d46ce 100644
--- a/fastspi_types.h
+++ b/src/fastspi_types.h
diff --git a/hsv2rgb.cpp b/src/hsv2rgb.cpp
index 1fb8d56b..1fb8d56b 100644
--- a/hsv2rgb.cpp
+++ b/src/hsv2rgb.cpp
diff --git a/hsv2rgb.h b/src/hsv2rgb.h
index ddc63baf..ddc63baf 100644
--- a/hsv2rgb.h
+++ b/src/hsv2rgb.h
diff --git a/led_sysdefs.h b/src/led_sysdefs.h
index 8ee568bf..8ee568bf 100644
--- a/led_sysdefs.h
+++ b/src/led_sysdefs.h
diff --git a/lib8tion.cpp b/src/lib8tion.cpp
index ecb051d8..ecb051d8 100644
--- a/lib8tion.cpp
+++ b/src/lib8tion.cpp
diff --git a/lib8tion.h b/src/lib8tion.h
index 0cc3baa4..0cc3baa4 100644
--- a/lib8tion.h
+++ b/src/lib8tion.h
diff --git a/lib8tion/math8.h b/src/lib8tion/math8.h
index a83b1ad2..a83b1ad2 100644
--- a/lib8tion/math8.h
+++ b/src/lib8tion/math8.h
diff --git a/lib8tion/random8.h b/src/lib8tion/random8.h
index d834abd5..d834abd5 100644
--- a/lib8tion/random8.h
+++ b/src/lib8tion/random8.h
diff --git a/lib8tion/scale8.h b/src/lib8tion/scale8.h
index 6324475b..6324475b 100644
--- a/lib8tion/scale8.h
+++ b/src/lib8tion/scale8.h
diff --git a/lib8tion/trig8.h b/src/lib8tion/trig8.h
index c5896ef8..c5896ef8 100644
--- a/lib8tion/trig8.h
+++ b/src/lib8tion/trig8.h
diff --git a/noise.cpp b/src/noise.cpp
index 3a40c476..3a40c476 100644
--- a/noise.cpp
+++ b/src/noise.cpp
diff --git a/noise.h b/src/noise.h
index 7355e23e..7355e23e 100644
--- a/noise.h
+++ b/src/noise.h
diff --git a/pixelset.h b/src/pixelset.h
index b8488c2c..b8488c2c 100644
--- a/pixelset.h
+++ b/src/pixelset.h
diff --git a/pixeltypes.h b/src/pixeltypes.h
index 6e91723d..6e91723d 100644
--- a/pixeltypes.h
+++ b/src/pixeltypes.h
diff --git a/platforms.cpp b/src/platforms.cpp
index 5b6847ad..5b6847ad 100644
--- a/platforms.cpp
+++ b/src/platforms.cpp
diff --git a/platforms.h b/src/platforms.h
index 7969c9e4..7969c9e4 100644
--- a/platforms.h
+++ b/src/platforms.h
diff --git a/platforms/apollo3/clockless_apollo3.h b/src/platforms/apollo3/clockless_apollo3.h
index fa487c2f..fa487c2f 100644
--- a/platforms/apollo3/clockless_apollo3.h
+++ b/src/platforms/apollo3/clockless_apollo3.h
diff --git a/platforms/apollo3/fastled_apollo3.h b/src/platforms/apollo3/fastled_apollo3.h
index 4c727dd0..4c727dd0 100644
--- a/platforms/apollo3/fastled_apollo3.h
+++ b/src/platforms/apollo3/fastled_apollo3.h
diff --git a/platforms/apollo3/fastpin_apollo3.h b/src/platforms/apollo3/fastpin_apollo3.h
index 6d0f1e60..6d0f1e60 100644
--- a/platforms/apollo3/fastpin_apollo3.h
+++ b/src/platforms/apollo3/fastpin_apollo3.h
diff --git a/platforms/apollo3/fastspi_apollo3.h b/src/platforms/apollo3/fastspi_apollo3.h
index 0c77d319..0c77d319 100644
--- a/platforms/apollo3/fastspi_apollo3.h
+++ b/src/platforms/apollo3/fastspi_apollo3.h
diff --git a/platforms/apollo3/led_sysdefs_apollo3.h b/src/platforms/apollo3/led_sysdefs_apollo3.h
index be74e24d..be74e24d 100644
--- a/platforms/apollo3/led_sysdefs_apollo3.h
+++ b/src/platforms/apollo3/led_sysdefs_apollo3.h
diff --git a/platforms/arm/common/m0clockless.h b/src/platforms/arm/common/m0clockless.h
index 6fd86595..6fd86595 100644
--- a/platforms/arm/common/m0clockless.h
+++ b/src/platforms/arm/common/m0clockless.h
diff --git a/platforms/arm/d21/clockless_arm_d21.h b/src/platforms/arm/d21/clockless_arm_d21.h
index 16526ed6..16526ed6 100644
--- a/platforms/arm/d21/clockless_arm_d21.h
+++ b/src/platforms/arm/d21/clockless_arm_d21.h
diff --git a/platforms/arm/d21/fastled_arm_d21.h b/src/platforms/arm/d21/fastled_arm_d21.h
index 98412749..98412749 100644
--- a/platforms/arm/d21/fastled_arm_d21.h
+++ b/src/platforms/arm/d21/fastled_arm_d21.h
diff --git a/platforms/arm/d21/fastpin_arm_d21.h b/src/platforms/arm/d21/fastpin_arm_d21.h
index f3fa79cb..f3fa79cb 100644
--- a/platforms/arm/d21/fastpin_arm_d21.h
+++ b/src/platforms/arm/d21/fastpin_arm_d21.h
diff --git a/platforms/arm/d21/led_sysdefs_arm_d21.h b/src/platforms/arm/d21/led_sysdefs_arm_d21.h
index a48db10a..a48db10a 100644
--- a/platforms/arm/d21/led_sysdefs_arm_d21.h
+++ b/src/platforms/arm/d21/led_sysdefs_arm_d21.h
diff --git a/platforms/arm/d51/README.txt b/src/platforms/arm/d51/README.txt
index b00fb670..b00fb670 100644
--- a/platforms/arm/d51/README.txt
+++ b/src/platforms/arm/d51/README.txt
diff --git a/platforms/arm/d51/clockless_arm_d51.h b/src/platforms/arm/d51/clockless_arm_d51.h
index 2bf00d27..2bf00d27 100644
--- a/platforms/arm/d51/clockless_arm_d51.h
+++ b/src/platforms/arm/d51/clockless_arm_d51.h
diff --git a/platforms/arm/d51/fastled_arm_d51.h b/src/platforms/arm/d51/fastled_arm_d51.h
index 0c14bf2f..0c14bf2f 100644
--- a/platforms/arm/d51/fastled_arm_d51.h
+++ b/src/platforms/arm/d51/fastled_arm_d51.h
diff --git a/platforms/arm/d51/fastpin_arm_d51.h b/src/platforms/arm/d51/fastpin_arm_d51.h
index 9d31cedb..9d31cedb 100644
--- a/platforms/arm/d51/fastpin_arm_d51.h
+++ b/src/platforms/arm/d51/fastpin_arm_d51.h
diff --git a/platforms/arm/d51/led_sysdefs_arm_d51.h b/src/platforms/arm/d51/led_sysdefs_arm_d51.h
index fd6a25e2..fd6a25e2 100644
--- a/platforms/arm/d51/led_sysdefs_arm_d51.h
+++ b/src/platforms/arm/d51/led_sysdefs_arm_d51.h
diff --git a/platforms/arm/k20/clockless_arm_k20.h b/src/platforms/arm/k20/clockless_arm_k20.h
index 0a7f7b94..0a7f7b94 100644
--- a/platforms/arm/k20/clockless_arm_k20.h
+++ b/src/platforms/arm/k20/clockless_arm_k20.h
diff --git a/platforms/arm/k20/clockless_block_arm_k20.h b/src/platforms/arm/k20/clockless_block_arm_k20.h
index 9beeb9fa..9beeb9fa 100644
--- a/platforms/arm/k20/clockless_block_arm_k20.h
+++ b/src/platforms/arm/k20/clockless_block_arm_k20.h
diff --git a/platforms/arm/k20/fastled_arm_k20.h b/src/platforms/arm/k20/fastled_arm_k20.h
index 06c5c8e8..06c5c8e8 100644
--- a/platforms/arm/k20/fastled_arm_k20.h
+++ b/src/platforms/arm/k20/fastled_arm_k20.h
diff --git a/platforms/arm/k20/fastpin_arm_k20.h b/src/platforms/arm/k20/fastpin_arm_k20.h
index 736bd461..736bd461 100644
--- a/platforms/arm/k20/fastpin_arm_k20.h
+++ b/src/platforms/arm/k20/fastpin_arm_k20.h
diff --git a/platforms/arm/k20/fastspi_arm_k20.h b/src/platforms/arm/k20/fastspi_arm_k20.h
index 3d492558..3d492558 100644
--- a/platforms/arm/k20/fastspi_arm_k20.h
+++ b/src/platforms/arm/k20/fastspi_arm_k20.h
diff --git a/platforms/arm/k20/led_sysdefs_arm_k20.h b/src/platforms/arm/k20/led_sysdefs_arm_k20.h
index 0dcb626a..0dcb626a 100644
--- a/platforms/arm/k20/led_sysdefs_arm_k20.h
+++ b/src/platforms/arm/k20/led_sysdefs_arm_k20.h
diff --git a/platforms/arm/k20/octows2811_controller.h b/src/platforms/arm/k20/octows2811_controller.h
index f365e61f..f365e61f 100644
--- a/platforms/arm/k20/octows2811_controller.h
+++ b/src/platforms/arm/k20/octows2811_controller.h
diff --git a/platforms/arm/k20/smartmatrix_t3.h b/src/platforms/arm/k20/smartmatrix_t3.h
index c9747f0b..c9747f0b 100644
--- a/platforms/arm/k20/smartmatrix_t3.h
+++ b/src/platforms/arm/k20/smartmatrix_t3.h
diff --git a/platforms/arm/k20/ws2812serial_controller.h b/src/platforms/arm/k20/ws2812serial_controller.h
index a761dd49..a761dd49 100644
--- a/platforms/arm/k20/ws2812serial_controller.h
+++ b/src/platforms/arm/k20/ws2812serial_controller.h
diff --git a/platforms/arm/k66/clockless_arm_k66.h b/src/platforms/arm/k66/clockless_arm_k66.h
index e9dcc0cd..e9dcc0cd 100644
--- a/platforms/arm/k66/clockless_arm_k66.h
+++ b/src/platforms/arm/k66/clockless_arm_k66.h
diff --git a/platforms/arm/k66/clockless_block_arm_k66.h b/src/platforms/arm/k66/clockless_block_arm_k66.h
index 70f8c7a5..70f8c7a5 100644
--- a/platforms/arm/k66/clockless_block_arm_k66.h
+++ b/src/platforms/arm/k66/clockless_block_arm_k66.h
diff --git a/platforms/arm/k66/fastled_arm_k66.h b/src/platforms/arm/k66/fastled_arm_k66.h
index 2113e10e..2113e10e 100644
--- a/platforms/arm/k66/fastled_arm_k66.h
+++ b/src/platforms/arm/k66/fastled_arm_k66.h
diff --git a/platforms/arm/k66/fastpin_arm_k66.h b/src/platforms/arm/k66/fastpin_arm_k66.h
index ef48396c..ef48396c 100644
--- a/platforms/arm/k66/fastpin_arm_k66.h
+++ b/src/platforms/arm/k66/fastpin_arm_k66.h
diff --git a/platforms/arm/k66/fastspi_arm_k66.h b/src/platforms/arm/k66/fastspi_arm_k66.h
index f990741b..f990741b 100644
--- a/platforms/arm/k66/fastspi_arm_k66.h
+++ b/src/platforms/arm/k66/fastspi_arm_k66.h
diff --git a/platforms/arm/k66/led_sysdefs_arm_k66.h b/src/platforms/arm/k66/led_sysdefs_arm_k66.h
index 0b0c701c..0b0c701c 100644
--- a/platforms/arm/k66/led_sysdefs_arm_k66.h
+++ b/src/platforms/arm/k66/led_sysdefs_arm_k66.h
diff --git a/platforms/arm/kl26/clockless_arm_kl26.h b/src/platforms/arm/kl26/clockless_arm_kl26.h
index 29a61fba..29a61fba 100644
--- a/platforms/arm/kl26/clockless_arm_kl26.h
+++ b/src/platforms/arm/kl26/clockless_arm_kl26.h
diff --git a/platforms/arm/kl26/fastled_arm_kl26.h b/src/platforms/arm/kl26/fastled_arm_kl26.h
index a0ef0ff7..a0ef0ff7 100644
--- a/platforms/arm/kl26/fastled_arm_kl26.h
+++ b/src/platforms/arm/kl26/fastled_arm_kl26.h
diff --git a/platforms/arm/kl26/fastpin_arm_kl26.h b/src/platforms/arm/kl26/fastpin_arm_kl26.h
index 8b3cbdfe..8b3cbdfe 100644
--- a/platforms/arm/kl26/fastpin_arm_kl26.h
+++ b/src/platforms/arm/kl26/fastpin_arm_kl26.h
diff --git a/platforms/arm/kl26/fastspi_arm_kl26.h b/src/platforms/arm/kl26/fastspi_arm_kl26.h
index b1e76677..b1e76677 100644
--- a/platforms/arm/kl26/fastspi_arm_kl26.h
+++ b/src/platforms/arm/kl26/fastspi_arm_kl26.h
diff --git a/platforms/arm/kl26/led_sysdefs_arm_kl26.h b/src/platforms/arm/kl26/led_sysdefs_arm_kl26.h
index 575e6399..575e6399 100644
--- a/platforms/arm/kl26/led_sysdefs_arm_kl26.h
+++ b/src/platforms/arm/kl26/led_sysdefs_arm_kl26.h
diff --git a/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h
index c30823b6..c30823b6 100644
--- a/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h
diff --git a/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
index ed3be816..ed3be816 100644
--- a/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
diff --git a/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h
index 5098af33..5098af33 100644
--- a/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h
diff --git a/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h
index 8960a8c9..8960a8c9 100644
--- a/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h
diff --git a/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h
index 068c7be1..068c7be1 100644
--- a/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h
diff --git a/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h
index ac490825..ac490825 100644
--- a/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h
diff --git a/platforms/arm/nrf51/clockless_arm_nrf51.h b/src/platforms/arm/nrf51/clockless_arm_nrf51.h
index c607e61e..c607e61e 100644
--- a/platforms/arm/nrf51/clockless_arm_nrf51.h
+++ b/src/platforms/arm/nrf51/clockless_arm_nrf51.h
diff --git a/platforms/arm/nrf51/fastled_arm_nrf51.h b/src/platforms/arm/nrf51/fastled_arm_nrf51.h
index 88344a35..88344a35 100644
--- a/platforms/arm/nrf51/fastled_arm_nrf51.h
+++ b/src/platforms/arm/nrf51/fastled_arm_nrf51.h
diff --git a/platforms/arm/nrf51/fastpin_arm_nrf51.h b/src/platforms/arm/nrf51/fastpin_arm_nrf51.h
index 6005c448..6005c448 100644
--- a/platforms/arm/nrf51/fastpin_arm_nrf51.h
+++ b/src/platforms/arm/nrf51/fastpin_arm_nrf51.h
diff --git a/platforms/arm/nrf51/fastspi_arm_nrf51.h b/src/platforms/arm/nrf51/fastspi_arm_nrf51.h
index 6826ebcb..6826ebcb 100644
--- a/platforms/arm/nrf51/fastspi_arm_nrf51.h
+++ b/src/platforms/arm/nrf51/fastspi_arm_nrf51.h
diff --git a/platforms/arm/nrf51/led_sysdefs_arm_nrf51.h b/src/platforms/arm/nrf51/led_sysdefs_arm_nrf51.h
index b63dfd32..b63dfd32 100644
--- a/platforms/arm/nrf51/led_sysdefs_arm_nrf51.h
+++ b/src/platforms/arm/nrf51/led_sysdefs_arm_nrf51.h
diff --git a/platforms/arm/nrf52/arbiter_nrf52.h b/src/platforms/arm/nrf52/arbiter_nrf52.h
index 8972d2d2..8972d2d2 100644
--- a/platforms/arm/nrf52/arbiter_nrf52.h
+++ b/src/platforms/arm/nrf52/arbiter_nrf52.h
diff --git a/platforms/arm/nrf52/clockless_arm_nrf52.h b/src/platforms/arm/nrf52/clockless_arm_nrf52.h
index 1dd3cd94..1dd3cd94 100644
--- a/platforms/arm/nrf52/clockless_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/clockless_arm_nrf52.h
diff --git a/platforms/arm/nrf52/fastled_arm_nrf52.h b/src/platforms/arm/nrf52/fastled_arm_nrf52.h
index 45300306..45300306 100644
--- a/platforms/arm/nrf52/fastled_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/fastled_arm_nrf52.h
diff --git a/platforms/arm/nrf52/fastpin_arm_nrf52.h b/src/platforms/arm/nrf52/fastpin_arm_nrf52.h
index 9d0a8ec9..9d0a8ec9 100644
--- a/platforms/arm/nrf52/fastpin_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/fastpin_arm_nrf52.h
diff --git a/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h b/src/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h
index 9020655c..9020655c 100644
--- a/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h
+++ b/src/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h
diff --git a/platforms/arm/nrf52/fastspi_arm_nrf52.h b/src/platforms/arm/nrf52/fastspi_arm_nrf52.h
index 89d006e3..89d006e3 100644
--- a/platforms/arm/nrf52/fastspi_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/fastspi_arm_nrf52.h
diff --git a/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h b/src/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h
index 3a7ea582..3a7ea582 100644
--- a/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h
diff --git a/platforms/arm/sam/clockless_arm_sam.h b/src/platforms/arm/sam/clockless_arm_sam.h
index d7c57940..d7c57940 100644
--- a/platforms/arm/sam/clockless_arm_sam.h
+++ b/src/platforms/arm/sam/clockless_arm_sam.h
diff --git a/platforms/arm/sam/clockless_block_arm_sam.h b/src/platforms/arm/sam/clockless_block_arm_sam.h
index a1799891..a1799891 100644
--- a/platforms/arm/sam/clockless_block_arm_sam.h
+++ b/src/platforms/arm/sam/clockless_block_arm_sam.h
diff --git a/platforms/arm/sam/fastled_arm_sam.h b/src/platforms/arm/sam/fastled_arm_sam.h
index 3567bb62..3567bb62 100644
--- a/platforms/arm/sam/fastled_arm_sam.h
+++ b/src/platforms/arm/sam/fastled_arm_sam.h
diff --git a/platforms/arm/sam/fastpin_arm_sam.h b/src/platforms/arm/sam/fastpin_arm_sam.h
index e1354c73..e1354c73 100644
--- a/platforms/arm/sam/fastpin_arm_sam.h
+++ b/src/platforms/arm/sam/fastpin_arm_sam.h
diff --git a/platforms/arm/sam/fastspi_arm_sam.h b/src/platforms/arm/sam/fastspi_arm_sam.h
index a9446439..a9446439 100644
--- a/platforms/arm/sam/fastspi_arm_sam.h
+++ b/src/platforms/arm/sam/fastspi_arm_sam.h
diff --git a/platforms/arm/sam/led_sysdefs_arm_sam.h b/src/platforms/arm/sam/led_sysdefs_arm_sam.h
index a4828648..a4828648 100644
--- a/platforms/arm/sam/led_sysdefs_arm_sam.h
+++ b/src/platforms/arm/sam/led_sysdefs_arm_sam.h
diff --git a/platforms/arm/stm32/clockless_arm_stm32.h b/src/platforms/arm/stm32/clockless_arm_stm32.h
index 0ac8a5d4..0ac8a5d4 100644
--- a/platforms/arm/stm32/clockless_arm_stm32.h
+++ b/src/platforms/arm/stm32/clockless_arm_stm32.h
diff --git a/platforms/arm/stm32/cm3_regs.h b/src/platforms/arm/stm32/cm3_regs.h
index 7bb7f759..7bb7f759 100644
--- a/platforms/arm/stm32/cm3_regs.h
+++ b/src/platforms/arm/stm32/cm3_regs.h
diff --git a/platforms/arm/stm32/fastled_arm_stm32.h b/src/platforms/arm/stm32/fastled_arm_stm32.h
index 3f86a873..3f86a873 100644
--- a/platforms/arm/stm32/fastled_arm_stm32.h
+++ b/src/platforms/arm/stm32/fastled_arm_stm32.h
diff --git a/platforms/arm/stm32/fastpin_arm_stm32.h b/src/platforms/arm/stm32/fastpin_arm_stm32.h
index bc69912c..bc69912c 100644
--- a/platforms/arm/stm32/fastpin_arm_stm32.h
+++ b/src/platforms/arm/stm32/fastpin_arm_stm32.h
diff --git a/platforms/arm/stm32/led_sysdefs_arm_stm32.h b/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h
index afcf1785..afcf1785 100644
--- a/platforms/arm/stm32/led_sysdefs_arm_stm32.h
+++ b/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h
diff --git a/platforms/avr/clockless_trinket.h b/src/platforms/avr/clockless_trinket.h
index a84c0329..a84c0329 100644
--- a/platforms/avr/clockless_trinket.h
+++ b/src/platforms/avr/clockless_trinket.h
diff --git a/platforms/avr/fastled_avr.h b/src/platforms/avr/fastled_avr.h
index 47236f44..47236f44 100644
--- a/platforms/avr/fastled_avr.h
+++ b/src/platforms/avr/fastled_avr.h
diff --git a/platforms/avr/fastpin_avr.h b/src/platforms/avr/fastpin_avr.h
index db2beeaf..db2beeaf 100644
--- a/platforms/avr/fastpin_avr.h
+++ b/src/platforms/avr/fastpin_avr.h
diff --git a/platforms/avr/fastspi_avr.h b/src/platforms/avr/fastspi_avr.h
index 245e4065..245e4065 100644
--- a/platforms/avr/fastspi_avr.h
+++ b/src/platforms/avr/fastspi_avr.h
diff --git a/platforms/avr/led_sysdefs_avr.h b/src/platforms/avr/led_sysdefs_avr.h
index 05d6e5ed..05d6e5ed 100644
--- a/platforms/avr/led_sysdefs_avr.h
+++ b/src/platforms/avr/led_sysdefs_avr.h
diff --git a/platforms/esp/32/clockless_block_esp32.h b/src/platforms/esp/32/clockless_block_esp32.h
index 45b7671c..45b7671c 100644
--- a/platforms/esp/32/clockless_block_esp32.h
+++ b/src/platforms/esp/32/clockless_block_esp32.h
diff --git a/platforms/esp/32/clockless_i2s_esp32.h b/src/platforms/esp/32/clockless_i2s_esp32.h
index d7af459d..d7af459d 100644
--- a/platforms/esp/32/clockless_i2s_esp32.h
+++ b/src/platforms/esp/32/clockless_i2s_esp32.h
diff --git a/src/platforms/esp/32/clockless_rmt_esp32.cpp b/src/platforms/esp/32/clockless_rmt_esp32.cpp
new file mode 100644
index 00000000..987f1bfc
--- /dev/null
+++ b/src/platforms/esp/32/clockless_rmt_esp32.cpp
@@ -0,0 +1,419 @@
+
+#ifdef ESP32
+
+#define FASTLED_INTERNAL
+#include "FastLED.h"
+
+// -- Forward reference
+class ESP32RMTController;
+
+// -- Array of all controllers
+// This array is filled at the time controllers are registered
+// (Usually when the sketch calls addLeds)
+static ESP32RMTController * gControllers[FASTLED_RMT_MAX_CONTROLLERS];
+
+// -- Current set of active controllers, indexed by the RMT
+// channel assigned to them.
+static ESP32RMTController * gOnChannel[FASTLED_RMT_MAX_CHANNELS];
+
+static int gNumControllers = 0;
+static int gNumStarted = 0;
+static int gNumDone = 0;
+static int gNext = 0;
+
+static intr_handle_t gRMT_intr_handle = NULL;
+
+// -- Global semaphore for the whole show process
+// Semaphore is not given until all data has been sent
+static xSemaphoreHandle gTX_sem = NULL;
+
+// -- Make sure we can't call show() too quickly
+CMinWait<50> gWait;
+
+static bool gInitialized = false;
+
+ESP32RMTController::ESP32RMTController(int DATA_PIN, int T1, int T2, int T3)
+ : mPixelData(0),
+ mSize(0),
+ mCur(0),
+ mWhichHalf(0),
+ mBuffer(0),
+ mBufferSize(0),
+ mCurPulse(0)
+{
+ // -- Precompute rmt items corresponding to a zero bit and a one bit
+ // according to the timing values given in the template instantiation
+ // T1H
+ mOne.level0 = 1;
+ mOne.duration0 = ESP_TO_RMT_CYCLES(T1+T2); // TO_RMT_CYCLES(T1+T2);
+ // T1L
+ mOne.level1 = 0;
+ mOne.duration1 = ESP_TO_RMT_CYCLES(T3); // TO_RMT_CYCLES(T3);
+
+ // T0H
+ mZero.level0 = 1;
+ mZero.duration0 = ESP_TO_RMT_CYCLES(T1); // TO_RMT_CYCLES(T1);
+ // T0L
+ mZero.level1 = 0;
+ mZero.duration1 = ESP_TO_RMT_CYCLES(T2+T3); // TO_RMT_CYCLES(T2 + T3);
+
+ gControllers[gNumControllers] = this;
+ gNumControllers++;
+
+ // -- Expected number of CPU cycles between buffer fills
+ mCyclesPerFill = (T1 + T2 + T3) * PULSES_PER_FILL;
+
+ // -- If there is ever an interval greater than 1.5 times
+ // the expected time, then bail out.
+ mMaxCyclesPerFill = mCyclesPerFill + mCyclesPerFill/2;
+
+ mPin = gpio_num_t(DATA_PIN);
+}
+
+// -- Get or create the buffer for the pixel data
+// We can't allocate it ahead of time because we don't have
+// the PixelController object until show is called.
+uint32_t * ESP32RMTController::getPixelBuffer(int size_in_bytes)
+{
+ if (mPixelData == 0) {
+ mSize = ((size_in_bytes-1) / sizeof(uint32_t)) + 1;
+ mPixelData = (uint32_t *) calloc( mSize, sizeof(uint32_t));
+ }
+ return mPixelData;
+}
+
+// -- Initialize RMT subsystem
+// This only needs to be done once
+void ESP32RMTController::init()
+{
+ if (gInitialized) return;
+
+ for (int i = 0; i < FASTLED_RMT_MAX_CHANNELS; i++) {
+ gOnChannel[i] = NULL;
+
+ // -- RMT configuration for transmission
+ rmt_config_t rmt_tx;
+ rmt_tx.channel = rmt_channel_t(i);
+ rmt_tx.rmt_mode = RMT_MODE_TX;
+ rmt_tx.gpio_num = gpio_num_t(0); // The particular pin will be assigned later
+ rmt_tx.mem_block_num = FASTLED_RMT_MEM_BLOCKS;
+ rmt_tx.clk_div = DIVIDER;
+ rmt_tx.tx_config.loop_en = false;
+ rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW;
+ rmt_tx.tx_config.carrier_en = false;
+ rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
+ rmt_tx.tx_config.idle_output_en = true;
+
+ // -- Apply the configuration
+ rmt_config(&rmt_tx);
+
+ if (FASTLED_RMT_BUILTIN_DRIVER) {
+ rmt_driver_install(rmt_channel_t(i), 0, 0);
+ } else {
+ // -- 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);
+ }
+ }
+
+ // -- Create a semaphore to block execution until all the controllers are done
+ if (gTX_sem == NULL) {
+ gTX_sem = xSemaphoreCreateBinary();
+ xSemaphoreGive(gTX_sem);
+ }
+
+ if ( ! FASTLED_RMT_BUILTIN_DRIVER) {
+ // -- Allocate the interrupt if we have not done so yet. This
+ // interrupt handler must work for all different kinds of
+ // strips, so it delegates to the refill function for each
+ // specific instantiation of ClocklessController.
+ if (gRMT_intr_handle == NULL)
+ esp_intr_alloc(ETS_RMT_INTR_SOURCE, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL3, interruptHandler, 0, &gRMT_intr_handle);
+ }
+
+ gInitialized = true;
+}
+
+// -- Show this string of pixels
+// This is the main entry point for the pixel controller
+void ESP32RMTController::showPixels()
+{
+ if (gNumStarted == 0) {
+ // -- First controller: make sure everything is set up
+ ESP32RMTController::init();
+
+#if FASTLED_ESP32_FLASH_LOCK == 1
+ // -- Make sure no flash operations happen right now
+ spi_flash_op_lock();
+#endif
+ }
+
+ // -- Keep track of the number of strips we've seen
+ gNumStarted++;
+
+ // -- The last call to showPixels is the one responsible for doing
+ // all of the actual worl
+ if (gNumStarted == gNumControllers) {
+ gNext = 0;
+
+ // -- This Take always succeeds immediately
+ xSemaphoreTake(gTX_sem, portMAX_DELAY);
+
+ // -- Make sure it's been at least 50us since last show
+ gWait.wait();
+
+ // -- First, fill all the available channels
+ int channel = 0;
+ while (channel < FASTLED_RMT_MAX_CHANNELS && gNext < gNumControllers) {
+ ESP32RMTController::startNext(channel);
+ // -- Important: when we use more than one memory block, we need to
+ // skip the channels that would otherwise overlap in memory.
+ channel += FASTLED_RMT_MEM_BLOCKS;
+ }
+
+ // -- Wait here while the data is sent. The interrupt handler
+ // will keep refilling the RMT buffers until it is all
+ // done; then it gives the semaphore back.
+ xSemaphoreTake(gTX_sem, portMAX_DELAY);
+ xSemaphoreGive(gTX_sem);
+
+ // -- Make sure we don't call showPixels too quickly
+ gWait.mark();
+
+ // -- Reset the counters
+ gNumStarted = 0;
+ gNumDone = 0;
+ gNext = 0;
+
+#if FASTLED_ESP32_FLASH_LOCK == 1
+ // -- Release the lock on flash operations
+ spi_flash_op_unlock();
+#endif
+
+ }
+}
+
+// -- Start up the next controller
+// This method is static so that it can dispatch to the
+// appropriate startOnChannel method of the given controller.
+void ESP32RMTController::startNext(int channel)
+{
+ if (gNext < gNumControllers) {
+ ESP32RMTController * pController = gControllers[gNext];
+ pController->startOnChannel(channel);
+ gNext++;
+ }
+}
+
+// -- Start this controller on the given channel
+// This function just initiates the RMT write; it does not wait
+// for it to finish.
+void ESP32RMTController::startOnChannel(int channel)
+{
+ // -- Assign this channel and configure the RMT
+ mRMT_channel = rmt_channel_t(channel);
+
+ // -- Store a reference to this controller, so we can get it
+ // inside the interrupt handler
+ gOnChannel[channel] = this;
+
+ // -- Assign the pin to this channel
+ rmt_set_pin(mRMT_channel, RMT_MODE_TX, mPin);
+
+ if (FASTLED_RMT_BUILTIN_DRIVER) {
+ // -- Use the built-in RMT driver to send all the data in one shot
+ rmt_register_tx_end_callback(doneOnChannel, 0);
+ rmt_write_items(mRMT_channel, mBuffer, mBufferSize, false);
+ } else {
+ // -- Use our custom driver to send the data incrementally
+
+ // -- Initialize the counters that keep track of where we are in
+ // the pixel data and the RMT buffer
+ mRMT_mem_start = & (RMTMEM.chan[mRMT_channel].data32[0].val);
+ mRMT_mem_ptr = mRMT_mem_start;
+ mCur = 0;
+ mWhichHalf = 0;
+ mLastFill = 0;
+
+ // -- Fill both halves of the RMT buffer (a totaly of 64 bits of pixel data)
+ fillNext(false);
+ fillNext(false);
+
+ // -- Turn on the interrupts
+ rmt_set_tx_intr_en(mRMT_channel, true);
+
+ // -- Kick off the transmission
+ tx_start();
+ }
+}
+
+// -- Start RMT transmission
+// Setting this RMT flag is what actually kicks off the peripheral
+void ESP32RMTController::tx_start()
+{
+ rmt_tx_start(mRMT_channel, true);
+ mLastFill = __clock_cycles();
+}
+
+// -- A controller is done
+// This function is called when a controller finishes writing
+// its data. It is called either by the custom interrupt
+// handler (below), or as a callback from the built-in
+// interrupt handler. It is static because we don't know which
+// controller is done until we look it up.
+void ESP32RMTController::doneOnChannel(rmt_channel_t channel, void * arg)
+{
+ ESP32RMTController * pController = gOnChannel[channel];
+
+ // -- Turn off output on the pin
+ // SZG: Do I really need to do this?
+ gpio_matrix_out(pController->mPin, 0x100, 0, 0);
+
+ // -- Turn off the interrupts
+ rmt_set_tx_intr_en(channel, false);
+
+ gOnChannel[channel] = NULL;
+ gNumDone++;
+
+ if (gNumDone == gNumControllers) {
+ // -- If this is the last controller, signal that we are all done
+ if (FASTLED_RMT_BUILTIN_DRIVER) {
+ xSemaphoreGive(gTX_sem);
+ } else {
+ portBASE_TYPE HPTaskAwoken = 0;
+ xSemaphoreGiveFromISR(gTX_sem, &HPTaskAwoken);
+ if (HPTaskAwoken == pdTRUE) portYIELD_FROM_ISR();
+ }
+ } else {
+ // -- Otherwise, if there are still controllers waiting, then
+ // start the next one on this channel
+ if (gNext < gNumControllers) {
+ startNext(channel);
+ }
+ }
+}
+
+// -- Custom interrupt handler
+// This interrupt handler handles two cases: a controller is
+// done writing its data, or a controller needs to fill the
+// next half of the RMT buffer with data.
+void IRAM_ATTR ESP32RMTController::interruptHandler(void *arg)
+{
+ // -- The basic structure of this code is borrowed from the
+ // interrupt handler in esp-idf/components/driver/rmt.c
+ uint32_t intr_st = RMT.int_st.val;
+ uint8_t channel;
+
+ bool stuff_to_do = false;
+ for (channel = 0; channel < FASTLED_RMT_MAX_CHANNELS; channel++) {
+ int tx_done_bit = channel * 3;
+ int tx_next_bit = channel + 24;
+
+ ESP32RMTController * pController = gOnChannel[channel];
+ if (pController != NULL) {
+ if (intr_st & BIT(tx_next_bit)) {
+ // -- More to send on this channel
+ pController->fillNext(true);
+ RMT.int_clr.val |= BIT(tx_next_bit);
+ } else {
+ // -- Transmission is complete on this channel
+ if (intr_st & BIT(tx_done_bit)) {
+ RMT.int_clr.val |= BIT(tx_done_bit);
+ doneOnChannel(rmt_channel_t(channel), 0);
+ }
+ }
+ }
+ }
+}
+
+// -- Fill RMT buffer
+// Puts 32 bits of pixel data into the next 32 slots in the RMT memory
+// Each data bit is represented by a 32-bit RMT item that specifies how
+// long to hold the signal high, followed by how long to hold it low.
+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) {
+ Serial.print(delta);
+ Serial.print(" BAIL ");
+ Serial.println(mCur);
+ mCur = mSize;
+ rmt_tx_stop(mRMT_channel);
+ }
+ }
+ }
+ mLastFill = now;
+
+ // -- Get the zero and one values into local variables
+ register uint32_t one_val = mOne.val;
+ register uint32_t zero_val = mZero.val;
+
+ // -- Use locals for speed
+ volatile register uint32_t * pItem = mRMT_mem_ptr;
+
+ for (register int i = 0; i < PULSES_PER_FILL/32; i++) {
+ if (mCur < mSize) {
+
+ // -- Get the next four bytes of pixel data
+ register uint32_t pixeldata = mPixelData[mCur];
+ mCur++;
+
+ // Shift bits out, MSB first, setting RMTMEM.chan[n].data32[x] to the
+ // rmt_item32_t value corresponding to the buffered bit value
+ for (register uint32_t j = 0; j < 32; j++) {
+ *pItem++ = (pixeldata & 0x80000000L) ? one_val : zero_val;
+ // Replaces: RMTMEM.chan[mRMT_channel].data32[mCurPulse].val = val;
+
+ pixeldata <<= 1;
+ }
+ } else {
+ // -- No more data; signal to the RMT we are done
+ for (uint32_t j = 0; j < 32; j++) {
+ * mRMT_mem_ptr++ = 0;
+ }
+ }
+ }
+
+ // -- Flip to the other half, resetting the pointer if necessary
+ mWhichHalf++;
+ if (mWhichHalf == 2) {
+ pItem = mRMT_mem_start;
+ mWhichHalf = 0;
+ }
+
+ // -- Store the new pointer back into the object
+ mRMT_mem_ptr = pItem;
+}
+
+// -- Init pulse buffer
+// Set up the buffer that will hold all of the pulse items for this
+// controller.
+// This function is only used when the built-in RMT driver is chosen
+void ESP32RMTController::initPulseBuffer(int size_in_bytes)
+{
+ if (mBuffer == 0) {
+ // -- Each byte has 8 bits, each bit needs a 32-bit RMT item
+ mBufferSize = size_in_bytes * 8 * 4;
+ mBuffer = (rmt_item32_t *) calloc( mBufferSize, sizeof(rmt_item32_t));
+ }
+ mCurPulse = 0;
+}
+
+// -- Convert a byte into RMT pulses
+// This function is only used when the built-in RMT driver is chosen
+void ESP32RMTController::convertByte(uint32_t byteval)
+{
+ // -- Write one byte's worth of RMT pulses to the big buffer
+ byteval <<= 24;
+ for (register uint32_t j = 0; j < 8; j++) {
+ mBuffer[mCurPulse] = (byteval & 0x80000000L) ? mOne : mZero;
+ byteval <<= 1;
+ mCurPulse++;
+ }
+}
+
+#endif
diff --git a/src/platforms/esp/32/clockless_rmt_esp32.h b/src/platforms/esp/32/clockless_rmt_esp32.h
new file mode 100644
index 00000000..68861b50
--- /dev/null
+++ b/src/platforms/esp/32/clockless_rmt_esp32.h
@@ -0,0 +1,411 @@
+/*
+ * Integration into FastLED ClocklessController
+ * Copyright (c) 2018,2019,2020 Samuel Z. Guyer
+ * Copyright (c) 2017 Thomas Basler
+ * Copyright (c) 2017 Martin F. Falatic
+ *
+ * ESP32 support is provided using the RMT peripheral device -- a unit
+ * on the chip designed specifically for generating (and receiving)
+ * precisely-timed digital signals. Nominally for use in infrared
+ * remote controls, we use it to generate the signals for clockless
+ * LED strips. The main advantage of using the RMT device is that,
+ * once programmed, it generates the signal asynchronously, allowing
+ * the CPU to continue executing other code. It is also not vulnerable
+ * to interrupts or other timing problems that could disrupt the signal.
+ *
+ * The implementation strategy is borrowed from previous work and from
+ * the RMT support built into the ESP32 IDF. The RMT device has 8
+ * channels, which can be programmed independently to send sequences
+ * of high/low bits. Memory for each channel is limited, however, so
+ * in order to send a long sequence of bits, we need to continuously
+ * refill the buffer until all the data is sent. To do this, we fill
+ * half the buffer and then set an interrupt to go off when that half
+ * is sent. Then we refill that half while the second half is being
+ * sent. This strategy effectively overlaps computation (by the CPU)
+ * and communication (by the RMT).
+ *
+ * Since the RMT device only has 8 channels, we need a strategy to
+ * allow more than 8 LED controllers. Our driver assigns controllers
+ * to channels on the fly, queuing up controllers as necessary until a
+ * channel is free. The main showPixels routine just fires off the
+ * first 8 controllers; the interrupt handler starts new controllers
+ * asynchronously as previous ones finish. So, for example, it can
+ * send the data for 8 controllers simultaneously, but 16 controllers
+ * would take approximately twice as much time.
+ *
+ * There is a #define that allows a program to control the total
+ * number of channels that the driver is allowed to use. It defaults
+ * to 8 -- use all the channels. Setting it to 1, for example, results
+ * in fully serial output:
+ *
+ * #define FASTLED_RMT_MAX_CHANNELS 1
+ *
+ * OTHER RMT APPLICATIONS
+ *
+ * The default FastLED driver takes over control of the RMT interrupt
+ * handler, making it hard to use the RMT device for other
+ * (non-FastLED) purposes. You can change it's behavior to use the ESP
+ * core driver instead, allowing other RMT applications to
+ * co-exist. To switch to this mode, add the following directive
+ * before you include FastLED.h:
+ *
+ * #define FASTLED_RMT_BUILTIN_DRIVER 1
+ *
+ * There may be a performance penalty for using this mode. We need to
+ * compute the RMT signal for the entire LED strip ahead of time,
+ * rather than overlapping it with communication. We also need a large
+ * buffer to hold the signal specification. Each bit of pixel data is
+ * represented by a 32-bit pulse specification, so it is a 32X blow-up
+ * in memory use.
+ *
+ * NEW: Use of Flash memory on the ESP32 can interfere with the timing
+ * of pixel output. The ESP-IDF system code disables all other
+ * code running on *either* core during these operation. To prevent
+ * this from happening, define this flag. It will force flash
+ * operations to wait until the show() is done.
+ *
+ * #define FASTLED_ESP32_FLASH_LOCK 1
+ *
+ * NEW (June 2020): The RMT controller has been split into two
+ * classes: ClocklessController, which is an instantiation of the
+ * FastLED CPixelLEDController template, and ESP32RMTController,
+ * which just handles driving the RMT peripheral. One benefit of
+ * this design is that ESP32RMTContoller is not a template, so
+ * its methods can be marked with the IRAM_ATTR and end up in
+ * IRAM memory. Another benefit is that all of the color channel
+ * processing is done up-front, in the templated class, so we
+ * can fill the RMT buffers more quickly.
+ *
+ * IN THEORY, this design would also allow FastLED.show() to
+ * send the data while the program continues to prepare the next
+ * frame of data.
+ *
+ * Based on public domain code created 19 Nov 2016 by Chris Osborn <fozztexx@fozztexx.com>
+ * http://insentricity.com *
+ *
+ */
+/*
+ * 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.
+ */
+
+#pragma once
+
+FASTLED_NAMESPACE_BEGIN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "esp32-hal.h"
+#include "esp_intr.h"
+#include "driver/gpio.h"
+#include "driver/rmt.h"
+#include "driver/periph_ctrl.h"
+#include "freertos/semphr.h"
+#include "soc/rmt_struct.h"
+
+#include "esp_log.h"
+
+extern void spi_flash_op_lock(void);
+extern void spi_flash_op_unlock(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+__attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
+ uint32_t cyc;
+ __asm__ __volatile__ ("rsr %0,ccount":"=a" (cyc));
+ return cyc;
+}
+
+#define FASTLED_HAS_CLOCKLESS 1
+#define NUM_COLOR_CHANNELS 3
+
+// NOT CURRENTLY IMPLEMENTED:
+// -- Set to true to print debugging information about timing
+// Useful for finding out if timing is being messed up by other things
+// on the processor (WiFi, for example)
+//#ifndef FASTLED_RMT_SHOW_TIMER
+//#define FASTLED_RMT_SHOW_TIMER false
+//#endif
+
+// -- Configuration constants
+#define DIVIDER 2 /* 4, 8 still seem to work, but timings become marginal */
+
+// -- RMT memory configuration
+// By default we use two memory blocks for each RMT channel instead of 1. The
+// reason is that one memory block is only 64 bits, which causes the refill
+// interrupt to fire too often. When combined with WiFi, this leads to conflicts
+// between interrupts and weird flashy effects on the LEDs. Special thanks to
+// Brian Bulkowski for finding this problem and developing a fix.
+#ifndef FASTLED_RMT_MEM_BLOCKS
+#define FASTLED_RMT_MEM_BLOCKS 2
+#endif
+
+#define MAX_PULSES (64 * FASTLED_RMT_MEM_BLOCKS) /* One block has a 64 "pulse" buffer */
+#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)
+#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))
+
+// -- Number of cycles to signal the strip to latch
+#define NS_PER_CYCLE ( 1000000000L / RMT_CYCLES_PER_SEC )
+#define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )
+#define RMT_RESET_DURATION NS_TO_CYCLES(50000)
+
+// -- Core or custom driver
+#ifndef FASTLED_RMT_BUILTIN_DRIVER
+#define FASTLED_RMT_BUILTIN_DRIVER false
+#endif
+
+// -- Max number of controllers we can support
+#ifndef FASTLED_RMT_MAX_CONTROLLERS
+#define FASTLED_RMT_MAX_CONTROLLERS 32
+#endif
+
+// -- Number of RMT channels to use (up to 8, but 4 by default)
+// Redefine this value to 1 to force serial output
+#ifndef FASTLED_RMT_MAX_CHANNELS
+#define FASTLED_RMT_MAX_CHANNELS (8/FASTLED_RMT_MEM_BLOCKS)
+#endif
+
+class ESP32RMTController
+{
+private:
+
+ // -- RMT has 8 channels, numbered 0 to 7
+ rmt_channel_t mRMT_channel;
+
+ // -- Store the GPIO pin
+ gpio_num_t mPin;
+
+ // -- Timing values for zero and one bits, derived from T1, T2, and T3
+ rmt_item32_t mZero;
+ rmt_item32_t mOne;
+
+ // -- Total expected time to send 32 bits
+ // Each strip should get an interrupt roughly at this interval
+ uint32_t mCyclesPerFill;
+ uint32_t mMaxCyclesPerFill;
+ uint32_t mLastFill;
+
+ // -- Pixel data
+ uint32_t * mPixelData;
+ int mSize;
+ int mCur;
+
+ // -- RMT memory
+ volatile uint32_t * mRMT_mem_ptr;
+ volatile uint32_t * mRMT_mem_start;
+ int mWhichHalf;
+
+ // -- Buffer to hold all of the pulses. For the version that uses
+ // the RMT driver built into the ESP core.
+ rmt_item32_t * mBuffer;
+ uint16_t mBufferSize; // bytes
+ int mCurPulse;
+
+public:
+
+ // -- Constructor
+ // Mainly just stores the template parameters from the LEDController as
+ // member variables.
+ ESP32RMTController(int DATA_PIN, int T1, int T2, int T3);
+
+ // -- Get max cycles per fill
+ uint32_t IRAM_ATTR getMaxCyclesPerFill() const { return mMaxCyclesPerFill; }
+
+ // -- Get or create the pixel data buffer
+ uint32_t * getPixelBuffer(int size_in_bytes);
+
+ // -- Initialize RMT subsystem
+ // This only needs to be done once
+ static void init();
+
+ // -- Show this string of pixels
+ // This is the main entry point for the pixel controller
+ void IRAM_ATTR showPixels();
+
+ // -- Start up the next controller
+ // This method is static so that it can dispatch to the
+ // appropriate startOnChannel method of the given controller.
+ static void IRAM_ATTR startNext(int channel);
+
+ // -- Start this controller on the given channel
+ // This function just initiates the RMT write; it does not wait
+ // for it to finish.
+ void IRAM_ATTR startOnChannel(int channel);
+
+ // -- Start RMT transmission
+ // Setting this RMT flag is what actually kicks off the peripheral
+ void IRAM_ATTR tx_start();
+
+ // -- A controller is done
+ // This function is called when a controller finishes writing
+ // its data. It is called either by the custom interrupt
+ // handler (below), or as a callback from the built-in
+ // interrupt handler. It is static because we don't know which
+ // controller is done until we look it up.
+ static void IRAM_ATTR doneOnChannel(rmt_channel_t channel, void * arg);
+
+ // -- Custom interrupt handler
+ // This interrupt handler handles two cases: a controller is
+ // done writing its data, or a controller needs to fill the
+ // next half of the RMT buffer with data.
+ static void IRAM_ATTR interruptHandler(void *arg);
+
+ // -- Fill RMT buffer
+ // Puts 32 bits of pixel data into the next 32 slots in the RMT memory
+ // Each data bit is represented by a 32-bit RMT item that specifies how
+ // long to hold the signal high, followed by how long to hold it low.
+ // NOTE: Now the default is to use 128-bit buffers, so half a buffer is
+ // is 64 bits. See FASTLED_RMT_MEM_BLOCKS
+ void IRAM_ATTR fillNext(bool check_time);
+
+ // -- Init pulse buffer
+ // Set up the buffer that will hold all of the pulse items for this
+ // controller.
+ // This function is only used when the built-in RMT driver is chosen
+ void initPulseBuffer(int size_in_bytes);
+
+ // -- Convert a byte into RMT pulses
+ // This function is only used when the built-in RMT driver is chosen
+ void convertByte(uint32_t byteval);
+};
+
+template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
+class ClocklessController : public CPixelLEDController<RGB_ORDER>
+{
+private:
+
+ // -- The actual controller object for ESP32
+ ESP32RMTController mRMTController;
+
+ // -- This instantiation forces a check on the pin choice
+ FastPin<DATA_PIN> mFastPin;
+
+public:
+
+ ClocklessController()
+ : mRMTController(DATA_PIN, T1, T2, T3)
+ {}
+
+ void init()
+ {
+ // mRMTController = new ESP32RMTController(DATA_PIN, T1, T2, T3);
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+protected:
+
+ // -- Load pixel data
+ // This method loads all of the pixel data into a separate buffer for use by
+ // by the RMT driver. Copying does two important jobs: it fixes the color
+ // order for the pixels, and it performs the scaling/adjusting ahead of time.
+ // It also packs the bytes into 32 bit chunks with the right bit order.
+ void loadPixelData(PixelController<RGB_ORDER> & pixels)
+ {
+ // -- Make sure the buffer is allocated
+ int size_in_bytes = pixels.size() * 3;
+ uint32_t * pData = mRMTController.getPixelBuffer(size_in_bytes);
+
+ // -- Read out the pixel data using the pixel controller methods that
+ // perform the scaling and adjustments
+ int count = 0;
+ int which = 0;
+ while (pixels.has(1)) {
+ // -- Get the next four bytes of data
+ uint8_t four[4] = {0,0,0,0};
+ for (int i = 0; i < 4; i++) {
+ switch (which) {
+ case 0:
+ four[i] = pixels.loadAndScale0();
+ break;
+ case 1:
+ four[i] = pixels.loadAndScale1();
+ break;
+ case 2:
+ four[i] = pixels.loadAndScale2();
+ pixels.advanceData();
+ pixels.stepDithering();
+ break;
+ }
+ // -- Move to the next color
+ which++;
+ if (which > 2) which = 0;
+
+ // -- Stop if there's no more data
+ if ( ! pixels.has(1)) break;
+ }
+
+ // -- Pack the four bytes into a 32-bit value with the right bit order
+ uint8_t a = four[0];
+ uint8_t b = four[1];
+ uint8_t c = four[2];
+ uint8_t d = four[3];
+ pData[count++] = a << 24 | b << 16 | c << 8 | d;
+ }
+ }
+
+ // -- Show pixels
+ // This is the main entry point for the controller.
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels)
+ {
+ if (FASTLED_RMT_BUILTIN_DRIVER) {
+ convertAllPixelData(pixels);
+ } else {
+ loadPixelData(pixels);
+ }
+
+ mRMTController.showPixels();
+ }
+
+ // -- Convert all pixels to RMT pulses
+ // This function is only used when the user chooses to use the
+ // built-in RMT driver, which needs all of the RMT pulses
+ // up-front.
+ void convertAllPixelData(PixelController<RGB_ORDER> & pixels)
+ {
+ // -- Make sure the data buffer is allocated
+ mRMTController.initPulseBuffer(pixels.size() * 3);
+
+ // -- Cycle through the R,G, and B values in the right order,
+ // storing the pulses in the big buffer
+
+ uint32_t byteval;
+ while (pixels.has(1)) {
+ byteval = pixels.loadAndScale0();
+ mRMTController.convertByte(byteval);
+ byteval = pixels.loadAndScale1();
+ mRMTController.convertByte(byteval);
+ byteval = pixels.loadAndScale2();
+ mRMTController.convertByte(byteval);
+ pixels.advanceData();
+ pixels.stepDithering();
+ }
+ }
+};
+
+
+FASTLED_NAMESPACE_END
diff --git a/platforms/esp/32/fastled_esp32.h b/src/platforms/esp/32/fastled_esp32.h
index edf27e7d..edf27e7d 100644
--- a/platforms/esp/32/fastled_esp32.h
+++ b/src/platforms/esp/32/fastled_esp32.h
diff --git a/platforms/esp/32/fastpin_esp32.h b/src/platforms/esp/32/fastpin_esp32.h
index 7876b281..7876b281 100644
--- a/platforms/esp/32/fastpin_esp32.h
+++ b/src/platforms/esp/32/fastpin_esp32.h
diff --git a/platforms/esp/32/led_sysdefs_esp32.h b/src/platforms/esp/32/led_sysdefs_esp32.h
index 5cd374e2..5cd374e2 100644
--- a/platforms/esp/32/led_sysdefs_esp32.h
+++ b/src/platforms/esp/32/led_sysdefs_esp32.h
diff --git a/platforms/esp/8266/clockless_block_esp8266.h b/src/platforms/esp/8266/clockless_block_esp8266.h
index 3eccbe1e..3eccbe1e 100644
--- a/platforms/esp/8266/clockless_block_esp8266.h
+++ b/src/platforms/esp/8266/clockless_block_esp8266.h
diff --git a/platforms/esp/8266/clockless_esp8266.h b/src/platforms/esp/8266/clockless_esp8266.h
index 131f2467..131f2467 100644
--- a/platforms/esp/8266/clockless_esp8266.h
+++ b/src/platforms/esp/8266/clockless_esp8266.h
diff --git a/platforms/esp/8266/fastled_esp8266.h b/src/platforms/esp/8266/fastled_esp8266.h
index 8c4048db..8c4048db 100644
--- a/platforms/esp/8266/fastled_esp8266.h
+++ b/src/platforms/esp/8266/fastled_esp8266.h
diff --git a/platforms/esp/8266/fastpin_esp8266.h b/src/platforms/esp/8266/fastpin_esp8266.h
index d64119f9..d64119f9 100644
--- a/platforms/esp/8266/fastpin_esp8266.h
+++ b/src/platforms/esp/8266/fastpin_esp8266.h
diff --git a/platforms/esp/8266/led_sysdefs_esp8266.h b/src/platforms/esp/8266/led_sysdefs_esp8266.h
index 26dffdcf..26dffdcf 100644
--- a/platforms/esp/8266/led_sysdefs_esp8266.h
+++ b/src/platforms/esp/8266/led_sysdefs_esp8266.h
diff --git a/power_mgt.cpp b/src/power_mgt.cpp
index e15fa709..e15fa709 100644
--- a/power_mgt.cpp
+++ b/src/power_mgt.cpp
diff --git a/power_mgt.h b/src/power_mgt.h
index 68718818..68718818 100644
--- a/power_mgt.h
+++ b/src/power_mgt.h
diff --git a/wiring.cpp b/src/wiring.cpp
index 744373a1..744373a1 100644
--- a/wiring.cpp
+++ b/src/wiring.cpp