diff options
author | Sam Guyer <sam.guyer@gmail.com> | 2020-11-16 19:34:20 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-11-16 19:34:20 +0300 |
commit | d5ddf40d3f3731adb36c122abba29cbf80654be3 (patch) | |
tree | b0f96294b16af89a5fbe9c82f3a3fdff9399661a | |
parent | 17e3b508953a0c6b3792d197b06027ab682b9ff5 (diff) | |
parent | 324d114bf70976a20dbcc2e400e09300db1003dd (diff) |
Merge pull request #1108 from samguyer/master
Major updates to ESP32 support
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | library.json | 3 | ||||
-rw-r--r-- | platforms/esp/32/clockless_esp32.h.orig | 786 | ||||
-rw-r--r-- | platforms/esp/32/clockless_rmt_esp32.h | 686 | ||||
-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.cpp | 419 | ||||
-rw-r--r-- | src/platforms/esp/32/clockless_rmt_esp32.h | 411 | ||||
-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
@@ -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/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/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/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 |