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

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml28
-rw-r--r--.gitignore5
-rw-r--r--PORTING.md13
-rw-r--r--README.md11
-rw-r--r--bitswap.cpp28
-rwxr-xr-xci/ci-compile36
-rw-r--r--code_of_conduct.md134
-rw-r--r--color.h84
-rw-r--r--component.mk3
-rw-r--r--docs/Doxyfile591
-rw-r--r--examples/ColorPalette/ColorPalette.ino4
-rw-r--r--examples/Cylon/Cylon.ino6
-rw-r--r--examples/DemoReel100/DemoReel100.ino5
-rw-r--r--examples/Fire2012/Fire2012.ino2
-rw-r--r--examples/Fire2012WithPalette/Fire2012WithPalette.ino4
-rw-r--r--examples/Multiple/ArrayOfLedArrays/ArrayOfLedArrays.ino12
-rw-r--r--examples/Multiple/MultipleStripsInOneArray/MultipleStripsInOneArray.ino12
-rw-r--r--examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino8
-rw-r--r--examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino14
-rw-r--r--examples/Noise/Noise.ino10
-rw-r--r--examples/NoisePlayground/NoisePlayground.ino14
-rw-r--r--examples/NoisePlusPalette/NoisePlusPalette.ino9
-rw-r--r--examples/RGBSetDemo/RGBSetDemo.ino2
-rw-r--r--examples/SmartMatrix/SmartMatrix.ino6
-rw-r--r--examples/TwinkleFox/TwinkleFox.ino4
-rw-r--r--examples/XYMatrix/XYMatrix.ino42
-rw-r--r--library.json5
-rw-r--r--library.properties2
-rw-r--r--pixelset.h305
-rw-r--r--platforms/arm/d21/clockless_arm_d21.h61
-rw-r--r--platforms/arm/d51/README.txt4
-rw-r--r--platforms/arm/d51/fastpin_arm_d51.h139
-rw-r--r--platforms/arm/k20/smartmatrix_t3.h55
-rw-r--r--platforms/arm/k20/ws2812serial_controller.h46
-rw-r--r--platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h215
-rw-r--r--platforms/arm/nrf51/clockless_arm_nrf51.h83
-rw-r--r--platforms/arm/nrf51/fastpin_arm_nrf51.h119
-rw-r--r--platforms/arm/nrf51/fastspi_arm_nrf51.h150
-rw-r--r--platforms/arm/sam/clockless_block_arm_sam.h184
-rw-r--r--platforms/arm/stm32/clockless_arm_stm32.h126
-rw-r--r--platforms/arm/stm32/cm3_regs.h63
-rw-r--r--platforms/arm/stm32/fastpin_arm_stm32.h178
-rw-r--r--platforms/esp/32/clockless_esp32.h.orig786
-rw-r--r--platforms/esp/32/clockless_rmt_esp32.h690
-rw-r--r--platforms/esp/8266/fastpin_esp8266.h101
-rw-r--r--release_notes.md15
-rw-r--r--src/FastLED.cpp (renamed from FastLED.cpp)54
-rw-r--r--src/FastLED.h (renamed from FastLED.h)24
-rw-r--r--src/bitswap.cpp28
-rw-r--r--src/bitswap.h (renamed from bitswap.h)4
-rw-r--r--src/chipsets.h (renamed from chipsets.h)14
-rw-r--r--src/color.h84
-rw-r--r--src/colorpalettes.cpp (renamed from colorpalettes.cpp)18
-rw-r--r--src/colorpalettes.h (renamed from colorpalettes.h)0
-rw-r--r--src/colorutils.cpp (renamed from colorutils.cpp)124
-rw-r--r--src/colorutils.h (renamed from colorutils.h)142
-rw-r--r--src/controller.h (renamed from controller.h)58
-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)5
-rw-r--r--src/fastled_progmem.h (renamed from fastled_progmem.h)0
-rw-r--r--src/fastpin.h (renamed from fastpin.h)27
-rw-r--r--src/fastspi.h (renamed from fastspi.h)5
-rw-r--r--src/fastspi_bitbang.h (renamed from fastspi_bitbang.h)1
-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)1
-rw-r--r--src/fastspi_types.h (renamed from fastspi_types.h)6
-rw-r--r--src/hsv2rgb.cpp (renamed from hsv2rgb.cpp)44
-rw-r--r--src/hsv2rgb.h (renamed from hsv2rgb.h)0
-rw-r--r--src/led_sysdefs.h (renamed from led_sysdefs.h)8
-rw-r--r--src/lib8tion.cpp (renamed from lib8tion.cpp)4
-rw-r--r--src/lib8tion.h (renamed from lib8tion.h)42
-rw-r--r--src/lib8tion/math8.h (renamed from lib8tion/math8.h)265
-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)425
-rw-r--r--src/lib8tion/trig8.h (renamed from lib8tion/trig8.h)59
-rw-r--r--src/noise.cpp (renamed from noise.cpp)605
-rw-r--r--src/noise.h (renamed from noise.h)0
-rw-r--r--src/pixelset.h306
-rw-r--r--src/pixeltypes.h (renamed from pixeltypes.h)97
-rw-r--r--src/platforms.cpp (renamed from platforms.cpp)8
-rw-r--r--src/platforms.h (renamed from platforms.h)4
-rw-r--r--src/platforms/apollo3/clockless_apollo3.h (renamed from platforms/apollo3/clockless_apollo3.h)107
-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)48
-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)6
-rw-r--r--src/platforms/arm/d21/clockless_arm_d21.h61
-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)87
-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.txt7
-rw-r--r--src/platforms/arm/d51/clockless_arm_d51.h (renamed from platforms/arm/d51/clockless_arm_d51.h)20
-rw-r--r--src/platforms/arm/d51/fastled_arm_d51.h (renamed from platforms/arm/d51/fastled_arm_d51.h)1
-rw-r--r--src/platforms/arm/d51/fastpin_arm_d51.h189
-rw-r--r--src/platforms/arm/d51/led_sysdefs_arm_d51.h (renamed from platforms/arm/d51/led_sysdefs_arm_d51.h)4
-rw-r--r--src/platforms/arm/k20/clockless_arm_k20.h (renamed from platforms/arm/k20/clockless_arm_k20.h)20
-rw-r--r--src/platforms/arm/k20/clockless_block_arm_k20.h (renamed from platforms/arm/k20/clockless_block_arm_k20.h)12
-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)12
-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)6
-rw-r--r--src/platforms/arm/k20/smartmatrix_t3.h54
-rw-r--r--src/platforms/arm/k20/ws2812serial_controller.h47
-rw-r--r--src/platforms/arm/k66/clockless_arm_k66.h (renamed from platforms/arm/k66/clockless_arm_k66.h)20
-rw-r--r--src/platforms/arm/k66/clockless_block_arm_k66.h (renamed from platforms/arm/k66/clockless_block_arm_k66.h)33
-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)12
-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.h214
-rw-r--r--src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/clockless_arm_mxrt1062.h)29
-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)2
-rw-r--r--src/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h (renamed from platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h)90
-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.h84
-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.h119
-rw-r--r--src/platforms/arm/nrf51/fastspi_arm_nrf51.h149
-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)1
-rw-r--r--src/platforms/arm/nrf52/clockless_arm_nrf52.h (renamed from platforms/arm/nrf52/clockless_arm_nrf52.h)83
-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)94
-rw-r--r--src/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h (renamed from platforms/arm/nrf52/fastpin_arm_nrf52_variants.h)35
-rw-r--r--src/platforms/arm/nrf52/fastspi_arm_nrf52.h (renamed from platforms/arm/nrf52/fastspi_arm_nrf52.h)1
-rw-r--r--src/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h (renamed from platforms/arm/nrf52/led_sysdefs_arm_nrf52.h)9
-rw-r--r--src/platforms/arm/sam/clockless_arm_sam.h (renamed from platforms/arm/sam/clockless_arm_sam.h)22
-rw-r--r--src/platforms/arm/sam/clockless_block_arm_sam.h183
-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)1
-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.h133
-rw-r--r--src/platforms/arm/stm32/cm3_regs.h63
-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.h220
-rw-r--r--src/platforms/arm/stm32/led_sysdefs_arm_stm32.h (renamed from platforms/arm/stm32/led_sysdefs_arm_stm32.h)37
-rw-r--r--src/platforms/avr/clockless_trinket.h (renamed from platforms/avr/clockless_trinket.h)33
-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)58
-rw-r--r--src/platforms/avr/fastspi_avr.h (renamed from platforms/avr/fastspi_avr.h)172
-rw-r--r--src/platforms/avr/led_sysdefs_avr.h (renamed from platforms/avr/led_sysdefs_avr.h)5
-rw-r--r--src/platforms/esp/32/clockless_block_esp32.h (renamed from platforms/esp/32/clockless_block_esp32.h)11
-rw-r--r--src/platforms/esp/32/clockless_i2s_esp32.h (renamed from platforms/esp/32/clockless_i2s_esp32.h)58
-rw-r--r--src/platforms/esp/32/clockless_rmt_esp32.cpp463
-rw-r--r--src/platforms/esp/32/clockless_rmt_esp32.h397
-rwxr-xr-xsrc/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)1
-rw-r--r--src/platforms/esp/32/fastspi_esp32.h (renamed from platforms/esp/32/fastspi_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)53
-rw-r--r--src/platforms/esp/8266/clockless_esp8266.h (renamed from platforms/esp/8266/clockless_esp8266.h)6
-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.h100
-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/platforms/fastspi_ardunio_core.h103
-rw-r--r--src/power_mgt.cpp (renamed from power_mgt.cpp)14
-rw-r--r--src/power_mgt.h (renamed from power_mgt.h)0
-rw-r--r--src/wiring.cpp (renamed from wiring.cpp)6
170 files changed, 5512 insertions, 5159 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..d47e46b0
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,28 @@
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+name: build
+jobs:
+
+ build:
+ runs-on: ubuntu-20.04
+ steps:
+ - name: checkout code
+ uses: actions/checkout@v2
+
+ - name: install python
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.8'
+
+ - name: install platformio
+ run: |
+ pip install platformio==5.0.3
+
+ - name: build FastLED examples
+ run: ./ci/ci-compile
diff --git a/.gitignore b/.gitignore
index 60b7a717..9321044f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
-html/
*.gch
+*~
+/.vscode
+/docs/html
+/docs/latex
diff --git a/PORTING.md b/PORTING.md
index 2f925ab2..beb4e6c6 100644
--- a/PORTING.md
+++ b/PORTING.md
@@ -1,6 +1,7 @@
-=New platform porting guide=
+New platform porting guide
+==========================
-== Fast porting for a new board on existing hardware ==
+# Fast porting for a new board on existing hardware
Sometimes "porting" FastLED simply consists of supplying new pin definitions for the given platform. For example, platforms/avr/fastpin_avr.h contains various pin definitions for all the AVR variant chipsets/boards that FastLED supports. Defining a set of pins involves setting up a set of definitions - for example here's one full set from the avr fastpin file:
@@ -26,7 +27,7 @@ The ```_FL_IO``` macro is used to define the port registers for the platform whi
The ```HAS_HARDWARE_PIN_SUPPORT``` define tells the rest of the FastLED library that there is hardware pin support available. There may be other platform specific defines for things like hardware SPI ports and such.
-== Setting up the basic files/folders ==
+## Setting up the basic files/folders
* Create platform directory (e.g. platforms/arm/kl26)
* Create configuration header led_sysdefs_arm_kl26.h:
@@ -38,7 +39,7 @@ The ```HAS_HARDWARE_PIN_SUPPORT``` define tells the rest of the FastLED library
* Modify led_sysdefs.h to conditionally include platform sysdefs header file
* Modify platforms.h to conditionally include platform fastled header
-== Porting fastpin.h ==
+## Porting fastpin.h
The heart of the FastLED library is the fast pin accesss. This is a templated class that provides 1-2 cycle pin access, bypassing digital write and other such things. As such, this will usually be the first bit of the library that you will want to port when moving to a new platform. Once you have FastPIN up and running then you can do some basic work like testing toggles or running bit-bang'd SPI output.
@@ -46,10 +47,10 @@ There's two low level FastPin classes. There's the base FastPIN template class,
Explaining how the macros work and should be used is currently beyond the scope of this document.
-== Porting fastspi.h ==
+## Porting fastspi.h
This is where you define the low level interface to the hardware SPI system (including a writePixels method that does a bunch of housekeeping for writing led data). Use the fastspi_nop.h file as a reference for the methods that need to be implemented. There are ofteh other useful methods that can help with the internals of the SPI code, I recommend taking a look at how the various platforms implement their SPI classes.
-== Porting clockless.h ==
+## Porting clockless.h
This is where you define the code for the clockless controllers. Across ARM platforms this will usually be fairly similar - though different arm platforms will have different clock sources that you can/should use.
diff --git a/README.md b/README.md
index 0069329e..831baea1 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,18 @@
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/FastLED/public)
[![arduino-library-badge](https://www.ardu-badge.com/badge/FastLED.svg)](https://www.ardu-badge.com/FastLED)
+![build status](https://github.com/FastLED/FastLED/workflows/build/badge.svg)
IMPORTANT NOTE: For AVR based systems, avr-gcc 4.8.x is supported and tested. This means Arduino 1.6.5 and later.
-FastLED 3.3
+FastLED 3.4
===========
This is a library for easily & efficiently controlling a wide variety of LED chipsets, like the ones
sold by adafruit (Neopixel, DotStar, LPD8806), Sparkfun (WS2801), and aliexpress. In addition to writing to the
leds, this library also includes a number of functions for high-performing 8bit math for manipulating
your RGB values, as well as low level classes for abstracting out access to pins and SPI hardware, while
-still keeping things as fast as possible. Tested with Arduino up to 1.6.5 from arduino.cc.
+still keeping things as fast as possible. Tested with Arduino up to 1.6.5 from arduino.cc.
Quick note for people installing from GitHub repo zips, rename the folder FastLED before copying it to your Arduino/libraries folder. Github likes putting -branchname into the name of the folder, which unfortunately, makes Arduino cranky!
@@ -23,7 +24,7 @@ We have multiple goals with this library:
## Getting help
-If you need help with using the library, please consider going to the reddit community first, which is at http://fastled.io/r (or https://reddit.com/r/FastLED) - there are hundreds of people in that group and many times you will get a quicker answer to your question there, as you will be likely to run into other people who have had the same issue. If you run into bugs with the library (compilation failures, the library doing the wrong thing), or if you'd like to request that we support a particular platform or LED chipset, then please open an issue at http://fastled.io/issues and we will try to figure out what is going wrong.
+If you need help with using the library, please consider going to the reddit community first, which is at http://fastled.io/r (or https://reddit.com/r/FastLED) - there are thousands of great people in that group and many times you will get a quicker answer to your question there, as you will be likely to run into other people who have had the same issue. If you run into bugs with the library (compilation failures, the library doing the wrong thing), or if you'd like to request that we support a particular platform or LED chipset, then please open an issue at http://fastled.io/issues and we will try to figure out what is going wrong.
## Simple example
@@ -48,7 +49,7 @@ Here's a list of all the LED chipsets are supported. More details on the led ch
* TM1803 - 3 wire chipset, sold by radio shack
* UCS1903 - another 3 wire led chipset, cheap
* GW6205 - another 3 wire led chipset
-* LPD8806 - SPI based chpiset, very high speed
+* LPD8806 - SPI based chipset, very high speed
* WS2801 - SPI based chipset, cheap and widely available
* SM16716 - SPI based chipset
* APA102 - SPI based chipset
@@ -68,7 +69,7 @@ Right now the library is supported on a variety of arduino compatable platforms.
* Arduino & compatibles - straight up arduino devices, uno, duo, leonardo, mega, nano, etc...
* Arduino Yún
* Adafruit Trinket & Gemma - Trinket Pro may be supported, but haven't tested to confirm yet
-* Teensy 2, Teensy++ 2, Teensy 3.0, Teensy 3.1/3.2, Teensy LC, Teensy 3.5, Teensy 3.6, and Teensy 4.0 - arduino compataible from pjrc.com with some extra goodies (note the teensy 3, 3.1, and LC are ARM, not AVR!)
+* Teensy 2, Teensy++ 2, Teensy 3.0, Teensy 3.1/3.2, Teensy LC, Teensy 3.5, Teensy 3.6, and Teensy 4.0 - arduino compatible from pjrc.com with some extra goodies (note the teensy LC, 3.2, 3.5, 3.6, 4.0 are ARM, not AVR!)
* Arduino Due and the digistump DigiX
* RFDuino
* SparkCore
diff --git a/bitswap.cpp b/bitswap.cpp
deleted file mode 100644
index 67530c72..00000000
--- a/bitswap.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-#define FASTLED_INTERNAL
-#include "FastLED.h"
-
-/// Simplified form of bits rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating
-/// data into LSB for a faster write (the code using this data can happily walk the array backwards)
-void transpose8x1_noinline(unsigned char *A, unsigned char *B) {
- uint32_t x, y, t;
-
- // Load the array and pack it into x and y.
- y = *(unsigned int*)(A);
- x = *(unsigned int*)(A+4);
-
- // pre-transform x
- t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
- t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
-
- // pre-transform y
- t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
- t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
-
- // final transform
- t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
- y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
- x = t;
-
- *((uint32_t*)B) = y;
- *((uint32_t*)(B+4)) = x;
-}
diff --git a/ci/ci-compile b/ci/ci-compile
new file mode 100755
index 00000000..208a173a
--- /dev/null
+++ b/ci/ci-compile
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# compile FastLED examples with platformio for various boards. This script
+# is usually run by the CI, but can also be run locally. Only dependency
+# is platformio.
+#
+# usage:
+# [BOARDS=boards] [EXAMPLES=examples] ./ci-compile
+#
+# e.g.
+# $ ./compile-ci
+# - compile all board/examples combinations
+#
+# $ BOARDS="esp32 esp01" EXAMPLES=Blink ./compile-ci
+# - compile only Blink example for the esp32 and esp8266 platforms
+#
+set -eou pipefail
+
+# List of examples that will be compiled by default
+EXAMPLES=${EXAMPLES:-"Blink ColorPalette ColorTemperature Cylon DemoReel100
+ Fire2012 FirstLight Multiple/MultipleStripsInOneArray
+ Multiple/ArrayOfLedArrays Noise NoisePlayground NoisePlusPalette Pacifica
+ Pride2015 RGBCalibrate RGBSetDemo TwinkleFox XYMatrix"}
+
+# list of boards to compile for by default
+BOARDS=${BOARDS:-"uno esp32dev esp01 yun digix teensy30"}
+
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
+BOARD_OPTS=$(for b in $BOARDS; do echo -n "--board $b "; done)
+
+cd "$DIR/.."
+
+for d in $EXAMPLES ; do
+ echo "*** building example $d for $BOARDS ***"
+ pio ci $BOARD_OPTS --lib=src "examples/$d/"*ino
+done
diff --git a/code_of_conduct.md b/code_of_conduct.md
new file mode 100644
index 00000000..d8e2efa4
--- /dev/null
+++ b/code_of_conduct.md
@@ -0,0 +1,134 @@
+
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+ overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+ advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+ address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+[INSERT CONTACT METHOD].
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
+at [https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
+
diff --git a/color.h b/color.h
deleted file mode 100644
index 1ed60b4d..00000000
--- a/color.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef __INC_COLOR_H
-#define __INC_COLOR_H
-
-#include "FastLED.h"
-
-FASTLED_NAMESPACE_BEGIN
-
-///@file color.h
-/// contains definitions for color correction and temperature
-///@defgroup ColorEnums Color correction/temperature
-/// definitions for color correction and light temperatures
-///@{
-typedef enum {
- // Color correction starting points
-
- /// typical values for SMD5050 LEDs
- ///@{
- TypicalSMD5050=0xFFB0F0 /* 255, 176, 240 */,
- TypicalLEDStrip=0xFFB0F0 /* 255, 176, 240 */,
- ///@}
-
- /// typical values for 8mm "pixels on a string"
- /// also for many through-hole 'T' package LEDs
- ///@{
- Typical8mmPixel=0xFFE08C /* 255, 224, 140 */,
- TypicalPixelString=0xFFE08C /* 255, 224, 140 */,
- ///@}
-
- /// uncorrected color
- UncorrectedColor=0xFFFFFF
-
-} LEDColorCorrection;
-
-
-typedef enum {
- /// @name Black-body radiation light sources
- /// Black-body radiation light sources emit a (relatively) continuous
- /// spectrum, and can be described as having a Kelvin 'temperature'
- ///@{
- /// 1900 Kelvin
- Candle=0xFF9329 /* 1900 K, 255, 147, 41 */,
- /// 2600 Kelvin
- Tungsten40W=0xFFC58F /* 2600 K, 255, 197, 143 */,
- /// 2850 Kelvin
- Tungsten100W=0xFFD6AA /* 2850 K, 255, 214, 170 */,
- /// 3200 Kelvin
- Halogen=0xFFF1E0 /* 3200 K, 255, 241, 224 */,
- /// 5200 Kelvin
- CarbonArc=0xFFFAF4 /* 5200 K, 255, 250, 244 */,
- /// 5400 Kelvin
- HighNoonSun=0xFFFFFB /* 5400 K, 255, 255, 251 */,
- /// 6000 Kelvin
- DirectSunlight=0xFFFFFF /* 6000 K, 255, 255, 255 */,
- /// 7000 Kelvin
- OvercastSky=0xC9E2FF /* 7000 K, 201, 226, 255 */,
- /// 20000 Kelvin
- ClearBlueSky=0x409CFF /* 20000 K, 64, 156, 255 */,
- ///@}
-
- /// @name Gaseous light sources
- /// Gaseous light sources emit discrete spectral bands, and while we can
- /// approximate their aggregate hue with RGB values, they don't actually
- /// have a proper Kelvin temperature.
- ///@{
- WarmFluorescent=0xFFF4E5 /* 0 K, 255, 244, 229 */,
- StandardFluorescent=0xF4FFFA /* 0 K, 244, 255, 250 */,
- CoolWhiteFluorescent=0xD4EBFF /* 0 K, 212, 235, 255 */,
- FullSpectrumFluorescent=0xFFF4F2 /* 0 K, 255, 244, 242 */,
- GrowLightFluorescent=0xFFEFF7 /* 0 K, 255, 239, 247 */,
- BlackLightFluorescent=0xA700FF /* 0 K, 167, 0, 255 */,
- MercuryVapor=0xD8F7FF /* 0 K, 216, 247, 255 */,
- SodiumVapor=0xFFD1B2 /* 0 K, 255, 209, 178 */,
- MetalHalide=0xF2FCFF /* 0 K, 242, 252, 255 */,
- HighPressureSodium=0xFFB74C /* 0 K, 255, 183, 76 */,
- ///@}
-
- /// Uncorrected temperature 0xFFFFFF
- UncorrectedTemperature=0xFFFFFF
-} ColorTemperature;
-
-FASTLED_NAMESPACE_END
-
-///@}
-#endif
diff --git a/component.mk b/component.mk
index 27ad11a7..874ca9b0 100644
--- a/component.mk
+++ b/component.mk
@@ -1 +1,2 @@
-COMPONENT_ADD_INCLUDEDIRS := .
+COMPONENT_ADD_INCLUDEDIRS := ./src src/platforms/esp/32
+COMPONENT_SRCDIRS := ./src src/platforms/esp/32
diff --git a/docs/Doxyfile b/docs/Doxyfile
index eb300236..25e4f92e 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.8
+# Doxyfile 1.8.18
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -17,11 +17,11 @@
# Project related configuration options
#---------------------------------------------------------------------------
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
@@ -32,13 +32,13 @@ DOXYFILE_ENCODING = UTF-8
# title of most generated pages and in a few other places.
# The default value is: My Project.
-PROJECT_NAME = "FastLED"
+PROJECT_NAME = FastLED
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 3.1
+PROJECT_NUMBER = 3.3.3
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
@@ -46,10 +46,10 @@ PROJECT_NUMBER = 3.1
PROJECT_BRIEF =
-# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
-# the documentation. The maximum height of the logo should not exceed 55 pixels
-# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
-# to the output directory.
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
PROJECT_LOGO =
@@ -58,9 +58,9 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
-OUTPUT_DIRECTORY =
+OUTPUT_DIRECTORY = ../docs
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
@@ -93,14 +93,22 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
-# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION = None
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES.
BRIEF_MEMBER_DESC = YES
-# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
@@ -119,7 +127,6 @@ REPEAT_BRIEF = YES
# specifies, contains, represents, a, an and the.
ABBREVIATE_BRIEF =
-
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# doxygen will generate a detailed section even if there is only a brief
# description.
@@ -135,7 +142,7 @@ ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
-# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
@@ -179,6 +186,16 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
@@ -205,9 +222,9 @@ MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
-# new page for each member. If set to NO, the documentation of a member will be
-# part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
@@ -226,16 +243,15 @@ TAB_SIZE = 4
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
ALIASES =
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST =
-
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@@ -264,19 +280,28 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
#
-# Note For files without extension you can use no_extension as a placeholder.
+# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
@@ -285,7 +310,7 @@ EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@@ -293,10 +318,19 @@ EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 5
+
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by by putting a % sign in front of the word
-# or globally by setting AUTOLINK_SUPPORT to NO.
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
@@ -318,7 +352,7 @@ BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
@@ -336,13 +370,20 @@ SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
+# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
@@ -401,7 +442,7 @@ LOOKUP_CACHE_SIZE = 0
# Build related configuration options
#---------------------------------------------------------------------------
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
@@ -411,35 +452,41 @@ LOOKUP_CACHE_SIZE = 0
EXTRACT_ALL = NO
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = NO
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
EXTRACT_PACKAGE = NO
-# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
EXTRACT_STATIC = NO
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
# only classes defined in header files are included. Does not have any effect
# for Java sources.
# The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES
-# This flag is only useful for Objective-C code. When set to YES local methods,
+# This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO only methods in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
# included.
# The default value is: NO.
@@ -464,21 +511,21 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO these classes will be included in the various overviews. This option has
-# no effect if EXTRACT_ALL is enabled.
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO these declarations will be
-# included in the documentation.
+# declarations. If set to NO, these declarations will be included in the
+# documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO these
+# documentation blocks found inside the body of a function. If set to NO, these
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
@@ -492,21 +539,28 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES upper-case letters are also
+# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
+# (including Cygwin) ands Mac users are advised to set this option to NO.
# The default value is: system dependent.
CASE_SENSE_NAMES = NO
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES the
+# their full class and namespace scopes in the documentation. If set to YES, the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
@@ -534,14 +588,14 @@ INLINE_INFO = YES
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order.
+# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
SORT_MEMBER_DOCS = YES
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO the members will appear in declaration order. Note that
+# name. If set to NO, the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
@@ -586,27 +640,25 @@ SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
-# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
-# todo list. This list is created by putting \todo commands in the
-# documentation.
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
# The default value is: YES.
GENERATE_TODOLIST = YES
-# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
-# test list. This list is created by putting \test commands in the
-# documentation.
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
# The default value is: YES.
GENERATE_TESTLIST = YES
-# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
# list. This list is created by putting \bug commands in the documentation.
# The default value is: YES.
GENERATE_BUGLIST = YES
-# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
# the deprecated list. This list is created by putting \deprecated commands in
# the documentation.
# The default value is: YES.
@@ -631,8 +683,8 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES the list
-# will mention the files that were used to generate the documentation.
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
# The default value is: YES.
SHOW_USED_FILES = YES
@@ -677,7 +729,7 @@ LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@@ -696,7 +748,7 @@ CITE_BIB_FILES =
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
# this implies that the warnings are on.
#
# Tip: Turn warnings on while writing the documentation.
@@ -704,7 +756,7 @@ QUIET = NO
WARNINGS = YES
-# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
@@ -721,12 +773,19 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
-# value. If set to NO doxygen will only warn about wrong or incomplete parameter
-# documentation, but not about the absence of documentation.
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = NO
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated
@@ -750,15 +809,15 @@ WARN_LOGFILE =
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = . lib8tion
+INPUT = ../ ../lib8tion
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# The default value is: UTF-8.
@@ -766,15 +825,21 @@ INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
+# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen
+# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS =
-
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# The default value is: NO.
@@ -788,7 +853,7 @@ RECURSIVE = NO
# Note that relative paths are relative to the directory from which doxygen is
# run.
-EXCLUDE = M0-clocklessnotes.md TODO.md
+EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@@ -857,6 +922,10 @@ IMAGE_PATH =
# Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
INPUT_FILTER =
@@ -866,11 +935,15 @@ INPUT_FILTER =
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER ) will also be used to filter the input files that are used for
+# INPUT_FILTER) will also be used to filter the input files that are used for
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO.
@@ -918,7 +991,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
+# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
@@ -930,7 +1003,7 @@ REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation.
# The default value is: YES.
@@ -950,12 +1023,12 @@ SOURCE_TOOLTIPS = YES
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
+# (see https://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@@ -977,6 +1050,35 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
+# were built. This is equivalent to specifying the "-p" option to a clang tool,
+# such as clang-check. These options will then be passed to the parser.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH =
+
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
@@ -1007,7 +1109,7 @@ IGNORE_PREFIX =
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
-# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = YES
@@ -1018,7 +1120,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
-HTML_OUTPUT = html/docs/3.1
+HTML_OUTPUT = html
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
@@ -1073,10 +1175,10 @@ HTML_STYLESHEET =
# cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefor more robust against future updates.
+# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra stylesheet files is of importance (e.g. the last
-# stylesheet in the list overrules the setting of the previous ones in the
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1093,9 +1195,9 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the stylesheet and background images according to
+# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
@@ -1124,12 +1226,24 @@ HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = YES
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
@@ -1153,13 +1267,13 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# environment (see: https://developer.apple.com/xcode/), introduced with OSX
+# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1198,7 +1312,7 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
@@ -1221,28 +1335,28 @@ GENERATE_HTMLHELP = NO
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
-# The GENERATE_CHI flag controls if a separate .chi index file is generated (
-# YES) or that it should be included in the master .chm file ( NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
-# The BINARY_TOC flag controls whether a binary table of contents is generated (
-# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1274,7 +1388,7 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1282,7 +1396,7 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1291,7 +1405,7 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1299,7 +1413,7 @@ QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1307,7 +1421,7 @@ QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
@@ -1356,13 +1470,13 @@ DISABLE_INDEX = NO
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
# the same information as the tab index, you could consider setting
# DISABLE_INDEX to YES when enabling this option.
-# The default value is: .
+# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = YES
@@ -1384,13 +1498,24 @@ ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
EXT_LINKS_IN_WINDOW = NO
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png The default and svg Looks nicer but requires the
+# pdf2svg tool.
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT = png
+
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@@ -1400,7 +1525,7 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
@@ -1411,9 +1536,15 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
+
+FORMULA_MACROFILE =
+
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option.
@@ -1439,11 +1570,11 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
# This tag requires that the tag USE_MATHJAX is set to YES.
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
@@ -1482,7 +1613,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
+# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@@ -1499,9 +1630,9 @@ SERVER_BASED_SEARCH = NO
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
# search results.
#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
+# Xapian (see: https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1512,9 +1643,9 @@ EXTERNAL_SEARCH = NO
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
# which will return the search results when EXTERNAL_SEARCH is enabled.
#
-# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1550,7 +1681,7 @@ EXTRA_SEARCH_MAPPINGS =
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = YES
@@ -1566,22 +1697,36 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
-# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1599,9 +1744,12 @@ COMPACT_LATEX = NO
PAPER_TYPE = a4
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1616,9 +1764,9 @@ EXTRA_PACKAGES =
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
-# for the replacement values of the other commands the user is refered to
-# HTML_HEADER.
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
@@ -1634,6 +1782,17 @@ LATEX_HEADER =
LATEX_FOOTER =
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or
@@ -1652,7 +1811,7 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1687,17 +1846,33 @@ LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BIB_STYLE = plain
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
-# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors.
# The default value is: NO.
@@ -1712,7 +1887,7 @@ GENERATE_RTF = NO
RTF_OUTPUT = rtf
-# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
@@ -1732,9 +1907,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@@ -1743,17 +1918,27 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
-# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
# classes and files.
# The default value is: NO.
@@ -1797,7 +1982,7 @@ MAN_LINKS = NO
# Configuration options related to the XML output
#---------------------------------------------------------------------------
-# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
@@ -1811,7 +1996,7 @@ GENERATE_XML = NO
XML_OUTPUT = xml
-# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size
# of the XML output.
@@ -1820,11 +2005,18 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
-# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
# that can be used to generate PDF.
# The default value is: NO.
@@ -1838,7 +2030,7 @@ GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
@@ -1851,10 +2043,10 @@ DOCBOOK_PROGRAMLISTING = NO
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
-# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
-# Definitions (see http://autogen.sf.net) file that captures the structure of
-# the code including all documentation. Note that this feature is still
-# experimental and incomplete at the moment.
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@@ -1863,7 +2055,7 @@ GENERATE_AUTOGEN_DEF = NO
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
-# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
# file that captures the structure of the code including all documentation.
#
# Note that this feature is still experimental and incomplete at the moment.
@@ -1871,7 +2063,7 @@ GENERATE_AUTOGEN_DEF = NO
GENERATE_PERLMOD = NO
-# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output.
# The default value is: NO.
@@ -1879,9 +2071,9 @@ GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO the
+# understand what is going on. On the other hand, if this tag is set to NO, the
# size of the Perl module output will be much smaller and Perl will parse it
# just the same.
# The default value is: YES.
@@ -1901,14 +2093,14 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
-# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
-ENABLE_PREPROCESSING = NO
+ENABLE_PREPROCESSING = YES
-# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
-# in the source code. If set to NO only conditional compilation will be
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES.
# The default value is: NO.
@@ -1924,7 +2116,7 @@ MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
-# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
@@ -2000,37 +2192,32 @@ TAGFILES =
GENERATE_TAGFILE =
-# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
-# class index. If set to NO only the inherited external classes will be listed.
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
# The default value is: NO.
ALLEXTERNALS = NO
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
-# the modules index. If set to NO, only the current project's groups will be
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
EXTERNAL_GROUPS = YES
-# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
# the related pages index. If set to NO, only the current project's pages will
# be listed.
# The default value is: YES.
EXTERNAL_PAGES = YES
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH = /usr/bin/perl
-
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
@@ -2039,15 +2226,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2055,7 +2233,7 @@ MSCGEN_PATH =
DIA_PATH =
-# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@@ -2068,7 +2246,7 @@ HIDE_UNDOC_RELATIONS = YES
# set to NO
# The default value is: NO.
-HAVE_DOT = YES
+HAVE_DOT = NO
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of
@@ -2128,7 +2306,7 @@ COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
# The default value is: NO.
@@ -2180,7 +2358,8 @@ INCLUDED_BY_GRAPH = YES
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2191,7 +2370,8 @@ CALL_GRAPH = NO
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2214,11 +2394,15 @@ GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
-# Possible values are: png, jpg, gif and svg.
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
# The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES.
@@ -2266,10 +2450,19 @@ DIAFILE_DIRS =
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
-# This tag requires that the tag HAVE_DOT is set to YES.
PLANTUML_JAR_PATH =
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized
@@ -2306,7 +2499,7 @@ MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default.
@@ -2323,7 +2516,7 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# files that are used to generate the various graphs.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
diff --git a/examples/ColorPalette/ColorPalette.ino b/examples/ColorPalette/ColorPalette.ino
index 4d64efb3..6ccd5c1b 100644
--- a/examples/ColorPalette/ColorPalette.ino
+++ b/examples/ColorPalette/ColorPalette.ino
@@ -62,7 +62,7 @@ void FillLEDsFromPaletteColors( uint8_t colorIndex)
{
uint8_t brightness = 255;
- for( int i = 0; i < NUM_LEDS; i++) {
+ for( int i = 0; i < NUM_LEDS; ++i) {
leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
colorIndex += 3;
}
@@ -101,7 +101,7 @@ void ChangePalettePeriodically()
// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette()
{
- for( int i = 0; i < 16; i++) {
+ for( int i = 0; i < 16; ++i) {
currentPalette[i] = CHSV( random8(), 255, random8());
}
}
diff --git a/examples/Cylon/Cylon.ino b/examples/Cylon/Cylon.ino
index f51c3487..96d4949a 100644
--- a/examples/Cylon/Cylon.ino
+++ b/examples/Cylon/Cylon.ino
@@ -6,7 +6,7 @@
// For led chips like Neopixels, which have a data line, ground, and power, you just
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN
-#define DATA_PIN 7
+#define DATA_PIN 2
#define CLOCK_PIN 13
// Define the array of leds
@@ -15,8 +15,8 @@ CRGB leds[NUM_LEDS];
void setup() {
Serial.begin(57600);
Serial.println("resetting");
- LEDS.addLeds<WS2812,DATA_PIN,RGB>(leds,NUM_LEDS);
- LEDS.setBrightness(84);
+ FastLED.addLeds<WS2812,DATA_PIN,RGB>(leds,NUM_LEDS);
+ FastLED.setBrightness(84);
}
void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }
diff --git a/examples/DemoReel100/DemoReel100.ino b/examples/DemoReel100/DemoReel100.ino
index b4478735..fb91edfc 100644
--- a/examples/DemoReel100/DemoReel100.ino
+++ b/examples/DemoReel100/DemoReel100.ino
@@ -11,9 +11,6 @@ FASTLED_USING_NAMESPACE
//
// -Mark Kriegsman, December 2014
-#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
-#warning "Requires FastLED 3.1 or later; check github for latest code."
-#endif
#define DATA_PIN 3
//#define CLK_PIN 4
@@ -117,7 +114,7 @@ void bpm()
void juggle() {
// eight colored dots, weaving in and out of sync with each other
fadeToBlackBy( leds, NUM_LEDS, 20);
- byte dothue = 0;
+ uint8_t dothue = 0;
for( int i = 0; i < 8; i++) {
leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255);
dothue += 32;
diff --git a/examples/Fire2012/Fire2012.ino b/examples/Fire2012/Fire2012.ino
index dec5cd7f..f008a956 100644
--- a/examples/Fire2012/Fire2012.ino
+++ b/examples/Fire2012/Fire2012.ino
@@ -72,7 +72,7 @@ void loop()
void Fire2012()
{
// Array of temperature readings at each simulation cell
- static byte heat[NUM_LEDS];
+ static uint8_t heat[NUM_LEDS];
// Step 1. Cool down every cell a little
for( int i = 0; i < NUM_LEDS; i++) {
diff --git a/examples/Fire2012WithPalette/Fire2012WithPalette.ino b/examples/Fire2012WithPalette/Fire2012WithPalette.ino
index e65a87fb..182a48ae 100644
--- a/examples/Fire2012WithPalette/Fire2012WithPalette.ino
+++ b/examples/Fire2012WithPalette/Fire2012WithPalette.ino
@@ -128,7 +128,7 @@ void loop()
void Fire2012WithPalette()
{
// Array of temperature readings at each simulation cell
- static byte heat[NUM_LEDS];
+ static uint8_t heat[NUM_LEDS];
// Step 1. Cool down every cell a little
for( int i = 0; i < NUM_LEDS; i++) {
@@ -150,7 +150,7 @@ void Fire2012WithPalette()
for( int j = 0; j < NUM_LEDS; j++) {
// Scale the heat value from 0-255 down to 0-240
// for best results with color palettes.
- byte colorindex = scale8( heat[j], 240);
+ uint8_t colorindex = scale8( heat[j], 240);
CRGB color = ColorFromPalette( gPal, colorindex);
int pixelnumber;
if( gReverseDirection ) {
diff --git a/examples/Multiple/ArrayOfLedArrays/ArrayOfLedArrays.ino b/examples/Multiple/ArrayOfLedArrays/ArrayOfLedArrays.ino
index 3b7a9c79..0189f49e 100644
--- a/examples/Multiple/ArrayOfLedArrays/ArrayOfLedArrays.ino
+++ b/examples/Multiple/ArrayOfLedArrays/ArrayOfLedArrays.ino
@@ -12,14 +12,14 @@ CRGB leds[NUM_STRIPS][NUM_LEDS_PER_STRIP];
// For mirroring strips, all the "special" stuff happens just in setup. We
// just addLeds multiple times, once for each strip
void setup() {
- // tell FastLED there's 60 NEOPIXEL leds on pin 10
- FastLED.addLeds<NEOPIXEL, 10>(leds[0], NUM_LEDS_PER_STRIP);
+ // tell FastLED there's 60 NEOPIXEL leds on pin 2
+ FastLED.addLeds<NEOPIXEL, 2>(leds[0], NUM_LEDS_PER_STRIP);
- // tell FastLED there's 60 NEOPIXEL leds on pin 11
- FastLED.addLeds<NEOPIXEL, 11>(leds[1], NUM_LEDS_PER_STRIP);
+ // tell FastLED there's 60 NEOPIXEL leds on pin 3
+ FastLED.addLeds<NEOPIXEL, 3>(leds[1], NUM_LEDS_PER_STRIP);
- // tell FastLED there's 60 NEOPIXEL leds on pin 12
- FastLED.addLeds<NEOPIXEL, 12>(leds[2], NUM_LEDS_PER_STRIP);
+ // tell FastLED there's 60 NEOPIXEL leds on pin 4
+ FastLED.addLeds<NEOPIXEL, 4>(leds[2], NUM_LEDS_PER_STRIP);
}
diff --git a/examples/Multiple/MultipleStripsInOneArray/MultipleStripsInOneArray.ino b/examples/Multiple/MultipleStripsInOneArray/MultipleStripsInOneArray.ino
index 15d58bcb..c4426ddb 100644
--- a/examples/Multiple/MultipleStripsInOneArray/MultipleStripsInOneArray.ino
+++ b/examples/Multiple/MultipleStripsInOneArray/MultipleStripsInOneArray.ino
@@ -13,14 +13,14 @@ CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];
// For mirroring strips, all the "special" stuff happens just in setup. We
// just addLeds multiple times, once for each strip
void setup() {
- // tell FastLED there's 60 NEOPIXEL leds on pin 10, starting at index 0 in the led array
- FastLED.addLeds<NEOPIXEL, 10>(leds, 0, NUM_LEDS_PER_STRIP);
+ // tell FastLED there's 60 NEOPIXEL leds on pin 2, starting at index 0 in the led array
+ FastLED.addLeds<NEOPIXEL, 2>(leds, 0, NUM_LEDS_PER_STRIP);
- // tell FastLED there's 60 NEOPIXEL leds on pin 11, starting at index 60 in the led array
- FastLED.addLeds<NEOPIXEL, 11>(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
+ // tell FastLED there's 60 NEOPIXEL leds on pin 3, starting at index 60 in the led array
+ FastLED.addLeds<NEOPIXEL, 3>(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
- // tell FastLED there's 60 NEOPIXEL leds on pin 12, starting at index 120 in the led array
- FastLED.addLeds<NEOPIXEL, 12>(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
+ // tell FastLED there's 60 NEOPIXEL leds on pin 4, starting at index 120 in the led array
+ FastLED.addLeds<NEOPIXEL, 4>(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
}
diff --git a/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino b/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino
index d8d73fe2..68190fe4 100644
--- a/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino
+++ b/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino
@@ -11,8 +11,8 @@ CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];
// OctoWS2811: 2,14,7,8,6,20,21,5
void setup() {
- LEDS.addLeds<OCTOWS2811>(leds, NUM_LEDS_PER_STRIP);
- LEDS.setBrightness(32);
+ FastLED.addLeds<OCTOWS2811>(leds, NUM_LEDS_PER_STRIP);
+ FastLED.setBrightness(32);
}
void loop() {
@@ -32,6 +32,6 @@ void loop() {
hue++;
- LEDS.show();
- LEDS.delay(10);
+ FastLED.show();
+ FastLED.delay(10);
}
diff --git a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino
index 8c447b54..4cd5d628 100644
--- a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino
+++ b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino
@@ -24,13 +24,13 @@ void setup() {
delay(5000);
Serial.begin(57600);
Serial.println("Starting...");
- // LEDS.addLeds<WS2811_PORTA,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
- // LEDS.addLeds<WS2811_PORTB,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
- // LEDS.addLeds<WS2811_PORTD,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip);
- LEDS.addLeds<WS2811_PORTDC,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
+ // FastLED.addLeds<WS2811_PORTA,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
+ // FastLED.addLeds<WS2811_PORTB,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
+ // FastLED.addLeds<WS2811_PORTD,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip);
+ FastLED.addLeds<WS2811_PORTDC,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
// Teensy 4 parallel output example
- // LEDS.addLeds<NUM_STRIPS, WS2811, 1>(leds,NUM_LEDS_PER_STRIP);
+ // FastLED.addLeds<NUM_STRIPS, WS2811, 1>(leds,NUM_LEDS_PER_STRIP);
}
void loop() {
@@ -51,6 +51,6 @@ void loop() {
hue++;
- LEDS.show();
- // LEDS.delay(100);
+ FastLED.show();
+ // FastLED.delay(100);
}
diff --git a/examples/Noise/Noise.ino b/examples/Noise/Noise.ino
index e196e6bb..f11d75d7 100644
--- a/examples/Noise/Noise.ino
+++ b/examples/Noise/Noise.ino
@@ -7,8 +7,10 @@
// Params for width and height
const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;
+
#define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight)
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
+
// Param for different pixel layouts
const bool kMatrixSerpentineLayout = true;
@@ -62,15 +64,15 @@ uint16_t speed = 20; // a nice starting speed, mixes well with a scale of 100
uint16_t scale = 311;
// This is the array that we keep our computed noise values in
-uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];
+uint16_t noise[MAX_DIMENSION][MAX_DIMENSION];
void setup() {
// uncomment the following lines if you want to see FPS count information
// Serial.begin(38400);
// Serial.println("resetting!");
delay(3000);
- LEDS.addLeds<WS2811,5,RGB>(leds,NUM_LEDS);
- LEDS.setBrightness(96);
+ FastLED.addLeds<WS2811,2,RGB>(leds,NUM_LEDS);
+ FastLED.setBrightness(96);
// Initialize our coordinates to some random values
x = random16();
@@ -107,6 +109,6 @@ void loop() {
}
ihue+=1;
- LEDS.show();
+ FastLED.show();
// delay(10);
}
diff --git a/examples/NoisePlayground/NoisePlayground.ino b/examples/NoisePlayground/NoisePlayground.ino
index e2c7cb31..6c047324 100644
--- a/examples/NoisePlayground/NoisePlayground.ino
+++ b/examples/NoisePlayground/NoisePlayground.ino
@@ -1,9 +1,11 @@
#include <FastLED.h>
-#define kMatrixWidth 16
-#define kMatrixHeight 16
+// Params for width and height
+const uint8_t kMatrixWidth = 16;
+const uint8_t kMatrixHeight = 16;
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
+
// Param for different pixel layouts
#define kMatrixSerpentineLayout true
@@ -37,11 +39,11 @@ int y_speed=1111;
void loop() {
// fill the led array 2/16-bit noise values
- fill_2dnoise16(LEDS.leds(), kMatrixWidth, kMatrixHeight, kMatrixSerpentineLayout,
+ fill_2dnoise16(leds, kMatrixWidth, kMatrixHeight, kMatrixSerpentineLayout,
octaves,x,xscale,y,yscale,v_time,
hue_octaves,hxy,hue_scale,hxy,hue_scale,hue_time, false);
- LEDS.show();
+ FastLED.show();
// adjust the intra-frame time values
x += x_speed;
@@ -61,8 +63,8 @@ void setup() {
Serial.println("resetting!");
delay(3000);
- LEDS.addLeds<WS2811,6,GRB>(leds,NUM_LEDS);
- LEDS.setBrightness(96);
+ FastLED.addLeds<WS2811,2,GRB>(leds,NUM_LEDS);
+ FastLED.setBrightness(96);
hxy = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
x = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
diff --git a/examples/NoisePlusPalette/NoisePlusPalette.ino b/examples/NoisePlusPalette/NoisePlusPalette.ino
index e95e4128..4670cc38 100644
--- a/examples/NoisePlusPalette/NoisePlusPalette.ino
+++ b/examples/NoisePlusPalette/NoisePlusPalette.ino
@@ -5,8 +5,11 @@
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
+// Params for width and height
const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;
+
+// Param for different pixel layouts
const bool kMatrixSerpentineLayout = true;
@@ -67,8 +70,8 @@ uint8_t colorLoop = 1;
void setup() {
delay(3000);
- LEDS.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
- LEDS.setBrightness(BRIGHTNESS);
+ FastLED.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
+ FastLED.setBrightness(BRIGHTNESS);
// Initialize our coordinates to some random values
x = random16();
@@ -163,7 +166,7 @@ void loop() {
// using the current palette
mapNoiseToLEDsUsingPalette();
- LEDS.show();
+ FastLED.show();
// delay(10);
}
diff --git a/examples/RGBSetDemo/RGBSetDemo.ino b/examples/RGBSetDemo/RGBSetDemo.ino
index 455fdccc..42478757 100644
--- a/examples/RGBSetDemo/RGBSetDemo.ino
+++ b/examples/RGBSetDemo/RGBSetDemo.ino
@@ -3,7 +3,7 @@
CRGBArray<NUM_LEDS> leds;
-void setup() { FastLED.addLeds<NEOPIXEL,6>(leds, NUM_LEDS); }
+void setup() { FastLED.addLeds<NEOPIXEL,2>(leds, NUM_LEDS); }
void loop(){
static uint8_t hue;
diff --git a/examples/SmartMatrix/SmartMatrix.ino b/examples/SmartMatrix/SmartMatrix.ino
index 50bcb811..e685cf67 100644
--- a/examples/SmartMatrix/SmartMatrix.ino
+++ b/examples/SmartMatrix/SmartMatrix.ino
@@ -63,8 +63,8 @@ void setup() {
// Serial.begin(38400);
// Serial.println("resetting!");
delay(3000);
- LEDS.addLeds<SMART_MATRIX>(leds,NUM_LEDS);
- LEDS.setBrightness(96);
+ FastLED.addLeds<SMART_MATRIX>(leds,NUM_LEDS);
+ FastLED.setBrightness(96);
// Initialize our coordinates to some random values
x = random16();
@@ -116,6 +116,6 @@ void loop() {
pSmartMatrix->fillCircle(circlex % 32,circley % 32,6,CRGB(CHSV(ihue+128,255,255)));
circlex += random16(2);
circley += random16(2);
- LEDS.show();
+ FastLED.show();
// delay(10);
}
diff --git a/examples/TwinkleFox/TwinkleFox.ino b/examples/TwinkleFox/TwinkleFox.ino
index 4821139b..89af25c5 100644
--- a/examples/TwinkleFox/TwinkleFox.ino
+++ b/examples/TwinkleFox/TwinkleFox.ino
@@ -1,9 +1,5 @@
#include "FastLED.h"
-#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
-#warning "Requires FastLED 3.1 or later; check github for latest code."
-#endif
-
#define NUM_LEDS 100
#define LED_TYPE WS2811
diff --git a/examples/XYMatrix/XYMatrix.ino b/examples/XYMatrix/XYMatrix.ino
index 53c21411..cce1fbf3 100644
--- a/examples/XYMatrix/XYMatrix.ino
+++ b/examples/XYMatrix/XYMatrix.ino
@@ -15,7 +15,7 @@
// No error checking is performed on the ranges of x and y.
//
// XYsafe(x,y) takes x and y coordinates and returns an LED index number,
-// for use like this: leds[ XY(x,y) ] == CRGB::Red;
+// for use like this: leds[ XYsafe(x,y) ] == CRGB::Red;
// Error checking IS performed on the ranges of x and y, and an
// index of "-1" is returned. Special instructions below
// explain how to use this without having to do your own error
@@ -30,6 +30,8 @@ const uint8_t kMatrixHeight = 16;
// Param for different pixel layouts
const bool kMatrixSerpentineLayout = true;
+const bool kMatrixVertical = false;
+
// Set 'kMatrixSerpentineLayout' to false if your pixels are
// laid out all running the same way, like this:
//
@@ -88,17 +90,29 @@ uint16_t XY( uint8_t x, uint8_t y)
uint16_t i;
if( kMatrixSerpentineLayout == false) {
- i = (y * kMatrixWidth) + x;
+ if (kMatrixVertical == false) {
+ i = (y * kMatrixWidth) + x;
+ } else {
+ i = kMatrixHeight * (kMatrixWidth - (x+1))+y;
+ }
}
if( kMatrixSerpentineLayout == true) {
- if( y & 0x01) {
- // Odd rows run backwards
- uint8_t reverseX = (kMatrixWidth - 1) - x;
- i = (y * kMatrixWidth) + reverseX;
- } else {
- // Even rows run forwards
- i = (y * kMatrixWidth) + x;
+ if (kMatrixVertical == false) {
+ if( y & 0x01) {
+ // Odd rows run backwards
+ uint8_t reverseX = (kMatrixWidth - 1) - x;
+ i = (y * kMatrixWidth) + reverseX;
+ } else {
+ // Even rows run forwards
+ i = (y * kMatrixWidth) + x;
+ }
+ } else { // vertical positioning
+ if ( x & 0x01) {
+ i = kMatrixHeight * (kMatrixWidth - (x+1))+y;
+ } else {
+ i = kMatrixHeight * (kMatrixWidth - x) - (y+1);
+ }
}
}
@@ -176,13 +190,13 @@ void loop()
FastLED.show();
}
-void DrawOneFrame( byte startHue8, int8_t yHueDelta8, int8_t xHueDelta8)
+void DrawOneFrame( uint8_t startHue8, int8_t yHueDelta8, int8_t xHueDelta8)
{
- byte lineStartHue = startHue8;
- for( byte y = 0; y < kMatrixHeight; y++) {
+ uint8_t lineStartHue = startHue8;
+ for( uint8_t y = 0; y < kMatrixHeight; y++) {
lineStartHue += yHueDelta8;
- byte pixelHue = lineStartHue;
- for( byte x = 0; x < kMatrixWidth; x++) {
+ uint8_t pixelHue = lineStartHue;
+ for( uint8_t x = 0; x < kMatrixWidth; x++) {
pixelHue += xHueDelta8;
leds[ XY(x, y)] = CHSV( pixelHue, 255, 255);
}
diff --git a/library.json b/library.json
index bcb24070..9e330204 100644
--- a/library.json
+++ b/library.json
@@ -33,7 +33,7 @@
"type": "git",
"url": "https://github.com/FastLED/FastLED.git"
},
- "version": "3.3.3",
+ "version": "3.4.0",
"license": "MIT",
"homepage": "http://fastled.io",
"frameworks": "arduino",
@@ -48,7 +48,8 @@
"srcFilter": [
"+<*.c>",
"+<*.cpp>",
- "+<*.h>"
+ "+<*.h>",
+ "+<platforms/esp/32/*.cpp>"
],
"libArchive": false
}
diff --git a/library.properties b/library.properties
index 2ebea658..fc8d17b1 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=FastLED
-version=3.3.3
+version=3.4.0
author=Daniel Garcia
maintainer=Daniel Garcia <dgarcia@fastled.io>
sentence=Multi-platform library for controlling dozens of different types of LEDs along with optimized math, effect, and noise functions.
diff --git a/pixelset.h b/pixelset.h
deleted file mode 100644
index c9272ef2..00000000
--- a/pixelset.h
+++ /dev/null
@@ -1,305 +0,0 @@
-#ifndef __INC_PIXELSET_H
-#define __INC_PIXELSET_H
-
-#include "FastLED.h"
-
-#ifndef abs
-#include <stdlib.h>
-#endif
-
-///// Represents a set of CRGB led objects. Provides the [] array operator, and works like a normal array in that case.
-///// This should be kept in sync with the set of functions provided by CRGB as well as functions in colorutils. Note
-///// that a pixel set is a window into another set of led data, it is not its own set of led data.
-template<class PIXEL_TYPE>
-class CPixelView {
-public:
- const int8_t dir;
- const int len;
- PIXEL_TYPE * const leds;
- PIXEL_TYPE * const end_pos;
-
-public:
-
- /// PixelSet copy constructor
- inline CPixelView(const CPixelView & other) : dir(other.dir), len(other.len), leds(other.leds), end_pos(other.end_pos) {}
-
- /// pixelset constructor for a pixel set starting at the given PIXEL_TYPE* and going for _len leds. Note that the length
- /// can be backwards, creating a PixelSet that walks backwards over the data
- /// @param leds point to the raw led data
- /// @param len how many leds in this set
- inline CPixelView(PIXEL_TYPE *_leds, int _len) : dir(_len < 0 ? -1 : 1), len(_len), leds(_leds), end_pos(_leds + _len) {}
-
- /// PixelSet constructor for the given set of leds, with start and end boundaries. Note that start can be after
- /// end, resulting in a set that will iterate backwards
- /// @param leds point to the raw led data
- /// @param start the start index of the leds for this array
- /// @param end the end index of the leds for this array
- inline CPixelView(PIXEL_TYPE *_leds, int _start, int _end) : dir(((_end-_start)<0) ? -1 : 1), len((_end - _start) + dir), leds(_leds + _start), end_pos(_leds + _start + len) {}
-
- /// Get the size of this set
- /// @return the size of the set
- int size() { return abs(len); }
-
- /// Whether or not this set goes backwards
- /// @return whether or not the set is backwards
- bool reversed() { return len < 0; }
-
- /// do these sets point to the same thing (note, this is different from the contents of the set being the same)
- bool operator==(const CPixelView & rhs) const { return leds == rhs.leds && len == rhs.len && dir == rhs.dir; }
-
- /// do these sets point to the different things (note, this is different from the contents of the set being the same)
- bool operator!=(const CPixelView & rhs) const { return leds != rhs.leds || len != rhs.len || dir != rhs.dir; }
-
- /// access a single element in this set, just like an array operator
- inline PIXEL_TYPE & operator[](int x) const { if(dir & 0x80) { return leds[-x]; } else { return leds[x]; } }
-
- /// Access an inclusive subset of the leds in this set. Note that start can be greater than end, which will
- /// result in a reverse ordering for many functions (useful for mirroring)
- /// @param start the first element from this set for the new subset
- /// @param end the last element for the new subset
- inline CPixelView operator()(int start, int end) { return CPixelView(leds, start, end); }
-
- /// Access an inclusive subset of the leds in this set, starting from the first.
- /// @param end the last element for the new subset
- /// Not sure i want this? inline CPixelView operator()(int end) { return CPixelView(leds, 0, end); }
-
- /// Return the reverse ordering of this set
- inline CPixelView operator-() { return CPixelView(leds, len - dir, 0); }
-
- /// Return a pointer to the first element in this set
- inline operator PIXEL_TYPE* () const { return leds; }
-
- /// Assign the passed in color to all elements in this set
- /// @param color the new color for the elements in the set
- inline CPixelView & operator=(const PIXEL_TYPE & color) {
- for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) = color; }
- return *this;
- }
-
-
- void dump() const {
-/**
- Serial.print("len: "); Serial.print(len); Serial.print(", dir:"); Serial.print((int)dir);
- Serial.print(", range:"); Serial.print((uint32_t)leds); Serial.print("-"); Serial.print((uint32_t)end_pos);
- Serial.print(", diff:"); Serial.print((int32_t)(end_pos - leds));
- Serial.println("");
- **/
- }
-
- /// Copy the contents of the passed in set to our set. Note if one set is smaller than the other, only the
- /// smallest number of items will be copied over.
- inline CPixelView & operator=(const CPixelView & rhs) {
- for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) {
- (*pixel) = (*rhspixel);
- }
- return *this;
- }
-
- /// @name modification/scaling operators
- //@{
- /// Add the passed in value to r,g, b for all the pixels in this set
- inline CPixelView & addToRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) += inc; } return *this; }
- /// Add every pixel in the other set to this set
- inline CPixelView & operator+=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) += (*rhspixel); } return *this; }
-
- /// Subtract the passed in value from r,g,b for all pixels in this set
- inline CPixelView & subFromRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) -= inc; } return *this; }
- /// Subtract every pixel in the other set from this set
- inline CPixelView & operator-=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) -= (*rhspixel); } return *this; }
-
- /// Increment every pixel value in this set
- inline CPixelView & operator++() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
- /// Increment every pixel value in this set
- inline CPixelView & operator++(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
-
- /// Decrement every pixel value in this set
- inline CPixelView & operator--() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
- /// Decrement every pixel value in this set
- inline CPixelView & operator--(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
-
- /// Divide every led by the given value
- inline CPixelView & operator/=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) /= d; } return *this; }
- /// Shift every led in this set right by the given number of bits
- inline CPixelView & operator>>=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) >>= d; } return *this; }
- /// Multiply every led in this set by the given value
- inline CPixelView & operator*=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) *= d; } return *this; }
-
- /// Scale every led by the given scale
- inline CPixelView & nscale8_video(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this;}
- /// Scale down every led by the given scale
- inline CPixelView & operator%=(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this; }
- /// Fade every led down by the given scale
- inline CPixelView & fadeLightBy(uint8_t fadefactor) { return nscale8_video(255 - fadefactor); }
-
- /// Scale every led by the given scale
- inline CPixelView & nscale8(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
- /// Scale every led by the given scale
- inline CPixelView & nscale8(PIXEL_TYPE & scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
- /// Scale every led in this set by every led in the other set
- inline CPixelView & nscale8(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel).nscale8((*rhspixel)); } return *this; }
-
- /// Fade every led down by the given scale
- inline CPixelView & fadeToBlackBy(uint8_t fade) { return nscale8(255 - fade); }
-
- /// Apply the PIXEL_TYPE |= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel to the higher of the two values)
- inline CPixelView & operator|=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= rhs; } return *this; }
- /// Apply the PIXEL_TYPE |= operator to every pixel in this set with every pixel in the passed in set
- inline CPixelView & operator|=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) |= (*rhspixel); } return *this; }
- /// Apply the PIXEL_TYPE |= operator to every pixel in this set
- inline CPixelView & operator|=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= d; } return *this; }
-
- /// Apply the PIXEL_TYPE &= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel down to the lower of the two values)
- inline CPixelView & operator&=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= rhs; } return *this; }
- /// Apply the PIXEL_TYPE &= operator to every pixel in this set with every pixel in the passed in set
- inline CPixelView & operator&=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) &= (*rhspixel); } return *this; }
- /// APply the PIXEL_TYPE &= operator to every pixel in this set with the passed in value
- inline CPixelView & operator&=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= d; } return *this; }
- //@}
-
- /// Returns whether or not any leds in this set are non-zero
- inline operator bool() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { if((*pixel)) return true; } return false; }
-
- // Color util functions
- inline CPixelView & fill_solid(const PIXEL_TYPE & color) { *this = color; return *this; }
- inline CPixelView & fill_solid(const CHSV & color) { if(dir>0) { *this = color; return *this; } }
-
- inline CPixelView & fill_rainbow(uint8_t initialhue, uint8_t deltahue=5) {
- if(dir >= 0) {
- ::fill_rainbow(leds,len,initialhue,deltahue);
- } else {
- ::fill_rainbow(leds+len+1,-len,initialhue,deltahue);
- }
- return *this;
- }
-
- inline CPixelView & fill_gradient(const CHSV & startcolor, const CHSV & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
- if(dir >= 0) {
- ::fill_gradient(leds,len,startcolor, endcolor, directionCode);
- } else {
- ::fill_gradient(leds + len + 1, (-len), endcolor, startcolor, directionCode);
- }
- return *this;
- }
-
- inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, TGradientDirectionCode directionCode = SHORTEST_HUES) {
- if(dir >= 0) {
- ::fill_gradient(leds, len, c1, c2, c3, directionCode);
- } else {
- ::fill_gradient(leds + len + 1, -len, c3, c2, c1, directionCode);
- }
- return *this;
- }
-
- inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, const CHSV & c4, TGradientDirectionCode directionCode = SHORTEST_HUES) {
- if(dir >= 0) {
- ::fill_gradient(leds, len, c1, c2, c3, c4, directionCode);
- } else {
- ::fill_gradient(leds + len + 1, -len, c4, c3, c2, c1, directionCode);
- }
- return *this;
- }
-
- inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & startcolor, const PIXEL_TYPE & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
- if(dir >= 0) {
- ::fill_gradient_RGB(leds,len,startcolor, endcolor);
- } else {
- ::fill_gradient_RGB(leds + len + 1, (-len), endcolor, startcolor);
- }
- return *this;
- }
-
- inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3) {
- if(dir >= 0) {
- ::fill_gradient_RGB(leds, len, c1, c2, c3);
- } else {
- ::fill_gradient_RGB(leds + len + 1, -len, c3, c2, c1);
- }
- return *this;
- }
-
- inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3, const PIXEL_TYPE & c4) {
- if(dir >= 0) {
- ::fill_gradient_RGB(leds, len, c1, c2, c3, c4);
- } else {
- ::fill_gradient_RGB(leds + len + 1, -len, c4, c3, c2, c1);
- }
- return *this;
- }
-
- inline CPixelView & nblend(const PIXEL_TYPE & overlay, fract8 amountOfOverlay) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { ::nblend((*pixel), overlay, amountOfOverlay); } return *this; }
- inline CPixelView & nblend(const CPixelView & rhs, fract8 amountOfOverlay) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { ::nblend((*pixel), (*rhspixel), amountOfOverlay); } return *this; }
-
- // Note: only bringing in a 1d blur, not sure 2d blur makes sense when looking at sub arrays
- inline CPixelView & blur1d(fract8 blur_amount) {
- if(dir >= 0) {
- ::blur1d(leds, len, blur_amount);
- } else {
- ::blur1d(leds + len + 1, -len, blur_amount);
- }
- return *this;
- }
-
- inline CPixelView & napplyGamma_video(float gamma) {
- if(dir >= 0) {
- ::napplyGamma_video(leds, len, gamma);
- } else {
- ::napplyGamma_video(leds + len + 1, -len, gamma);
- }
- return *this;
- }
-
- inline CPixelView & napplyGamma_video(float gammaR, float gammaG, float gammaB) {
- if(dir >= 0) {
- ::napplyGamma_video(leds, len, gammaR, gammaG, gammaB);
- } else {
- ::napplyGamma_video(leds + len + 1, -len, gammaR, gammaG, gammaB);
- }
- return *this;
- }
-
- // TODO: Make this a fully specified/proper iterator
- template <class T>
- class pixelset_iterator_base {
- T * leds;
- const int8_t dir;
- public:
- __attribute__((always_inline)) inline pixelset_iterator_base(const pixelset_iterator_base & rhs) : leds(rhs.leds), dir(rhs.dir) {}
- __attribute__((always_inline)) inline pixelset_iterator_base(T * _leds, const char _dir) : leds(_leds), dir(_dir) {}
-
- __attribute__((always_inline)) inline pixelset_iterator_base& operator++() { leds += dir; return *this; }
- __attribute__((always_inline)) inline pixelset_iterator_base operator++(int) { pixelset_iterator_base tmp(*this); leds += dir; return tmp; }
-
- __attribute__((always_inline)) inline bool operator==(pixelset_iterator_base & other) const { return leds == other.leds; } // && set==other.set; }
- __attribute__((always_inline)) inline bool operator!=(pixelset_iterator_base & other) const { return leds != other.leds; } // || set != other.set; }
-
- __attribute__((always_inline)) inline PIXEL_TYPE& operator*() const { return *leds; }
- };
-
- typedef pixelset_iterator_base<PIXEL_TYPE> iterator;
- typedef pixelset_iterator_base<const PIXEL_TYPE> const_iterator;
-
- iterator begin() { return iterator(leds, dir); }
- iterator end() { return iterator(end_pos, dir); }
-
- iterator begin() const { return iterator(leds, dir); }
- iterator end() const { return iterator(end_pos, dir); }
-
- const_iterator cbegin() const { return const_iterator(leds, dir); }
- const_iterator cend() const { return const_iterator(end_pos, dir); }
-};
-
-typedef CPixelView<CRGB> CRGBSet;
-
-__attribute__((always_inline))
-inline CRGB *operator+(const CRGBSet & pixels, int offset) { return (CRGB*)pixels + offset; }
-
-
-template<int SIZE>
-class CRGBArray : public CPixelView<CRGB> {
- CRGB rawleds[SIZE];
-public:
- CRGBArray() : CPixelView<CRGB>(rawleds, SIZE) {}
- using CPixelView::operator=;
-};
-
-#endif
diff --git a/platforms/arm/d21/clockless_arm_d21.h b/platforms/arm/d21/clockless_arm_d21.h
deleted file mode 100644
index 366a6bde..00000000
--- a/platforms/arm/d21/clockless_arm_d21.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __INC_CLOCKLESS_ARM_D21
-#define __INC_CLOCKLESS_ARM_D21
-
-#include "../common/m0clockless.h"
-FASTLED_NAMESPACE_BEGIN
-#define FASTLED_HAS_CLOCKLESS 1
-
-template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class ClocklessController : public CPixelLEDController<RGB_ORDER> {
- typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
- typedef typename FastPinBB<DATA_PIN>::port_t data_t;
-
- data_t mPinMask;
- data_ptr_t mPort;
- CMinWait<WAIT_TIME> mWait;
-public:
- virtual void init() {
- FastPinBB<DATA_PIN>::setOutput();
- mPinMask = FastPinBB<DATA_PIN>::mask();
- mPort = FastPinBB<DATA_PIN>::port();
- }
-
- virtual uint16_t getMaxRefreshRate() const { return 400; }
-
- virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
- cli();
- if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- sei();
- mWait.mark();
- }
-
- // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
- // gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
- struct M0ClocklessData data;
- data.d[0] = pixels.d[0];
- data.d[1] = pixels.d[1];
- data.d[2] = pixels.d[2];
- data.s[0] = pixels.mScale[0];
- data.s[1] = pixels.mScale[1];
- data.s[2] = pixels.mScale[2];
- data.e[0] = pixels.e[0];
- data.e[1] = pixels.e[1];
- data.e[2] = pixels.e[2];
- data.adj = pixels.mAdvance;
-
- typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
- return showLedData<8,4,T1,T2,T3,RGB_ORDER, WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
- }
-
-
-};
-
-FASTLED_NAMESPACE_END
-
-
-#endif // __INC_CLOCKLESS_ARM_D21
diff --git a/platforms/arm/d51/README.txt b/platforms/arm/d51/README.txt
deleted file mode 100644
index b00fb670..00000000
--- a/platforms/arm/d51/README.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-FastLED updates for adafruit FEATHER M4 and fixes to ITSBITSY M4 compiles
- SAMD51
-
-only tested on FEATHER M4 with DOTSTAR and neopixel strips
diff --git a/platforms/arm/d51/fastpin_arm_d51.h b/platforms/arm/d51/fastpin_arm_d51.h
deleted file mode 100644
index dd40dbfd..00000000
--- a/platforms/arm/d51/fastpin_arm_d51.h
+++ /dev/null
@@ -1,139 +0,0 @@
-#ifndef __INC_FASTPIN_ARM_D51_H
-#define __INC_FASTPIN_ARM_D51_H
-
-FASTLED_NAMESPACE_BEGIN
-
-#if defined(FASTLED_FORCE_SOFTWARE_PINS)
-#warning "Software pin support forced, pin access will be slightly slower."
-#define NO_HARDWARE_PIN_SUPPORT
-#undef HAS_HARDWARE_PIN_SUPPORT
-
-#else
-
-/// Template definition for STM32 style ARM pins, providing direct access to the various GPIO registers. Note that this
-/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
-/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
-/// The registers are data output, set output, clear output, toggle output, input, and direction
-
-template<uint8_t PIN, uint8_t _BIT, uint32_t _MASK, int _GRP> class _ARMPIN {
-public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
-
- #if 0
- inline static void setOutput() {
- if(_BIT<8) {
- _CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
- } else {
- _CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
- }
- }
- inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
- #endif
-
- inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; }
- inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
-
- inline static void hi() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTSET.reg = _MASK; }
- inline static void lo() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTCLR.reg = _MASK; }
- inline static void set(register port_t val) __attribute__ ((always_inline)) { PORT->Group[_GRP].OUT.reg = val; }
-
- inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
-
- inline static void toggle() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTTGL.reg = _MASK; }
-
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
-
- inline static port_t hival() __attribute__ ((always_inline)) { return PORT->Group[_GRP].OUT.reg | _MASK; }
- inline static port_t loval() __attribute__ ((always_inline)) { return PORT->Group[_GRP].OUT.reg & ~_MASK; }
- inline static port_ptr_t port() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUT.reg; }
- inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUTSET.reg; }
- inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUTCLR.reg; }
- inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
-};
-
-#define _R(T) struct __gen_struct_ ## T
-#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile PortGroup * r() { return T; } };
-
-#define _FL_IO(L) _RD32(GPIO ## L)
-
-#define _FL_DEFPIN(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, BIT, 1 << BIT, L> {};
-
-// Actual pin definitions
-#if defined(ADAFRUIT_ITSYBITSY_M4_EXPRESS)
-
-#define MAX_PIN 19
-// D0-D13, including D6+D8 (DotStar CLK + DATA)
-_FL_DEFPIN( 0, 16, 0); _FL_DEFPIN( 1, 17, 0); _FL_DEFPIN( 2, 7, 0); _FL_DEFPIN( 3, 22, 1);
-_FL_DEFPIN( 4, 14, 0); _FL_DEFPIN( 5, 15, 0); _FL_DEFPIN( 6, 2, 1); _FL_DEFPIN( 7, 18, 0);
-_FL_DEFPIN( 8, 3, 1); _FL_DEFPIN( 9, 19, 0); _FL_DEFPIN(10, 20, 0); _FL_DEFPIN(11, 21, 0);
-_FL_DEFPIN(12, 23, 0); _FL_DEFPIN(13, 22, 0);
-// A0-A5
-_FL_DEFPIN(14, 2, 0); _FL_DEFPIN(15, 5, 0); _FL_DEFPIN(16, 8, 1); _FL_DEFPIN(17, 9, 1);
-_FL_DEFPIN(18, 4, 0); _FL_DEFPIN(19, 6, 0); /* A6 is present in variant.h but couldn't find it on the schematic */
-// SDA/SCL
-_FL_DEFPIN(21, 12, 0); _FL_DEFPIN(22, 13, 0);
-
-// 23..25 MISO/SCK/MOSI
-_FL_DEFPIN(23, 23, 1); _FL_DEFPIN(24, 1, 0); _FL_DEFPIN(25, 0, 0);
-
-#define SPI_DATA 25
-#define SPI_CLOCK 24
-
-#define HAS_HARDWARE_PIN_SUPPORT 1
-
-// Actual pin definitions
-#elif defined(ADAFRUIT_METRO_M4_AIRLIFT_LITE)
-
-#define MAX_PIN 20
-// D0-D13, including D6+D8 (DotStar CLK + DATA)
-_FL_DEFPIN( 0, 23, 0); _FL_DEFPIN( 1, 22, 0); _FL_DEFPIN( 2, 17, 1); _FL_DEFPIN( 3, 16, 1);
-_FL_DEFPIN( 4, 13, 1); _FL_DEFPIN( 5, 14, 1); _FL_DEFPIN( 6, 15, 1); _FL_DEFPIN( 7, 12, 1);
-_FL_DEFPIN( 8, 21, 0); _FL_DEFPIN( 9, 20, 0); _FL_DEFPIN(10, 18, 0); _FL_DEFPIN(11, 19, 0);
-_FL_DEFPIN(12, 17, 0); _FL_DEFPIN(13, 16, 0);
-// A0-A5
-_FL_DEFPIN(14, 2, 0); _FL_DEFPIN(15, 5, 0); _FL_DEFPIN(16, 6, 0); _FL_DEFPIN(17, 0, 1);
-_FL_DEFPIN(18, 8, 1); _FL_DEFPIN(19, 9, 1);
-// SDA/SCL
-_FL_DEFPIN(22, 2, 1); _FL_DEFPIN(23, 3, 1);
-
-// 23..25 MISO/SCK/MOSI
-_FL_DEFPIN(24, 14, 0); _FL_DEFPIN(25, 13, 0); _FL_DEFPIN(26, 12, 0);
-
-#define SPI_DATA 26
-#define SPI_CLOCK 25
-
-#define HAS_HARDWARE_PIN_SUPPORT 1
-
-#elif defined(ADAFRUIT_FEATHER_M4_EXPRESS)
-
-#define MAX_PIN 19
-// D0-D13, including D8 (neopixel) no pins 2 3
-_FL_DEFPIN( 0, 17, 1); _FL_DEFPIN( 1, 16, 1);
-_FL_DEFPIN( 4, 14, 0); _FL_DEFPIN( 5, 16, 0); _FL_DEFPIN( 6, 18, 0);
-_FL_DEFPIN( 8, 3, 1); _FL_DEFPIN( 9, 19, 0); _FL_DEFPIN(10, 20, 0); _FL_DEFPIN(11, 21, 0);
-_FL_DEFPIN(12, 22, 0); _FL_DEFPIN(13, 23, 0);
-// A0-A5
-_FL_DEFPIN(14, 2, 0); _FL_DEFPIN(15, 5, 0); _FL_DEFPIN(16, 8, 1); _FL_DEFPIN(17, 9, 1);
-_FL_DEFPIN(18, 4, 0); _FL_DEFPIN(19, 6, 0); /* A6 is present in variant.h but couldn't find it on the schematic */
-// SDA/SCL
-_FL_DEFPIN(21, 12, 0); _FL_DEFPIN(22, 13, 0);
-// 23..25 MISO/MOSI/SCK
-_FL_DEFPIN(23, 22, 1); _FL_DEFPIN(24, 23, 1); _FL_DEFPIN(25, 17, 0);
-
-#define SPI_DATA 24
-#define SPI_CLOCK 25
-
-#define HAS_HARDWARE_PIN_SUPPORT 1
-#endif
-
-
-
-#endif // FASTLED_FORCE_SOFTWARE_PINS
-
-FASTLED_NAMESPACE_END
-
-
-#endif // __INC_FASTPIN_ARM_D51_H
diff --git a/platforms/arm/k20/smartmatrix_t3.h b/platforms/arm/k20/smartmatrix_t3.h
deleted file mode 100644
index 95af46cf..00000000
--- a/platforms/arm/k20/smartmatrix_t3.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef __INC_SMARTMATRIX_T3_H
-#define __INC_SMARTMATRIX_T3_H
-
-#ifdef SmartMatrix_h
-#include <SmartMatrix.h>
-
-FASTLED_NAMESPACE_BEGIN
-
-extern SmartMatrix *pSmartMatrix;
-
-// note - dmx simple must be included before FastSPI for this code to be enabled
-class CSmartMatrixController : public CPixelLEDController<RGB_ORDER> {
- SmartMatrix matrix;
-
-public:
- // initialize the LED controller
- virtual void init() {
- // Initialize 32x32 LED Matrix
- matrix.begin();
- matrix.setBrightness(255);
- matrix.setColorCorrection(ccNone);
-
- // Clear screen
- clearLeds(0);
- matrix.swapBuffers();
- pSmartMatrix = &matrix;
- }
-
- virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- if(SMART_MATRIX_CAN_TRIPLE_BUFFER) {
- rgb24 *md = matrix.getRealBackBuffer();
- } else {
- rgb24 *md = matrix.backBuffer();
- }
- while(pixels.has(1)) {
- md->red = pixels.loadAndScale0();
- md->green = pixels.loadAndScale1();
- md->blue = pixels.loadAndScale2();
- md++;
- pixels.advanceData();
- pixels.stepDithering();
- }
- matrix.swapBuffers();
- if(SMART_MATRIX_CAN_TRIPLE_BUFFER && pixels.advanceBy() > 0) {
- matrix.setBackBuffer(pixels.mData);
- }
- }
-
-};
-
-FASTLED_NAMESPACE_END
-
-#endif
-
-#endif
diff --git a/platforms/arm/k20/ws2812serial_controller.h b/platforms/arm/k20/ws2812serial_controller.h
deleted file mode 100644
index 0bca7d5e..00000000
--- a/platforms/arm/k20/ws2812serial_controller.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __INC_WS2812SERIAL_CONTROLLER_H
-#define __INC_WS2812SERIAL_CONTROLLER_H
-
-#ifdef USE_WS2812SERIAL
-
-FASTLED_NAMESPACE_BEGIN
-
-template<int DATA_PIN, EOrder RGB_ORDER>
-class CWS2812SerialController : public CPixelLEDController<RGB_ORDER, 8, 0xFF> {
- WS2812Serial *pserial;
- uint8_t *drawbuffer,*framebuffer;
-
- void _init(int nLeds) {
- if (pserial == NULL) {
- drawbuffer = (uint8_t*)malloc(nLeds * 3);
- framebuffer = (uint8_t*)malloc(nLeds * 12);
- pserial = new WS2812Serial(nLeds, framebuffer, drawbuffer, DATA_PIN, WS2812_RGB);
- pserial->begin();
- }
- }
-public:
- CWS2812SerialController() { pserial = NULL; }
-
- virtual void init() { /* do nothing yet */ }
-
- virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> & pixels) {
- _init(pixels.size());
-
- uint8_t *p = drawbuffer;
-
- while(pixels.has(1)) {
- *p++ = pixels.loadAndScale0();
- *p++ = pixels.loadAndScale1();
- *p++ = pixels.loadAndScale2();
- pixels.stepDithering();
- pixels.advanceData();
- }
- pserial->show();
- }
-
-};
-
-FASTLED_NAMESPACE_END
-
-#endif // USE_WS2812SERIAL
-#endif // __INC_WS2812SERIAL_CONTROLLER_H
diff --git a/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h b/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h
deleted file mode 100644
index 73f73de8..00000000
--- a/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h
+++ /dev/null
@@ -1,215 +0,0 @@
-#ifndef __INC_BLOCK_CLOCKLESS_ARM_MXRT1062_H
-#define __INC_BLOCK_CLOCKLESS_ARM_MXRT1062_H
-
-FASTLED_NAMESPACE_BEGIN
-
-// Definition for a single channel clockless controller for the teensy4
-// See clockless.h for detailed info on how the template parameters are used.
-#if defined(FASTLED_TEENSY4)
-
-#define __FL_T4_MASK ((1<<(LANES))-1)
-template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class FlexibleInlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, __FL_T4_MASK> {
-
- uint8_t m_bitOffsets[16];
- uint8_t m_nActualLanes;
- uint8_t m_nLowBit;
- uint8_t m_nHighBit;
- uint32_t m_nWriteMask;
- uint8_t m_nOutBlocks;
- uint32_t m_offsets[3];
- CMinWait<WAIT_TIME> mWait;
-public:
-
- virtual int size() { return CLEDController::size() * m_nActualLanes; }
-
-// For each pin, if we've hit our lane count, break, otherwise set the pin to output,
-// store the bit offset in our offset array, add this pin to the write mask, and if this
-// pin ends a block sequence, then break out of the switch as well
-#define _BLOCK_PIN(P) case P: { \
- if(m_nActualLanes == LANES) break; \
- FastPin<P>::setOutput(); \
- m_bitOffsets[m_nActualLanes++] = FastPin<P>::pinbit(); \
- m_nWriteMask |= FastPin<P>::mask(); \
- if( P == 27 || P == 7 || P == 30) break; \
-}
-
- virtual void init() {
- // pre-initialize
- memset(m_bitOffsets,0,16);
- m_nActualLanes = 0;
- m_nLowBit = 33;
- m_nHighBit = 0;
- m_nWriteMask = 0;
-
- // setup the bits and data tracking for parallel output
- switch(FIRST_PIN) {
- // GPIO6 block output
- _BLOCK_PIN( 1);
- _BLOCK_PIN( 0);
- _BLOCK_PIN(24);
- _BLOCK_PIN(25);
- _BLOCK_PIN(19);
- _BLOCK_PIN(18);
- _BLOCK_PIN(14);
- _BLOCK_PIN(15);
- _BLOCK_PIN(17);
- _BLOCK_PIN(16);
- _BLOCK_PIN(22);
- _BLOCK_PIN(23);
- _BLOCK_PIN(20);
- _BLOCK_PIN(21);
- _BLOCK_PIN(26);
- _BLOCK_PIN(27);
- // GPIO7 block output
- _BLOCK_PIN(10);
- _BLOCK_PIN(12);
- _BLOCK_PIN(11);
- _BLOCK_PIN(13);
- _BLOCK_PIN( 6);
- _BLOCK_PIN( 9);
- _BLOCK_PIN(32);
- _BLOCK_PIN( 8);
- _BLOCK_PIN( 7);
- // GPIO 37 block output
- _BLOCK_PIN(37);
- _BLOCK_PIN(36);
- _BLOCK_PIN(35);
- _BLOCK_PIN(34);
- _BLOCK_PIN(39);
- _BLOCK_PIN(38);
- _BLOCK_PIN(28);
- _BLOCK_PIN(31);
- _BLOCK_PIN(30);
- }
-
- for(int i = 0; i < m_nActualLanes; i++) {
- if(m_bitOffsets[i] < m_nLowBit) { m_nLowBit = m_bitOffsets[i]; }
- if(m_bitOffsets[i] > m_nHighBit) { m_nHighBit = m_bitOffsets[i]; }
- }
-
- m_nOutBlocks = (m_nHighBit + 8)/8;
-
- }
-
- virtual uint16_t getMaxRefreshRate() const { return 400; }
-
- virtual void showPixels(PixelController<RGB_ORDER, LANES, __FL_T4_MASK> & pixels) {
- mWait.wait();
- #if FASTLED_ALLOW_INTERRUPTS == 0
- uint32_t clocks = showRGBInternal(pixels);
- // Adjust the timer
- long microsTaken = CLKS_TO_MICROS(clocks);
- MS_COUNTER += (1 + (microsTaken / 1000));
- #else
- showRGBInternal(pixels);
- #endif
-
- mWait.mark();
- }
-
- typedef union {
- uint8_t bytes[32];
- uint8_t bg[4][8];
- uint16_t shorts[16];
- uint32_t raw[8];
- } _outlines;
-
-
- template<int BITS,int PX> __attribute__ ((always_inline)) inline void writeBits(register uint32_t & next_mark, register _outlines & b, PixelController<RGB_ORDER, LANES, __FL_T4_MASK> &pixels) {
- _outlines b2;
- transpose8x1(b.bg[3], b2.bg[3]);
- transpose8x1(b.bg[2], b2.bg[2]);
- transpose8x1(b.bg[1], b2.bg[1]);
- transpose8x1(b.bg[0], b2.bg[0]);
-
- register uint8_t d = pixels.template getd<PX>(pixels);
- register uint8_t scale = pixels.template getscale<PX>(pixels);
-
- int x = 0;
- for(uint32_t i = 8; i > 0;) {
- i--;
- while(ARM_DWT_CYCCNT < next_mark);
- *FastPin<FIRST_PIN>::sport() = m_nWriteMask;
- next_mark = ARM_DWT_CYCCNT + m_offsets[0];
-
- uint32_t out = (b2.bg[3][i] << 24) | (b2.bg[2][i] << 16) | (b2.bg[1][i] << 8) | b2.bg[0][i];
-
- out = ((~out) & m_nWriteMask);
- while((next_mark - ARM_DWT_CYCCNT) > m_offsets[1]);
- *FastPin<FIRST_PIN>::cport() = out;
-
- out = m_nWriteMask;
- while((next_mark - ARM_DWT_CYCCNT) > m_offsets[2]);
- *FastPin<FIRST_PIN>::cport() = out;
-
- // Read and store up to two bytes
- if (x < m_nActualLanes) {
- b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale<PX>(pixels,x,d,scale);
- x++;
- if (x < m_nActualLanes) {
- b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale<PX>(pixels,x,d,scale);
- x++;
- }
- }
- }
- }
-
- uint32_t showRGBInternal(PixelController<RGB_ORDER,LANES, __FL_T4_MASK> &allpixels) {
- allpixels.preStepFirstByteDithering();
- _outlines b0;
- uint32_t start = ARM_DWT_CYCCNT;
-
- for(int i = 0; i < m_nActualLanes; i++) {
- b0.bytes[m_bitOffsets[i]] = allpixels.loadAndScale0(i);
- }
-
- cli();
- m_offsets[0] = _FASTLED_NS_TO_DWT(T1+T2+T3);
- m_offsets[1] = _FASTLED_NS_TO_DWT(T2+T3);
- m_offsets[2] = _FASTLED_NS_TO_DWT(T3);
- uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD));
-
- uint32_t next_mark = ARM_DWT_CYCCNT + m_offsets[0];
-
- while(allpixels.has(1)) {
- allpixels.stepDithering();
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- cli();
- // if interrupts took longer than 45µs, punt on the current frame
- if(ARM_DWT_CYCCNT > next_mark) {
- if((ARM_DWT_CYCCNT-next_mark) > wait_off) { sei(); return ARM_DWT_CYCCNT - start; }
- }
- #endif
-
- // Write first byte, read next byte
- writeBits<8+XTRA0,1>(next_mark, b0, allpixels);
-
- // Write second byte, read 3rd byte
- writeBits<8+XTRA0,2>(next_mark, b0, allpixels);
- allpixels.advanceData();
-
- // Write third byte
- writeBits<8+XTRA0,0>(next_mark, b0, allpixels);
-
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- sei();
- #endif
- }
-
- sei();
-
- return ARM_DWT_CYCCNT - start;
- }
-};
-
-template<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, int NUM_LANES, EOrder RGB_ORDER=GRB>
-class __FIBCC : public FlexibleInlineBlockClocklessController<NUM_LANES,DATA_PIN,CHIPSET<DATA_PIN,RGB_ORDER>::__T1(),CHIPSET<DATA_PIN,RGB_ORDER>::__T2(),CHIPSET<DATA_PIN,RGB_ORDER>::__T3(),RGB_ORDER,CHIPSET<DATA_PIN,RGB_ORDER>::__XTRA0(),CHIPSET<DATA_PIN,RGB_ORDER>::__FLIP(),CHIPSET<DATA_PIN,RGB_ORDER>::__WAIT_TIME()> {};
-
-#define __FASTLED_HAS_FIBCC 1
-
-#endif //defined(FASTLED_TEENSY4)
-
-FASTLED_NAMESPACE_END
-
-#endif
diff --git a/platforms/arm/nrf51/clockless_arm_nrf51.h b/platforms/arm/nrf51/clockless_arm_nrf51.h
deleted file mode 100644
index b7489579..00000000
--- a/platforms/arm/nrf51/clockless_arm_nrf51.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __INC_CLOCKLESS_ARM_NRF51
-#define __INC_CLOCKLESS_ARM_NRF51
-
-#if defined(NRF51)
-
-#include <nrf51_bitfields.h>
-#define FASTLED_HAS_CLOCKLESS 1
-
-#if (FASTLED_ALLOW_INTERRUPTS==1)
-#define SEI_CHK LED_TIMER->CC[0] = (WAIT_TIME * (F_CPU/1000000)); LED_TIMER->TASKS_CLEAR; LED_TIMER->EVENTS_COMPARE[0] = 0;
-#define CLI_CHK cli(); if(LED_TIMER->EVENTS_COMPARE[0]) { LED_TIMER->TASKS_STOP = 1; return 0; }
-#define INNER_SEI sei();
-#else
-#define SEI_CHK
-#define CLI_CHK
-#define INNER_SEI delaycycles<1>();
-#endif
-
-
-#include "../common/m0clockless.h"
-template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 75>
-class ClocklessController : public CPixelLEDController<RGB_ORDER> {
- typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
- typedef typename FastPinBB<DATA_PIN>::port_t data_t;
-
- data_t mPinMask;
- data_ptr_t mPort;
- CMinWait<WAIT_TIME> mWait;
-public:
- virtual void init() {
- FastPinBB<DATA_PIN>::setOutput();
- mPinMask = FastPinBB<DATA_PIN>::mask();
- mPort = FastPinBB<DATA_PIN>::port();
- }
-
- virtual uint16_t getMaxRefreshRate() const { return 400; }
-
- virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
- cli();
- if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- sei();
- mWait.mark();
- }
-
- // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
- // gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
- struct M0ClocklessData data;
- data.d[0] = pixels.d[0];
- data.d[1] = pixels.d[1];
- data.d[2] = pixels.d[2];
- data.s[0] = pixels.mScale[0];
- data.s[1] = pixels.mScale[1];
- data.s[2] = pixels.mScale[2];
- data.e[0] = pixels.e[0];
- data.e[1] = pixels.e[1];
- data.e[2] = pixels.e[2];
- data.adj = pixels.mAdvance;
-
- typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
-
- // timer mode w/prescaler of 0
- LED_TIMER->MODE = TIMER_MODE_MODE_Timer;
- LED_TIMER->PRESCALER = 0;
- LED_TIMER->EVENTS_COMPARE[0] = 0;
- LED_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
- LED_TIMER->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;
- LED_TIMER->TASKS_START = 1;
-
- int ret = showLedData<4,8,T1,T2,T3,RGB_ORDER,WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
-
- LED_TIMER->TASKS_STOP = 1;
- return ret; // 0x00FFFFFF - _VAL;
- }
-};
-
-
-#endif // NRF51
-#endif // __INC_CLOCKLESS_ARM_NRF51
diff --git a/platforms/arm/nrf51/fastpin_arm_nrf51.h b/platforms/arm/nrf51/fastpin_arm_nrf51.h
deleted file mode 100644
index 3d02edc1..00000000
--- a/platforms/arm/nrf51/fastpin_arm_nrf51.h
+++ /dev/null
@@ -1,119 +0,0 @@
-#ifndef __FASTPIN_ARM_NRF51_H
-#define __FASTPIN_ARM_NRF51_H
-
-#if defined(NRF51)
-/// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this
-/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
-/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
-/// The registers are data output, set output, clear output, toggle output, input, and direction
-#if 0
-template<uint8_t PIN, uint32_t _MASK, typename _DIRSET, typename _DIRCLR, typename _OUTSET, typename _OUTCLR, typename _OUT> class _ARMPIN {
-public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
-
- inline static void setOutput() { _DIRSET::r() = _MASK; }
- inline static void setInput() { _DIRCLR::r() = _MASK; }
-
- inline static void hi() __attribute__ ((always_inline)) { _OUTSET::r() = _MASK; }
- inline static void lo() __attribute__ ((always_inline)) { _OUTCLR::r() = _MASK; }
- inline static void set(register port_t val) __attribute__ ((always_inline)) { _OUT::r() = val; }
-
- inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
-
- inline static void toggle() __attribute__ ((always_inline)) { _OUT::r() ^= _MASK; }
-
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
-
- inline static port_t hival() __attribute__ ((always_inline)) { return _OUT::r() | _MASK; }
- inline static port_t loval() __attribute__ ((always_inline)) { return _OUT::r() & ~_MASK; }
- inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_OUT::r(); }
- inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
-};
-
-#define ADDR(X) *(volatile uint32_t*)X
-#define NR_GPIO_ADDR(base,offset) (*(volatile uint32_t *))((uint32_t)(base + offset))
-#define NR_DIRSET ADDR(0x50000518UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x518)
-#define NR_DIRCLR ADDR(0x5000051CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x51C)
-#define NR_OUTSET ADDR(0x50000508UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x508)
-#define NR_OUTCLR ADDR(0x5000050CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x50C)
-#define NR_OUT ADDR(0x50000504UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x504)
-
-#define _RD32_NRF(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; }};
-
-_RD32_NRF(NR_DIRSET);
-_RD32_NRF(NR_DIRCLR);
-_RD32_NRF(NR_OUTSET);
-_RD32_NRF(NR_OUTCLR);
-_RD32_NRF(NR_OUT);
-
-#define _FL_DEFPIN(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN, \
- _R(NR_DIRSET), _R(NR_DIRCLR), _R(NR_OUTSET), _R(NR_OUTCLR), _R(NR_OUT)> {};
-#else
-
-typedef struct { /*!< GPIO Structure */
- // __I uint32_t RESERVED0[321];
- __IO uint32_t OUT; /*!< Write GPIO port. */
- __IO uint32_t OUTSET; /*!< Set individual bits in GPIO port. */
- __IO uint32_t OUTCLR; /*!< Clear individual bits in GPIO port. */
- __I uint32_t IN; /*!< Read GPIO port. */
- __IO uint32_t DIR; /*!< Direction of GPIO pins. */
- __IO uint32_t DIRSET; /*!< DIR set register. */
- __IO uint32_t DIRCLR; /*!< DIR clear register. */
- __I uint32_t RESERVED1[120];
- __IO uint32_t PIN_CNF[32]; /*!< Configuration of GPIO pins. */
-} FL_NRF_GPIO_Type;
-
-#define FL_NRF_GPIO_BASE 0x50000504UL
-#define FL_NRF_GPIO ((FL_NRF_GPIO_Type *) FL_NRF_GPIO_BASE)
-
-template<uint8_t PIN, uint32_t _MASK> class _ARMPIN {
-public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
-
- inline static void setOutput() { FL_NRF_GPIO->DIRSET = _MASK; }
- inline static void setInput() { FL_NRF_GPIO->DIRCLR = _MASK; }
-
- inline static void hi() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTSET = _MASK; }
- inline static void lo() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTCLR= _MASK; }
- inline static void set(register port_t val) __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT = val; }
-
- inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
-
- inline static void toggle() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT ^= _MASK; }
-
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
-
- inline static port_t hival() __attribute__ ((always_inline)) { return FL_NRF_GPIO->OUT | _MASK; }
- inline static port_t loval() __attribute__ ((always_inline)) { return FL_NRF_GPIO->OUT & ~_MASK; }
- inline static port_ptr_t port() __attribute__ ((always_inline)) { return &FL_NRF_GPIO->OUT; }
- inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
-
- inline static bool isset() __attribute__ ((always_inline)) { return (FL_NRF_GPIO->IN & _MASK) != 0; }
-};
-
-
-#define _FL_DEFPIN(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN> {};
-#endif
-
-// Actual pin definitions
-#define MAX_PIN 31
-_FL_DEFPIN(0); _FL_DEFPIN(1); _FL_DEFPIN(2); _FL_DEFPIN(3);
-_FL_DEFPIN(4); _FL_DEFPIN(5); _FL_DEFPIN(6); _FL_DEFPIN(7);
-_FL_DEFPIN(8); _FL_DEFPIN(9); _FL_DEFPIN(10); _FL_DEFPIN(11);
-_FL_DEFPIN(12); _FL_DEFPIN(13); _FL_DEFPIN(14); _FL_DEFPIN(15);
-_FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
-_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23);
-_FL_DEFPIN(24); _FL_DEFPIN(25); _FL_DEFPIN(26); _FL_DEFPIN(27);
-_FL_DEFPIN(28); _FL_DEFPIN(29); _FL_DEFPIN(30); _FL_DEFPIN(31);
-
-#define HAS_HARDWARE_PIN_SUPPORT
-
-#endif
-
-#endif
diff --git a/platforms/arm/nrf51/fastspi_arm_nrf51.h b/platforms/arm/nrf51/fastspi_arm_nrf51.h
deleted file mode 100644
index 6299e89d..00000000
--- a/platforms/arm/nrf51/fastspi_arm_nrf51.h
+++ /dev/null
@@ -1,150 +0,0 @@
-#ifndef __INC_FASTSPI_NRF_H
-#define __INC_FASTSPI_NRF_H
-
-#ifdef NRF51
-
-#ifndef FASTLED_FORCE_SOFTWARE_SPI
-#define FASTLED_ALL_PINS_HARDWARE_SPI
-
-// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should
-// be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the
-// idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead)
-template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
-class NRF51SPIOutput {
-
- struct saveData {
- uint32_t sck;
- uint32_t mosi;
- uint32_t miso;
- uint32_t freq;
- uint32_t enable;
- } mSavedData;
-
- void saveSPIData() {
- mSavedData.sck = NRF_SPI0->PSELSCK;
- mSavedData.mosi = NRF_SPI0->PSELMOSI;
- mSavedData.miso = NRF_SPI0->PSELMISO;
- mSavedData.freq = NRF_SPI0->FREQUENCY;
- mSavedData.enable = NRF_SPI0->ENABLE;
- }
-
- void restoreSPIData() {
- NRF_SPI0->PSELSCK = mSavedData.sck;
- NRF_SPI0->PSELMOSI = mSavedData.mosi;
- NRF_SPI0->PSELMISO = mSavedData.miso;
- NRF_SPI0->FREQUENCY = mSavedData.freq;
- mSavedData.enable = NRF_SPI0->ENABLE;
- }
-
-public:
- NRF51SPIOutput() { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
- NRF51SPIOutput(Selectable *pSelect) { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
-
- // set the object representing the selectable
- void setSelect(Selectable *pSelect) { /* TODO */ }
-
- // initialize the SPI subssytem
- void init() {
- FastPin<_DATA_PIN>::setOutput();
- FastPin<_CLOCK_PIN>::setOutput();
- NRF_SPI0->PSELSCK = _CLOCK_PIN;
- NRF_SPI0->PSELMOSI = _DATA_PIN;
- NRF_SPI0->PSELMISO = 0xFFFFFFFF;
- NRF_SPI0->FREQUENCY = 0x80000000;
- NRF_SPI0->ENABLE = 1;
- NRF_SPI0->EVENTS_READY = 0;
- }
-
- // latch the CS select
- void select() { saveSPIData(); init(); }
-
- // release the CS select
- void release() { shouldWait(); restoreSPIData(); }
-
- static bool shouldWait(bool wait = false) __attribute__((always_inline)) __attribute__((always_inline)) {
- // static bool sWait=false;
- // bool oldWait = sWait;
- // sWait = wait;
- // never going to bother with waiting since we're always running the spi clock at max speed on the rfduino
- // TODO: When we set clock rate, implement/fix waiting properly, otherwise the world hangs up
- return false;
- }
-
- // wait until all queued up data has been written
- static void waitFully() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
- static void wait() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
-
- // write a byte out via SPI (returns immediately on writing register)
- static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); NRF_SPI0->TXD = b; NRF_SPI0->INTENCLR; shouldWait(true); }
-
- // write a word out via SPI (returns immediately on writing register)
- static void writeWord(uint16_t w) __attribute__((always_inline)){ writeByte(w>>8); writeByte(w & 0xFF); }
-
- // A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes)
- static void writeBytesValueRaw(uint8_t value, int len) { while(len--) { writeByte(value); } }
-
- // A full cycle of writing a value for len bytes, including select, release, and waiting
- void writeBytesValue(uint8_t value, int len) {
- select();
- while(len--) {
- writeByte(value);
- }
- waitFully();
- release();
- }
-
- // A full cycle of writing a raw block of data out, including select, release, and waiting
- template<class D> void writeBytes(uint8_t *data, int len) {
- uint8_t *end = data + len;
- select();
- while(data != end) {
- writeByte(D::adjust(*data++));
- }
- D::postBlock(len);
- waitFully();
- release();
- }
-
- void writeBytes(uint8_t *data, int len) {
- writeBytes<DATA_NOP>(data, len);
- }
-
- // write a single bit out, which bit from the passed in byte is determined by template parameter
- template <uint8_t BIT> inline static void writeBit(uint8_t b) {
- waitFully();
- NRF_SPI0->ENABLE = 0;
- if(b & 1<<BIT) {
- FastPin<_DATA_PIN>::hi();
- } else {
- FastPin<_DATA_PIN>::lo();
- }
- FastPin<_CLOCK_PIN>::toggle();
- FastPin<_CLOCK_PIN>::toggle();
- NRF_SPI0->ENABLE = 1;
- }
-
- template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
- select();
- int len = pixels.mLen;
- while(pixels.has(1)) {
- if(FLAGS & FLAG_START_BIT) {
- writeBit<0>(1);
- }
- writeByte(D::adjust(pixels.loadAndScale0()));
- writeByte(D::adjust(pixels.loadAndScale1()));
- writeByte(D::adjust(pixels.loadAndScale2()));
-
- pixels.advanceData();
- pixels.stepDithering();
- }
- D::postBlock(len);
- waitFully();
- release();
- }
-
-};
-
-#endif
-#endif
-
-#endif
diff --git a/platforms/arm/sam/clockless_block_arm_sam.h b/platforms/arm/sam/clockless_block_arm_sam.h
deleted file mode 100644
index 355f945d..00000000
--- a/platforms/arm/sam/clockless_block_arm_sam.h
+++ /dev/null
@@ -1,184 +0,0 @@
- #ifndef __INC_BLOCK_CLOCKLESS_H
-#define __INC_BLOCK_CLOCKLESS_H
-
-FASTLED_NAMESPACE_BEGIN
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//
-// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point
-// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the
-// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles.
-//
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-#if defined(__SAM3X8E__)
-#define PORT_MASK (((1<<LANES)-1) & ((FIRST_PIN==2) ? 0xFF : 0xFF))
-
-#define FASTLED_HAS_BLOCKLESS 1
-
-#define PORTD_FIRST_PIN 25
-#define PORTA_FIRST_PIN 69
-#define PORTB_FIRST_PIN 90
-
-typedef union {
- uint8_t bytes[8];
- uint32_t raw[2];
-} Lines;
-
-#define TADJUST 0
-#define TOTAL ( (T1+TADJUST) + (T2+TADJUST) + (T3+TADJUST) )
-#define T1_MARK (TOTAL - (T1+TADJUST))
-#define T2_MARK (T1_MARK - (T2+TADJUST))
-template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PORT_MASK> {
- typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t;
- typedef typename FastPin<FIRST_PIN>::port_t data_t;
-
- data_t mPinMask;
- data_ptr_t mPort;
- CMinWait<WAIT_TIME> mWait;
-public:
- virtual int size() { return CLEDController::size() * LANES; }
- virtual void init() {
- static_assert(LANES <= 8, "Maximum of 8 lanes for Due parallel controllers!");
- if(FIRST_PIN == PORTA_FIRST_PIN) {
- switch(LANES) {
- case 8: FastPin<31>::setOutput();
- case 7: FastPin<58>::setOutput();
- case 6: FastPin<100>::setOutput();
- case 5: FastPin<59>::setOutput();
- case 4: FastPin<60>::setOutput();
- case 3: FastPin<61>::setOutput();
- case 2: FastPin<68>::setOutput();
- case 1: FastPin<69>::setOutput();
- }
- } else if(FIRST_PIN == PORTD_FIRST_PIN) {
- switch(LANES) {
- case 8: FastPin<11>::setOutput();
- case 7: FastPin<29>::setOutput();
- case 6: FastPin<15>::setOutput();
- case 5: FastPin<14>::setOutput();
- case 4: FastPin<28>::setOutput();
- case 3: FastPin<27>::setOutput();
- case 2: FastPin<26>::setOutput();
- case 1: FastPin<25>::setOutput();
- }
- } else if(FIRST_PIN == PORTB_FIRST_PIN) {
- switch(LANES) {
- case 8: FastPin<97>::setOutput();
- case 7: FastPin<96>::setOutput();
- case 6: FastPin<95>::setOutput();
- case 5: FastPin<94>::setOutput();
- case 4: FastPin<93>::setOutput();
- case 3: FastPin<92>::setOutput();
- case 2: FastPin<91>::setOutput();
- case 1: FastPin<90>::setOutput();
- }
- }
- mPinMask = FastPin<FIRST_PIN>::mask();
- mPort = FastPin<FIRST_PIN>::port();
- }
-
- virtual uint16_t getMaxRefreshRate() const { return 400; }
-
- virtual void showPixels(PixelController<RGB_ORDER, LANES, PORT_MASK> & pixels) {
- mWait.wait();
- showRGBInternal(pixels);
- sei();
- mWait.mark();
- }
-
- static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
- // Serial.println("Entering show");
-
- int nLeds = allpixels.mLen;
-
- // Setup the pixel controller and load/scale the first byte
- Lines b0,b1,b2;
-
- allpixels.preStepFirstByteDithering();
- for(uint8_t i = 0; i < LANES; i++) {
- b0.bytes[i] = allpixels.loadAndScale0(i);
- }
-
- // Setup and start the clock
- TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1);
- pmc_enable_periph_clk(DUE_TIMER_ID);
- TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL);
-
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- cli();
- #endif
- uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL));
- while(nLeds--) {
- allpixels.stepDithering();
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- cli();
- if(DUE_TIMER_VAL > next_mark) {
- if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) {
- sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL;
- }
- }
- #endif
-
- // Write first byte, read next byte
- writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels);
-
- // Write second byte, read 3rd byte
- writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels);
-
- allpixels.advanceData();
- // Write third byte
- writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels);
-
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- sei();
- #endif
- }
-
- return DUE_TIMER_VAL;
- }
-
- template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, PixelController<RGB_ORDER,LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
- Lines b2;
- transpose8x1(b.bytes,b2.bytes);
-
- register uint8_t d = pixels.template getd<PX>(pixels);
- register uint8_t scale = pixels.template getscale<PX>(pixels);
-
- for(uint32_t i = 0; (i < LANES) && (i<8); i++) {
- while(DUE_TIMER_VAL < next_mark);
- next_mark = (DUE_TIMER_VAL+TOTAL);
-
- *FastPin<FIRST_PIN>::sport() = PORT_MASK;
-
- while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
- *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
-
- while((next_mark - (DUE_TIMER_VAL)) > T3);
- *FastPin<FIRST_PIN>::cport() = PORT_MASK;
-
- b3.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
- }
-
- for(uint32_t i = LANES; i < 8; i++) {
- while(DUE_TIMER_VAL < next_mark);
- next_mark = (DUE_TIMER_VAL+TOTAL);
- *FastPin<FIRST_PIN>::sport() = PORT_MASK;
-
- while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
- *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
-
- while((next_mark - DUE_TIMER_VAL) > T3);
- *FastPin<FIRST_PIN>::cport() = PORT_MASK;
- }
- }
-
-
-};
-
-#endif
-
-FASTLED_NAMESPACE_END
-
-#endif
diff --git a/platforms/arm/stm32/clockless_arm_stm32.h b/platforms/arm/stm32/clockless_arm_stm32.h
deleted file mode 100644
index e4b4de08..00000000
--- a/platforms/arm/stm32/clockless_arm_stm32.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef __INC_CLOCKLESS_ARM_STM32_H
-#define __INC_CLOCKLESS_ARM_STM32_H
-
-FASTLED_NAMESPACE_BEGIN
-// Definition for a single channel clockless controller for the stm32 family of chips, like that used in the spark core
-// See clockless.h for detailed info on how the template parameters are used.
-
-#define FASTLED_HAS_CLOCKLESS 1
-
-template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class ClocklessController : public CPixelLEDController<RGB_ORDER> {
- typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
- typedef typename FastPin<DATA_PIN>::port_t data_t;
-
- data_t mPinMask;
- data_ptr_t mPort;
- CMinWait<WAIT_TIME> mWait;
-public:
- virtual void init() {
- FastPin<DATA_PIN>::setOutput();
- mPinMask = FastPin<DATA_PIN>::mask();
- mPort = FastPin<DATA_PIN>::port();
- }
-
- virtual uint16_t getMaxRefreshRate() const { return 400; }
-
-protected:
-
- virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
- if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- mWait.mark();
- }
-
-#define _CYCCNT (*(volatile uint32_t*)(0xE0001004UL))
-
- template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
- for(register uint32_t i = BITS-1; i > 0; i--) {
- while(_CYCCNT < (T1+T2+T3-20));
- FastPin<DATA_PIN>::fastset(port, hi);
- _CYCCNT = 4;
- if(b&0x80) {
- while(_CYCCNT < (T1+T2-20));
- FastPin<DATA_PIN>::fastset(port, lo);
- } else {
- while(_CYCCNT < (T1-10));
- FastPin<DATA_PIN>::fastset(port, lo);
- }
- b <<= 1;
- }
-
- while(_CYCCNT < (T1+T2+T3-20));
- FastPin<DATA_PIN>::fastset(port, hi);
- _CYCCNT = 4;
-
- if(b&0x80) {
- while(_CYCCNT < (T1+T2-20));
- FastPin<DATA_PIN>::fastset(port, lo);
- } else {
- while(_CYCCNT < (T1-10));
- FastPin<DATA_PIN>::fastset(port, lo);
- }
- }
-
- // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
- // gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
- // Get access to the clock
- CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
- DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
- DWT->CYCCNT = 0;
-
- register data_ptr_t port = FastPin<DATA_PIN>::port();
- register data_t hi = *port | FastPin<DATA_PIN>::mask();;
- register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
- *port = lo;
-
- // Setup the pixel controller and load/scale the first byte
- pixels.preStepFirstByteDithering();
- register uint8_t b = pixels.loadAndScale0();
-
- cli();
-
- uint32_t next_mark = (T1+T2+T3);
-
- DWT->CYCCNT = 0;
- while(pixels.has(1)) {
- pixels.stepDithering();
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- cli();
- // if interrupts took longer than 45µs, punt on the current frame
- if(DWT->CYCCNT > next_mark) {
- if((DWT->CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
- }
-
- hi = *port | FastPin<DATA_PIN>::mask();
- lo = *port & ~FastPin<DATA_PIN>::mask();
- #endif
-
- // Write first byte, read next byte
- writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
- b = pixels.loadAndScale1();
-
- // Write second byte, read 3rd byte
- writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
- b = pixels.loadAndScale2();
-
- // Write third byte, read 1st byte of next pixel
- writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
- b = pixels.advanceAndLoadAndScale0();
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- sei();
- #endif
- };
-
- sei();
- return DWT->CYCCNT;
- }
-};
-
-FASTLED_NAMESPACE_END
-
- #endif
diff --git a/platforms/arm/stm32/cm3_regs.h b/platforms/arm/stm32/cm3_regs.h
deleted file mode 100644
index f81f24cb..00000000
--- a/platforms/arm/stm32/cm3_regs.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef __CM3_REGS
-#define __CM3_REGS
-
-#include <stdint.h>
-
-#ifdef __cplusplus
- #define __I volatile /*!< Defines 'read only' permissions */
-#else
- #define __I volatile const /*!< Defines 'read only' permissions */
-#endif
-#define __O volatile /*!< Defines 'write only' permissions */
-#define __IO volatile /*!< Defines 'read / write' permissions */
-
-
-typedef struct
-{
- __IO uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */
- __O uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */
- __IO uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */
- __IO uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */
-} CoreDebug_Type;
-
-#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */
-#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */
-
-#define CoreDebug_DEMCR_TRCENA_Pos 24 /*!< CoreDebug DEMCR: TRCENA Position */
-#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */
-
-typedef struct
-{
- __IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */
- __IO uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */
- __IO uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */
- __IO uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */
- __IO uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */
- __IO uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */
- __IO uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */
- __I uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */
- __IO uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */
- __IO uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */
- __IO uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */
- uint32_t RESERVED0[1];
- __IO uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */
- __IO uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */
- __IO uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */
- uint32_t RESERVED1[1];
- __IO uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */
- __IO uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */
- __IO uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */
- uint32_t RESERVED2[1];
- __IO uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */
- __IO uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */
- __IO uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */
-} DWT_Type;
-
-
-#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */
-#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */
-
-#define DWT_CTRL_CYCCNTENA_Pos 0 /*!< DWT CTRL: CYCCNTENA Position */
-#define DWT_CTRL_CYCCNTENA_Msk (0x1UL << DWT_CTRL_CYCCNTENA_Pos) /*!< DWT CTRL: CYCCNTENA Mask */
-
-#endif // __CM3_REGS
diff --git a/platforms/arm/stm32/fastpin_arm_stm32.h b/platforms/arm/stm32/fastpin_arm_stm32.h
deleted file mode 100644
index 274d0f60..00000000
--- a/platforms/arm/stm32/fastpin_arm_stm32.h
+++ /dev/null
@@ -1,178 +0,0 @@
-#ifndef __FASTPIN_ARM_STM32_H
-#define __FASTPIN_ARM_STM32_H
-
-FASTLED_NAMESPACE_BEGIN
-
-#if defined(FASTLED_FORCE_SOFTWARE_PINS)
-#warning "Software pin support forced, pin access will be sloightly slower."
-#define NO_HARDWARE_PIN_SUPPORT
-#undef HAS_HARDWARE_PIN_SUPPORT
-
-#else
-
-/// Template definition for STM32 style ARM pins, providing direct access to the various GPIO registers. Note that this
-/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
-/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
-/// The registers are data output, set output, clear output, toggle output, input, and direction
-
-template<uint8_t PIN, uint8_t _BIT, uint32_t _MASK, typename _GPIO> class _ARMPIN {
-public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
-
- #if 0
- inline static void setOutput() {
- if(_BIT<8) {
- _CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
- } else {
- _CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
- }
- }
- inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
- #endif
-
- inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; }
- inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
-
- inline static void hi() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = _MASK; }
- inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BRR = _MASK; }
- // inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = (_MASK<<16); }
- inline static void set(register port_t val) __attribute__ ((always_inline)) { _GPIO::r()->ODR = val; }
-
- inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
-
- inline static void toggle() __attribute__ ((always_inline)) { if(_GPIO::r()->ODR & _MASK) { lo(); } else { hi(); } }
-
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
-
- inline static port_t hival() __attribute__ ((always_inline)) { return _GPIO::r()->ODR | _MASK; }
- inline static port_t loval() __attribute__ ((always_inline)) { return _GPIO::r()->ODR & ~_MASK; }
- inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_GPIO::r()->ODR; }
- inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRR; }
- inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO::r()->BRR; }
- inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
-};
-
-#if defined(STM32F10X_MD)
- #define _R(T) struct __gen_struct_ ## T
- #define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile GPIO_TypeDef * r() { return T; } };
- #define _FL_IO(L,C) _RD32(GPIO ## L); _FL_DEFINE_PORT3(L, C, _R(GPIO ## L));
-#elif defined(__STM32F1__)
- #define _R(T) struct __gen_struct_ ## T
- #define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline gpio_reg_map* r() { return T->regs; } };
- #define _FL_IO(L,C) _RD32(GPIO ## L); _FL_DEFINE_PORT3(L, C, _R(GPIO ## L));
-#else
- #error "Platform not supported"
-#endif
-
-#define _FL_DEFPIN(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, BIT, 1 << BIT, _R(GPIO ## L)> {};
-
-#ifdef GPIOA
-_FL_IO(A,0);
-#endif
-#ifdef GPIOB
-_FL_IO(B,1);
-#endif
-#ifdef GPIOC
-_FL_IO(C,2);
-#endif
-#ifdef GPIOD
-_FL_IO(D,3);
-#endif
-#ifdef GPIOE
-_FL_IO(E,4);
-#endif
-#ifdef GPIOF
-_FL_IO(F,5);
-#endif
-#ifdef GPIOG
-_FL_IO(G,6);
-#endif
-
-// Actual pin definitions
-#if defined(SPARK) // Sparkfun STM32F103 based board
-
-
-
-#define MAX_PIN 19
-_FL_DEFPIN(0, 7, B);
-_FL_DEFPIN(1, 6, B);
-_FL_DEFPIN(2, 5, B);
-_FL_DEFPIN(3, 4, B);
-_FL_DEFPIN(4, 3, B);
-_FL_DEFPIN(5, 15, A);
-_FL_DEFPIN(6, 14, A);
-_FL_DEFPIN(7, 13, A);
-_FL_DEFPIN(8, 8, A);
-_FL_DEFPIN(9, 9, A);
-_FL_DEFPIN(10, 0, A);
-_FL_DEFPIN(11, 1, A);
-_FL_DEFPIN(12, 4, A);
-_FL_DEFPIN(13, 5, A);
-_FL_DEFPIN(14, 6, A);
-_FL_DEFPIN(15, 7, A);
-_FL_DEFPIN(16, 0, B);
-_FL_DEFPIN(17, 1, B);
-_FL_DEFPIN(18, 3, A);
-_FL_DEFPIN(19, 2, A);
-
-
-#define SPI_DATA 15
-#define SPI_CLOCK 13
-
-#define HAS_HARDWARE_PIN_SUPPORT
-
-#endif // SPARK
-
-#if defined(__STM32F1__) // Generic STM32F103 aka "Blue Pill"
-
-#define MAX_PIN 46
-
-_FL_DEFPIN(10, 0, A); // PA0 - PA7
-_FL_DEFPIN(11, 1, A);
-_FL_DEFPIN(12, 2, A);
-_FL_DEFPIN(13, 3, A);
-_FL_DEFPIN(14, 4, A);
-_FL_DEFPIN(15, 5, A);
-_FL_DEFPIN(16, 6, A);
-_FL_DEFPIN(17, 7, A);
-_FL_DEFPIN(29, 8, A); // PA8 - PA15
-_FL_DEFPIN(30, 9, A);
-_FL_DEFPIN(31, 10, A);
-_FL_DEFPIN(32, 11, A);
-_FL_DEFPIN(33, 12, A);
-_FL_DEFPIN(34, 13, A);
-_FL_DEFPIN(37, 14, A);
-_FL_DEFPIN(38, 15, A);
-
-_FL_DEFPIN(18, 0, B); // PB0 - PB11
-_FL_DEFPIN(19, 1, B);
-_FL_DEFPIN(20, 2, B);
-_FL_DEFPIN(39, 3, B);
-_FL_DEFPIN(40, 4, B);
-_FL_DEFPIN(41, 5, B);
-_FL_DEFPIN(42, 6, B);
-_FL_DEFPIN(43, 7, B);
-_FL_DEFPIN(45, 8, B);
-_FL_DEFPIN(46, 9, B);
-_FL_DEFPIN(21, 10, B);
-_FL_DEFPIN(22, 11, B);
-
-_FL_DEFPIN(2, 13, C); // PC13 - PC15
-_FL_DEFPIN(3, 14, C);
-_FL_DEFPIN(4, 15, C);
-
-#define SPI_DATA BOARD_SPI1_MOSI_PIN
-#define SPI_CLOCK BOARD_SPI1_SCK_PIN
-
-#define HAS_HARDWARE_PIN_SUPPORT
-
-#endif // __STM32F1__
-
-#endif // FASTLED_FORCE_SOFTWARE_PINS
-
-FASTLED_NAMESPACE_END
-
-#endif // __INC_FASTPIN_ARM_STM32
diff --git a/platforms/esp/32/clockless_esp32.h.orig b/platforms/esp/32/clockless_esp32.h.orig
deleted file mode 100644
index e0cd00da..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 bf4dd142..00000000
--- a/platforms/esp/32/clockless_rmt_esp32.h
+++ /dev/null
@@ -1,690 +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 t1 = __clock_cycles();
-
- 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/platforms/esp/8266/fastpin_esp8266.h b/platforms/esp/8266/fastpin_esp8266.h
deleted file mode 100644
index 1ce7934b..00000000
--- a/platforms/esp/8266/fastpin_esp8266.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#pragma once
-
-FASTLED_NAMESPACE_BEGIN
-
-struct FASTLED_ESP_IO {
- volatile uint32_t _GPO;
- volatile uint32_t _GPOS;
- volatile uint32_t _GPOC;
-};
-
-#define _GPB (*(FASTLED_ESP_IO*)(0x60000000+(0x300)))
-
-
-template<uint8_t PIN, uint32_t MASK> class _ESPPIN {
-
-public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
-
- inline static void setOutput() { pinMode(PIN, OUTPUT); }
- inline static void setInput() { pinMode(PIN, INPUT); }
-
- inline static void hi() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOS = MASK; } else { GP16O |= MASK; } }
- inline static void lo() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOC = MASK; } else { GP16O &= ~MASK; } }
- inline static void set(register port_t val) __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO = val; } else { GP16O = val; }}
-
- inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
-
- inline static void toggle() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO ^= MASK; } else { GP16O ^= MASK; } }
-
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
-
- inline static port_t hival() __attribute__ ((always_inline)) { if (PIN<16) { return GPO | MASK; } else { return GP16O | MASK; } }
- inline static port_t loval() __attribute__ ((always_inline)) { if (PIN<16) { return GPO & ~MASK; } else { return GP16O & ~MASK; } }
- inline static port_ptr_t port() __attribute__ ((always_inline)) { if(PIN<16) { return &_GPB._GPO; } else { return &GP16O; } }
- inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPB._GPOS; } // there is no GP160 support for this
- inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPB._GPOC; }
- inline static port_t mask() __attribute__ ((always_inline)) { return MASK; }
-
- inline static bool isset() __attribute__ ((always_inline)) { return (PIN < 16) ? (GPO & MASK) : (GP16O & MASK); }
-};
-
-#define _FL_DEFPIN(PIN, REAL_PIN) template<> class FastPin<PIN> : public _ESPPIN<REAL_PIN, (1<<(REAL_PIN & 0xFF))> {};
-
-
-#ifdef FASTLED_ESP8266_RAW_PIN_ORDER
-#define MAX_PIN 16
-_FL_DEFPIN(0,0); _FL_DEFPIN(1,1); _FL_DEFPIN(2,2); _FL_DEFPIN(3,3);
-_FL_DEFPIN(4,4); _FL_DEFPIN(5,5);
-
-// These pins should be disabled, as they always cause WDT resets
-// _FL_DEFPIN(6,6); _FL_DEFPIN(7,7);
-// _FL_DEFPIN(8,8); _FL_DEFPIN(9,9); _FL_DEFPIN(10,10); _FL_DEFPIN(11,11);
-
-_FL_DEFPIN(12,12); _FL_DEFPIN(13,13); _FL_DEFPIN(14,14); _FL_DEFPIN(15,15);
-_FL_DEFPIN(16,16);
-
-#define PORTA_FIRST_PIN 12
-#elif defined(FASTLED_ESP8266_D1_PIN_ORDER)
-#define MAX_PIN 15
-_FL_DEFPIN(0,3);
-_FL_DEFPIN(1,1);
-_FL_DEFPIN(2,16);
-_FL_DEFPIN(3,5);
-_FL_DEFPIN(4,4);
-_FL_DEFPIN(5,14);
-_FL_DEFPIN(6,12);
-_FL_DEFPIN(7,13);
-_FL_DEFPIN(8,0);
-_FL_DEFPIN(9,2);
-_FL_DEFPIN(10,15);
-_FL_DEFPIN(11,13);
-_FL_DEFPIN(12,12);
-_FL_DEFPIN(13,14);
-_FL_DEFPIN(14,4);
-_FL_DEFPIN(15,5);
-
-#define PORTA_FIRST_PIN 12
-
-#else // if defined(FASTLED_ESP8266_NODEMCU_PIN_ORDER)
-#define MAX_PIN 10
-
-// This seems to be the standard Dxx pin mapping on most of the esp boards that i've found
-_FL_DEFPIN(0,16); _FL_DEFPIN(1,5); _FL_DEFPIN(2,4); _FL_DEFPIN(3,0);
-_FL_DEFPIN(4,2); _FL_DEFPIN(5,14); _FL_DEFPIN(6,12); _FL_DEFPIN(7,13);
-_FL_DEFPIN(8,15); _FL_DEFPIN(9,3); _FL_DEFPIN(10,1);
-
-#define PORTA_FIRST_PIN 6
-
-// The rest of the pins - these are generally not available
-// _FL_DEFPIN(11,6);
-// _FL_DEFPIN(12,7); _FL_DEFPIN(13,8); _FL_DEFPIN(14,9); _FL_DEFPIN(15,10);
-// _FL_DEFPIN(16,11);
-
-#endif
-
-#define HAS_HARDWARE_PIN_SUPPORT
-
-FASTLED_NAMESPACE_END
diff --git a/release_notes.md b/release_notes.md
index 9c38eedf..e7eb7792 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -1,3 +1,18 @@
+FastLED 3.4.0
+=============
+
+* Improved reliability on ESP32 when wifi is active
+* Merged in contributed support for Adafruit boards: QT Py SAMD21, Circuit Playground Express, Circuit Playground Bluefruit, and ItsyBitsy nRF52840 Express
+* Merged in contributed support for SparkFun Artemis boards
+* Merged in contributed support for Arduino Nano Every / Arduino Uno Wifi Rev. 2
+* Merged in contributed support for Seeedstudio Odyssey and XIAO boards
+* Merged in contributed support for AVR chips ATmega1284, ATmega4809, and LGT8F328
+* XYMatrix example now supports 90-degree rotated orientation
+* Moved source code files into "src" subdirectory
+* Many small code cleanups and bug fixes
+* Released December 2020, with many thanks to everyone contributing to FastLED!
+
+
FastLED 3.3.3
=============
diff --git a/FastLED.cpp b/src/FastLED.cpp
index bfcb73c4..255dcfa3 100644
--- a/FastLED.cpp
+++ b/src/FastLED.cpp
@@ -31,8 +31,8 @@ CFastLED::CFastLED() {
}
CLEDController &CFastLED::addLeds(CLEDController *pLed,
- struct CRGB *data,
- int nLedsOrOffset, int nLedsIfOffset) {
+ struct CRGB *data,
+ int nLedsOrOffset, int nLedsIfOffset) {
int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0;
int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset;
@@ -67,7 +67,7 @@ int CFastLED::count() {
int x = 0;
CLEDController *pCur = CLEDController::head();
while( pCur) {
- x++;
+ ++x;
pCur = pCur->next();
}
return x;
@@ -204,33 +204,33 @@ extern int noise_min;
extern int noise_max;
void CFastLED::countFPS(int nFrames) {
- static int br = 0;
- static uint32_t lastframe = 0; // millis();
-
- if(br++ >= nFrames) {
- uint32_t now = millis();
- now -= lastframe;
- if( now == 0 ) {
- now = 1; // prevent division by zero below
- }
- m_nFPS = (br * 1000) / now;
- br = 0;
- lastframe = millis();
- }
+ static int br = 0;
+ static uint32_t lastframe = 0; // millis();
+
+ if(br++ >= nFrames) {
+ uint32_t now = millis();
+ now -= lastframe;
+ if(now == 0) {
+ now = 1; // prevent division by zero below
+ }
+ m_nFPS = (br * 1000) / now;
+ br = 0;
+ lastframe = millis();
+ }
}
void CFastLED::setMaxRefreshRate(uint16_t refresh, bool constrain) {
- if(constrain) {
- // if we're constraining, the new value of m_nMinMicros _must_ be higher than previously (because we're only
- // allowed to slow things down if constraining)
- if(refresh > 0) {
- m_nMinMicros = ( (1000000/refresh) > m_nMinMicros) ? (1000000/refresh) : m_nMinMicros;
- }
- } else if(refresh > 0) {
- m_nMinMicros = 1000000 / refresh;
- } else {
- m_nMinMicros = 0;
- }
+ if(constrain) {
+ // if we're constraining, the new value of m_nMinMicros _must_ be higher than previously (because we're only
+ // allowed to slow things down if constraining)
+ if(refresh > 0) {
+ m_nMinMicros = ((1000000 / refresh) > m_nMinMicros) ? (1000000 / refresh) : m_nMinMicros;
+ }
+ } else if(refresh > 0) {
+ m_nMinMicros = 1000000 / refresh;
+ } else {
+ m_nMinMicros = 0;
+ }
}
extern "C" int atexit(void (* /*func*/ )()) { return 0; }
diff --git a/FastLED.h b/src/FastLED.h
index d7b6375a..042496fc 100644
--- a/FastLED.h
+++ b/src/FastLED.h
@@ -8,12 +8,12 @@
#define FASTLED_HAS_PRAGMA_MESSAGE
#endif
-#define FASTLED_VERSION 3003002
+#define FASTLED_VERSION 3004000
#ifndef FASTLED_INTERNAL
# ifdef FASTLED_HAS_PRAGMA_MESSAGE
-# pragma message "FastLED version 3.003.003"
+# pragma message "FastLED version 3.004.000"
# else
-# warning FastLED version 3.003.003 (Not really a warning, just telling you here.)
+# warning FastLED version 3.004.000 (Not really a warning, just telling you here.)
# endif
#endif
@@ -316,11 +316,11 @@ public:
}
#if defined(__FASTLED_HAS_FIBCC) && (__FASTLED_HAS_FIBCC == 1)
- template<uint8_t NUM_LANES, template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, EOrder RGB_ORDER=RGB>
- static CLEDController &addLeds(struct CRGB *data, int nLeds) {
- static __FIBCC<CHIPSET, DATA_PIN, NUM_LANES, RGB_ORDER> c;
- return addLeds(&c, data, nLeds);
- }
+ template<uint8_t NUM_LANES, template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, EOrder RGB_ORDER=RGB>
+ static CLEDController &addLeds(struct CRGB *data, int nLeds) {
+ static __FIBCC<CHIPSET, DATA_PIN, NUM_LANES, RGB_ORDER> c;
+ return addLeds(&c, data, nLeds);
+ }
#endif
#ifdef FASTSPI_USE_DMX_SIMPLE
@@ -556,19 +556,19 @@ public:
uint16_t getFPS() { return m_nFPS; }
/// Get how many controllers have been registered
- /// @returns the number of controllers (strips) that have been added with addLeds
+ /// @returns the number of controllers (strips) that have been added with addLeds
int count();
/// Get a reference to a registered controller
- /// @returns a reference to the Nth controller
+ /// @returns a reference to the Nth controller
CLEDController & operator[](int x);
/// Get the number of leds in the first controller
- /// @returns the number of LEDs in the first controller
+ /// @returns the number of LEDs in the first controller
int size() { return (*this)[0].size(); }
/// Get a pointer to led data for the first controller
- /// @returns pointer to the CRGB buffer for the first controller
+ /// @returns pointer to the CRGB buffer for the first controller
CRGB *leds() { return (*this)[0].leds(); }
};
diff --git a/src/bitswap.cpp b/src/bitswap.cpp
new file mode 100644
index 00000000..5be71f02
--- /dev/null
+++ b/src/bitswap.cpp
@@ -0,0 +1,28 @@
+#define FASTLED_INTERNAL
+#include "FastLED.h"
+
+/// Simplified form of bits rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating
+/// data into LSB for a faster write (the code using this data can happily walk the array backwards)
+void transpose8x1_noinline(unsigned char *A, unsigned char *B) {
+ uint32_t x, y, t;
+
+ // Load the array and pack it into x and y.
+ y = *(unsigned int*)(A);
+ x = *(unsigned int*)(A+4);
+
+ // pre-transform x
+ t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
+ t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
+
+ // pre-transform y
+ t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
+ t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
+
+ // final transform
+ t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
+ y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
+ x = t;
+
+ *((uint32_t*)B) = y;
+ *((uint32_t*)(B+4)) = x;
+}
diff --git a/bitswap.h b/src/bitswap.h
index 64fed49e..79eec540 100644
--- a/bitswap.h
+++ b/src/bitswap.h
@@ -126,7 +126,7 @@ __attribute__((always_inline)) inline void swapbits8(bitswap_type in, bitswap_ty
// SWAPSB(b.c,1);
// SWAPSB(b.d,0);
- for(int i = 0; i < 8; i++) {
+ for(int i = 0; i < 8; ++i) {
just8bits work;
work.a3 = in.word[0] >> 31;
work.a2 = in.word[0] >> 23;
@@ -145,7 +145,7 @@ __attribute__((always_inline)) inline void swapbits8(bitswap_type in, bitswap_ty
/// Slow version of the 8 byte by 8 bit rotation
__attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned char *B) {
- for(int row = 0; row < 7; row++) {
+ for(int row = 0; row < 7; ++row) {
uint8_t x = A[row];
uint8_t bit = (1<<row);
diff --git a/chipsets.h b/src/chipsets.h
index 8e9051d5..60457254 100644
--- a/chipsets.h
+++ b/src/chipsets.h
@@ -16,7 +16,7 @@ FASTLED_NAMESPACE_BEGIN
#if defined(ARDUINO) //&& defined(SoftwareSerial_h)
-#if defined(SoftwareSerial_h)
+#if defined(SoftwareSerial_h) || defined(__SoftwareSerial_h)
#include <SoftwareSerial.h>
#define HAS_PIXIE
@@ -28,6 +28,7 @@ template<uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
class PixieController : public CPixelLEDController<RGB_ORDER> {
SoftwareSerial Serial;
CMinWait<2000> mWait;
+
public:
PixieController() : Serial(-1, DATA_PIN) {}
@@ -92,8 +93,8 @@ class LPD8806Controller : public CPixelLEDController<RGB_ORDER> {
};
SPI mSPI;
-public:
+public:
LPD8806Controller() {}
virtual void init() {
mSPI.init();
@@ -123,6 +124,7 @@ class WS2801Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI;
CMinWait<1000> mWaitDelay;
+
public:
WS2801Controller() {}
@@ -132,7 +134,6 @@ public:
}
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWaitDelay.wait();
mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(pixels);
@@ -166,7 +167,6 @@ public:
}
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
@@ -232,7 +232,6 @@ public:
}
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
@@ -297,7 +296,6 @@ public:
}
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
@@ -360,7 +358,6 @@ public:
}
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
@@ -418,7 +415,6 @@ public:
}
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
// Make sure the FLAG_START_BIT flag is set to ensure that an extra 1 bit is sent at the start
// of each triplet of bytes for rgb data
@@ -458,7 +454,7 @@ protected:
// We want to force all avr's to use the Trinket controller when running at 8Mhz, because even the 328's at 8Mhz
// need the more tightly defined timeframes.
-#if (CLOCKLESS_FREQUENCY == 8000000 || CLOCKLESS_FREQUENCY == 16000000 || CLOCKLESS_FREQUENCY == 24000000) // || CLOCKLESS_FREQUENCY == 48000000 || CLOCKLESS_FREQUENCY == 96000000) // 125ns/clock
+#if defined(__LGT8F__) || (CLOCKLESS_FREQUENCY == 8000000 || CLOCKLESS_FREQUENCY == 16000000 || CLOCKLESS_FREQUENCY == 24000000) // || CLOCKLESS_FREQUENCY == 48000000 || CLOCKLESS_FREQUENCY == 96000000) // 125ns/clock
#define FMUL (CLOCKLESS_FREQUENCY/8000000)
// GE8822
diff --git a/src/color.h b/src/color.h
new file mode 100644
index 00000000..63687cb5
--- /dev/null
+++ b/src/color.h
@@ -0,0 +1,84 @@
+#ifndef __INC_COLOR_H
+#define __INC_COLOR_H
+
+#include "FastLED.h"
+
+FASTLED_NAMESPACE_BEGIN
+
+///@file color.h
+/// contains definitions for color correction and temperature
+///@defgroup ColorEnums Color correction/temperature
+/// definitions for color correction and light temperatures
+///@{
+typedef enum {
+ // Color correction starting points
+
+ /// typical values for SMD5050 LEDs
+ ///@{
+ TypicalSMD5050=0xFFB0F0 /* 255, 176, 240 */,
+ TypicalLEDStrip=0xFFB0F0 /* 255, 176, 240 */,
+ ///@}
+
+ /// typical values for 8mm "pixels on a string"
+ /// also for many through-hole 'T' package LEDs
+ ///@{
+ Typical8mmPixel=0xFFE08C /* 255, 224, 140 */,
+ TypicalPixelString=0xFFE08C /* 255, 224, 140 */,
+ ///@}
+
+ /// uncorrected color
+ UncorrectedColor=0xFFFFFF
+
+} LEDColorCorrection;
+
+
+typedef enum {
+ /// @name Black-body radiation light sources
+ /// Black-body radiation light sources emit a (relatively) continuous
+ /// spectrum, and can be described as having a Kelvin 'temperature'
+ ///@{
+ /// 1900 Kelvin
+ Candle=0xFF9329 /* 1900 K, 255, 147, 41 */,
+ /// 2600 Kelvin
+ Tungsten40W=0xFFC58F /* 2600 K, 255, 197, 143 */,
+ /// 2850 Kelvin
+ Tungsten100W=0xFFD6AA /* 2850 K, 255, 214, 170 */,
+ /// 3200 Kelvin
+ Halogen=0xFFF1E0 /* 3200 K, 255, 241, 224 */,
+ /// 5200 Kelvin
+ CarbonArc=0xFFFAF4 /* 5200 K, 255, 250, 244 */,
+ /// 5400 Kelvin
+ HighNoonSun=0xFFFFFB /* 5400 K, 255, 255, 251 */,
+ /// 6000 Kelvin
+ DirectSunlight=0xFFFFFF /* 6000 K, 255, 255, 255 */,
+ /// 7000 Kelvin
+ OvercastSky=0xC9E2FF /* 7000 K, 201, 226, 255 */,
+ /// 20000 Kelvin
+ ClearBlueSky=0x409CFF /* 20000 K, 64, 156, 255 */,
+ ///@}
+
+ /// @name Gaseous light sources
+ /// Gaseous light sources emit discrete spectral bands, and while we can
+ /// approximate their aggregate hue with RGB values, they don't actually
+ /// have a proper Kelvin temperature.
+ ///@{
+ WarmFluorescent=0xFFF4E5 /* 0 K, 255, 244, 229 */,
+ StandardFluorescent=0xF4FFFA /* 0 K, 244, 255, 250 */,
+ CoolWhiteFluorescent=0xD4EBFF /* 0 K, 212, 235, 255 */,
+ FullSpectrumFluorescent=0xFFF4F2 /* 0 K, 255, 244, 242 */,
+ GrowLightFluorescent=0xFFEFF7 /* 0 K, 255, 239, 247 */,
+ BlackLightFluorescent=0xA700FF /* 0 K, 167, 0, 255 */,
+ MercuryVapor=0xD8F7FF /* 0 K, 216, 247, 255 */,
+ SodiumVapor=0xFFD1B2 /* 0 K, 255, 209, 178 */,
+ MetalHalide=0xF2FCFF /* 0 K, 242, 252, 255 */,
+ HighPressureSodium=0xFFB74C /* 0 K, 255, 183, 76 */,
+ ///@}
+
+ /// Uncorrected temperature 0xFFFFFF
+ UncorrectedTemperature=0xFFFFFF
+} ColorTemperature;
+
+FASTLED_NAMESPACE_END
+
+///@}
+#endif
diff --git a/colorpalettes.cpp b/src/colorpalettes.cpp
index 3c3a1f51..68e42f03 100644
--- a/colorpalettes.cpp
+++ b/src/colorpalettes.cpp
@@ -161,14 +161,14 @@ extern const TProgmemRGBPalette16 HeatColors_p FL_PROGMEM =
// you want a 'standard' FastLED rainbow as well.
DEFINE_GRADIENT_PALETTE( Rainbow_gp ) {
- 0, 255, 0, 0, // Red
- 32, 171, 85, 0, // Orange
- 64, 171,171, 0, // Yellow
- 96, 0,255, 0, // Green
- 128, 0,171, 85, // Aqua
- 160, 0, 0,255, // Blue
- 192, 85, 0,171, // Purple
- 224, 171, 0, 85, // Pink
- 255, 255, 0, 0};// and back to Red
+ 0, 255, 0, 0, // Red
+ 32, 171, 85, 0, // Orange
+ 64, 171, 171, 0, // Yellow
+ 96, 0, 255, 0, // Green
+ 128, 0, 171, 85, // Aqua
+ 160, 0, 0, 255, // Blue
+ 192, 85, 0, 171, // Purple
+ 224, 171, 0, 85, // Pink
+ 255, 255, 0, 0};// and back to Red
#endif
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 10d35924..a1acaa5a 100644
--- a/colorutils.cpp
+++ b/src/colorutils.cpp
@@ -13,7 +13,7 @@ FASTLED_NAMESPACE_BEGIN
void fill_solid( struct CRGB * leds, int numToFill,
const struct CRGB& color)
{
- for( int i = 0; i < numToFill; i++) {
+ for( int i = 0; i < numToFill; ++i) {
leds[i] = color;
}
}
@@ -21,7 +21,7 @@ void fill_solid( struct CRGB * leds, int numToFill,
void fill_solid( struct CHSV * targetArray, int numToFill,
const struct CHSV& hsvColor)
{
- for( int i = 0; i < numToFill; i++) {
+ for( int i = 0; i < numToFill; ++i) {
targetArray[i] = hsvColor;
}
}
@@ -41,7 +41,7 @@ void fill_rainbow( struct CRGB * pFirstLED, int numToFill,
hsv.hue = initialhue;
hsv.val = 255;
hsv.sat = 240;
- for( int i = 0; i < numToFill; i++) {
+ for( int i = 0; i < numToFill; ++i) {
pFirstLED[i] = hsv;
hsv.hue += deltahue;
}
@@ -55,7 +55,7 @@ void fill_rainbow( struct CHSV * targetArray, int numToFill,
hsv.hue = initialhue;
hsv.val = 255;
hsv.sat = 240;
- for( int i = 0; i < numToFill; i++) {
+ for( int i = 0; i < numToFill; ++i) {
targetArray[i] = hsv;
hsv.hue += deltahue;
}
@@ -98,7 +98,7 @@ void fill_gradient_RGB( CRGB* leds,
accum88 r88 = startcolor.r << 8;
accum88 g88 = startcolor.g << 8;
accum88 b88 = startcolor.b << 8;
- for( uint16_t i = startpos; i <= endpos; i++) {
+ for( uint16_t i = startpos; i <= endpos; ++i) {
leds[i] = CRGB( r88 >> 8, g88 >> 8, b88 >> 8);
r88 += rdelta87;
g88 += gdelta87;
@@ -171,7 +171,7 @@ void fill_gradient_RGB( CRGB* leds, uint16_t numLeds, const CRGB& c1, const CRGB
void nscale8_video( CRGB* leds, uint16_t num_leds, uint8_t scale)
{
- for( uint16_t i = 0; i < num_leds; i++) {
+ for( uint16_t i = 0; i < num_leds; ++i) {
leds[i].nscale8_video( scale);
}
}
@@ -204,7 +204,7 @@ void nscale8_raw( CRGB* leds, uint16_t num_leds, uint8_t scale)
void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale)
{
- for( uint16_t i = 0; i < num_leds; i++) {
+ for( uint16_t i = 0; i < num_leds; ++i) {
leds[i].nscale8( scale);
}
}
@@ -216,7 +216,7 @@ void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask)
fg = colormask.g;
fb = colormask.b;
- for( uint16_t i = 0; i < numLeds; i++) {
+ for( uint16_t i = 0; i < numLeds; ++i) {
leds[i].r = scale8_LEAVING_R1_DIRTY( leds[i].r, fr);
leds[i].g = scale8_LEAVING_R1_DIRTY( leds[i].g, fg);
leds[i].b = scale8 ( leds[i].b, fb);
@@ -261,10 +261,10 @@ CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay )
void nblend( CRGB* existing, CRGB* overlay, uint16_t count, fract8 amountOfOverlay)
{
- for( uint16_t i = count; i; i--) {
+ for( uint16_t i = count; i; --i) {
nblend( *existing, *overlay, amountOfOverlay);
- existing++;
- overlay++;
+ ++existing;
+ ++overlay;
}
}
@@ -277,7 +277,7 @@ CRGB blend( const CRGB& p1, const CRGB& p2, fract8 amountOfP2 )
CRGB* blend( const CRGB* src1, const CRGB* src2, CRGB* dest, uint16_t count, fract8 amountOfsrc2 )
{
- for( uint16_t i = 0; i < count; i++) {
+ for( uint16_t i = 0; i < count; ++i) {
dest[i] = blend(src1[i], src2[i], amountOfsrc2);
}
return dest;
@@ -338,10 +338,10 @@ CHSV& nblend( CHSV& existing, const CHSV& overlay, fract8 amountOfOverlay, TGrad
void nblend( CHSV* existing, CHSV* overlay, uint16_t count, fract8 amountOfOverlay, TGradientDirectionCode directionCode )
{
if(existing == overlay) return;
- for( uint16_t i = count; i; i--) {
+ for( uint16_t i = count; i; --i) {
nblend( *existing, *overlay, amountOfOverlay, directionCode);
- existing++;
- overlay++;
+ ++existing;
+ ++overlay;
}
}
@@ -354,7 +354,7 @@ CHSV blend( const CHSV& p1, const CHSV& p2, fract8 amountOfP2, TGradientDirectio
CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest, uint16_t count, fract8 amountOfsrc2, TGradientDirectionCode directionCode )
{
- for( uint16_t i = 0; i < count; i++) {
+ for( uint16_t i = 0; i < count; ++i) {
dest[i] = blend(src1[i], src2[i], amountOfsrc2, directionCode);
}
return dest;
@@ -385,7 +385,7 @@ void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount)
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
- for( uint16_t i = 0; i < numLeds; i++) {
+ for( uint16_t i = 0; i < numLeds; ++i) {
CRGB cur = leds[i];
CRGB part = cur;
part.nscale8( seep);
@@ -403,13 +403,29 @@ void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount)
blurColumns(leds, width, height, blur_amount);
}
-// blurRows: perform a blur1d on every row of a rectangular matrix
void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount)
{
- for( uint8_t row = 0; row < height; row++) {
+/* for( uint8_t row = 0; row < height; row++) {
CRGB* rowbase = leds + (row * width);
blur1d( rowbase, width, blur_amount);
}
+*/
+ // blur rows same as columns, for irregular matrix
+ uint8_t keep = 255 - blur_amount;
+ uint8_t seep = blur_amount >> 1;
+ for( uint8_t row = 0; row < height; row++) {
+ CRGB carryover = CRGB::Black;
+ for( uint8_t i = 0; i < width; i++) {
+ CRGB cur = leds[XY(i,row)];
+ CRGB part = cur;
+ part.nscale8( seep);
+ cur.nscale8( keep);
+ cur += carryover;
+ if( i) leds[XY(i-1,row)] += part;
+ leds[XY(i,row)] = cur;
+ carryover = part;
+ }
+ }
}
// blurColumns: perform a blur1d on each column of a rectangular matrix
@@ -418,9 +434,9 @@ void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount)
// blur columns
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
- for( uint8_t col = 0; col < width; col++) {
+ for( uint8_t col = 0; col < width; ++col) {
CRGB carryover = CRGB::Black;
- for( uint8_t i = 0; i < height; i++) {
+ for( uint8_t i = 0; i < height; ++i) {
CRGB cur = leds[XY(col,i)];
CRGB part = cur;
part.nscale8( seep);
@@ -529,7 +545,7 @@ CRGB ColorFromPalette( const CRGBPalette16& pal, uint8_t index, uint8_t brightne
if( hi4 == 15 ) {
entry = &(pal[0]);
} else {
- entry++;
+ ++entry;
}
uint8_t f2 = lo4 << 4;
@@ -556,25 +572,25 @@ CRGB ColorFromPalette( const CRGBPalette16& pal, uint8_t index, uint8_t brightne
if( brightness != 255) {
if( brightness ) {
- brightness++; // adjust for rounding
+ ++brightness; // adjust for rounding
// Now, since brightness is nonzero, we don't need the full scale8_video logic;
// we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
if( red1 ) {
red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- red1++;
+ ++red1;
#endif
}
if( green1 ) {
green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- green1++;
+ ++green1;
#endif
}
if( blue1 ) {
blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- blue1++;
+ ++blue1;
#endif
}
cleanup_R1();
@@ -634,25 +650,25 @@ CRGB ColorFromPalette( const TProgmemRGBPalette16& pal, uint8_t index, uint8_t b
if( brightness != 255) {
if( brightness ) {
- brightness++; // adjust for rounding
+ ++brightness; // adjust for rounding
// Now, since brightness is nonzero, we don't need the full scale8_video logic;
// we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
if( red1 ) {
red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- red1++;
+ ++red1;
#endif
}
if( green1 ) {
green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- green1++;
+ ++green1;
#endif
}
if( blue1 ) {
blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- blue1++;
+ ++blue1;
#endif
}
cleanup_R1();
@@ -698,7 +714,7 @@ CRGB ColorFromPalette( const CRGBPalette32& pal, uint8_t index, uint8_t brightne
if( hi5 == 31 ) {
entry = &(pal[0]);
} else {
- entry++;
+ ++entry;
}
uint8_t f2 = lo3 << 5;
@@ -725,25 +741,25 @@ CRGB ColorFromPalette( const CRGBPalette32& pal, uint8_t index, uint8_t brightne
if( brightness != 255) {
if( brightness ) {
- brightness++; // adjust for rounding
+ ++brightness; // adjust for rounding
// Now, since brightness is nonzero, we don't need the full scale8_video logic;
// we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
if( red1 ) {
red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- red1++;
+ ++red1;
#endif
}
if( green1 ) {
green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- green1++;
+ ++green1;
#endif
}
if( blue1 ) {
blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- blue1++;
+ ++blue1;
#endif
}
cleanup_R1();
@@ -809,25 +825,25 @@ CRGB ColorFromPalette( const TProgmemRGBPalette32& pal, uint8_t index, uint8_t b
if( brightness != 255) {
if( brightness ) {
- brightness++; // adjust for rounding
+ ++brightness; // adjust for rounding
// Now, since brightness is nonzero, we don't need the full scale8_video logic;
// we can just to scale8 and then add one (unless scale8 fixed) to all nonzero inputs.
if( red1 ) {
red1 = scale8_LEAVING_R1_DIRTY( red1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- red1++;
+ ++red1;
#endif
}
if( green1 ) {
green1 = scale8_LEAVING_R1_DIRTY( green1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- green1++;
+ ++green1;
#endif
}
if( blue1 ) {
blue1 = scale8_LEAVING_R1_DIRTY( blue1, brightness);
#if !(FASTLED_SCALE8_FIXED==1)
- blue1++;
+ ++blue1;
#endif
}
cleanup_R1();
@@ -852,7 +868,7 @@ CRGB ColorFromPalette( const CRGBPalette256& pal, uint8_t index, uint8_t brightn
uint8_t blue = entry->blue;
if( brightness != 255) {
- brightness++; // adjust for rounding
+ ++brightness; // adjust for rounding
red = scale8_video_LEAVING_R1_DIRTY( red, brightness);
green = scale8_video_LEAVING_R1_DIRTY( green, brightness);
blue = scale8_video_LEAVING_R1_DIRTY( blue, brightness);
@@ -883,7 +899,7 @@ CHSV ColorFromPalette( const struct CHSVPalette16& pal, uint8_t index, uint8_t b
if( hi4 == 15 ) {
entry = &(pal[0]);
} else {
- entry++;
+ ++entry;
}
uint8_t f2 = lo4 << 4;
@@ -973,7 +989,7 @@ CHSV ColorFromPalette( const struct CHSVPalette32& pal, uint8_t index, uint8_t b
if( hi5 == 31 ) {
entry = &(pal[0]);
} else {
- entry++;
+ ++entry;
}
uint8_t f2 = lo3 << 5;
@@ -1050,14 +1066,14 @@ CHSV ColorFromPalette( const struct CHSVPalette256& pal, uint8_t index, uint8_t
void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette256& destpal256)
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal16, i);
}
}
void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256& destpal256)
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal16, i);
}
}
@@ -1065,7 +1081,7 @@ void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette256&
void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32& destpal32)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
uint8_t j = i * 2;
destpal32[j+0] = srcpal16[i];
destpal32[j+1] = srcpal16[i];
@@ -1074,7 +1090,7 @@ void UpscalePalette(const struct CRGBPalette16& srcpal16, struct CRGBPalette32&
void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32& destpal32)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
uint8_t j = i * 2;
destpal32[j+0] = srcpal16[i];
destpal32[j+1] = srcpal16[i];
@@ -1083,14 +1099,14 @@ void UpscalePalette(const struct CHSVPalette16& srcpal16, struct CHSVPalette32&
void UpscalePalette(const struct CRGBPalette32& srcpal32, struct CRGBPalette256& destpal256)
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal32, i);
}
}
void UpscalePalette(const struct CHSVPalette32& srcpal32, struct CHSVPalette256& destpal256)
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
destpal256[(uint8_t)(i)] = ColorFromPalette( srcpal32, i);
}
}
@@ -1117,18 +1133,18 @@ void nblendPaletteTowardPalette( CRGBPalette16& current, CRGBPalette16& target,
p2 = (uint8_t*)target.entries;
const uint8_t totalChannels = sizeof(CRGBPalette16);
- for( uint8_t i = 0; i < totalChannels; i++) {
+ for( uint8_t i = 0; i < totalChannels; ++i) {
// if the values are equal, no changes are needed
if( p1[i] == p2[i] ) { continue; }
// if the current value is less than the target, increase it by one
- if( p1[i] < p2[i] ) { p1[i]++; changes++; }
+ if( p1[i] < p2[i] ) { ++p1[i]; ++changes; }
// if the current value is greater than the target,
// increase it by one (or two if it's still greater).
if( p1[i] > p2[i] ) {
- p1[i]--; changes++;
- if( p1[i] > p2[i] ) { p1[i]--; }
+ --p1[i]; ++changes;
+ if( p1[i] > p2[i] ) { --p1[i]; }
}
// if we've hit the maximum number of changes, exit
@@ -1182,14 +1198,14 @@ CRGB& napplyGamma_video( CRGB& rgb, float gammaR, float gammaG, float gammaB)
void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gamma)
{
- for( uint16_t i = 0; i < count; i++) {
+ for( uint16_t i = 0; i < count; ++i) {
rgbarray[i] = applyGamma_video( rgbarray[i], gamma);
}
}
void napplyGamma_video( CRGB* rgbarray, uint16_t count, float gammaR, float gammaG, float gammaB)
{
- for( uint16_t i = 0; i < count; i++) {
+ for( uint16_t i = 0; i < count; ++i) {
rgbarray[i] = applyGamma_video( rgbarray[i], gammaR, gammaG, gammaB);
}
}
diff --git a/colorutils.h b/src/colorutils.h
index 4fcf3940..f09d525f 100644
--- a/colorutils.h
+++ b/src/colorutils.h
@@ -168,7 +168,7 @@ void fill_gradient( T* targetArray,
accum88 hue88 = startcolor.hue << 8;
accum88 sat88 = startcolor.sat << 8;
accum88 val88 = startcolor.val << 8;
- for( uint16_t i = startpos; i <= endpos; i++) {
+ for( uint16_t i = startpos; i <= endpos; ++i) {
targetArray[i] = CHSV( hue88 >> 8, sat88 >> 8, val88 >> 8);
hue88 += huedelta87;
sat88 += satdelta87;
@@ -452,17 +452,17 @@ public:
CHSVPalette16( const CHSVPalette16& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
CHSVPalette16& operator=( const CHSVPalette16& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
CHSVPalette16( const TProgmemHSVPalette16& rhs)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
entries[i].hue = xyz.red;
entries[i].sat = xyz.green;
@@ -471,7 +471,7 @@ public:
}
CHSVPalette16& operator=( const TProgmemHSVPalette16& rhs)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
entries[i].hue = xyz.red;
entries[i].sat = xyz.green;
@@ -508,10 +508,10 @@ public:
const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
if( p == q) return true;
- for( uint8_t i = 0; i < (sizeof( entries)); i++) {
+ for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
if( *p != *q) return false;
- p++;
- q++;
+ ++p;
+ ++q;
}
return true;
}
@@ -555,11 +555,11 @@ public:
CHSVPalette256( const CHSVPalette256& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
CHSVPalette256& operator=( const CHSVPalette256& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
@@ -613,10 +613,10 @@ public:
const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
if( p == q) return true;
- for( uint16_t i = 0; i < (sizeof( entries)); i++) {
+ for( uint16_t i = 0; i < (sizeof( entries)); ++i) {
if( *p != *q) return false;
- p++;
- q++;
+ ++p;
+ ++q;
}
return true;
}
@@ -660,45 +660,45 @@ public:
CRGBPalette16( const CRGBPalette16& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
CRGBPalette16( const CRGB rhs[16])
{
- memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
}
CRGBPalette16& operator=( const CRGBPalette16& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
CRGBPalette16& operator=( const CRGB rhs[16])
{
- memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
return *this;
}
CRGBPalette16( const CHSVPalette16& rhs)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
}
CRGBPalette16( const CHSV rhs[16])
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
}
}
CRGBPalette16& operator=( const CHSVPalette16& rhs)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
return *this;
}
CRGBPalette16& operator=( const CHSV rhs[16])
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
}
return *this;
@@ -706,13 +706,13 @@ public:
CRGBPalette16( const TProgmemRGBPalette16& rhs)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
}
}
CRGBPalette16& operator=( const TProgmemRGBPalette16& rhs)
{
- for( uint8_t i = 0; i < 16; i++) {
+ for( uint8_t i = 0; i < 16; ++i) {
entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
}
return *this;
@@ -723,10 +723,10 @@ public:
const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
if( p == q) return true;
- for( uint8_t i = 0; i < (sizeof( entries)); i++) {
+ for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
if( *p != *q) return false;
- p++;
- q++;
+ ++p;
+ ++q;
}
return true;
}
@@ -828,7 +828,7 @@ public:
uint16_t count = 0;
do {
u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
- count++;;
+ ++count;
} while ( u.index != 255);
int8_t lastSlotUsed = -1;
@@ -840,7 +840,7 @@ public:
uint8_t istart8 = 0;
uint8_t iend8 = 0;
while( indexstart < 255) {
- progent++;
+ ++progent;
u.dword = FL_PGM_READ_DWORD_NEAR( progent);
int indexend = u.index;
CRGB rgbend( u.r, u.g, u.b);
@@ -870,7 +870,7 @@ public:
uint16_t count = 0;
do {
u = *(ent + count);
- count++;;
+ ++count;
} while ( u.index != 255);
int8_t lastSlotUsed = -1;
@@ -883,7 +883,7 @@ public:
uint8_t istart8 = 0;
uint8_t iend8 = 0;
while( indexstart < 255) {
- ent++;
+ ++ent;
u = *ent;
int indexend = u.index;
CRGB rgbend( u.r, u.g, u.b);
@@ -918,7 +918,7 @@ public:
const CHSV& c08,const CHSV& c09,const CHSV& c10,const CHSV& c11,
const CHSV& c12,const CHSV& c13,const CHSV& c14,const CHSV& c15 )
{
- for( uint8_t i = 0; i < 2; i++) {
+ for( uint8_t i = 0; i < 2; ++i) {
entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
@@ -928,17 +928,17 @@ public:
CHSVPalette32( const CHSVPalette32& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
CHSVPalette32& operator=( const CHSVPalette32& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
CHSVPalette32( const TProgmemHSVPalette32& rhs)
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
entries[i].hue = xyz.red;
entries[i].sat = xyz.green;
@@ -947,7 +947,7 @@ public:
}
CHSVPalette32& operator=( const TProgmemHSVPalette32& rhs)
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
CRGB xyz = FL_PGM_READ_DWORD_NEAR( rhs + i);
entries[i].hue = xyz.red;
entries[i].sat = xyz.green;
@@ -984,10 +984,10 @@ public:
const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
if( p == q) return true;
- for( uint8_t i = 0; i < (sizeof( entries)); i++) {
+ for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
if( *p != *q) return false;
- p++;
- q++;
+ ++p;
+ ++q;
}
return true;
}
@@ -1024,7 +1024,7 @@ public:
const CRGB& c08,const CRGB& c09,const CRGB& c10,const CRGB& c11,
const CRGB& c12,const CRGB& c13,const CRGB& c14,const CRGB& c15 )
{
- for( uint8_t i = 0; i < 2; i++) {
+ for( uint8_t i = 0; i < 2; ++i) {
entries[0+i]=c00; entries[2+i]=c01; entries[4+i]=c02; entries[6+i]=c03;
entries[8+i]=c04; entries[10+i]=c05; entries[12+i]=c06; entries[14+i]=c07;
entries[16+i]=c08; entries[18+i]=c09; entries[20+i]=c10; entries[22+i]=c11;
@@ -1034,45 +1034,45 @@ public:
CRGBPalette32( const CRGBPalette32& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
CRGBPalette32( const CRGB rhs[32])
{
- memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
}
CRGBPalette32& operator=( const CRGBPalette32& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
CRGBPalette32& operator=( const CRGB rhs[32])
{
- memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
return *this;
}
CRGBPalette32( const CHSVPalette32& rhs)
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
}
CRGBPalette32( const CHSV rhs[32])
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
}
}
CRGBPalette32& operator=( const CHSVPalette32& rhs)
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
return *this;
}
CRGBPalette32& operator=( const CHSV rhs[32])
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
}
return *this;
@@ -1080,13 +1080,13 @@ public:
CRGBPalette32( const TProgmemRGBPalette32& rhs)
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
}
}
CRGBPalette32& operator=( const TProgmemRGBPalette32& rhs)
{
- for( uint8_t i = 0; i < 32; i++) {
+ for( uint8_t i = 0; i < 32; ++i) {
entries[i] = FL_PGM_READ_DWORD_NEAR( rhs + i);
}
return *this;
@@ -1097,10 +1097,10 @@ public:
const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
if( p == q) return true;
- for( uint8_t i = 0; i < (sizeof( entries)); i++) {
+ for( uint8_t i = 0; i < (sizeof( entries)); ++i) {
if( *p != *q) return false;
- p++;
- q++;
+ ++p;
+ ++q;
}
return true;
}
@@ -1225,7 +1225,7 @@ public:
uint16_t count = 0;
do {
u.dword = FL_PGM_READ_DWORD_NEAR(progent + count);
- count++;;
+ ++count;
} while ( u.index != 255);
int8_t lastSlotUsed = -1;
@@ -1237,7 +1237,7 @@ public:
uint8_t istart8 = 0;
uint8_t iend8 = 0;
while( indexstart < 255) {
- progent++;
+ ++progent;
u.dword = FL_PGM_READ_DWORD_NEAR( progent);
int indexend = u.index;
CRGB rgbend( u.r, u.g, u.b);
@@ -1267,7 +1267,7 @@ public:
uint16_t count = 0;
do {
u = *(ent + count);
- count++;;
+ ++count;
} while ( u.index != 255);
int8_t lastSlotUsed = -1;
@@ -1280,7 +1280,7 @@ public:
uint8_t istart8 = 0;
uint8_t iend8 = 0;
while( indexstart < 255) {
- ent++;
+ ++ent;
u = *ent;
int indexend = u.index;
CRGB rgbend( u.r, u.g, u.b);
@@ -1322,45 +1322,45 @@ public:
CRGBPalette256( const CRGBPalette256& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
}
CRGBPalette256( const CRGB rhs[256])
{
- memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
}
CRGBPalette256& operator=( const CRGBPalette256& rhs)
{
- memmove8( &(entries[0]), &(rhs.entries[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs.entries[0]), sizeof( entries));
return *this;
}
CRGBPalette256& operator=( const CRGB rhs[256])
{
- memmove8( &(entries[0]), &(rhs[0]), sizeof( entries));
+ memmove8( (void *) &(entries[0]), &(rhs[0]), sizeof( entries));
return *this;
}
CRGBPalette256( const CHSVPalette256& rhs)
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
}
CRGBPalette256( const CHSV rhs[256])
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
}
}
CRGBPalette256& operator=( const CHSVPalette256& rhs)
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
entries[i] = rhs.entries[i]; // implicit HSV-to-RGB conversion
}
return *this;
}
CRGBPalette256& operator=( const CHSV rhs[256])
{
- for( int i = 0; i < 256; i++) {
+ for( int i = 0; i < 256; ++i) {
entries[i] = rhs[i]; // implicit HSV-to-RGB conversion
}
return *this;
@@ -1393,10 +1393,10 @@ public:
const uint8_t* p = (const uint8_t*)(&(this->entries[0]));
const uint8_t* q = (const uint8_t*)(&(rhs.entries[0]));
if( p == q) return true;
- for( uint16_t i = 0; i < (sizeof( entries)); i++) {
+ for( uint16_t i = 0; i < (sizeof( entries)); ++i) {
if( *p != *q) return false;
- p++;
- q++;
+ ++p;
+ ++q;
}
return true;
}
@@ -1475,7 +1475,7 @@ public:
int indexstart = 0;
while( indexstart < 255) {
- progent++;
+ ++progent;
u.dword = FL_PGM_READ_DWORD_NEAR( progent);
int indexend = u.index;
CRGB rgbend( u.r, u.g, u.b);
@@ -1494,7 +1494,7 @@ public:
int indexstart = 0;
while( indexstart < 255) {
- ent++;
+ ++ent;
u = *ent;
int indexend = u.index;
CRGB rgbend( u.r, u.g, u.b);
@@ -1557,7 +1557,7 @@ void fill_palette(CRGB* L, uint16_t N, uint8_t startIndex, uint8_t incIndex,
const PALETTE& pal, uint8_t brightness, TBlendType blendType)
{
uint8_t colorIndex = startIndex;
- for( uint16_t i = 0; i < N; i++) {
+ for( uint16_t i = 0; i < N; ++i) {
L[i] = ColorFromPalette( pal, colorIndex, brightness, blendType);
colorIndex += incIndex;
}
@@ -1572,7 +1572,7 @@ void map_data_into_colors_through_palette(
uint8_t opacity=255,
TBlendType blendType=LINEARBLEND)
{
- for( uint16_t i = 0; i < dataCount; i++) {
+ for( uint16_t i = 0; i < dataCount; ++i) {
uint8_t d = dataArray[i];
CRGB rgb = ColorFromPalette( pal, d, brightness, blendType);
if( opacity == 255 ) {
diff --git a/controller.h b/src/controller.h
index 30e4c111..fe32d70d 100644
--- a/controller.h
+++ b/src/controller.h
@@ -50,7 +50,7 @@ protected:
/// set all the leds on the controller to a given color
///@param data the crgb color to set the leds to
- ///@param nLeds the numner of leds to set to this color
+ ///@param nLeds the number of leds to set to this color
///@param scale the rgb scaling value for outputting color
virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) = 0;
@@ -154,7 +154,7 @@ public:
CRGB adj(0,0,0);
if(scale > 0) {
- for(uint8_t i = 0; i < 3; i++) {
+ for(uint8_t i = 0; i < 3; ++i) {
uint8_t cc = colorCorrection.raw[i];
uint8_t ct = colorTemperature.raw[i];
if(cc > 0 && ct > 0) {
@@ -195,13 +195,13 @@ struct PixelController {
mScale = other.mScale;
mAdvance = other.mAdvance;
mLenRemaining = mLen = other.mLen;
- for(int i = 0; i < LANES; i++) { mOffsets[i] = other.mOffsets[i]; }
+ for(int i = 0; i < LANES; ++i) { mOffsets[i] = other.mOffsets[i]; }
}
void initOffsets(int len) {
int nOffset = 0;
- for(int i = 0; i < LANES; i++) {
+ for(int i = 0; i < LANES; ++i) {
mOffsets[i] = nOffset;
if((1<<i) & MASK) { nOffset += (len * mAdvance); }
}
@@ -256,7 +256,7 @@ struct PixelController {
// R is the digther signal 'counter'.
static uint8_t R = 0;
- R++;
+ ++R;
// R is wrapped around at 2^ditherBits,
// so if ditherBits is 2, R will cycle through (0,1,2,3)
@@ -293,14 +293,14 @@ struct PixelController {
// actual dithering.
// Setup the initial D and E values
- for(int i = 0; i < 3; i++) {
+ for(int i = 0; i < 3; ++i) {
uint8_t s = mScale.raw[i];
e[i] = s ? (256/s) + 1 : 0;
d[i] = scale8(Q, e[i]);
#if (FASTLED_SCALE8_FIXED == 1)
- if(d[i]) (d[i]--);
+ if(d[i]) (--d[i]);
#endif
- if(e[i]) e[i]--;
+ if(e[i]) --e[i];
}
#endif
}
@@ -324,7 +324,7 @@ struct PixelController {
__attribute__((always_inline)) inline int advanceBy() { return mAdvance; }
// advance the data pointer forward, adjust position counter
- __attribute__((always_inline)) inline void advanceData() { mData += mAdvance; mLenRemaining--;}
+ __attribute__((always_inline)) inline void advanceData() { mData += mAdvance; --mLenRemaining;}
// step the dithering forward
__attribute__((always_inline)) inline void stepDithering() {
@@ -388,28 +388,28 @@ struct PixelController {
template<EOrder RGB_ORDER, int LANES=1, uint32_t MASK=0xFFFFFFFF> class CPixelLEDController : public CLEDController {
protected:
- virtual void showPixels(PixelController<RGB_ORDER,LANES,MASK> & pixels) = 0;
-
- /// set all the leds on the controller to a given color
- ///@param data the crgb color to set the leds to
- ///@param nLeds the numner of leds to set to this color
- ///@param scale the rgb scaling value for outputting color
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER, LANES, MASK> pixels(data, nLeds, scale, getDither());
- showPixels(pixels);
- }
-
-/// write the passed in rgb data out to the leds managed by this controller
-///@param data the rgb data to write out to the strip
-///@param nLeds the number of leds being written out
-///@param scale the rgb scaling to apply to each led before writing it out
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER, LANES, MASK> pixels(data, nLeds, scale, getDither());
- showPixels(pixels);
- }
+ virtual void showPixels(PixelController<RGB_ORDER,LANES,MASK> & pixels) = 0;
+
+ /// set all the leds on the controller to a given color
+ ///@param data the crgb color to set the leds to
+ ///@param nLeds the numner of leds to set to this color
+ ///@param scale the rgb scaling value for outputting color
+ virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
+ PixelController<RGB_ORDER, LANES, MASK> pixels(data, nLeds, scale, getDither());
+ showPixels(pixels);
+ }
+
+ /// write the passed in rgb data out to the leds managed by this controller
+ ///@param data the rgb data to write out to the strip
+ ///@param nLeds the number of leds being written out
+ ///@param scale the rgb scaling to apply to each led before writing it out
+ virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
+ PixelController<RGB_ORDER, LANES, MASK> pixels(data, nLeds, scale, getDither());
+ showPixels(pixels);
+ }
public:
- CPixelLEDController() : CLEDController() {}
+ CPixelLEDController() : CLEDController() {}
};
diff --git a/cpp_compat.h b/src/cpp_compat.h
index ab5b773a..ab5b773a 100644
--- a/cpp_compat.h
+++ b/src/cpp_compat.h
diff --git a/dmx.h b/src/dmx.h
index 04cb5de0..04cb5de0 100644
--- a/dmx.h
+++ b/src/dmx.h
diff --git a/fastled_config.h b/src/fastled_config.h
index 6e415274..6e415274 100644
--- a/fastled_config.h
+++ b/src/fastled_config.h
diff --git a/fastled_delay.h b/src/fastled_delay.h
index 4649f7d0..a14e8a29 100644
--- a/fastled_delay.h
+++ b/src/fastled_delay.h
@@ -12,6 +12,7 @@ FASTLED_NAMESPACE_BEGIN
/// this should make sure that chipsets that have
template<int WAIT> class CMinWait {
uint16_t mLastMicros;
+
public:
CMinWait() { mLastMicros = 0; }
@@ -51,8 +52,8 @@ public:
// predeclaration to not upset the compiler
template<int CYCLES> inline void delaycycles();
template<int CYCLES> inline void delaycycles_min1() {
- delaycycles<1>();
- delaycycles<CYCLES-1>();
+ delaycycles<1>();
+ delaycycles<CYCLES-1>();
}
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 ed2b8e7e..085a7d1b 100644
--- a/fastpin.h
+++ b/src/fastpin.h
@@ -42,6 +42,7 @@ class Pin : public Selectable {
mPort = (volatile RwReg*)portOutputRegister(digitalPinToPort(mPin));
mInPort = (volatile RoReg*)portInputRegister(digitalPinToPort(mPin));
}
+
public:
Pin(int pin) : mPin(pin) { _init(); }
@@ -98,6 +99,7 @@ class Pin : public Selectable {
mPort = NULL;
mInPort = NULL;
}
+
public:
Pin(int pin) : mPin(pin) { _init(); }
@@ -169,6 +171,7 @@ template<uint8_t PIN> class FastPin {
sInPort = portInputRegister(digitalPinToPort(PIN));
#endif
}
+
public:
typedef volatile RwReg * port_ptr_t;
typedef RwReg port_t;
@@ -206,8 +209,8 @@ template<uint8_t PIN> class FastPin {
static_assert(validpin(), "Invalid pin specified");
- static void _init() {
- }
+ static void _init() { }
+
public:
typedef volatile RwReg * port_ptr_t;
typedef RwReg port_t;
@@ -253,15 +256,17 @@ template<uint8_t port> struct __FL_PORT_INFO {
// are numeric in nature, e.g. GPIO0, GPIO1. Use _FL_DEFINE_PORT3 for ports that are letters.
// The first parameter will be the letter, the second parameter will be an integer/counter of smoe kind
// (this is because attempts to turn macro parameters into character constants break in some compilers)
-#define _FL_DEFINE_PORT(L, BASE) template<> struct __FL_PORT_INFO<L> { static bool hasPort() { return 1; } \
- static const char *portName() { return #L; } \
- typedef BASE __t_baseType; \
- static const void *portAddr() { return (void*)&__t_baseType::r(); } };
-
-#define _FL_DEFINE_PORT3(L, LC, BASE) template<> struct __FL_PORT_INFO<LC> { static bool hasPort() { return 1; } \
- static const char *portName() { return #L; } \
- typedef BASE __t_baseType; \
- static const void *portAddr() { return (void*)&__t_baseType::r(); } };
+#define _FL_DEFINE_PORT(L, BASE) template<> struct __FL_PORT_INFO<L> { \
+ static bool hasPort() { return 1; } \
+ static const char *portName() { return #L; } \
+ typedef BASE __t_baseType; \
+ static const void *portAddr() { return (void*)&__t_baseType::r(); } };
+
+#define _FL_DEFINE_PORT3(L, LC, BASE) template<> struct __FL_PORT_INFO<LC> { \
+ static bool hasPort() { return 1; } \
+ static const char *portName() { return #L; } \
+ typedef BASE __t_baseType; \
+ static const void *portAddr() { return (void*)&__t_baseType::r(); } };
FASTLED_NAMESPACE_END
diff --git a/fastspi.h b/src/fastspi.h
index 3996de47..ae084f84 100644
--- a/fastspi.h
+++ b/src/fastspi.h
@@ -132,6 +132,11 @@ class SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> : public AVRUSART1SP
#endif
+#elif defined(ARDUNIO_CORE_SPI)
+
+template<uint32_t SPI_SPEED>
+class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public ArdunioCoreSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED, SPI> {};
+
#endif
#else
diff --git a/fastspi_bitbang.h b/src/fastspi_bitbang.h
index 019b6dc0..86663f17 100644
--- a/fastspi_bitbang.h
+++ b/src/fastspi_bitbang.h
@@ -203,6 +203,7 @@ private:
}
#endif
}
+
public:
// select the SPI output (TODO: research whether this really means hi or lo. Alt TODO: move select responsibility out of the SPI classes
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 00c41d34..a12a962a 100644
--- a/fastspi_ref.h
+++ b/src/fastspi_ref.h
@@ -11,6 +11,7 @@ FASTLED_NAMESPACE_BEGIN
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class REFHardwareSPIOutput {
Selectable *m_pSelect;
+
public:
SAMHardwareSPIOutput() { m_pSelect = NULL; }
SAMHArdwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
diff --git a/fastspi_types.h b/src/fastspi_types.h
index 5510bba8..ea7d46ce 100644
--- a/fastspi_types.h
+++ b/src/fastspi_types.h
@@ -19,9 +19,9 @@ FASTLED_NAMESPACE_BEGIN
/// TODO: Convinience macro for building these
class DATA_NOP {
public:
- static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data) { return data; }
- static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data, register uint8_t scale) { return scale8(data, scale); }
- static __attribute__((always_inline)) inline void postBlock(int /* len */) { }
+ static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data) { return data; }
+ static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data, register uint8_t scale) { return scale8(data, scale); }
+ static __attribute__((always_inline)) inline void postBlock(int /* len */) { }
};
#define FLAG_START_BIT 0x80
diff --git a/hsv2rgb.cpp b/src/hsv2rgb.cpp
index cdb576bc..4585a544 100644
--- a/hsv2rgb.cpp
+++ b/src/hsv2rgb.cpp
@@ -440,21 +440,23 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
if( sat == 0) {
r = 255; b = 255; g = 255;
} else {
+ uint8_t desat = 255 - sat;
+ desat = scale8_video( desat, desat);
+
+ uint8_t satscale = 255 - desat;
+ //satscale = sat; // uncomment to revert to pre-2021 saturation behavior
+
//nscale8x3_video( r, g, b, sat);
#if (FASTLED_SCALE8_FIXED==1)
- if( r ) r = scale8_LEAVING_R1_DIRTY( r, sat);
- if( g ) g = scale8_LEAVING_R1_DIRTY( g, sat);
- if( b ) b = scale8_LEAVING_R1_DIRTY( b, sat);
+ r = scale8_LEAVING_R1_DIRTY( r, satscale);
+ g = scale8_LEAVING_R1_DIRTY( g, satscale);
+ b = scale8_LEAVING_R1_DIRTY( b, satscale);
+ cleanup_R1();
#else
- if( r ) r = scale8_LEAVING_R1_DIRTY( r, sat) + 1;
- if( g ) g = scale8_LEAVING_R1_DIRTY( g, sat) + 1;
- if( b ) b = scale8_LEAVING_R1_DIRTY( b, sat) + 1;
+ if( r ) r = scale8( r, satscale) + 1;
+ if( g ) g = scale8( g, satscale) + 1;
+ if( b ) b = scale8( b, satscale) + 1;
#endif
- cleanup_R1();
-
- uint8_t desat = 255 - sat;
- desat = scale8( desat, desat);
-
uint8_t brightness_floor = desat;
r += brightness_floor;
g += brightness_floor;
@@ -471,15 +473,15 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
} else {
// nscale8x3_video( r, g, b, val);
#if (FASTLED_SCALE8_FIXED==1)
- if( r ) r = scale8_LEAVING_R1_DIRTY( r, val);
- if( g ) g = scale8_LEAVING_R1_DIRTY( g, val);
- if( b ) b = scale8_LEAVING_R1_DIRTY( b, val);
+ r = scale8_LEAVING_R1_DIRTY( r, val);
+ g = scale8_LEAVING_R1_DIRTY( g, val);
+ b = scale8_LEAVING_R1_DIRTY( b, val);
+ cleanup_R1();
#else
- if( r ) r = scale8_LEAVING_R1_DIRTY( r, val) + 1;
- if( g ) g = scale8_LEAVING_R1_DIRTY( g, val) + 1;
- if( b ) b = scale8_LEAVING_R1_DIRTY( b, val) + 1;
+ if( r ) r = scale8( r, val) + 1;
+ if( g ) g = scale8( g, val) + 1;
+ if( b ) b = scale8( b, val) + 1;
#endif
- cleanup_R1();
}
}
@@ -496,19 +498,19 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
void hsv2rgb_raw(const struct CHSV * phsv, struct CRGB * prgb, int numLeds) {
- for(int i = 0; i < numLeds; i++) {
+ for(int i = 0; i < numLeds; ++i) {
hsv2rgb_raw(phsv[i], prgb[i]);
}
}
void hsv2rgb_rainbow( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
- for(int i = 0; i < numLeds; i++) {
+ for(int i = 0; i < numLeds; ++i) {
hsv2rgb_rainbow(phsv[i], prgb[i]);
}
}
void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
- for(int i = 0; i < numLeds; i++) {
+ for(int i = 0; i < numLeds; ++i) {
hsv2rgb_spectrum(phsv[i], prgb[i]);
}
}
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 1301a1a0..5db322f8 100644
--- a/led_sysdefs.h
+++ b/src/led_sysdefs.h
@@ -24,15 +24,17 @@
#elif defined(__SAM3X8E__)
// Include sam/due headers
#include "platforms/arm/sam/led_sysdefs_arm_sam.h"
-#elif defined(STM32F10X_MD) || defined(__STM32F1__)
+#elif defined(STM32F10X_MD) || defined(__STM32F1__) || defined(STM32F2XX)
#include "platforms/arm/stm32/led_sysdefs_arm_stm32.h"
-#elif defined(__SAMD21G18A__) || defined(__SAMD21J18A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__) || defined(__SAMD51G19A__) || defined(__SAMD51J19A__)
+#elif defined(__SAMD21G18A__) || defined(__SAMD21J18A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__)
#include "platforms/arm/d21/led_sysdefs_arm_d21.h"
+#elif defined(__SAMD51G19A__) || defined(__SAMD51J19A__) || defined(__SAMD51P19A__)
+#include "platforms/arm/d51/led_sysdefs_arm_d51.h"
#elif defined(ESP8266)
#include "platforms/esp/8266/led_sysdefs_esp8266.h"
#elif defined(ESP32)
#include "platforms/esp/32/led_sysdefs_esp32.h"
-#elif defined(__AVR__)
+#elif defined(__AVR__) || defined(__AVR_ATmega4809__)
// AVR platforms
#include "platforms/avr/led_sysdefs_avr.h"
#elif defined(ARDUINO_ARCH_APOLLO3)
diff --git a/lib8tion.cpp b/src/lib8tion.cpp
index 1306e5c0..ecb051d8 100644
--- a/lib8tion.cpp
+++ b/src/lib8tion.cpp
@@ -142,7 +142,7 @@ void test1abs( int8_t i)
void testabs()
{
delay(5000);
- for( int8_t q = -128; q != 127; q++) {
+ for( int8_t q = -128; q != 127; ++q) {
test1abs(q);
}
for(;;){};
@@ -225,7 +225,7 @@ void testnscale8x3()
{
delay(5000);
byte r, g, b, sc;
- for( byte z = 0; z < 10; z++) {
+ for( byte z = 0; z < 10; ++z) {
r = random8(); g = random8(); b = random8(); sc = random8();
Serial.print("nscale8x3_video( ");
diff --git a/lib8tion.h b/src/lib8tion.h
index 62db2b1d..0cc3baa4 100644
--- a/lib8tion.h
+++ b/src/lib8tion.h
@@ -825,20 +825,20 @@ LIB8STATIC uint8_t squarewave8( uint8_t in, uint8_t pulsewidth=128)
/// Template class for represneting fractional ints.
template<class T, int F, int I> class q {
- T i:I;
- T f:F;
+ T i:I;
+ T f:F;
public:
- q(float fx) { i = fx; f = (fx-i) * (1<<F); }
- q(uint8_t _i, uint8_t _f) {i=_i; f=_f; }
- uint32_t operator*(uint32_t v) { return (v*i) + ((v*f)>>F); }
- uint16_t operator*(uint16_t v) { return (v*i) + ((v*f)>>F); }
- int32_t operator*(int32_t v) { return (v*i) + ((v*f)>>F); }
- int16_t operator*(int16_t v) { return (v*i) + ((v*f)>>F); }
+ q(float fx) { i = fx; f = (fx-i) * (1<<F); }
+ q(uint8_t _i, uint8_t _f) {i=_i; f=_f; }
+ uint32_t operator*(uint32_t v) { return (v*i) + ((v*f)>>F); }
+ uint16_t operator*(uint16_t v) { return (v*i) + ((v*f)>>F); }
+ int32_t operator*(int32_t v) { return (v*i) + ((v*f)>>F); }
+ int16_t operator*(int16_t v) { return (v*i) + ((v*f)>>F); }
#ifdef FASTLED_ARM
- int operator*(int v) { return (v*i) + ((v*f)>>F); }
+ int operator*(int v) { return (v*i) + ((v*f)>>F); }
#endif
#ifdef FASTLED_APOLLO3
- int operator*(int v) { return (v*i) + ((v*f)>>F); }
+ int operator*(int v) { return (v*i) + ((v*f)>>F); }
#endif
};
@@ -1048,17 +1048,17 @@ LIB8STATIC uint16_t div1024_32_16( uint32_t in32)
uint16_t out16;
#if defined(__AVR__)
asm volatile (
- " lsr %D[in] \n\t"
- " ror %C[in] \n\t"
- " ror %B[in] \n\t"
- " lsr %D[in] \n\t"
- " ror %C[in] \n\t"
- " ror %B[in] \n\t"
- " mov %B[out],%C[in] \n\t"
- " mov %A[out],%B[in] \n\t"
- : [in] "+r" (in32),
- [out] "=r" (out16)
- );
+ " lsr %D[in] \n\t"
+ " ror %C[in] \n\t"
+ " ror %B[in] \n\t"
+ " lsr %D[in] \n\t"
+ " ror %C[in] \n\t"
+ " ror %B[in] \n\t"
+ " mov %B[out],%C[in] \n\t"
+ " mov %A[out],%B[in] \n\t"
+ : [in] "+r" (in32),
+ [out] "=r" (out16)
+ );
#else
out16 = (in32 >> 10) & 0xFFFF;
#endif
diff --git a/lib8tion/math8.h b/src/lib8tion/math8.h
index 4dab820f..a83b1ad2 100644
--- a/lib8tion/math8.h
+++ b/src/lib8tion/math8.h
@@ -28,18 +28,19 @@ LIB8STATIC_ALWAYS_INLINE uint8_t qadd8( uint8_t i, uint8_t j)
return t;
#elif QADD8_AVRASM == 1
asm volatile(
- /* First, add j to i, conditioning the C flag */
- "add %0, %1 \n\t"
-
- /* Now test the C flag.
- If C is clear, we branch around a load of 0xFF into i.
- If C is set, we go ahead and load 0xFF into i.
- */
- "brcc L_%= \n\t"
- "ldi %0, 0xFF \n\t"
- "L_%=: "
- : "+a" (i)
- : "a" (j) );
+ /* First, add j to i, conditioning the C flag */
+ "add %0, %1 \n\t"
+
+ /* Now test the C flag.
+ If C is clear, we branch around a load of 0xFF into i.
+ If C is set, we go ahead and load 0xFF into i.
+ */
+ "brcc L_%= \n\t"
+ "ldi %0, 0xFF \n\t"
+ "L_%=: "
+ : "+a" (i)
+ : "a" (j)
+ );
return i;
#elif QADD8_ARM_DSP_ASM == 1
asm volatile( "uqadd8 %0, %0, %1" : "+r" (i) : "r" (j));
@@ -61,19 +62,19 @@ LIB8STATIC_ALWAYS_INLINE int8_t qadd7( int8_t i, int8_t j)
return t;
#elif QADD7_AVRASM == 1
asm volatile(
- /* First, add j to i, conditioning the V flag */
- "add %0, %1 \n\t"
-
- /* Now test the V flag.
- If V is clear, we branch around a load of 0x7F into i.
- If V is set, we go ahead and load 0x7F into i.
- */
- "brvc L_%= \n\t"
- "ldi %0, 0x7F \n\t"
- "L_%=: "
- : "+a" (i)
- : "a" (j) );
-
+ /* First, add j to i, conditioning the V flag */
+ "add %0, %1 \n\t"
+
+ /* Now test the V flag.
+ If V is clear, we branch around a load of 0x7F into i.
+ If V is set, we go ahead and load 0x7F into i.
+ */
+ "brvc L_%= \n\t"
+ "ldi %0, 0x7F \n\t"
+ "L_%=: "
+ : "+a" (i)
+ : "a" (j)
+ );
return i;
#elif QADD7_ARM_DSP_ASM == 1
asm volatile( "qadd8 %0, %0, %1" : "+r" (i) : "r" (j));
@@ -94,19 +95,19 @@ LIB8STATIC_ALWAYS_INLINE uint8_t qsub8( uint8_t i, uint8_t j)
#elif QSUB8_AVRASM == 1
asm volatile(
- /* First, subtract j from i, conditioning the C flag */
- "sub %0, %1 \n\t"
-
- /* Now test the C flag.
- If C is clear, we branch around a load of 0x00 into i.
- If C is set, we go ahead and load 0x00 into i.
- */
- "brcc L_%= \n\t"
- "ldi %0, 0x00 \n\t"
- "L_%=: "
- : "+a" (i)
- : "a" (j) );
-
+ /* First, subtract j from i, conditioning the C flag */
+ "sub %0, %1 \n\t"
+
+ /* Now test the C flag.
+ If C is clear, we branch around a load of 0x00 into i.
+ If C is set, we go ahead and load 0x00 into i.
+ */
+ "brcc L_%= \n\t"
+ "ldi %0, 0x00 \n\t"
+ "L_%=: "
+ : "+a" (i)
+ : "a" (j)
+ );
return i;
#else
#error "No implementation for qsub8 available."
@@ -136,11 +137,12 @@ LIB8STATIC_ALWAYS_INLINE uint16_t add8to16( uint8_t i, uint16_t j)
return t;
#elif ADD8_AVRASM == 1
// Add i(one byte) to j(two bytes)
- asm volatile( "add %A[j], %[i] \n\t"
- "adc %B[j], __zero_reg__ \n\t"
- : [j] "+a" (j)
- : [i] "a" (i)
- );
+ asm volatile(
+ "add %A[j], %[i] \n\t"
+ "adc %B[j], __zero_reg__ \n\t"
+ : [j] "+a" (j)
+ : [i] "a" (i)
+ );
return i;
#else
#error "No implementation for add8to16 available."
@@ -172,12 +174,13 @@ LIB8STATIC_ALWAYS_INLINE uint8_t avg8( uint8_t i, uint8_t j)
return (i + j) >> 1;
#elif AVG8_AVRASM == 1
asm volatile(
- /* First, add j to i, 9th bit overflows into C flag */
- "add %0, %1 \n\t"
- /* Divide by two, moving C flag into high 8th bit */
- "ror %0 \n\t"
- : "+a" (i)
- : "a" (j) );
+ /* First, add j to i, 9th bit overflows into C flag */
+ "add %0, %1 \n\t"
+ /* Divide by two, moving C flag into high 8th bit */
+ "ror %0 \n\t"
+ : "+a" (i)
+ : "a" (j)
+ );
return i;
#else
#error "No implementation for avg8 available."
@@ -193,16 +196,17 @@ LIB8STATIC_ALWAYS_INLINE uint16_t avg16( uint16_t i, uint16_t j)
return (uint32_t)((uint32_t)(i) + (uint32_t)(j)) >> 1;
#elif AVG16_AVRASM == 1
asm volatile(
- /* First, add jLo (heh) to iLo, 9th bit overflows into C flag */
- "add %A[i], %A[j] \n\t"
- /* Now, add C + jHi to iHi, 17th bit overflows into C flag */
- "adc %B[i], %B[j] \n\t"
- /* Divide iHi by two, moving C flag into high 16th bit, old 9th bit now in C */
- "ror %B[i] \n\t"
- /* Divide iLo by two, moving C flag into high 8th bit */
- "ror %A[i] \n\t"
- : [i] "+a" (i)
- : [j] "a" (j) );
+ /* First, add jLo (heh) to iLo, 9th bit overflows into C flag */
+ "add %A[i], %A[j] \n\t"
+ /* Now, add C + jHi to iHi, 17th bit overflows into C flag */
+ "adc %B[i], %B[j] \n\t"
+ /* Divide iHi by two, moving C flag into high 16th bit, old 9th bit now in C */
+ "ror %B[i] \n\t"
+ /* Divide iLo by two, moving C flag into high 8th bit */
+ "ror %A[i] \n\t"
+ : [i] "+a" (i)
+ : [j] "a" (j)
+ );
return i;
#else
#error "No implementation for avg16 available."
@@ -220,11 +224,12 @@ LIB8STATIC_ALWAYS_INLINE int8_t avg7( int8_t i, int8_t j)
return ((i + j) >> 1) + (i & 0x1);
#elif AVG7_AVRASM == 1
asm volatile(
- "asr %1 \n\t"
- "asr %0 \n\t"
- "adc %0, %1 \n\t"
- : "+a" (i)
- : "a" (j) );
+ "asr %1 \n\t"
+ "asr %0 \n\t"
+ "adc %0, %1 \n\t"
+ : "+a" (i)
+ : "a" (j)
+ );
return i;
#else
#error "No implementation for avg7 available."
@@ -241,17 +246,18 @@ LIB8STATIC_ALWAYS_INLINE int16_t avg15( int16_t i, int16_t j)
return ((int32_t)((int32_t)(i) + (int32_t)(j)) >> 1) + (i & 0x1);
#elif AVG15_AVRASM == 1
asm volatile(
- /* first divide j by 2, throwing away lowest bit */
- "asr %B[j] \n\t"
- "ror %A[j] \n\t"
- /* now divide i by 2, with lowest bit going into C */
- "asr %B[i] \n\t"
- "ror %A[i] \n\t"
- /* add j + C to i */
- "adc %A[i], %A[j] \n\t"
- "adc %B[i], %B[j] \n\t"
- : [i] "+a" (i)
- : [j] "a" (j) );
+ /* first divide j by 2, throwing away lowest bit */
+ "asr %B[j] \n\t"
+ "ror %A[j] \n\t"
+ /* now divide i by 2, with lowest bit going into C */
+ "asr %B[i] \n\t"
+ "ror %A[i] \n\t"
+ /* add j + C to i */
+ "adc %A[i], %A[j] \n\t"
+ "adc %B[i], %B[j] \n\t"
+ : [i] "+a" (i)
+ : [j] "a" (j)
+ );
return i;
#else
#error "No implementation for avg15 available."
@@ -271,12 +277,12 @@ LIB8STATIC_ALWAYS_INLINE uint8_t mod8( uint8_t a, uint8_t m)
{
#if defined(__AVR__)
asm volatile (
- "L_%=: sub %[a],%[m] \n\t"
- " brcc L_%= \n\t"
- " add %[a],%[m] \n\t"
- : [a] "+r" (a)
- : [m] "r" (m)
- );
+ "L_%=: sub %[a],%[m] \n\t"
+ " brcc L_%= \n\t"
+ " add %[a],%[m] \n\t"
+ : [a] "+r" (a)
+ : [m] "r" (m)
+ );
#else
while( a >= m) a -= m;
#endif
@@ -298,13 +304,13 @@ LIB8STATIC uint8_t addmod8( uint8_t a, uint8_t b, uint8_t m)
{
#if defined(__AVR__)
asm volatile (
- " add %[a],%[b] \n\t"
- "L_%=: sub %[a],%[m] \n\t"
- " brcc L_%= \n\t"
- " add %[a],%[m] \n\t"
- : [a] "+r" (a)
- : [b] "r" (b), [m] "r" (m)
- );
+ " add %[a],%[b] \n\t"
+ "L_%=: sub %[a],%[m] \n\t"
+ " brcc L_%= \n\t"
+ " add %[a],%[m] \n\t"
+ : [a] "+r" (a)
+ : [b] "r" (b), [m] "r" (m)
+ );
#else
a += b;
while( a >= m) a -= m;
@@ -327,13 +333,13 @@ LIB8STATIC uint8_t submod8( uint8_t a, uint8_t b, uint8_t m)
{
#if defined(__AVR__)
asm volatile (
- " sub %[a],%[b] \n\t"
- "L_%=: sub %[a],%[m] \n\t"
- " brcc L_%= \n\t"
- " add %[a],%[m] \n\t"
- : [a] "+r" (a)
- : [b] "r" (b), [m] "r" (m)
- );
+ " sub %[a],%[b] \n\t"
+ "L_%=: sub %[a],%[m] \n\t"
+ " brcc L_%= \n\t"
+ " add %[a],%[m] \n\t"
+ : [a] "+r" (a)
+ : [b] "r" (b), [m] "r" (m)
+ );
#else
a -= b;
while( a >= m) a -= m;
@@ -348,16 +354,16 @@ LIB8STATIC_ALWAYS_INLINE uint8_t mul8( uint8_t i, uint8_t j)
return ((int)i * (int)(j) ) & 0xFF;
#elif MUL8_AVRASM == 1
asm volatile(
- /* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
- "mul %0, %1 \n\t"
- /* Extract the LOW 8-bits (r0) */
- "mov %0, r0 \n\t"
- /* Restore r1 to "0"; it's expected to always be that */
- "clr __zero_reg__ \n\t"
- : "+a" (i)
- : "a" (j)
- : "r0", "r1");
-
+ /* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
+ "mul %0, %1 \n\t"
+ /* Extract the LOW 8-bits (r0) */
+ "mov %0, r0 \n\t"
+ /* Restore r1 to "0"; it's expected to always be that */
+ "clr __zero_reg__ \n\t"
+ : "+a" (i)
+ : "a" (j)
+ : "r0", "r1"
+ );
return i;
#else
#error "No implementation for mul8 available."
@@ -375,24 +381,24 @@ LIB8STATIC_ALWAYS_INLINE uint8_t qmul8( uint8_t i, uint8_t j)
return p;
#elif QMUL8_AVRASM == 1
asm volatile(
- /* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
- " mul %0, %1 \n\t"
- /* If high byte of result is zero, all is well. */
- " tst r1 \n\t"
- " breq Lnospill_%= \n\t"
- /* If high byte of result > 0, saturate low byte to 0xFF */
- " ldi %0,0xFF \n\t"
- " rjmp Ldone_%= \n\t"
- "Lnospill_%=: \n\t"
- /* Extract the LOW 8-bits (r0) */
- " mov %0, r0 \n\t"
- "Ldone_%=: \n\t"
- /* Restore r1 to "0"; it's expected to always be that */
- " clr __zero_reg__ \n\t"
- : "+a" (i)
- : "a" (j)
- : "r0", "r1");
-
+ /* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
+ " mul %0, %1 \n\t"
+ /* If high byte of result is zero, all is well. */
+ " tst r1 \n\t"
+ " breq Lnospill_%= \n\t"
+ /* If high byte of result > 0, saturate low byte to 0xFF */
+ " ldi %0,0xFF \n\t"
+ " rjmp Ldone_%= \n\t"
+ "Lnospill_%=: \n\t"
+ /* Extract the LOW 8-bits (r0) */
+ " mov %0, r0 \n\t"
+ "Ldone_%=: \n\t"
+ /* Restore r1 to "0"; it's expected to always be that */
+ " clr __zero_reg__ \n\t"
+ : "+a" (i)
+ : "a" (j)
+ : "r0", "r1"
+ );
return i;
#else
#error "No implementation for qmul8 available."
@@ -407,16 +413,15 @@ LIB8STATIC_ALWAYS_INLINE int8_t abs8( int8_t i)
if( i < 0) i = -i;
return i;
#elif ABS8_AVRASM == 1
-
-
asm volatile(
- /* First, check the high bit, and prepare to skip if it's clear */
- "sbrc %0, 7 \n"
+ /* First, check the high bit, and prepare to skip if it's clear */
+ "sbrc %0, 7 \n"
- /* Negate the value */
- "neg %0 \n"
+ /* Negate the value */
+ "neg %0 \n"
- : "+r" (i) : "r" (i) );
+ : "+r" (i) : "r" (i)
+ );
return i;
#else
#error "No implementation for abs8 available."
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 56392258..6324475b 100644
--- a/lib8tion/scale8.h
+++ b/src/lib8tion/scale8.h
@@ -55,7 +55,7 @@ LIB8STATIC_ALWAYS_INLINE uint8_t scale8( uint8_t i, fract8 scale)
: [work] "+r" (work), [cnt] "+r" (cnt)
: [scale] "r" (scale), [i] "r" (i)
:
- );
+ );
return work;
#else
asm volatile(
@@ -69,18 +69,18 @@ LIB8STATIC_ALWAYS_INLINE uint8_t scale8( uint8_t i, fract8 scale)
// walk and chew gum at the same time
"adc %0, r1 \n\t"
#else
- /* Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0 */
- "mul %0, %1 \n\t"
- /* Move the high 8-bits of the product (r1) back to i */
- "mov %0, r1 \n\t"
- /* Restore r1 to "0"; it's expected to always be that */
+ /* Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0 */
+ "mul %0, %1 \n\t"
+ /* Move the high 8-bits of the product (r1) back to i */
+ "mov %0, r1 \n\t"
+ /* Restore r1 to "0"; it's expected to always be that */
#endif
- "clr __zero_reg__ \n\t"
-
- : "+a" (i) /* writes to i */
- : "a" (scale) /* uses scale */
- : "r0", "r1" /* clobbers r0, r1 */ );
+ "clr __zero_reg__ \n\t"
+ : "+a" (i) /* writes to i */
+ : "a" (scale) /* uses scale */
+ : "r0", "r1" /* clobbers r0, r1 */
+ );
/* Return the result */
return i;
#endif
@@ -115,8 +115,8 @@ LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video( uint8_t i, fract8 scale)
"L_%=: \n\t"
: [j] "+a" (j)
: [i] "a" (i), [scale] "a" (scale)
- : "r0", "r1");
-
+ : "r0", "r1"
+ );
return j;
// uint8_t nonzeroscale = (scale != 0) ? 1 : 0;
// asm volatile(
@@ -127,11 +127,9 @@ LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video( uint8_t i, fract8 scale)
// " add %0, %2 \n"
// " clr __zero_reg__ \n"
// "L_%=: \n"
-
// : "+a" (i)
// : "a" (scale), "a" (nonzeroscale)
// : "r0", "r1");
-
// // Return the result
// return i;
#else
@@ -153,28 +151,27 @@ LIB8STATIC_ALWAYS_INLINE uint8_t scale8_LEAVING_R1_DIRTY( uint8_t i, fract8 scal
#endif
#elif SCALE8_AVRASM == 1
asm volatile(
- #if (FASTLED_SCALE8_FIXED==1)
- // Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0
- "mul %0, %1 \n\t"
- // Add i to r0, possibly setting the carry flag
- "add r0, %0 \n\t"
- // load the immediate 0 into i (note, this does _not_ touch any flags)
- "ldi %0, 0x00 \n\t"
- // walk and chew gum at the same time
- "adc %0, r1 \n\t"
- #else
- /* Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0 */
- "mul %0, %1 \n\t"
- /* Move the high 8-bits of the product (r1) back to i */
- "mov %0, r1 \n\t"
- #endif
- /* R1 IS LEFT DIRTY HERE; YOU MUST ZERO IT OUT YOURSELF */
- /* "clr __zero_reg__ \n\t" */
-
- : "+a" (i) /* writes to i */
- : "a" (scale) /* uses scale */
- : "r0", "r1" /* clobbers r0, r1 */ );
-
+#if (FASTLED_SCALE8_FIXED==1)
+ // Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0
+ "mul %0, %1 \n\t"
+ // Add i to r0, possibly setting the carry flag
+ "add r0, %0 \n\t"
+ // load the immediate 0 into i (note, this does _not_ touch any flags)
+ "ldi %0, 0x00 \n\t"
+ // walk and chew gum at the same time
+ "adc %0, r1 \n\t"
+#else
+ /* Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0 */
+ "mul %0, %1 \n\t"
+ /* Move the high 8-bits of the product (r1) back to i */
+ "mov %0, r1 \n\t"
+#endif
+ /* R1 IS LEFT DIRTY HERE; YOU MUST ZERO IT OUT YOURSELF */
+ /* "clr __zero_reg__ \n\t" */
+ : "+a" (i) /* writes to i */
+ : "a" (scale) /* uses scale */
+ : "r0", "r1" /* clobbers r0, r1 */
+ );
// Return the result
return i;
#else
@@ -197,27 +194,28 @@ LIB8STATIC_ALWAYS_INLINE void nscale8_LEAVING_R1_DIRTY( uint8_t& i, fract8 scale
#endif
#elif SCALE8_AVRASM == 1
asm volatile(
- #if (FASTLED_SCALE8_FIXED==1)
- // Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0
- "mul %0, %1 \n\t"
- // Add i to r0, possibly setting the carry flag
- "add r0, %0 \n\t"
- // load the immediate 0 into i (note, this does _not_ touch any flags)
- "ldi %0, 0x00 \n\t"
- // walk and chew gum at the same time
- "adc %0, r1 \n\t"
- #else
- /* Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0 */
- "mul %0, %1 \n\t"
- /* Move the high 8-bits of the product (r1) back to i */
- "mov %0, r1 \n\t"
- #endif
- /* R1 IS LEFT DIRTY HERE; YOU MUST ZERO IT OUT YOURSELF */
- /* "clr __zero_reg__ \n\t" */
-
- : "+a" (i) /* writes to i */
- : "a" (scale) /* uses scale */
- : "r0", "r1" /* clobbers r0, r1 */ );
+#if (FASTLED_SCALE8_FIXED==1)
+ // Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0
+ "mul %0, %1 \n\t"
+ // Add i to r0, possibly setting the carry flag
+ "add r0, %0 \n\t"
+ // load the immediate 0 into i (note, this does _not_ touch any flags)
+ "ldi %0, 0x00 \n\t"
+ // walk and chew gum at the same time
+ "adc %0, r1 \n\t"
+#else
+ /* Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0 */
+ "mul %0, %1 \n\t"
+ /* Move the high 8-bits of the product (r1) back to i */
+ "mov %0, r1 \n\t"
+#endif
+ /* R1 IS LEFT DIRTY HERE; YOU MUST ZERO IT OUT YOURSELF */
+ /* "clr __zero_reg__ \n\t" */
+
+ : "+a" (i) /* writes to i */
+ : "a" (scale) /* uses scale */
+ : "r0", "r1" /* clobbers r0, r1 */
+ );
#else
#error "No implementation for nscale8_LEAVING_R1_DIRTY available."
#endif
@@ -246,8 +244,8 @@ LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video_LEAVING_R1_DIRTY( uint8_t i, fract
"L_%=: \n\t"
: [j] "+a" (j)
: [i] "a" (i), [scale] "a" (scale)
- : "r0", "r1");
-
+ : "r0", "r1"
+ );
return j;
// uint8_t nonzeroscale = (scale != 0) ? 1 : 0;
// asm volatile(
@@ -258,11 +256,9 @@ LIB8STATIC_ALWAYS_INLINE uint8_t scale8_video_LEAVING_R1_DIRTY( uint8_t i, fract
// " add %0, %2 \n"
// " clr __zero_reg__ \n"
// "L_%=: \n"
-
// : "+a" (i)
// : "a" (scale), "a" (nonzeroscale)
// : "r0", "r1");
-
// // Return the result
// return i;
#else
@@ -289,7 +285,8 @@ LIB8STATIC_ALWAYS_INLINE void nscale8_video_LEAVING_R1_DIRTY( uint8_t & i, fract
"L_%=: \n\t"
: [i] "+a" (i)
: [scale] "a" (scale)
- : "r0", "r1");
+ : "r0", "r1"
+ );
#else
#error "No implementation for scale8_video_LEAVING_R1_DIRTY available."
#endif
@@ -427,50 +424,50 @@ LIB8STATIC_ALWAYS_INLINE uint16_t scale16by8( uint16_t i, fract8 scale )
#if FASTLED_SCALE8_FIXED == 1
uint16_t result = 0;
asm volatile(
- // result.A = HighByte( (i.A x scale) + i.A )
- " mul %A[i], %[scale] \n\t"
- " add r0, %A[i] \n\t"
- // " adc r1, [zero] \n\t"
- // " mov %A[result], r1 \n\t"
- " adc %A[result], r1 \n\t"
-
- // result.A-B += i.B x scale
- " mul %B[i], %[scale] \n\t"
- " add %A[result], r0 \n\t"
- " adc %B[result], r1 \n\t"
-
- // cleanup r1
- " clr __zero_reg__ \n\t"
-
- // result.A-B += i.B
- " add %A[result], %B[i] \n\t"
- " adc %B[result], __zero_reg__ \n\t"
-
- : [result] "+r" (result)
- : [i] "r" (i), [scale] "r" (scale)
- : "r0", "r1"
- );
+ // result.A = HighByte( (i.A x scale) + i.A )
+ " mul %A[i], %[scale] \n\t"
+ " add r0, %A[i] \n\t"
+ // " adc r1, [zero] \n\t"
+ // " mov %A[result], r1 \n\t"
+ " adc %A[result], r1 \n\t"
+
+ // result.A-B += i.B x scale
+ " mul %B[i], %[scale] \n\t"
+ " add %A[result], r0 \n\t"
+ " adc %B[result], r1 \n\t"
+
+ // cleanup r1
+ " clr __zero_reg__ \n\t"
+
+ // result.A-B += i.B
+ " add %A[result], %B[i] \n\t"
+ " adc %B[result], __zero_reg__ \n\t"
+
+ : [result] "+r" (result)
+ : [i] "r" (i), [scale] "r" (scale)
+ : "r0", "r1"
+ );
return result;
#else
uint16_t result = 0;
asm volatile(
- // result.A = HighByte(i.A x j )
- " mul %A[i], %[scale] \n\t"
- " mov %A[result], r1 \n\t"
- //" clr %B[result] \n\t"
-
- // result.A-B += i.B x j
- " mul %B[i], %[scale] \n\t"
- " add %A[result], r0 \n\t"
- " adc %B[result], r1 \n\t"
-
- // cleanup r1
- " clr __zero_reg__ \n\t"
-
- : [result] "+r" (result)
- : [i] "r" (i), [scale] "r" (scale)
- : "r0", "r1"
- );
+ // result.A = HighByte(i.A x j )
+ " mul %A[i], %[scale] \n\t"
+ " mov %A[result], r1 \n\t"
+ //" clr %B[result] \n\t"
+
+ // result.A-B += i.B x j
+ " mul %B[i], %[scale] \n\t"
+ " add %A[result], r0 \n\t"
+ " adc %B[result], r1 \n\t"
+
+ // cleanup r1
+ " clr __zero_reg__ \n\t"
+
+ : [result] "+r" (result)
+ : [i] "r" (i), [scale] "r" (scale)
+ : "r0", "r1"
+ );
return result;
#endif
#else
@@ -503,137 +500,137 @@ LIB8STATIC uint16_t scale16( uint16_t i, fract16 scale )
// will be zero, which is not what we want.
uint32_t result;
asm volatile(
- // result.A-B = i.A x scale.A
- " mul %A[i], %A[scale] \n\t"
- // save results...
- // basic idea:
- //" mov %A[result], r0 \n\t"
- //" mov %B[result], r1 \n\t"
- // which can be written as...
- " movw %A[result], r0 \n\t"
- // Because we're going to add i.A-B to
- // result.A-D, we DO need to keep both
- // the r0 and r1 portions of the product
- // UNlike in the 'unfixed scale8' version.
- // So the movw here is needed.
- : [result] "=r" (result)
- : [i] "r" (i),
- [scale] "r" (scale)
- : "r0", "r1"
- );
-
- asm volatile(
- // result.C-D = i.B x scale.B
- " mul %B[i], %B[scale] \n\t"
- //" mov %C[result], r0 \n\t"
- //" mov %D[result], r1 \n\t"
- " movw %C[result], r0 \n\t"
- : [result] "+r" (result)
- : [i] "r" (i),
- [scale] "r" (scale)
- : "r0", "r1"
- );
+ // result.A-B = i.A x scale.A
+ " mul %A[i], %A[scale] \n\t"
+ // save results...
+ // basic idea:
+ //" mov %A[result], r0 \n\t"
+ //" mov %B[result], r1 \n\t"
+ // which can be written as...
+ " movw %A[result], r0 \n\t"
+ // Because we're going to add i.A-B to
+ // result.A-D, we DO need to keep both
+ // the r0 and r1 portions of the product
+ // UNlike in the 'unfixed scale8' version.
+ // So the movw here is needed.
+ : [result] "=r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale)
+ : "r0", "r1"
+ );
- const uint8_t zero = 0;
asm volatile(
- // result.B-D += i.B x scale.A
- " mul %B[i], %A[scale] \n\t"
-
- " add %B[result], r0 \n\t"
- " adc %C[result], r1 \n\t"
- " adc %D[result], %[zero] \n\t"
-
- // result.B-D += i.A x scale.B
- " mul %A[i], %B[scale] \n\t"
-
- " add %B[result], r0 \n\t"
- " adc %C[result], r1 \n\t"
- " adc %D[result], %[zero] \n\t"
-
- // cleanup r1
- " clr r1 \n\t"
-
- : [result] "+r" (result)
- : [i] "r" (i),
- [scale] "r" (scale),
- [zero] "r" (zero)
- : "r0", "r1"
- );
+ // result.C-D = i.B x scale.B
+ " mul %B[i], %B[scale] \n\t"
+ //" mov %C[result], r0 \n\t"
+ //" mov %D[result], r1 \n\t"
+ " movw %C[result], r0 \n\t"
+ : [result] "+r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale)
+ : "r0", "r1"
+);
+
+const uint8_t zero = 0;
+asm volatile(
+ // result.B-D += i.B x scale.A
+ " mul %B[i], %A[scale] \n\t"
+
+ " add %B[result], r0 \n\t"
+ " adc %C[result], r1 \n\t"
+ " adc %D[result], %[zero] \n\t"
+
+ // result.B-D += i.A x scale.B
+ " mul %A[i], %B[scale] \n\t"
+
+ " add %B[result], r0 \n\t"
+ " adc %C[result], r1 \n\t"
+ " adc %D[result], %[zero] \n\t"
+
+ // cleanup r1
+ " clr r1 \n\t"
+
+ : [result] "+r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale),
+ [zero] "r" (zero)
+ : "r0", "r1"
+ );
asm volatile(
- // result.A-D += i.A-B
- " add %A[result], %A[i] \n\t"
- " adc %B[result], %B[i] \n\t"
- " adc %C[result], %[zero] \n\t"
- " adc %D[result], %[zero] \n\t"
- : [result] "+r" (result)
- : [i] "r" (i),
- [zero] "r" (zero)
- );
+ // result.A-D += i.A-B
+ " add %A[result], %A[i] \n\t"
+ " adc %B[result], %B[i] \n\t"
+ " adc %C[result], %[zero] \n\t"
+ " adc %D[result], %[zero] \n\t"
+ : [result] "+r" (result)
+ : [i] "r" (i),
+ [zero] "r" (zero)
+ );
result = result >> 16;
return result;
#else
uint32_t result;
asm volatile(
- // result.A-B = i.A x scale.A
- " mul %A[i], %A[scale] \n\t"
- // save results...
- // basic idea:
- //" mov %A[result], r0 \n\t"
- //" mov %B[result], r1 \n\t"
- // which can be written as...
- " movw %A[result], r0 \n\t"
- // We actually don't need to do anything with r0,
- // as result.A is never used again here, so we
- // could just move the high byte, but movw is
- // one clock cycle, just like mov, so might as
- // well, in case we want to use this code for
- // a generic 16x16 multiply somewhere.
-
- : [result] "=r" (result)
- : [i] "r" (i),
- [scale] "r" (scale)
- : "r0", "r1"
- );
+ // result.A-B = i.A x scale.A
+ " mul %A[i], %A[scale] \n\t"
+ // save results...
+ // basic idea:
+ //" mov %A[result], r0 \n\t"
+ //" mov %B[result], r1 \n\t"
+ // which can be written as...
+ " movw %A[result], r0 \n\t"
+ // We actually don't need to do anything with r0,
+ // as result.A is never used again here, so we
+ // could just move the high byte, but movw is
+ // one clock cycle, just like mov, so might as
+ // well, in case we want to use this code for
+ // a generic 16x16 multiply somewhere.
+
+ : [result] "=r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale)
+ : "r0", "r1"
+ );
asm volatile(
- // result.C-D = i.B x scale.B
- " mul %B[i], %B[scale] \n\t"
- //" mov %C[result], r0 \n\t"
- //" mov %D[result], r1 \n\t"
- " movw %C[result], r0 \n\t"
- : [result] "+r" (result)
- : [i] "r" (i),
- [scale] "r" (scale)
- : "r0", "r1"
- );
+ // result.C-D = i.B x scale.B
+ " mul %B[i], %B[scale] \n\t"
+ //" mov %C[result], r0 \n\t"
+ //" mov %D[result], r1 \n\t"
+ " movw %C[result], r0 \n\t"
+ : [result] "+r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale)
+ : "r0", "r1"
+ );
const uint8_t zero = 0;
asm volatile(
- // result.B-D += i.B x scale.A
- " mul %B[i], %A[scale] \n\t"
+ // result.B-D += i.B x scale.A
+ " mul %B[i], %A[scale] \n\t"
- " add %B[result], r0 \n\t"
- " adc %C[result], r1 \n\t"
- " adc %D[result], %[zero] \n\t"
+ " add %B[result], r0 \n\t"
+ " adc %C[result], r1 \n\t"
+ " adc %D[result], %[zero] \n\t"
- // result.B-D += i.A x scale.B
- " mul %A[i], %B[scale] \n\t"
+ // result.B-D += i.A x scale.B
+ " mul %A[i], %B[scale] \n\t"
- " add %B[result], r0 \n\t"
- " adc %C[result], r1 \n\t"
- " adc %D[result], %[zero] \n\t"
+ " add %B[result], r0 \n\t"
+ " adc %C[result], r1 \n\t"
+ " adc %D[result], %[zero] \n\t"
- // cleanup r1
- " clr r1 \n\t"
+ // cleanup r1
+ " clr r1 \n\t"
- : [result] "+r" (result)
- : [i] "r" (i),
- [scale] "r" (scale),
- [zero] "r" (zero)
- : "r0", "r1"
- );
+ : [result] "+r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale),
+ [zero] "r" (zero)
+ : "r0", "r1"
+ );
result = result >> 16;
return result;
diff --git a/lib8tion/trig8.h b/src/lib8tion/trig8.h
index 4907c6ff..bcb9f68a 100644
--- a/lib8tion/trig8.h
+++ b/src/lib8tion/trig8.h
@@ -16,9 +16,6 @@
#if defined(__AVR__)
#define sin16 sin16_avr
-#else
-#define sin16 sin16_C
-#endif
/// Fast 16-bit approximation of sin(x). This approximation never varies more than
/// 0.69% from the floating point value you'd get by doing
@@ -78,6 +75,9 @@ LIB8STATIC int16_t sin16_avr( uint16_t theta )
return y;
}
+#else
+#define sin16 sin16_C
+
/// Fast 16-bit approximation of sin(x). This approximation never varies more than
/// 0.69% from the floating point value you'd get by doing
///
@@ -109,6 +109,7 @@ LIB8STATIC int16_t sin16_C( uint16_t theta )
return y;
}
+#endif
/// Fast 16-bit approximation of cos(x). This approximation never varies more than
/// 0.69% from the floating point value you'd get by doing
@@ -139,15 +140,11 @@ LIB8STATIC int16_t cos16( uint16_t theta)
//
// On Arduino/AVR, this approximation is more than
// 20X faster than floating point sin(x) and cos(x)
+//
+const uint8_t b_m16_interleave[] = { 0, 49, 49, 41, 90, 27, 117, 10 };
#if defined(__AVR__) && !defined(LIB8_ATTINY)
#define sin8 sin8_avr
-#else
-#define sin8 sin8_C
-#endif
-
-
-const uint8_t b_m16_interleave[] = { 0, 49, 49, 41, 90, 27, 117, 10 };
/// Fast 8-bit approximation of sin(x). This approximation never varies more than
/// 2% from the floating point value you'd get by doing
@@ -161,15 +158,15 @@ LIB8STATIC uint8_t sin8_avr( uint8_t theta)
uint8_t offset = theta;
asm volatile(
- "sbrc %[theta],6 \n\t"
- "com %[offset] \n\t"
- : [theta] "+r" (theta), [offset] "+r" (offset)
- );
+ "sbrc %[theta],6 \n\t"
+ "com %[offset] \n\t"
+ : [theta] "+r" (theta), [offset] "+r" (offset)
+ );
offset &= 0x3F; // 0..63
uint8_t secoffset = offset & 0x0F; // 0..15
- if( theta & 0x40) secoffset++;
+ if( theta & 0x40) ++secoffset;
uint8_t m16; uint8_t b;
@@ -179,24 +176,24 @@ LIB8STATIC uint8_t sin8_avr( uint8_t theta)
const uint8_t* p = b_m16_interleave;
p += s2;
b = *p;
- p++;
+ ++p;
m16 = *p;
uint8_t mx;
uint8_t xr1;
asm volatile(
- "mul %[m16],%[secoffset] \n\t"
- "mov %[mx],r0 \n\t"
- "mov %[xr1],r1 \n\t"
- "eor r1, r1 \n\t"
- "swap %[mx] \n\t"
- "andi %[mx],0x0F \n\t"
- "swap %[xr1] \n\t"
- "andi %[xr1], 0xF0 \n\t"
- "or %[mx], %[xr1] \n\t"
- : [mx] "=d" (mx), [xr1] "=d" (xr1)
- : [m16] "d" (m16), [secoffset] "d" (secoffset)
- );
+ "mul %[m16],%[secoffset] \n\t"
+ "mov %[mx],r0 \n\t"
+ "mov %[xr1],r1 \n\t"
+ "eor r1, r1 \n\t"
+ "swap %[mx] \n\t"
+ "andi %[mx],0x0F \n\t"
+ "swap %[xr1] \n\t"
+ "andi %[xr1], 0xF0 \n\t"
+ "or %[mx], %[xr1] \n\t"
+ : [mx] "=d" (mx), [xr1] "=d" (xr1)
+ : [m16] "d" (m16), [secoffset] "d" (secoffset)
+ );
int8_t y = mx + b;
if( theta & 0x80 ) y = -y;
@@ -206,6 +203,8 @@ LIB8STATIC uint8_t sin8_avr( uint8_t theta)
return y;
}
+#else
+#define sin8 sin8_C
/// Fast 8-bit approximation of sin(x). This approximation never varies more than
/// 2% from the floating point value you'd get by doing
@@ -223,14 +222,14 @@ LIB8STATIC uint8_t sin8_C( uint8_t theta)
offset &= 0x3F; // 0..63
uint8_t secoffset = offset & 0x0F; // 0..15
- if( theta & 0x40) secoffset++;
+ if( theta & 0x40) ++secoffset;
uint8_t section = offset >> 4; // 0..3
uint8_t s2 = section * 2;
const uint8_t* p = b_m16_interleave;
p += s2;
uint8_t b = *p;
- p++;
+ ++p;
uint8_t m16 = *p;
uint8_t mx = (m16 * secoffset) >> 4;
@@ -243,6 +242,8 @@ LIB8STATIC uint8_t sin8_C( uint8_t theta)
return y;
}
+#endif
+
/// Fast 8-bit approximation of cos(x). This approximation never varies more than
/// 2% from the floating point value you'd get by doing
///
diff --git a/noise.cpp b/src/noise.cpp
index 7d42d64d..3a40c476 100644
--- a/noise.cpp
+++ b/src/noise.cpp
@@ -6,21 +6,24 @@ FASTLED_NAMESPACE_BEGIN
#define P(x) FL_PGM_READ_BYTE_NEAR(p + x)
-FL_PROGMEM static uint8_t const p[] = { 151,160,137,91,90,15,
- 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
- 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
- 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
- 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
- 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
- 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
- 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
- 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
- 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
- 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
- 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
- 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,151
- };
-
+FL_PROGMEM static uint8_t const p[] = {
+ 151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
+ 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
+ 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
+ 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
+ 74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
+ 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
+ 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
+ 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
+ 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
+ 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
+ 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
+ 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
+ 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
+ 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
+ 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
+ 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,
+ 151};
#if FASTLED_NOISE_ALLOW_AVERAGE_TO_OVERFLOW == 1
#define AVG15(U,V) (((U)+(V)) >> 1)
@@ -74,55 +77,55 @@ static int16_t inline __attribute__((always_inline)) avg15_inline_avr_mul( int1
#endif
static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y, int16_t z) {
#if 0
- switch(hash & 0xF) {
- case 0: return (( x) + ( y))>>1;
- case 1: return ((-x) + ( y))>>1;
- case 2: return (( x) + (-y))>>1;
- case 3: return ((-x) + (-y))>>1;
- case 4: return (( x) + ( z))>>1;
- case 5: return ((-x) + ( z))>>1;
- case 6: return (( x) + (-z))>>1;
- case 7: return ((-x) + (-z))>>1;
- case 8: return (( y) + ( z))>>1;
- case 9: return ((-y) + ( z))>>1;
- case 10: return (( y) + (-z))>>1;
- case 11: return ((-y) + (-z))>>1;
- case 12: return (( y) + ( x))>>1;
- case 13: return ((-y) + ( z))>>1;
- case 14: return (( y) + (-x))>>1;
- case 15: return ((-y) + (-z))>>1;
- }
+ switch(hash & 0xF) {
+ case 0: return (( x) + ( y))>>1;
+ case 1: return ((-x) + ( y))>>1;
+ case 2: return (( x) + (-y))>>1;
+ case 3: return ((-x) + (-y))>>1;
+ case 4: return (( x) + ( z))>>1;
+ case 5: return ((-x) + ( z))>>1;
+ case 6: return (( x) + (-z))>>1;
+ case 7: return ((-x) + (-z))>>1;
+ case 8: return (( y) + ( z))>>1;
+ case 9: return ((-y) + ( z))>>1;
+ case 10: return (( y) + (-z))>>1;
+ case 11: return ((-y) + (-z))>>1;
+ case 12: return (( y) + ( x))>>1;
+ case 13: return ((-y) + ( z))>>1;
+ case 14: return (( y) + (-x))>>1;
+ case 15: return ((-y) + (-z))>>1;
+ }
#else
- hash = hash&15;
- int16_t u = hash<8?x:y;
- int16_t v = hash<4?y:hash==12||hash==14?x:z;
- if(hash&1) { u = -u; }
- if(hash&2) { v = -v; }
+ hash = hash&15;
+ int16_t u = hash<8?x:y;
+ int16_t v = hash<4?y:hash==12||hash==14?x:z;
+ if(hash&1) { u = -u; }
+ if(hash&2) { v = -v; }
- return AVG15(u,v);
+ return AVG15(u,v);
#endif
}
static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y) {
- hash = hash & 7;
- int16_t u,v;
- if(hash < 4) { u = x; v = y; } else { u = y; v = x; }
- if(hash&1) { u = -u; }
- if(hash&2) { v = -v; }
+ hash = hash & 7;
+ int16_t u,v;
+ if(hash < 4) { u = x; v = y; } else { u = y; v = x; }
+ if(hash&1) { u = -u; }
+ if(hash&2) { v = -v; }
- return AVG15(u,v);
+ return AVG15(u,v);
}
static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x) {
- hash = hash & 15;
- int16_t u,v;
- if(hash > 8) { u=x;v=x; }
- else if(hash < 4) { u=x;v=1; }
- else { u=1;v=x; }
- if(hash&1) { u = -u; }
- if(hash&2) { v = -v; }
+ hash = hash & 15;
+ int16_t u,v;
+ if(hash > 8) { u=x;v=x; }
+ else if(hash < 4) { u=x;v=1; }
+ else { u=1;v=x; }
+ if(hash&1) { u = -u; }
+ if(hash&2) { v = -v; }
- return AVG15(u,v);
+ return AVG15(u,v);
}
// selectBasedOnHashBit performs this:
@@ -150,115 +153,115 @@ static int8_t inline __attribute__((always_inline)) selectBasedOnHashBit(uint8_t
static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y, int8_t z) {
#if 0
- switch(hash & 0xF) {
- case 0: return (( x) + ( y))>>1;
- case 1: return ((-x) + ( y))>>1;
- case 2: return (( x) + (-y))>>1;
- case 3: return ((-x) + (-y))>>1;
- case 4: return (( x) + ( z))>>1;
- case 5: return ((-x) + ( z))>>1;
- case 6: return (( x) + (-z))>>1;
- case 7: return ((-x) + (-z))>>1;
- case 8: return (( y) + ( z))>>1;
- case 9: return ((-y) + ( z))>>1;
- case 10: return (( y) + (-z))>>1;
- case 11: return ((-y) + (-z))>>1;
- case 12: return (( y) + ( x))>>1;
- case 13: return ((-y) + ( z))>>1;
- case 14: return (( y) + (-x))>>1;
- case 15: return ((-y) + (-z))>>1;
- }
+ switch(hash & 0xF) {
+ case 0: return (( x) + ( y))>>1;
+ case 1: return ((-x) + ( y))>>1;
+ case 2: return (( x) + (-y))>>1;
+ case 3: return ((-x) + (-y))>>1;
+ case 4: return (( x) + ( z))>>1;
+ case 5: return ((-x) + ( z))>>1;
+ case 6: return (( x) + (-z))>>1;
+ case 7: return ((-x) + (-z))>>1;
+ case 8: return (( y) + ( z))>>1;
+ case 9: return ((-y) + ( z))>>1;
+ case 10: return (( y) + (-z))>>1;
+ case 11: return ((-y) + (-z))>>1;
+ case 12: return (( y) + ( x))>>1;
+ case 13: return ((-y) + ( z))>>1;
+ case 14: return (( y) + (-x))>>1;
+ case 15: return ((-y) + (-z))>>1;
+ }
#else
- hash &= 0xF;
+ hash &= 0xF;
- int8_t u, v;
- //u = (hash&8)?y:x;
- u = selectBasedOnHashBit( hash, 3, y, x);
+ int8_t u, v;
+ //u = (hash&8)?y:x;
+ u = selectBasedOnHashBit( hash, 3, y, x);
#if 1
- v = hash<4?y:hash==12||hash==14?x:z;
+ v = hash<4?y:hash==12||hash==14?x:z;
#else
- // Verbose version for analysis; generates idenitical code.
- if( hash < 4) { // 00 01 02 03
- v = y;
- } else {
- if( hash==12 || hash==14) { // 0C 0E
- v = x;
- } else {
- v = z; // 04 05 06 07 08 09 0A 0B 0D 0F
- }
- }
+ // Verbose version for analysis; generates idenitical code.
+ if( hash < 4) { // 00 01 02 03
+ v = y;
+ } else {
+ if( hash==12 || hash==14) { // 0C 0E
+ v = x;
+ } else {
+ v = z; // 04 05 06 07 08 09 0A 0B 0D 0F
+ }
+ }
#endif
- if(hash&1) { u = -u; }
- if(hash&2) { v = -v; }
+ if(hash&1) { u = -u; }
+ if(hash&2) { v = -v; }
- return avg7(u,v);
+ return avg7(u,v);
#endif
}
static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y)
{
- // since the tests below can be done bit-wise on the bottom
- // three bits, there's no need to mask off the higher bits
- // hash = hash & 7;
+ // since the tests below can be done bit-wise on the bottom
+ // three bits, there's no need to mask off the higher bits
+ // hash = hash & 7;
- int8_t u,v;
- if( hash & 4) {
- u = y; v = x;
- } else {
- u = x; v = y;
- }
+ int8_t u,v;
+ if( hash & 4) {
+ u = y; v = x;
+ } else {
+ u = x; v = y;
+ }
- if(hash&1) { u = -u; }
- if(hash&2) { v = -v; }
+ if(hash&1) { u = -u; }
+ if(hash&2) { v = -v; }
- return avg7(u,v);
+ return avg7(u,v);
}
static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x)
{
- // since the tests below can be done bit-wise on the bottom
- // four bits, there's no need to mask off the higher bits
- // hash = hash & 15;
+ // since the tests below can be done bit-wise on the bottom
+ // four bits, there's no need to mask off the higher bits
+ // hash = hash & 15;
- int8_t u,v;
- if(hash & 8) {
- u=x; v=x;
- } else {
- if(hash & 4) {
- u=1; v=x;
- } else {
- u=x; v=1;
- }
- }
+ int8_t u,v;
+ if(hash & 8) {
+ u=x; v=x;
+ } else {
+ if(hash & 4) {
+ u=1; v=x;
+ } else {
+ u=x; v=1;
+ }
+ }
- if(hash&1) { u = -u; }
- if(hash&2) { v = -v; }
+ if(hash&1) { u = -u; }
+ if(hash&2) { v = -v; }
- return avg7(u,v);
+ return avg7(u,v);
}
#ifdef FADE_12
uint16_t logfade12(uint16_t val) {
- return scale16(val,val)>>4;
+ return scale16(val,val)>>4;
}
static int16_t inline __attribute__((always_inline)) lerp15by12( int16_t a, int16_t b, fract16 frac)
{
- //if(1) return (lerp(frac,a,b));
+ //if(1) return (lerp(frac,a,b));
int16_t result;
if( b > a) {
uint16_t delta = b - a;
uint16_t scaled = scale16(delta,frac<<4);
result = a + scaled;
- } else {
+ } else {
uint16_t delta = a - b;
uint16_t scaled = scale16(delta,frac<<4);
- result = a - scaled;
- }
+ result = a - scaled;
+ }
return result;
}
#endif
@@ -285,183 +288,183 @@ static int8_t inline __attribute__((always_inline)) lerp7by8( int8_t a, int8_t b
int16_t inoise16_raw(uint32_t x, uint32_t y, uint32_t z)
{
- // Find the unit cube containing the point
- uint8_t X = (x>>16)&0xFF;
- uint8_t Y = (y>>16)&0xFF;
- uint8_t Z = (z>>16)&0xFF;
-
- // Hash cube corner coordinates
- uint8_t A = P(X)+Y;
- uint8_t AA = P(A)+Z;
- uint8_t AB = P(A+1)+Z;
- uint8_t B = P(X+1)+Y;
- uint8_t BA = P(B) + Z;
- uint8_t BB = P(B+1)+Z;
-
- // Get the relative position of the point in the cube
- uint16_t u = x & 0xFFFF;
- uint16_t v = y & 0xFFFF;
- uint16_t w = z & 0xFFFF;
-
- // Get a signed version of the above for the grad function
- int16_t xx = (u >> 1) & 0x7FFF;
- int16_t yy = (v >> 1) & 0x7FFF;
- int16_t zz = (w >> 1) & 0x7FFF;
- uint16_t N = 0x8000L;
-
- u = EASE16(u); v = EASE16(v); w = EASE16(w);
-
- // skip the log fade adjustment for the moment, otherwise here we would
- // adjust fade values for u,v,w
- int16_t X1 = LERP(grad16(P(AA), xx, yy, zz), grad16(P(BA), xx - N, yy, zz), u);
- int16_t X2 = LERP(grad16(P(AB), xx, yy-N, zz), grad16(P(BB), xx - N, yy - N, zz), u);
- int16_t X3 = LERP(grad16(P(AA+1), xx, yy, zz-N), grad16(P(BA+1), xx - N, yy, zz-N), u);
- int16_t X4 = LERP(grad16(P(AB+1), xx, yy-N, zz-N), grad16(P(BB+1), xx - N, yy - N, zz - N), u);
-
- int16_t Y1 = LERP(X1,X2,v);
- int16_t Y2 = LERP(X3,X4,v);
+ // Find the unit cube containing the point
+ uint8_t X = (x>>16)&0xFF;
+ uint8_t Y = (y>>16)&0xFF;
+ uint8_t Z = (z>>16)&0xFF;
+
+ // Hash cube corner coordinates
+ uint8_t A = P(X)+Y;
+ uint8_t AA = P(A)+Z;
+ uint8_t AB = P(A+1)+Z;
+ uint8_t B = P(X+1)+Y;
+ uint8_t BA = P(B) + Z;
+ uint8_t BB = P(B+1)+Z;
+
+ // Get the relative position of the point in the cube
+ uint16_t u = x & 0xFFFF;
+ uint16_t v = y & 0xFFFF;
+ uint16_t w = z & 0xFFFF;
+
+ // Get a signed version of the above for the grad function
+ int16_t xx = (u >> 1) & 0x7FFF;
+ int16_t yy = (v >> 1) & 0x7FFF;
+ int16_t zz = (w >> 1) & 0x7FFF;
+ uint16_t N = 0x8000L;
+
+ u = EASE16(u); v = EASE16(v); w = EASE16(w);
+
+ // skip the log fade adjustment for the moment, otherwise here we would
+ // adjust fade values for u,v,w
+ int16_t X1 = LERP(grad16(P(AA), xx, yy, zz), grad16(P(BA), xx - N, yy, zz), u);
+ int16_t X2 = LERP(grad16(P(AB), xx, yy-N, zz), grad16(P(BB), xx - N, yy - N, zz), u);
+ int16_t X3 = LERP(grad16(P(AA+1), xx, yy, zz-N), grad16(P(BA+1), xx - N, yy, zz-N), u);
+ int16_t X4 = LERP(grad16(P(AB+1), xx, yy-N, zz-N), grad16(P(BB+1), xx - N, yy - N, zz - N), u);
+
+ int16_t Y1 = LERP(X1,X2,v);
+ int16_t Y2 = LERP(X3,X4,v);
+
+ int16_t ans = LERP(Y1,Y2,w);
- int16_t ans = LERP(Y1,Y2,w);
-
- return ans;
+ return ans;
}
uint16_t inoise16(uint32_t x, uint32_t y, uint32_t z) {
- int32_t ans = inoise16_raw(x,y,z);
- ans = ans + 19052L;
- uint32_t pan = ans;
- // pan = (ans * 220L) >> 7. That's the same as:
- // pan = (ans * 440L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
- // Identical math, except for the highest bit, which we don't care about anyway,
- // since we're returning the 'middle' 16 out of a 32-bit value anyway.
- pan *= 440L;
- return (pan>>8);
+ int32_t ans = inoise16_raw(x,y,z);
+ ans = ans + 19052L;
+ uint32_t pan = ans;
+ // pan = (ans * 220L) >> 7. That's the same as:
+ // pan = (ans * 440L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
+ // Identical math, except for the highest bit, which we don't care about anyway,
+ // since we're returning the 'middle' 16 out of a 32-bit value anyway.
+ pan *= 440L;
+ return (pan>>8);
- // // return scale16by8(pan,220)<<1;
- // return ((inoise16_raw(x,y,z)+19052)*220)>>7;
- // return scale16by8(inoise16_raw(x,y,z)+19052,220)<<1;
+ // // return scale16by8(pan,220)<<1;
+ // return ((inoise16_raw(x,y,z)+19052)*220)>>7;
+ // return scale16by8(inoise16_raw(x,y,z)+19052,220)<<1;
}
int16_t inoise16_raw(uint32_t x, uint32_t y)
{
- // Find the unit cube containing the point
- uint8_t X = x>>16;
- uint8_t Y = y>>16;
+ // Find the unit cube containing the point
+ uint8_t X = x>>16;
+ uint8_t Y = y>>16;
- // Hash cube corner coordinates
- uint8_t A = P(X)+Y;
- uint8_t AA = P(A);
- uint8_t AB = P(A+1);
- uint8_t B = P(X+1)+Y;
- uint8_t BA = P(B);
- uint8_t BB = P(B+1);
+ // Hash cube corner coordinates
+ uint8_t A = P(X)+Y;
+ uint8_t AA = P(A);
+ uint8_t AB = P(A+1);
+ uint8_t B = P(X+1)+Y;
+ uint8_t BA = P(B);
+ uint8_t BB = P(B+1);
- // Get the relative position of the point in the cube
- uint16_t u = x & 0xFFFF;
- uint16_t v = y & 0xFFFF;
+ // Get the relative position of the point in the cube
+ uint16_t u = x & 0xFFFF;
+ uint16_t v = y & 0xFFFF;
- // Get a signed version of the above for the grad function
- int16_t xx = (u >> 1) & 0x7FFF;
- int16_t yy = (v >> 1) & 0x7FFF;
- uint16_t N = 0x8000L;
+ // Get a signed version of the above for the grad function
+ int16_t xx = (u >> 1) & 0x7FFF;
+ int16_t yy = (v >> 1) & 0x7FFF;
+ uint16_t N = 0x8000L;
- u = EASE16(u); v = EASE16(v);
+ u = EASE16(u); v = EASE16(v);
- int16_t X1 = LERP(grad16(P(AA), xx, yy), grad16(P(BA), xx - N, yy), u);
- int16_t X2 = LERP(grad16(P(AB), xx, yy-N), grad16(P(BB), xx - N, yy - N), u);
+ int16_t X1 = LERP(grad16(P(AA), xx, yy), grad16(P(BA), xx - N, yy), u);
+ int16_t X2 = LERP(grad16(P(AB), xx, yy-N), grad16(P(BB), xx - N, yy - N), u);
- int16_t ans = LERP(X1,X2,v);
+ int16_t ans = LERP(X1,X2,v);
- return ans;
+ return ans;
}
uint16_t inoise16(uint32_t x, uint32_t y) {
- int32_t ans = inoise16_raw(x,y);
- ans = ans + 17308L;
- uint32_t pan = ans;
- // pan = (ans * 242L) >> 7. That's the same as:
- // pan = (ans * 484L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
- // Identical math, except for the highest bit, which we don't care about anyway,
- // since we're returning the 'middle' 16 out of a 32-bit value anyway.
- pan *= 484L;
- return (pan>>8);
-
- // return (uint32_t)(((int32_t)inoise16_raw(x,y)+(uint32_t)17308)*242)>>7;
- // return scale16by8(inoise16_raw(x,y)+17308,242)<<1;
+ int32_t ans = inoise16_raw(x,y);
+ ans = ans + 17308L;
+ uint32_t pan = ans;
+ // pan = (ans * 242L) >> 7. That's the same as:
+ // pan = (ans * 484L) >> 8. And this way avoids a 7X four-byte shift-loop on AVR.
+ // Identical math, except for the highest bit, which we don't care about anyway,
+ // since we're returning the 'middle' 16 out of a 32-bit value anyway.
+ pan *= 484L;
+ return (pan>>8);
+
+ // return (uint32_t)(((int32_t)inoise16_raw(x,y)+(uint32_t)17308)*242)>>7;
+ // return scale16by8(inoise16_raw(x,y)+17308,242)<<1;
}
int16_t inoise16_raw(uint32_t x)
{
- // Find the unit cube containing the point
- uint8_t X = x>>16;
+ // Find the unit cube containing the point
+ uint8_t X = x>>16;
- // Hash cube corner coordinates
- uint8_t A = P(X);
- uint8_t AA = P(A);
- uint8_t B = P(X+1);
- uint8_t BA = P(B);
+ // Hash cube corner coordinates
+ uint8_t A = P(X);
+ uint8_t AA = P(A);
+ uint8_t B = P(X+1);
+ uint8_t BA = P(B);
- // Get the relative position of the point in the cube
- uint16_t u = x & 0xFFFF;
+ // Get the relative position of the point in the cube
+ uint16_t u = x & 0xFFFF;
- // Get a signed version of the above for the grad function
- int16_t xx = (u >> 1) & 0x7FFF;
- uint16_t N = 0x8000L;
+ // Get a signed version of the above for the grad function
+ int16_t xx = (u >> 1) & 0x7FFF;
+ uint16_t N = 0x8000L;
- u = EASE16(u);
+ u = EASE16(u);
- int16_t ans = LERP(grad16(P(AA), xx), grad16(P(BA), xx - N), u);
+ int16_t ans = LERP(grad16(P(AA), xx), grad16(P(BA), xx - N), u);
- return ans;
+ return ans;
}
uint16_t inoise16(uint32_t x) {
- return ((uint32_t)((int32_t)inoise16_raw(x) + 17308L)) << 1;
+ return ((uint32_t)((int32_t)inoise16_raw(x) + 17308L)) << 1;
}
int8_t inoise8_raw(uint16_t x, uint16_t y, uint16_t z)
{
- // Find the unit cube containing the point
- uint8_t X = x>>8;
- uint8_t Y = y>>8;
- uint8_t Z = z>>8;
-
- // Hash cube corner coordinates
- uint8_t A = P(X)+Y;
- uint8_t AA = P(A)+Z;
- uint8_t AB = P(A+1)+Z;
- uint8_t B = P(X+1)+Y;
- uint8_t BA = P(B) + Z;
- uint8_t BB = P(B+1)+Z;
-
- // Get the relative position of the point in the cube
- uint8_t u = x;
- uint8_t v = y;
- uint8_t w = z;
-
- // Get a signed version of the above for the grad function
- int8_t xx = ((uint8_t)(x)>>1) & 0x7F;
- int8_t yy = ((uint8_t)(y)>>1) & 0x7F;
- int8_t zz = ((uint8_t)(z)>>1) & 0x7F;
- uint8_t N = 0x80;
-
- u = EASE8(u); v = EASE8(v); w = EASE8(w);
-
- int8_t X1 = lerp7by8(grad8(P(AA), xx, yy, zz), grad8(P(BA), xx - N, yy, zz), u);
- int8_t X2 = lerp7by8(grad8(P(AB), xx, yy-N, zz), grad8(P(BB), xx - N, yy - N, zz), u);
- int8_t X3 = lerp7by8(grad8(P(AA+1), xx, yy, zz-N), grad8(P(BA+1), xx - N, yy, zz-N), u);
- int8_t X4 = lerp7by8(grad8(P(AB+1), xx, yy-N, zz-N), grad8(P(BB+1), xx - N, yy - N, zz - N), u);
+ // Find the unit cube containing the point
+ uint8_t X = x>>8;
+ uint8_t Y = y>>8;
+ uint8_t Z = z>>8;
+
+ // Hash cube corner coordinates
+ uint8_t A = P(X)+Y;
+ uint8_t AA = P(A)+Z;
+ uint8_t AB = P(A+1)+Z;
+ uint8_t B = P(X+1)+Y;
+ uint8_t BA = P(B) + Z;
+ uint8_t BB = P(B+1)+Z;
+
+ // Get the relative position of the point in the cube
+ uint8_t u = x;
+ uint8_t v = y;
+ uint8_t w = z;
+
+ // Get a signed version of the above for the grad function
+ int8_t xx = ((uint8_t)(x)>>1) & 0x7F;
+ int8_t yy = ((uint8_t)(y)>>1) & 0x7F;
+ int8_t zz = ((uint8_t)(z)>>1) & 0x7F;
+ uint8_t N = 0x80;
+
+ u = EASE8(u); v = EASE8(v); w = EASE8(w);
+
+ int8_t X1 = lerp7by8(grad8(P(AA), xx, yy, zz), grad8(P(BA), xx - N, yy, zz), u);
+ int8_t X2 = lerp7by8(grad8(P(AB), xx, yy-N, zz), grad8(P(BB), xx - N, yy - N, zz), u);
+ int8_t X3 = lerp7by8(grad8(P(AA+1), xx, yy, zz-N), grad8(P(BA+1), xx - N, yy, zz-N), u);
+ int8_t X4 = lerp7by8(grad8(P(AB+1), xx, yy-N, zz-N), grad8(P(BB+1), xx - N, yy - N, zz - N), u);
+
+ int8_t Y1 = lerp7by8(X1,X2,v);
+ int8_t Y2 = lerp7by8(X3,X4,v);
+
+ int8_t ans = lerp7by8(Y1,Y2,w);
- int8_t Y1 = lerp7by8(X1,X2,v);
- int8_t Y2 = lerp7by8(X3,X4,v);
-
- int8_t ans = lerp7by8(Y1,Y2,w);
-
- return ans;
+ return ans;
}
uint8_t inoise8(uint16_t x, uint16_t y, uint16_t z) {
-// return scale8(76+(inoise8_raw(x,y,z)),215)<<1;
+ //return scale8(76+(inoise8_raw(x,y,z)),215)<<1;
int8_t n = inoise8_raw( x, y, z); // -64..+64
n+= 64; // 0..128
uint8_t ans = qadd8( n, n); // 0..255
@@ -470,36 +473,36 @@ uint8_t inoise8(uint16_t x, uint16_t y, uint16_t z) {
int8_t inoise8_raw(uint16_t x, uint16_t y)
{
- // Find the unit cube containing the point
- uint8_t X = x>>8;
- uint8_t Y = y>>8;
+ // Find the unit cube containing the point
+ uint8_t X = x>>8;
+ uint8_t Y = y>>8;
- // Hash cube corner coordinates
- uint8_t A = P(X)+Y;
- uint8_t AA = P(A);
- uint8_t AB = P(A+1);
- uint8_t B = P(X+1)+Y;
- uint8_t BA = P(B);
- uint8_t BB = P(B+1);
+ // Hash cube corner coordinates
+ uint8_t A = P(X)+Y;
+ uint8_t AA = P(A);
+ uint8_t AB = P(A+1);
+ uint8_t B = P(X+1)+Y;
+ uint8_t BA = P(B);
+ uint8_t BB = P(B+1);
- // Get the relative position of the point in the cube
- uint8_t u = x;
- uint8_t v = y;
+ // Get the relative position of the point in the cube
+ uint8_t u = x;
+ uint8_t v = y;
- // Get a signed version of the above for the grad function
- int8_t xx = ((uint8_t)(x)>>1) & 0x7F;
- int8_t yy = ((uint8_t)(y)>>1) & 0x7F;
- uint8_t N = 0x80;
+ // Get a signed version of the above for the grad function
+ int8_t xx = ((uint8_t)(x)>>1) & 0x7F;
+ int8_t yy = ((uint8_t)(y)>>1) & 0x7F;
+ uint8_t N = 0x80;
- u = EASE8(u); v = EASE8(v);
-
- int8_t X1 = lerp7by8(grad8(P(AA), xx, yy), grad8(P(BA), xx - N, yy), u);
- int8_t X2 = lerp7by8(grad8(P(AB), xx, yy-N), grad8(P(BB), xx - N, yy - N), u);
+ u = EASE8(u); v = EASE8(v);
- int8_t ans = lerp7by8(X1,X2,v);
+ int8_t X1 = lerp7by8(grad8(P(AA), xx, yy), grad8(P(BA), xx - N, yy), u);
+ int8_t X2 = lerp7by8(grad8(P(AB), xx, yy-N), grad8(P(BB), xx - N, yy - N), u);
- return ans;
- // return scale8((70+(ans)),234)<<1;
+ int8_t ans = lerp7by8(X1,X2,v);
+
+ return ans;
+ // return scale8((70+(ans)),234)<<1;
}
@@ -562,8 +565,8 @@ uint8_t inoise8(uint16_t x) {
void fill_raw_noise8(uint8_t *pData, uint8_t num_points, uint8_t octaves, uint16_t x, int scale, uint16_t time) {
uint32_t _xx = x;
uint32_t scx = scale;
- for(int o = 0; o < octaves; o++) {
- for(int i = 0,xx=_xx; i < num_points; i++, xx+=scx) {
+ for(int o = 0; o < octaves; ++o) {
+ for(int i = 0,xx=_xx; i < num_points; ++i, xx+=scx) {
pData[i] = qadd8(pData[i],inoise8(xx,time)>>o);
}
@@ -575,8 +578,8 @@ void fill_raw_noise8(uint8_t *pData, uint8_t num_points, uint8_t octaves, uint16
void fill_raw_noise16into8(uint8_t *pData, uint8_t num_points, uint8_t octaves, uint32_t x, int scale, uint32_t time) {
uint32_t _xx = x;
uint32_t scx = scale;
- for(int o = 0; o < octaves; o++) {
- for(int i = 0,xx=_xx; i < num_points; i++, xx+=scx) {
+ for(int o = 0; o < octaves; ++o) {
+ for(int i = 0,xx=_xx; i < num_points; ++i, xx+=scx) {
uint32_t accum = (inoise16(xx,time))>>o;
accum += (pData[i]<<8);
if(accum > 65535) { accum = 65535; }
@@ -601,19 +604,19 @@ void fill_raw_2dnoise8(uint8_t *pData, int width, int height, uint8_t octaves, q
fract8 invamp = 255-amplitude;
uint16_t xx = x;
- for(int i = 0; i < height; i++, y+=scaley) {
+ for(int i = 0; i < height; ++i, y+=scaley) {
uint8_t *pRow = pData + (i*width);
xx = x;
- for(int j = 0; j < width; j++, xx+=scalex) {
+ for(int j = 0; j < width; ++j, xx+=scalex) {
uint8_t noise_base = inoise8(xx,y,time);
noise_base = (0x80 & noise_base) ? (noise_base - 127) : (127 - noise_base);
noise_base = scale8(noise_base<<1,amplitude);
if(skip == 1) {
pRow[j] = scale8(pRow[j],invamp) + noise_base;
} else {
- for(int ii = i; ii<(i+skip) && ii<height; ii++) {
+ for(int ii = i; ii<(i+skip) && ii<height; ++ii) {
uint8_t *pRow = pData + (ii*width);
- for(int jj=j; jj<(j+skip) && jj<width; jj++) {
+ for(int jj=j; jj<(j+skip) && jj<width; ++jj) {
pRow[jj] = scale8(pRow[jj],invamp) + noise_base;
}
}
@@ -646,9 +649,9 @@ void fill_raw_2dnoise16(uint16_t *pData, int width, int height, uint8_t octaves,
if(skip==1) {
pRow[j] = scale16(pRow[j],invamp) + noise_base;
} else {
- for(int ii = i; ii<(i+skip) && ii<height; ii++) {
+ for(int ii = i; ii<(i+skip) && ii<height; ++ii) {
uint16_t *pRow = pData + (ii*width);
- for(int jj=j; jj<(j+skip) && jj<width; jj++) {
+ for(int jj=j; jj<(j+skip) && jj<width; ++jj) {
pRow[jj] = scale16(pRow[jj],invamp) + noise_base;
}
}
@@ -682,9 +685,9 @@ void fill_raw_2dnoise16into8(uint8_t *pData, int width, int height, uint8_t octa
if(skip==1) {
pRow[j] = qadd8(scale8(pRow[j],invamp),noise_base);
} else {
- for(int ii = i; ii<(i+skip) && ii<height; ii++) {
+ for(int ii = i; ii<(i+skip) && ii<height; ++ii) {
uint8_t *pRow = pData + (ii*width);
- for(int jj=j; jj<(j+skip) && jj<width; jj++) {
+ for(int jj=j; jj<(j+skip) && jj<width; ++jj) {
pRow[jj] = scale8(pRow[jj],invamp) + noise_base;
}
}
@@ -710,7 +713,7 @@ void fill_noise8(CRGB *leds, int num_leds,
fill_raw_noise8(V,num_leds,octaves,x,scale,time);
fill_raw_noise8(H,num_leds,hue_octaves,hue_x,hue_scale,time);
- for(int i = 0; i < num_leds; i++) {
+ for(int i = 0; i < num_leds; ++i) {
leds[i] = CHSV(H[i],255,V[i]);
}
}
@@ -728,7 +731,7 @@ void fill_noise16(CRGB *leds, int num_leds,
fill_raw_noise16into8(V,num_leds,octaves,x,scale,time);
fill_raw_noise8(H,num_leds,hue_octaves,hue_x,hue_scale,time);
- for(int i = 0; i < num_leds; i++) {
+ for(int i = 0; i < num_leds; ++i) {
leds[i] = CHSV(H[i] + hue_shift,255,V[i]);
}
}
@@ -747,9 +750,9 @@ void fill_2dnoise8(CRGB *leds, int width, int height, bool serpentine,
int w1 = width-1;
int h1 = height-1;
- for(int i = 0; i < height; i++) {
+ for(int i = 0; i < height; ++i) {
int wb = i*width;
- for(int j = 0; j < width; j++) {
+ for(int j = 0; j < width; ++j) {
CRGB led(CHSV(H[h1-i][w1-j],255,V[i][j]));
int pos = j;
@@ -785,9 +788,9 @@ void fill_2dnoise16(CRGB *leds, int width, int height, bool serpentine,
int h1 = height-1;
hue_shift >>= 8;
- for(int i = 0; i < height; i++) {
+ for(int i = 0; i < height; ++i) {
int wb = i*width;
- for(int j = 0; j < width; j++) {
+ for(int j = 0; j < width; ++j) {
CRGB led(CHSV(hue_shift + (H[h1-i][w1-j]),196,V[i][j]));
int pos = j;
diff --git a/noise.h b/src/noise.h
index 7355e23e..7355e23e 100644
--- a/noise.h
+++ b/src/noise.h
diff --git a/src/pixelset.h b/src/pixelset.h
new file mode 100644
index 00000000..b8488c2c
--- /dev/null
+++ b/src/pixelset.h
@@ -0,0 +1,306 @@
+#ifndef __INC_PIXELSET_H
+#define __INC_PIXELSET_H
+
+#include "FastLED.h"
+
+#ifndef abs
+#include <stdlib.h>
+#endif
+
+///// Represents a set of CRGB led objects. Provides the [] array operator, and works like a normal array in that case.
+///// This should be kept in sync with the set of functions provided by CRGB as well as functions in colorutils. Note
+///// that a pixel set is a window into another set of led data, it is not its own set of led data.
+template<class PIXEL_TYPE>
+class CPixelView {
+public:
+ const int8_t dir;
+ const int len;
+ PIXEL_TYPE * const leds;
+ PIXEL_TYPE * const end_pos;
+
+public:
+ /// PixelSet copy constructor
+ inline CPixelView(const CPixelView & other) : dir(other.dir), len(other.len), leds(other.leds), end_pos(other.end_pos) {}
+
+ /// pixelset constructor for a pixel set starting at the given PIXEL_TYPE* and going for _len leds. Note that the length
+ /// can be backwards, creating a PixelSet that walks backwards over the data
+ /// @param leds point to the raw led data
+ /// @param len how many leds in this set
+ inline CPixelView(PIXEL_TYPE *_leds, int _len) : dir(_len < 0 ? -1 : 1), len(_len), leds(_leds), end_pos(_leds + _len) {}
+
+ /// PixelSet constructor for the given set of leds, with start and end boundaries. Note that start can be after
+ /// end, resulting in a set that will iterate backwards
+ /// @param leds point to the raw led data
+ /// @param start the start index of the leds for this array
+ /// @param end the end index of the leds for this array
+ inline CPixelView(PIXEL_TYPE *_leds, int _start, int _end) : dir(((_end-_start)<0) ? -1 : 1), len((_end - _start) + dir), leds(_leds + _start), end_pos(_leds + _start + len) {}
+
+ /// Get the size of this set
+ /// @return the size of the set
+ int size() { return abs(len); }
+
+ /// Whether or not this set goes backwards
+ /// @return whether or not the set is backwards
+ bool reversed() { return len < 0; }
+
+ /// do these sets point to the same thing (note, this is different from the contents of the set being the same)
+ bool operator==(const CPixelView & rhs) const { return leds == rhs.leds && len == rhs.len && dir == rhs.dir; }
+
+ /// do these sets point to the different things (note, this is different from the contents of the set being the same)
+ bool operator!=(const CPixelView & rhs) const { return leds != rhs.leds || len != rhs.len || dir != rhs.dir; }
+
+ /// access a single element in this set, just like an array operator
+ inline PIXEL_TYPE & operator[](int x) const { if(dir & 0x80) { return leds[-x]; } else { return leds[x]; } }
+
+ /// Access an inclusive subset of the leds in this set. Note that start can be greater than end, which will
+ /// result in a reverse ordering for many functions (useful for mirroring)
+ /// @param start the first element from this set for the new subset
+ /// @param end the last element for the new subset
+ inline CPixelView operator()(int start, int end) { return CPixelView(leds, start, end); }
+
+ /// Access an inclusive subset of the leds in this set, starting from the first.
+ /// @param end the last element for the new subset
+ /// Not sure i want this? inline CPixelView operator()(int end) { return CPixelView(leds, 0, end); }
+
+ /// Return the reverse ordering of this set
+ inline CPixelView operator-() { return CPixelView(leds, len - dir, 0); }
+
+ /// Return a pointer to the first element in this set
+ inline operator PIXEL_TYPE* () const { return leds; }
+
+ /// Assign the passed in color to all elements in this set
+ /// @param color the new color for the elements in the set
+ inline CPixelView & operator=(const PIXEL_TYPE & color) {
+ for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) = color; }
+ return *this;
+ }
+
+
+ void dump() const {
+ /**
+ Serial.print("len: "); Serial.print(len); Serial.print(", dir:"); Serial.print((int)dir);
+ Serial.print(", range:"); Serial.print((uint32_t)leds); Serial.print("-"); Serial.print((uint32_t)end_pos);
+ Serial.print(", diff:"); Serial.print((int32_t)(end_pos - leds));
+ Serial.println("");
+ **/
+ }
+
+ /// Copy the contents of the passed in set to our set. Note if one set is smaller than the other, only the
+ /// smallest number of items will be copied over.
+ inline CPixelView & operator=(const CPixelView & rhs) {
+ for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) {
+ (*pixel) = (*rhspixel);
+ }
+ return *this;
+ }
+
+ /// @name modification/scaling operators
+ //@{
+ /// Add the passed in value to r,g, b for all the pixels in this set
+ inline CPixelView & addToRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) += inc; } return *this; }
+ /// Add every pixel in the other set to this set
+ inline CPixelView & operator+=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) += (*rhspixel); } return *this; }
+
+ /// Subtract the passed in value from r,g,b for all pixels in this set
+ inline CPixelView & subFromRGB(uint8_t inc) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) -= inc; } return *this; }
+ /// Subtract every pixel in the other set from this set
+ inline CPixelView & operator-=(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) -= (*rhspixel); } return *this; }
+
+ /// Increment every pixel value in this set
+ inline CPixelView & operator++() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
+ /// Increment every pixel value in this set
+ inline CPixelView & operator++(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)++; } return *this; }
+
+ /// Decrement every pixel value in this set
+ inline CPixelView & operator--() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
+ /// Decrement every pixel value in this set
+ inline CPixelView & operator--(int DUMMY_ARG) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel)--; } return *this; }
+
+ /// Divide every led by the given value
+ inline CPixelView & operator/=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) /= d; } return *this; }
+ /// Shift every led in this set right by the given number of bits
+ inline CPixelView & operator>>=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) >>= d; } return *this; }
+ /// Multiply every led in this set by the given value
+ inline CPixelView & operator*=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) *= d; } return *this; }
+
+ /// Scale every led by the given scale
+ inline CPixelView & nscale8_video(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this;}
+ /// Scale down every led by the given scale
+ inline CPixelView & operator%=(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8_video(scaledown); } return *this; }
+ /// Fade every led down by the given scale
+ inline CPixelView & fadeLightBy(uint8_t fadefactor) { return nscale8_video(255 - fadefactor); }
+
+ /// Scale every led by the given scale
+ inline CPixelView & nscale8(uint8_t scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
+ /// Scale every led by the given scale
+ inline CPixelView & nscale8(PIXEL_TYPE & scaledown) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel).nscale8(scaledown); } return *this; }
+ /// Scale every led in this set by every led in the other set
+ inline CPixelView & nscale8(CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel).nscale8((*rhspixel)); } return *this; }
+
+ /// Fade every led down by the given scale
+ inline CPixelView & fadeToBlackBy(uint8_t fade) { return nscale8(255 - fade); }
+
+ /// Apply the PIXEL_TYPE |= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel to the higher of the two values)
+ inline CPixelView & operator|=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= rhs; } return *this; }
+ /// Apply the PIXEL_TYPE |= operator to every pixel in this set with every pixel in the passed in set
+ inline CPixelView & operator|=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) |= (*rhspixel); } return *this; }
+ /// Apply the PIXEL_TYPE |= operator to every pixel in this set
+ inline CPixelView & operator|=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) |= d; } return *this; }
+
+ /// Apply the PIXEL_TYPE &= operator to every pixel in this set with the given PIXEL_TYPE value (bringing each channel down to the lower of the two values)
+ inline CPixelView & operator&=(const PIXEL_TYPE & rhs) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= rhs; } return *this; }
+ /// Apply the PIXEL_TYPE &= operator to every pixel in this set with every pixel in the passed in set
+ inline CPixelView & operator&=(const CPixelView & rhs) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { (*pixel) &= (*rhspixel); } return *this; }
+ /// APply the PIXEL_TYPE &= operator to every pixel in this set with the passed in value
+ inline CPixelView & operator&=(uint8_t d) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { (*pixel) &= d; } return *this; }
+ //@}
+
+ /// Returns whether or not any leds in this set are non-zero
+ inline operator bool() { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { if((*pixel)) return true; } return false; }
+
+ // Color util functions
+ inline CPixelView & fill_solid(const PIXEL_TYPE & color) { *this = color; return *this; }
+ inline CPixelView & fill_solid(const CHSV & color) { if(dir>0) { *this = color; return *this; } }
+
+ inline CPixelView & fill_rainbow(uint8_t initialhue, uint8_t deltahue=5) {
+ if(dir >= 0) {
+ ::fill_rainbow(leds,len,initialhue,deltahue);
+ } else {
+ ::fill_rainbow(leds+len+1,-len,initialhue,deltahue);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient(const CHSV & startcolor, const CHSV & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient(leds,len,startcolor, endcolor, directionCode);
+ } else {
+ ::fill_gradient(leds + len + 1, (-len), endcolor, startcolor, directionCode);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient(leds, len, c1, c2, c3, directionCode);
+ } else {
+ ::fill_gradient(leds + len + 1, -len, c3, c2, c1, directionCode);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient(const CHSV & c1, const CHSV & c2, const CHSV & c3, const CHSV & c4, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient(leds, len, c1, c2, c3, c4, directionCode);
+ } else {
+ ::fill_gradient(leds + len + 1, -len, c4, c3, c2, c1, directionCode);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & startcolor, const PIXEL_TYPE & endcolor, TGradientDirectionCode directionCode = SHORTEST_HUES) {
+ if(dir >= 0) {
+ ::fill_gradient_RGB(leds,len,startcolor, endcolor);
+ } else {
+ ::fill_gradient_RGB(leds + len + 1, (-len), endcolor, startcolor);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3) {
+ if(dir >= 0) {
+ ::fill_gradient_RGB(leds, len, c1, c2, c3);
+ } else {
+ ::fill_gradient_RGB(leds + len + 1, -len, c3, c2, c1);
+ }
+ return *this;
+ }
+
+ inline CPixelView & fill_gradient_RGB(const PIXEL_TYPE & c1, const PIXEL_TYPE & c2, const PIXEL_TYPE & c3, const PIXEL_TYPE & c4) {
+ if(dir >= 0) {
+ ::fill_gradient_RGB(leds, len, c1, c2, c3, c4);
+ } else {
+ ::fill_gradient_RGB(leds + len + 1, -len, c4, c3, c2, c1);
+ }
+ return *this;
+ }
+
+ inline CPixelView & nblend(const PIXEL_TYPE & overlay, fract8 amountOfOverlay) { for(iterator pixel = begin(), _end = end(); pixel != _end; ++pixel) { ::nblend((*pixel), overlay, amountOfOverlay); } return *this; }
+ inline CPixelView & nblend(const CPixelView & rhs, fract8 amountOfOverlay) { for(iterator pixel = begin(), rhspixel = rhs.begin(), _end = end(), rhs_end = rhs.end(); (pixel != _end) && (rhspixel != rhs_end); ++pixel, ++rhspixel) { ::nblend((*pixel), (*rhspixel), amountOfOverlay); } return *this; }
+
+ // Note: only bringing in a 1d blur, not sure 2d blur makes sense when looking at sub arrays
+ inline CPixelView & blur1d(fract8 blur_amount) {
+ if(dir >= 0) {
+ ::blur1d(leds, len, blur_amount);
+ } else {
+ ::blur1d(leds + len + 1, -len, blur_amount);
+ }
+ return *this;
+ }
+
+ inline CPixelView & napplyGamma_video(float gamma) {
+ if(dir >= 0) {
+ ::napplyGamma_video(leds, len, gamma);
+ } else {
+ ::napplyGamma_video(leds + len + 1, -len, gamma);
+ }
+ return *this;
+ }
+
+ inline CPixelView & napplyGamma_video(float gammaR, float gammaG, float gammaB) {
+ if(dir >= 0) {
+ ::napplyGamma_video(leds, len, gammaR, gammaG, gammaB);
+ } else {
+ ::napplyGamma_video(leds + len + 1, -len, gammaR, gammaG, gammaB);
+ }
+ return *this;
+ }
+
+ // TODO: Make this a fully specified/proper iterator
+ template <class T>
+ class pixelset_iterator_base {
+ T * leds;
+ const int8_t dir;
+
+ public:
+ __attribute__((always_inline)) inline pixelset_iterator_base(const pixelset_iterator_base & rhs) : leds(rhs.leds), dir(rhs.dir) {}
+ __attribute__((always_inline)) inline pixelset_iterator_base(T * _leds, const char _dir) : leds(_leds), dir(_dir) {}
+
+ __attribute__((always_inline)) inline pixelset_iterator_base& operator++() { leds += dir; return *this; }
+ __attribute__((always_inline)) inline pixelset_iterator_base operator++(int) { pixelset_iterator_base tmp(*this); leds += dir; return tmp; }
+
+ __attribute__((always_inline)) inline bool operator==(pixelset_iterator_base & other) const { return leds == other.leds; } // && set==other.set; }
+ __attribute__((always_inline)) inline bool operator!=(pixelset_iterator_base & other) const { return leds != other.leds; } // || set != other.set; }
+
+ __attribute__((always_inline)) inline PIXEL_TYPE& operator*() const { return *leds; }
+ };
+
+ typedef pixelset_iterator_base<PIXEL_TYPE> iterator;
+ typedef pixelset_iterator_base<const PIXEL_TYPE> const_iterator;
+
+ iterator begin() { return iterator(leds, dir); }
+ iterator end() { return iterator(end_pos, dir); }
+
+ iterator begin() const { return iterator(leds, dir); }
+ iterator end() const { return iterator(end_pos, dir); }
+
+ const_iterator cbegin() const { return const_iterator(leds, dir); }
+ const_iterator cend() const { return const_iterator(end_pos, dir); }
+};
+
+typedef CPixelView<CRGB> CRGBSet;
+
+__attribute__((always_inline))
+inline CRGB *operator+(const CRGBSet & pixels, int offset) { return (CRGB*)pixels + offset; }
+
+
+template<int SIZE>
+class CRGBArray : public CPixelView<CRGB> {
+ CRGB rawleds[SIZE];
+
+public:
+ CRGBArray() : CPixelView<CRGB>(rawleds, SIZE) {}
+ using CPixelView::operator=;
+};
+
+#endif
diff --git a/pixeltypes.h b/src/pixeltypes.h
index f4e57061..6e91723d 100644
--- a/pixeltypes.h
+++ b/src/pixeltypes.h
@@ -51,9 +51,7 @@ struct CHSV {
}
/// default values are UNITIALIZED
- inline CHSV() __attribute__((always_inline))
- {
- }
+ inline CHSV() __attribute__((always_inline)) = default;
/// allow construction from H, S, V
inline CHSV( uint8_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline))
@@ -62,20 +60,9 @@ struct CHSV {
}
/// allow copy construction
- inline CHSV(const CHSV& rhs) __attribute__((always_inline))
- {
- h = rhs.h;
- s = rhs.s;
- v = rhs.v;
- }
+ inline CHSV(const CHSV& rhs) __attribute__((always_inline)) = default;
- inline CHSV& operator= (const CHSV& rhs) __attribute__((always_inline))
- {
- h = rhs.h;
- s = rhs.s;
- v = rhs.v;
- return *this;
- }
+ inline CHSV& operator= (const CHSV& rhs) __attribute__((always_inline)) = default;
inline CHSV& setHSV(uint8_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline))
{
@@ -131,9 +118,7 @@ struct CRGB {
}
// default values are UNINITIALIZED
- inline CRGB() __attribute__((always_inline))
- {
- }
+ inline CRGB() __attribute__((always_inline)) = default;
/// allow construction from R, G, B
inline CRGB( uint8_t ir, uint8_t ig, uint8_t ib) __attribute__((always_inline))
@@ -162,13 +147,7 @@ struct CRGB {
}
/// allow copy construction
- inline CRGB(const CRGB& rhs) __attribute__((always_inline))
- {
- r = rhs.r;
- g = rhs.g;
- b = rhs.b;
- }
-
+ inline CRGB(const CRGB& rhs) __attribute__((always_inline)) = default;
/// allow construction from HSV color
inline CRGB(const CHSV& rhs) __attribute__((always_inline))
{
@@ -176,13 +155,7 @@ struct CRGB {
}
/// allow assignment from one RGB struct to another
- inline CRGB& operator= (const CRGB& rhs) __attribute__((always_inline))
- {
- r = rhs.r;
- g = rhs.g;
- b = rhs.b;
- return *this;
- }
+ inline CRGB& operator= (const CRGB& rhs) __attribute__((always_inline)) = default;
/// allow assignment from 32-bit (really 24-bit) 0xRRGGBB color code
inline CRGB& operator= (const uint32_t colorcode) __attribute__((always_inline))
@@ -317,10 +290,10 @@ struct CRGB {
/// right shift each of the channels by a constant
inline CRGB& operator>>= (uint8_t d)
{
- r >>= d;
- g >>= d;
- b >>= d;
- return *this;
+ r >>= d;
+ g >>= d;
+ b >>= d;
+ return *this;
}
/// multiply each of the channels by a constant,
@@ -450,11 +423,11 @@ struct CRGB {
#if (defined SmartMatrix_h || defined SmartMatrix3_h)
operator rgb24() const {
- rgb24 ret;
- ret.red = r;
- ret.green = g;
- ret.blue = b;
- return ret;
+ rgb24 ret;
+ ret.red = r;
+ ret.green = g;
+ ret.blue = b;
+ return ret;
}
#endif
@@ -503,25 +476,25 @@ struct CRGB {
/// return a new CRGB object after performing a linear interpolation between this object and the passed in object
inline CRGB lerp8( const CRGB& other, fract8 frac) const
{
- CRGB ret;
+ CRGB ret;
- ret.r = lerp8by8(r,other.r,frac);
- ret.g = lerp8by8(g,other.g,frac);
- ret.b = lerp8by8(b,other.b,frac);
+ ret.r = lerp8by8(r,other.r,frac);
+ ret.g = lerp8by8(g,other.g,frac);
+ ret.b = lerp8by8(b,other.b,frac);
- return ret;
+ return ret;
}
/// return a new CRGB object after performing a linear interpolation between this object and the passed in object
inline CRGB lerp16( const CRGB& other, fract16 frac) const
{
- CRGB ret;
+ CRGB ret;
- ret.r = lerp16by16(r<<8,other.r<<8,frac)>>8;
- ret.g = lerp16by16(g<<8,other.g<<8,frac)>>8;
- ret.b = lerp16by16(b<<8,other.b<<8,frac)>>8;
+ ret.r = lerp16by16(r<<8,other.r<<8,frac)>>8;
+ ret.g = lerp16by16(g<<8,other.g<<8,frac)>>8;
+ ret.b = lerp16by16(b<<8,other.b<<8,frac)>>8;
- return ret;
+ return ret;
}
/// getParity returns 0 or 1, depending on the
@@ -565,14 +538,14 @@ struct CRGB {
// going 'up'
if( (b > 0) && (b < 255)) {
if( r == g && g == b) {
- r++;
- g++;
+ ++r;
+ ++g;
}
- b++;
+ ++b;
} else if( (r > 0) && (r < 255)) {
- r++;
+ ++r;
} else if( (g > 0) && (g < 255)) {
- g++;
+ ++g;
} else {
if( r == g && g == b) {
r ^= 0x01;
@@ -584,14 +557,14 @@ struct CRGB {
// going 'down'
if( b > 1) {
if( r == g && g == b) {
- r--;
- g--;
+ --r;
+ --g;
}
- b--;
+ --b;
} else if( g > 1) {
- g--;
+ --g;
} else if( r > 1) {
- r--;
+ --r;
} else {
if( r == g && g == b) {
r ^= 0x01;
diff --git a/platforms.cpp b/src/platforms.cpp
index 47a00883..5b6847ad 100644
--- a/platforms.cpp
+++ b/src/platforms.cpp
@@ -17,16 +17,16 @@
#endif
// NOTE: Update platforms.cpp in root of FastLED library if this changes
#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE0)
- void PWM0_IRQHandler(void) { isrCount++; PWM_Arbiter<0>::isr_handler(); }
+ void PWM0_IRQHandler(void) { ++isrCount; PWM_Arbiter<0>::isr_handler(); }
#endif
#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE1)
- void PWM1_IRQHandler(void) { isrCount++; PWM_Arbiter<1>::isr_handler(); }
+ void PWM1_IRQHandler(void) { ++isrCount; PWM_Arbiter<1>::isr_handler(); }
#endif
#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE2)
- void PWM2_IRQHandler(void) { isrCount++; PWM_Arbiter<2>::isr_handler(); }
+ void PWM2_IRQHandler(void) { ++isrCount; PWM_Arbiter<2>::isr_handler(); }
#endif
#if defined(FASTLED_NRF52_ENABLE_PWM_INSTANCE3)
- void PWM3_IRQHandler(void) { isrCount++; PWM_Arbiter<3>::isr_handler(); }
+ void PWM3_IRQHandler(void) { ++isrCount; PWM_Arbiter<3>::isr_handler(); }
#endif
#ifdef __cplusplus
}
diff --git a/platforms.h b/src/platforms.h
index 7969c9e4..5351e2c1 100644
--- a/platforms.h
+++ b/src/platforms.h
@@ -24,11 +24,11 @@
#elif defined(__SAM3X8E__)
// Include sam/due headers
#include "platforms/arm/sam/fastled_arm_sam.h"
-#elif defined(STM32F10X_MD) || defined(__STM32F1__)
+#elif defined(STM32F10X_MD) || defined(__STM32F1__) || defined(STM32F2XX)
#include "platforms/arm/stm32/fastled_arm_stm32.h"
#elif defined(__SAMD21G18A__) || defined(__SAMD21J18A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__)
#include "platforms/arm/d21/fastled_arm_d21.h"
-#elif defined(__SAMD51G19A__) || defined(__SAMD51J19A__)
+#elif defined(__SAMD51G19A__) || defined(__SAMD51J19A__) || defined(__SAMD51P19A__)
#include "platforms/arm/d51/fastled_arm_d51.h"
#elif defined(ESP8266)
#include "platforms/esp/8266/fastled_esp8266.h"
diff --git a/platforms/apollo3/clockless_apollo3.h b/src/platforms/apollo3/clockless_apollo3.h
index d881eee4..fa487c2f 100644
--- a/platforms/apollo3/clockless_apollo3.h
+++ b/src/platforms/apollo3/clockless_apollo3.h
@@ -31,7 +31,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<DATA_PIN>::port_t data_t;
- CMinWait<WAIT_TIME> mWait;
+ CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
@@ -39,86 +39,85 @@ public:
// Configure DATA_PIN for FastGPIO (settings are in fastpin_apollo3.h)
FastPin<DATA_PIN>::setOutput();
- FastPin<DATA_PIN>::lo();
+ FastPin<DATA_PIN>::lo();
// Make sure the system clock is running at the full 48MHz
- am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
+ am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0);
// Make sure interrupts are enabled
- //am_hal_interrupt_master_enable();
+ //am_hal_interrupt_master_enable();
- // Enable SysTick Interrupts in the NVIC
- //NVIC_EnableIRQ(SysTick_IRQn);
+ // Enable SysTick Interrupts in the NVIC
+ //NVIC_EnableIRQ(SysTick_IRQn);
// SysTick is 24-bit and counts down (not up)
- // Stop the SysTick (just in case it is already running).
- // This clears the ENABLE bit in the SysTick Control and Status Register (SYST_CSR).
- // In Ambiq naming convention, the control register is SysTick->CTRL
- am_hal_systick_stop();
-
- // Call SysTick_Config
- // This is defined in core_cm4.h
- // It loads the specified LOAD value into the SysTick Reload Value Register (SYST_RVR)
- // In Ambiq naming convention, the reload register is SysTick->LOAD
- // It sets the SysTick interrupt priority
- // It clears the SysTick Current Value Register (SYST_CVR)
- // In Ambiq naming convention, the current value register is SysTick->VAL
- // Finally it sets these bits in the SysTick Control and Status Register (SYST_CSR):
- // CLKSOURCE: SysTick uses the processor clock
- // TICKINT: When the count reaches zero, the SysTick exception (interrupt) is changed to pending
- // ENABLE: Enables the counter
- // SysTick_Config returns 0 if successful. 1 indicates a failure (the LOAD value was invalid).
- SysTick_Config(0xFFFFFFUL); // The LOAD value needs to be 24-bit
+ // Stop the SysTick (just in case it is already running).
+ // This clears the ENABLE bit in the SysTick Control and Status Register (SYST_CSR).
+ // In Ambiq naming convention, the control register is SysTick->CTRL
+ am_hal_systick_stop();
+
+ // Call SysTick_Config
+ // This is defined in core_cm4.h
+ // It loads the specified LOAD value into the SysTick Reload Value Register (SYST_RVR)
+ // In Ambiq naming convention, the reload register is SysTick->LOAD
+ // It sets the SysTick interrupt priority
+ // It clears the SysTick Current Value Register (SYST_CVR)
+ // In Ambiq naming convention, the current value register is SysTick->VAL
+ // Finally it sets these bits in the SysTick Control and Status Register (SYST_CSR):
+ // CLKSOURCE: SysTick uses the processor clock
+ // TICKINT: When the count reaches zero, the SysTick exception (interrupt) is changed to pending
+ // ENABLE: Enables the counter
+ // SysTick_Config returns 0 if successful. 1 indicates a failure (the LOAD value was invalid).
+ SysTick_Config(0xFFFFFFUL); // The LOAD value needs to be 24-bit
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
+ mWait.wait();
if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- mWait.mark();
- }
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
+ }
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint8_t & b) {
// SysTick counts down (not up) and is 24-bit
for(register uint32_t i = BITS-1; i > 0; i--) { // We could speed this up by using Bit Banding
- while(__am_hal_systick_count() > next_mark) { ; } // Wait for the remainder of this cycle to complete
- // Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
- // SysTick counts down (not up) and is 24-bit
- next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
- FastPin<DATA_PIN>::hi();
- if(b&0x80) {
- // "1 code" = longer pulse width
- while((__am_hal_systick_count() - next_mark) > (T3+(3*(F_CPU/24000000)))) { ; }
- FastPin<DATA_PIN>::lo();
- } else {
- // "0 code" = shorter pulse width
- while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
- FastPin<DATA_PIN>::lo();
- }
- b <<= 1;
+ while(__am_hal_systick_count() > next_mark) { ; } // Wait for the remainder of this cycle to complete
+ // Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
+ // SysTick counts down (not up) and is 24-bit
+ next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
+ FastPin<DATA_PIN>::hi();
+ if(b&0x80) {
+ // "1 code" = longer pulse width
+ while((__am_hal_systick_count() - next_mark) > (T3+(3*(F_CPU/24000000)))) { ; }
+ FastPin<DATA_PIN>::lo();
+ } else {
+ // "0 code" = shorter pulse width
+ while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
+ FastPin<DATA_PIN>::lo();
+ }
+ b <<= 1;
}
- while(__am_hal_systick_count() > next_mark) { ; }// Wait for the remainder of this cycle to complete
+ while(__am_hal_systick_count() > next_mark) { ; }// Wait for the remainder of this cycle to complete
// Calculate next_mark (the time of the next DATA_PIN transition) by subtracting T1+T2+T3
// SysTick counts down (not up) and is 24-bit
next_mark = (__am_hal_systick_count() - (T1+T2+T3)) & 0xFFFFFFUL;
FastPin<DATA_PIN>::hi();
- if(b&0x80) {
+ if(b&0x80) {
// "1 code" = longer pulse width
- while((__am_hal_systick_count() - next_mark) > (T3+(2*(F_CPU/24000000)))) { ; }
- FastPin<DATA_PIN>::lo();
- } else {
+ while((__am_hal_systick_count() - next_mark) > (T3+(2*(F_CPU/24000000)))) { ; }
+ FastPin<DATA_PIN>::lo();
+ } else {
// "0 code" = shorter pulse width
- while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
- FastPin<DATA_PIN>::lo();
- }
+ while((__am_hal_systick_count() - next_mark) > (T2+T3+(4*(F_CPU/24000000)))) { ; }
+ FastPin<DATA_PIN>::lo();
+ }
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
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 eb9e4537..6d0f1e60 100644
--- a/platforms/apollo3/fastpin_apollo3.h
+++ b/src/platforms/apollo3/fastpin_apollo3.h
@@ -11,30 +11,29 @@ FASTLED_NAMESPACE_BEGIN
#else
template<uint8_t PIN, uint8_t PAD> class _APOLLO3PIN {
-
public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
- inline static void setOutput() { pinMode(PIN, OUTPUT); am_hal_gpio_fastgpio_enable(PAD); }
- inline static void setInput() { am_hal_gpio_fastgpio_disable(PAD); pinMode(PIN, INPUT); }
+ inline static void setOutput() { pinMode(PIN, OUTPUT); am_hal_gpio_fastgpio_enable(PAD); }
+ inline static void setInput() { am_hal_gpio_fastgpio_disable(PAD); pinMode(PIN, INPUT); }
- inline static void hi() __attribute__ ((always_inline)) { am_hal_gpio_fastgpio_set(PAD); }
- inline static void lo() __attribute__ ((always_inline)) { am_hal_gpio_fastgpio_clr(PAD); }
- inline static void set(register port_t val) __attribute__ ((always_inline)) { if(val) { am_hal_gpio_fastgpio_set(PAD); } else { am_hal_gpio_fastgpio_clr(PAD); } }
+ inline static void hi() __attribute__ ((always_inline)) { am_hal_gpio_fastgpio_set(PAD); }
+ inline static void lo() __attribute__ ((always_inline)) { am_hal_gpio_fastgpio_clr(PAD); }
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { if(val) { am_hal_gpio_fastgpio_set(PAD); } else { am_hal_gpio_fastgpio_clr(PAD); } }
- inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
- inline static void toggle() __attribute__ ((always_inline)) { if( am_hal_gpio_fastgpio_read(PAD)) { lo(); } else { hi(); } }
+ inline static void toggle() __attribute__ ((always_inline)) { if( am_hal_gpio_fastgpio_read(PAD)) { lo(); } else { hi(); } }
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { set(val); }
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { set(val); }
- inline static port_t hival() __attribute__ ((always_inline)) { return 0; }
- inline static port_t loval() __attribute__ ((always_inline)) { return 0; }
- inline static port_ptr_t port() __attribute__ ((always_inline)) { return NULL; }
- inline static port_t mask() __attribute__ ((always_inline)) { return 0; }
+ inline static port_t hival() __attribute__ ((always_inline)) { return 0; }
+ inline static port_t loval() __attribute__ ((always_inline)) { return 0; }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { return NULL; }
+ inline static port_t mask() __attribute__ ((always_inline)) { return 0; }
};
// For the Apollo3 we need to define both the pin number and the associated pad
@@ -126,6 +125,21 @@ _FL_DEFPIN(45, 45); _FL_DEFPIN(47, 47); _FL_DEFPIN(48, 48); _FL_DEFPIN(49, 49);
#define HAS_HARDWARE_PIN_SUPPORT 1
+#elif defined(ARDUINO_AM_AP3_SFE_ARTEMIS_DK)
+
+#define MAX_PIN 49
+_FL_DEFPIN(0, 0); _FL_DEFPIN(1, 1); _FL_DEFPIN(2, 2); _FL_DEFPIN(3, 3); _FL_DEFPIN(4, 4);
+_FL_DEFPIN(5, 5); _FL_DEFPIN(6, 6); _FL_DEFPIN(7, 7); _FL_DEFPIN(8, 8); _FL_DEFPIN(9, 9);
+_FL_DEFPIN(10, 10); _FL_DEFPIN(11, 11); _FL_DEFPIN(12, 12); _FL_DEFPIN(13, 13); _FL_DEFPIN(14, 14);
+_FL_DEFPIN(15, 15); _FL_DEFPIN(16, 16); _FL_DEFPIN(17, 17); _FL_DEFPIN(18, 18); _FL_DEFPIN(19, 19);
+_FL_DEFPIN(20, 20); _FL_DEFPIN(21, 21); _FL_DEFPIN(22, 22); _FL_DEFPIN(23, 23); _FL_DEFPIN(24, 24);
+_FL_DEFPIN(25, 25); _FL_DEFPIN(26, 26); _FL_DEFPIN(27, 27); _FL_DEFPIN(28, 28); _FL_DEFPIN(29, 29);
+_FL_DEFPIN(31, 31); _FL_DEFPIN(32, 32); _FL_DEFPIN(33, 33); _FL_DEFPIN(34, 34);
+_FL_DEFPIN(35, 35); _FL_DEFPIN(36, 36); _FL_DEFPIN(37, 37); _FL_DEFPIN(38, 38); _FL_DEFPIN(39, 39);
+_FL_DEFPIN(40, 40); _FL_DEFPIN(41, 41); _FL_DEFPIN(42, 42); _FL_DEFPIN(43, 43); _FL_DEFPIN(44, 44);
+_FL_DEFPIN(45, 45); _FL_DEFPIN(47, 47); _FL_DEFPIN(48, 48); _FL_DEFPIN(49, 49);
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
#else
#error "Unrecognised APOLLO3 board!"
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 d5a0cf6f..6fd86595 100644
--- a/platforms/arm/common/m0clockless.h
+++ b/src/platforms/arm/common/m0clockless.h
@@ -25,9 +25,9 @@ showLedData(volatile uint32_t *_port, uint32_t _bitmask, const uint8_t *_leds, u
// high register variable
register const uint8_t *leds = _leds;
#if (FASTLED_SCALE8_FIXED == 1)
- pData->s[0]++;
- pData->s[1]++;
- pData->s[2]++;
+ ++pData->s[0];
+ ++pData->s[1];
+ ++pData->s[2];
#endif
asm __volatile__ (
///////////////////////////////////////////////////////////////////////////
diff --git a/src/platforms/arm/d21/clockless_arm_d21.h b/src/platforms/arm/d21/clockless_arm_d21.h
new file mode 100644
index 00000000..16526ed6
--- /dev/null
+++ b/src/platforms/arm/d21/clockless_arm_d21.h
@@ -0,0 +1,61 @@
+#ifndef __INC_CLOCKLESS_ARM_D21
+#define __INC_CLOCKLESS_ARM_D21
+
+#include "../common/m0clockless.h"
+FASTLED_NAMESPACE_BEGIN
+#define FASTLED_HAS_CLOCKLESS 1
+
+template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
+ typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
+ typedef typename FastPinBB<DATA_PIN>::port_t data_t;
+
+ data_t mPinMask;
+ data_ptr_t mPort;
+ CMinWait<WAIT_TIME> mWait;
+
+public:
+ virtual void init() {
+ FastPinBB<DATA_PIN>::setOutput();
+ mPinMask = FastPinBB<DATA_PIN>::mask();
+ mPort = FastPinBB<DATA_PIN>::port();
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ mWait.wait();
+ cli();
+ if(!showRGBInternal(pixels)) {
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ sei();
+ mWait.mark();
+ }
+
+ // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
+ // gcc will use register Y for the this pointer.
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
+ struct M0ClocklessData data;
+ data.d[0] = pixels.d[0];
+ data.d[1] = pixels.d[1];
+ data.d[2] = pixels.d[2];
+ data.s[0] = pixels.mScale[0];
+ data.s[1] = pixels.mScale[1];
+ data.s[2] = pixels.mScale[2];
+ data.e[0] = pixels.e[0];
+ data.e[1] = pixels.e[1];
+ data.e[2] = pixels.e[2];
+ data.adj = pixels.mAdvance;
+
+ typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
+ return showLedData<8,4,T1,T2,T3,RGB_ORDER, WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
+ }
+
+};
+
+FASTLED_NAMESPACE_END
+
+
+#endif // __INC_CLOCKLESS_ARM_D21
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 cbfe5dbb..93dc43c6 100644
--- a/platforms/arm/d21/fastpin_arm_d21.h
+++ b/src/platforms/arm/d21/fastpin_arm_d21.h
@@ -17,41 +17,41 @@ FASTLED_NAMESPACE_BEGIN
template<uint8_t PIN, uint8_t _BIT, uint32_t _MASK, int _GRP> class _ARMPIN {
public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
-
- #if 0
- inline static void setOutput() {
- if(_BIT<8) {
- _CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
- } else {
- _CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ #if 0
+ inline static void setOutput() {
+ if(_BIT<8) {
+ _CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
+ } else {
+ _CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
+ }
}
- }
- inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
- #endif
+ inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
+ #endif
- inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; }
- inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
+ inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; }
+ inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
- inline static void hi() __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUTSET.reg = _MASK; }
- inline static void lo() __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUTCLR.reg = _MASK; }
- inline static void set(register port_t val) __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUT.reg = val; }
+ inline static void hi() __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUTSET.reg = _MASK; }
+ inline static void lo() __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUTCLR.reg = _MASK; }
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUT.reg = val; }
- inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
- inline static void toggle() __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUTTGL.reg = _MASK; }
+ inline static void toggle() __attribute__ ((always_inline)) { PORT_IOBUS->Group[_GRP].OUTTGL.reg = _MASK; }
- inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
- inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
- inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
- inline static port_t hival() __attribute__ ((always_inline)) { return PORT_IOBUS->Group[_GRP].OUT.reg | _MASK; }
- inline static port_t loval() __attribute__ ((always_inline)) { return PORT_IOBUS->Group[_GRP].OUT.reg & ~_MASK; }
- inline static port_ptr_t port() __attribute__ ((always_inline)) { return &PORT_IOBUS->Group[_GRP].OUT.reg; }
- inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &PORT_IOBUS->Group[_GRP].OUTSET.reg; }
- inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &PORT_IOBUS->Group[_GRP].OUTCLR.reg; }
- inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
+ inline static port_t hival() __attribute__ ((always_inline)) { return PORT_IOBUS->Group[_GRP].OUT.reg | _MASK; }
+ inline static port_t loval() __attribute__ ((always_inline)) { return PORT_IOBUS->Group[_GRP].OUT.reg & ~_MASK; }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { return &PORT_IOBUS->Group[_GRP].OUT.reg; }
+ inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &PORT_IOBUS->Group[_GRP].OUTSET.reg; }
+ inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &PORT_IOBUS->Group[_GRP].OUTCLR.reg; }
+ inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
};
#define _R(T) struct __gen_struct_ ## T
@@ -109,6 +109,24 @@ _FL_DEFPIN( 8, 7,0); _FL_DEFPIN( 9, 5,0); _FL_DEFPIN(10, 6,0);
#define HAS_HARDWARE_PIN_SUPPORT 1
+#elif defined(ARDUINO_SEEED_ZERO)
+
+#define MAX_PIN 24
+
+_FL_DEFPIN( 0,11,0); _FL_DEFPIN( 1,10,0); _FL_DEFPIN( 2,14,0); _FL_DEFPIN( 3,9,0);
+_FL_DEFPIN( 4,8,0); _FL_DEFPIN( 5,15,0); _FL_DEFPIN( 6,20,0); _FL_DEFPIN( 7,21,0);
+_FL_DEFPIN( 8,6,0); _FL_DEFPIN( 9,7,0); _FL_DEFPIN( 10,18,0); _FL_DEFPIN( 11,16,0);
+_FL_DEFPIN( 12,19,0); _FL_DEFPIN( 13,17,0); _FL_DEFPIN( 14,2,0); _FL_DEFPIN( 15,8,1);
+_FL_DEFPIN( 16,9,1); _FL_DEFPIN( 17,4,0); _FL_DEFPIN( 18,5,0); _FL_DEFPIN( 19,2,1);
+_FL_DEFPIN( 20,22,0); _FL_DEFPIN( 21,23,0); _FL_DEFPIN( 22,12,0);
+_FL_DEFPIN( 23,10,1);//MOSI
+_FL_DEFPIN( 24,11,1);//SCK
+
+#define SPI_DATA 23
+#define SPI_CLOCK 24
+
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
#elif defined(ARDUINO_SAMD_ZERO)
#define MAX_PIN 42
@@ -215,6 +233,19 @@ _FL_DEFPIN( 3, 7, 0); _FL_DEFPIN( 4, 6, 0); _FL_DEFPIN( 7, 0, 0); _FL_DEFPIN( 8,
#define HAS_HARDWARE_PIN_SUPPORT 1
+#elif defined(ADAFRUIT_QTPY_M0)
+
+#define MAX_PIN 10
+_FL_DEFPIN( 0, 2, 0); _FL_DEFPIN( 1, 3, 0); _FL_DEFPIN( 2, 4, 0); _FL_DEFPIN( 3, 5, 0);
+_FL_DEFPIN( 4, 16, 0); _FL_DEFPIN( 5, 17, 0); _FL_DEFPIN( 6, 6, 0); _FL_DEFPIN( 7, 7, 0);
+_FL_DEFPIN( 8, 11, 0); _FL_DEFPIN( 9, 9, 0); _FL_DEFPIN( 10, 10, 0);
+
+#define SPI_DATA 10
+#define SPI_CLOCK 8
+
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+
#elif defined(ADAFRUIT_ITSYBITSY_M0)
#define MAX_PIN 16
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/src/platforms/arm/d51/README.txt b/src/platforms/arm/d51/README.txt
new file mode 100644
index 00000000..036a02a6
--- /dev/null
+++ b/src/platforms/arm/d51/README.txt
@@ -0,0 +1,7 @@
+FastLED updates for adafruit FEATHER M4 and fixes to ITSBITSY M4 compiles
+ SAMD51
+
+Tested on
+ - FEATHER M4 with DOTSTAR and neopixel strips
+ - Seeed Wio Terminal and WS2812B and APA102 LED strips using either SPI or GPIO pins
+
diff --git a/platforms/arm/d51/clockless_arm_d51.h b/src/platforms/arm/d51/clockless_arm_d51.h
index 0c3f6d4d..2bf00d27 100644
--- a/platforms/arm/d51/clockless_arm_d51.h
+++ b/src/platforms/arm/d51/clockless_arm_d51.h
@@ -22,6 +22,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual void init() {
FastPin<DATA_PIN>::setOutput();
@@ -32,18 +33,17 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
+ mWait.wait();
if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- mWait.mark();
- }
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
+ }
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
- for(register uint32_t i = BITS-1; i > 0; i--) {
+ for(register uint32_t i = BITS-1; i > 0; --i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
FastPin<DATA_PIN>::fastset(port, hi);
@@ -79,8 +79,8 @@ protected:
ARM_DWT_CYCCNT = 0;
register data_ptr_t port = FastPin<DATA_PIN>::port();
- register data_t hi = *port | FastPin<DATA_PIN>::mask();;
- register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
+ register data_t hi = *port | FastPin<DATA_PIN>::mask();
+ register data_t lo = *port & ~FastPin<DATA_PIN>::mask();
*port = lo;
// Setup the pixel controller and load/scale the first byte
diff --git a/platforms/arm/d51/fastled_arm_d51.h b/src/platforms/arm/d51/fastled_arm_d51.h
index 0c14bf2f..912a9018 100644
--- a/platforms/arm/d51/fastled_arm_d51.h
+++ b/src/platforms/arm/d51/fastled_arm_d51.h
@@ -2,6 +2,7 @@
#define __INC_FASTLED_ARM_D51_H
#include "fastpin_arm_d51.h"
+#include "../../fastspi_ardunio_core.h"
#include "clockless_arm_d51.h"
#endif
diff --git a/src/platforms/arm/d51/fastpin_arm_d51.h b/src/platforms/arm/d51/fastpin_arm_d51.h
new file mode 100644
index 00000000..6fb5682f
--- /dev/null
+++ b/src/platforms/arm/d51/fastpin_arm_d51.h
@@ -0,0 +1,189 @@
+#ifndef __INC_FASTPIN_ARM_D51_H
+#define __INC_FASTPIN_ARM_D51_H
+
+FASTLED_NAMESPACE_BEGIN
+
+#if defined(FASTLED_FORCE_SOFTWARE_PINS)
+#warning "Software pin support forced, pin access will be slightly slower."
+#define NO_HARDWARE_PIN_SUPPORT
+#undef HAS_HARDWARE_PIN_SUPPORT
+
+#else
+
+/// Template definition for STM32 style ARM pins, providing direct access to the various GPIO registers. Note that this
+/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
+/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
+/// The registers are data output, set output, clear output, toggle output, input, and direction
+
+template<uint8_t PIN, uint8_t _BIT, uint32_t _MASK, int _GRP> class _ARMPIN {
+public:
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ #if 0
+ inline static void setOutput() {
+ if(_BIT<8) {
+ _CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
+ } else {
+ _CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
+ }
+ }
+ inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
+ #endif
+
+ inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; }
+ inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
+
+ inline static void hi() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTSET.reg = _MASK; }
+ inline static void lo() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTCLR.reg = _MASK; }
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { PORT->Group[_GRP].OUT.reg = val; }
+
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+
+ inline static void toggle() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTTGL.reg = _MASK; }
+
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
+
+ inline static port_t hival() __attribute__ ((always_inline)) { return PORT->Group[_GRP].OUT.reg | _MASK; }
+ inline static port_t loval() __attribute__ ((always_inline)) { return PORT->Group[_GRP].OUT.reg & ~_MASK; }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUT.reg; }
+ inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUTSET.reg; }
+ inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUTCLR.reg; }
+ inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
+};
+
+#define _R(T) struct __gen_struct_ ## T
+#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile PortGroup * r() { return T; } };
+
+#define _FL_IO(L) _RD32(GPIO ## L)
+
+#define _FL_DEFPIN(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, BIT, 1ul << BIT, L> {};
+
+// Actual pin definitions
+#if defined(ADAFRUIT_ITSYBITSY_M4_EXPRESS)
+
+#define MAX_PIN 19
+// D0-D13, including D6+D8 (DotStar CLK + DATA)
+_FL_DEFPIN( 0, 16, 0); _FL_DEFPIN( 1, 17, 0); _FL_DEFPIN( 2, 7, 0); _FL_DEFPIN( 3, 22, 1);
+_FL_DEFPIN( 4, 14, 0); _FL_DEFPIN( 5, 15, 0); _FL_DEFPIN( 6, 2, 1); _FL_DEFPIN( 7, 18, 0);
+_FL_DEFPIN( 8, 3, 1); _FL_DEFPIN( 9, 19, 0); _FL_DEFPIN(10, 20, 0); _FL_DEFPIN(11, 21, 0);
+_FL_DEFPIN(12, 23, 0); _FL_DEFPIN(13, 22, 0);
+// A0-A5
+_FL_DEFPIN(14, 2, 0); _FL_DEFPIN(15, 5, 0); _FL_DEFPIN(16, 8, 1); _FL_DEFPIN(17, 9, 1);
+_FL_DEFPIN(18, 4, 0); _FL_DEFPIN(19, 6, 0); /* A6 is present in variant.h but couldn't find it on the schematic */
+// SDA/SCL
+_FL_DEFPIN(21, 12, 0); _FL_DEFPIN(22, 13, 0);
+
+// 23..25 MISO/SCK/MOSI
+_FL_DEFPIN(23, 23, 1); _FL_DEFPIN(24, 1, 0); _FL_DEFPIN(25, 0, 0);
+
+#define SPI_DATA 25
+#define SPI_CLOCK 24
+
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+// Actual pin definitions
+#elif defined(ADAFRUIT_METRO_M4_AIRLIFT_LITE)
+
+#define MAX_PIN 20
+// D0-D13, including D6+D8 (DotStar CLK + DATA)
+_FL_DEFPIN( 0, 23, 0); _FL_DEFPIN( 1, 22, 0); _FL_DEFPIN( 2, 17, 1); _FL_DEFPIN( 3, 16, 1);
+_FL_DEFPIN( 4, 13, 1); _FL_DEFPIN( 5, 14, 1); _FL_DEFPIN( 6, 15, 1); _FL_DEFPIN( 7, 12, 1);
+_FL_DEFPIN( 8, 21, 0); _FL_DEFPIN( 9, 20, 0); _FL_DEFPIN(10, 18, 0); _FL_DEFPIN(11, 19, 0);
+_FL_DEFPIN(12, 17, 0); _FL_DEFPIN(13, 16, 0);
+// A0-A5
+_FL_DEFPIN(14, 2, 0); _FL_DEFPIN(15, 5, 0); _FL_DEFPIN(16, 6, 0); _FL_DEFPIN(17, 0, 1);
+_FL_DEFPIN(18, 8, 1); _FL_DEFPIN(19, 9, 1);
+// SDA/SCL
+_FL_DEFPIN(22, 2, 1); _FL_DEFPIN(23, 3, 1);
+
+// 23..25 MISO/SCK/MOSI
+_FL_DEFPIN(24, 14, 0); _FL_DEFPIN(25, 13, 0); _FL_DEFPIN(26, 12, 0);
+
+#define SPI_DATA 26
+#define SPI_CLOCK 25
+
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+#elif defined(ADAFRUIT_FEATHER_M4_EXPRESS)
+
+#define MAX_PIN 19
+// D0-D13, including D8 (neopixel) no pins 2 3
+_FL_DEFPIN( 0, 17, 1); _FL_DEFPIN( 1, 16, 1);
+_FL_DEFPIN( 4, 14, 0); _FL_DEFPIN( 5, 16, 0); _FL_DEFPIN( 6, 18, 0);
+_FL_DEFPIN( 8, 3, 1); _FL_DEFPIN( 9, 19, 0); _FL_DEFPIN(10, 20, 0); _FL_DEFPIN(11, 21, 0);
+_FL_DEFPIN(12, 22, 0); _FL_DEFPIN(13, 23, 0);
+// A0-A5
+_FL_DEFPIN(14, 2, 0); _FL_DEFPIN(15, 5, 0); _FL_DEFPIN(16, 8, 1); _FL_DEFPIN(17, 9, 1);
+_FL_DEFPIN(18, 4, 0); _FL_DEFPIN(19, 6, 0); /* A6 is present in variant.h but couldn't find it on the schematic */
+// SDA/SCL
+_FL_DEFPIN(21, 12, 0); _FL_DEFPIN(22, 13, 0);
+// 23..25 MISO/MOSI/SCK
+_FL_DEFPIN(23, 22, 1); _FL_DEFPIN(24, 23, 1); _FL_DEFPIN(25, 17, 0);
+
+#define SPI_DATA 24
+#define SPI_CLOCK 25
+
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+#elif defined(SEEED_WIO_TERMINAL)
+
+#define MAX_PIN 9
+// D0/A0-D8/A8
+_FL_DEFPIN( 0, 8, 1); _FL_DEFPIN( 1, 9, 1); _FL_DEFPIN( 2, 7, 0); _FL_DEFPIN( 3, 4, 1);
+_FL_DEFPIN( 4, 5, 1); _FL_DEFPIN( 5, 6, 1); _FL_DEFPIN( 6, 4, 0); _FL_DEFPIN( 7, 7, 1);
+_FL_DEFPIN( 8, 6, 0);
+// SDA/SCL
+_FL_DEFPIN(12, 17, 0); _FL_DEFPIN(13, 16, 0);
+// match GPIO pin nubers 9..11 MISO/MOSI/SCK
+_FL_DEFPIN(PIN_SPI_MISO, 0, 1); _FL_DEFPIN(PIN_SPI_MOSI, 2, 1); _FL_DEFPIN(PIN_SPI_SCK, 3, 1);
+
+#define SPI_DATA PIN_SPI_MOSI
+#define SPI_CLOCK PIN_SPI_SCK
+
+#define ARDUNIO_CORE_SPI
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+#elif defined(ADAFRUIT_MATRIXPORTAL_M4_EXPRESS)
+
+#define MAX_PIN 21
+// 0/1 - SERCOM/UART (Serial1)
+_FL_DEFPIN( 0, 1, 0); _FL_DEFPIN( 1, 0, 0);
+// 2..3 buttons
+_FL_DEFPIN( 2, 22, 1); _FL_DEFPIN( 3, 23, 1);
+// 4 neopixel
+_FL_DEFPIN( 4, 23, 0);
+// SDA/SCL
+_FL_DEFPIN( 5, 31, 1); _FL_DEFPIN( 6, 30, 1);
+// 7..12 RGBRGB pins
+_FL_DEFPIN( 7, 0, 1); _FL_DEFPIN( 8, 1, 1); _FL_DEFPIN( 9, 2, 1); _FL_DEFPIN(10, 3, 1);
+_FL_DEFPIN(11, 4, 1); _FL_DEFPIN(12, 5, 1);
+// 13 LED
+_FL_DEFPIN(13, 14, 0);
+// 14..21 Control pins
+_FL_DEFPIN(14, 6, 1); _FL_DEFPIN(15, 14, 1); _FL_DEFPIN(16, 12, 1); _FL_DEFPIN(17, 7, 1);
+_FL_DEFPIN(18, 8, 1); _FL_DEFPIN(19, 9, 1); _FL_DEFPIN(20, 15, 1); _FL_DEFPIN(21, 13, 1);
+// 22..26 Analog pins
+_FL_DEFPIN(22, 2, 1); _FL_DEFPIN(23, 5, 1); _FL_DEFPIN(24, 4, 1); _FL_DEFPIN(25, 6, 1);
+_FL_DEFPIN(26, 7, 1);
+// 34..36 ESP SPI
+_FL_DEFPIN(34, 16, 0); _FL_DEFPIN(35, 17, 0); _FL_DEFPIN(36, 19, 0);
+// 48..50 external SPI #2 on sercom 0
+_FL_DEFPIN(48, 5, 0); _FL_DEFPIN(49, 4, 0); _FL_DEFPIN(50, 7, 0);
+
+#define SPI_DATA 4
+#define SPI_CLOCK 7
+
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+#endif
+
+
+#endif // FASTLED_FORCE_SOFTWARE_PINS
+
+FASTLED_NAMESPACE_END
+
+
+#endif // __INC_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..77726fa2 100644
--- a/platforms/arm/d51/led_sysdefs_arm_d51.h
+++ b/src/platforms/arm/d51/led_sysdefs_arm_d51.h
@@ -3,8 +3,6 @@
#define FASTLED_ARM
-// Note this is an M4, not an M0+, but this enables the shared m0clockless.h
-#define FASTLED_ARM_M0_PLUS
#ifndef INTERRUPT_THRESHOLD
#define INTERRUPT_THRESHOLD 1
@@ -12,7 +10,7 @@
// Default to allowing interrupts
#ifndef FASTLED_ALLOW_INTERRUPTS
-#define FASTLED_ALLOW_INTERRUPTS 0
+#define FASTLED_ALLOW_INTERRUPTS 1
#endif
#if FASTLED_ALLOW_INTERRUPTS == 1
diff --git a/platforms/arm/k20/clockless_arm_k20.h b/src/platforms/arm/k20/clockless_arm_k20.h
index bc2090b3..0a7f7b94 100644
--- a/platforms/arm/k20/clockless_arm_k20.h
+++ b/src/platforms/arm/k20/clockless_arm_k20.h
@@ -17,6 +17,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual void init() {
FastPin<DATA_PIN>::setOutput();
@@ -27,18 +28,17 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
+ mWait.wait();
if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- mWait.mark();
- }
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
+ }
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
- for(register uint32_t i = BITS-1; i > 0; i--) {
+ for(register uint32_t i = BITS-1; i > 0; --i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
FastPin<DATA_PIN>::fastset(port, hi);
@@ -74,8 +74,8 @@ protected:
ARM_DWT_CYCCNT = 0;
register data_ptr_t port = FastPin<DATA_PIN>::port();
- register data_t hi = *port | FastPin<DATA_PIN>::mask();;
- register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
+ register data_t hi = *port | FastPin<DATA_PIN>::mask();
+ register data_t lo = *port & ~FastPin<DATA_PIN>::mask();
*port = lo;
// Setup the pixel controller and load/scale the first byte
diff --git a/platforms/arm/k20/clockless_block_arm_k20.h b/src/platforms/arm/k20/clockless_block_arm_k20.h
index 66c6191c..9beeb9fa 100644
--- a/platforms/arm/k20/clockless_block_arm_k20.h
+++ b/src/platforms/arm/k20/clockless_block_arm_k20.h
@@ -27,6 +27,7 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual int size() { return CLEDController::size() * LANES; }
@@ -93,7 +94,7 @@ public:
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; i < (USED_LANES/2); i++) {
+ for(register uint32_t i = 0; i < (USED_LANES/2); ++i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
@@ -117,7 +118,7 @@ public:
b.bytes[USED_LANES-1] = pixels.template loadAndScale<PX>(pixels,USED_LANES-1,d,scale);
}
- for(register uint32_t i = USED_LANES/2; i < 8; i++) {
+ for(register uint32_t i = USED_LANES/2; i < 8; ++i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
@@ -150,7 +151,7 @@ public:
register Lines b0;
allpixels.preStepFirstByteDithering();
- for(int i = 0; i < USED_LANES; i++) {
+ for(int i = 0; i < USED_LANES; ++i) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
@@ -197,6 +198,7 @@ class SixteenWayInlineBlockClocklessController : public CPixelLEDController<RGB_
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual void init() {
static_assert(LANES <= 16, "Maximum of 16 lanes for Teensy parallel controllers!");
@@ -250,7 +252,7 @@ public:
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; (i < LANES) && (i < 8); i++) {
+ for(register uint32_t i = 0; (i < LANES) && (i < 8); ++i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<PORTD_FIRST_PIN>::sport() = PMASK_LO;
@@ -286,7 +288,7 @@ public:
register Lines b0;
allpixels.preStepFirstByteDithering();
- for(int i = 0; i < LANES; i++) {
+ for(int i = 0; i < LANES; ++i) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
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 05123243..3d492558 100644
--- a/platforms/arm/k20/fastspi_arm_k20.h
+++ b/src/platforms/arm/k20/fastspi_arm_k20.h
@@ -29,6 +29,7 @@ template<int VAL, int BIT> class BitWork {
public:
static int highestBit() __attribute__((always_inline)) { return (VAL & 1 << BIT) ? BIT : BitWork<VAL, BIT-1>::highestBit(); }
};
+
template<int VAL> class BitWork<VAL, 0> {
public:
static int highestBit() __attribute__((always_inline)) { return 0; }
@@ -86,7 +87,7 @@ template <int VAL> void getScalars(uint32_t & preScalar, uint32_t & scalar, uint
dbl = 0;
if(scalar == 0) { dbl = 1; }
- else if(scalar < 3) { scalar--; }
+ else if(scalar < 3) { --scalar; }
}
}
return;
@@ -246,7 +247,6 @@ public:
ARMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
-
void init() {
// set the pins to output
FastPin<_DATA_PIN>::setOutput();
@@ -316,8 +316,8 @@ public:
if(WAIT_STATE == PRE) { wait(); }
cli();
SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) |
- ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
- SPI_PUSHR_CTAS(1) | (w & 0xFFFF);
+ ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
+ SPI_PUSHR_CTAS(1) | (w & 0xFFFF);
SPIX.SR |= SPI_SR_TCF;
sei();
if(WAIT_STATE == POST) { wait(); }
@@ -327,8 +327,8 @@ public:
if(WAIT_STATE == PRE) { wait(); }
cli();
SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) |
- ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
- SPI_PUSHR_CTAS(0) | (b & 0xFF);
+ ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
+ SPI_PUSHR_CTAS(0) | (b & 0xFF);
SPIX.SR |= SPI_SR_TCF;
sei();
if(WAIT_STATE == POST) { wait(); }
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 84c28667..f365e61f 100644
--- a/platforms/arm/k20/octows2811_controller.h
+++ b/src/platforms/arm/k20/octows2811_controller.h
@@ -44,11 +44,11 @@ public:
while(pixels.has(1)) {
Lines b;
- for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale0(i); }
+ for(int i = 0; i < 8; ++i) { b.bytes[i] = pixels.loadAndScale0(i); }
transpose8x1_MSB(b.bytes,pData); pData += 8;
- for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale1(i); }
+ for(int i = 0; i < 8; ++i) { b.bytes[i] = pixels.loadAndScale1(i); }
transpose8x1_MSB(b.bytes,pData); pData += 8;
- for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale2(i); }
+ for(int i = 0; i < 8; ++i) { b.bytes[i] = pixels.loadAndScale2(i); }
transpose8x1_MSB(b.bytes,pData); pData += 8;
pixels.stepDithering();
pixels.advanceData();
diff --git a/src/platforms/arm/k20/smartmatrix_t3.h b/src/platforms/arm/k20/smartmatrix_t3.h
new file mode 100644
index 00000000..c9747f0b
--- /dev/null
+++ b/src/platforms/arm/k20/smartmatrix_t3.h
@@ -0,0 +1,54 @@
+#ifndef __INC_SMARTMATRIX_T3_H
+#define __INC_SMARTMATRIX_T3_H
+
+#ifdef SmartMatrix_h
+#include <SmartMatrix.h>
+
+FASTLED_NAMESPACE_BEGIN
+
+extern SmartMatrix *pSmartMatrix;
+
+// note - dmx simple must be included before FastSPI for this code to be enabled
+class CSmartMatrixController : public CPixelLEDController<RGB_ORDER> {
+ SmartMatrix matrix;
+
+public:
+ // initialize the LED controller
+ virtual void init() {
+ // Initialize 32x32 LED Matrix
+ matrix.begin();
+ matrix.setBrightness(255);
+ matrix.setColorCorrection(ccNone);
+
+ // Clear screen
+ clearLeds(0);
+ matrix.swapBuffers();
+ pSmartMatrix = &matrix;
+ }
+
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ if(SMART_MATRIX_CAN_TRIPLE_BUFFER) {
+ rgb24 *md = matrix.getRealBackBuffer();
+ } else {
+ rgb24 *md = matrix.backBuffer();
+ }
+ while(pixels.has(1)) {
+ md->red = pixels.loadAndScale0();
+ md->green = pixels.loadAndScale1();
+ md->blue = pixels.loadAndScale2();
+ md++;
+ pixels.advanceData();
+ pixels.stepDithering();
+ }
+ matrix.swapBuffers();
+ if(SMART_MATRIX_CAN_TRIPLE_BUFFER && pixels.advanceBy() > 0) {
+ matrix.setBackBuffer(pixels.mData);
+ }
+ }
+};
+
+FASTLED_NAMESPACE_END
+
+#endif
+
+#endif
diff --git a/src/platforms/arm/k20/ws2812serial_controller.h b/src/platforms/arm/k20/ws2812serial_controller.h
new file mode 100644
index 00000000..a761dd49
--- /dev/null
+++ b/src/platforms/arm/k20/ws2812serial_controller.h
@@ -0,0 +1,47 @@
+#ifndef __INC_WS2812SERIAL_CONTROLLER_H
+#define __INC_WS2812SERIAL_CONTROLLER_H
+
+#ifdef USE_WS2812SERIAL
+
+FASTLED_NAMESPACE_BEGIN
+
+template<int DATA_PIN, EOrder RGB_ORDER>
+class CWS2812SerialController : public CPixelLEDController<RGB_ORDER, 8, 0xFF> {
+ WS2812Serial *pserial;
+ uint8_t *drawbuffer,*framebuffer;
+
+ void _init(int nLeds) {
+ if (pserial == NULL) {
+ drawbuffer = (uint8_t*)malloc(nLeds * 3);
+ framebuffer = (uint8_t*)malloc(nLeds * 12);
+ pserial = new WS2812Serial(nLeds, framebuffer, drawbuffer, DATA_PIN, WS2812_RGB);
+ pserial->begin();
+ }
+ }
+
+public:
+ CWS2812SerialController() { pserial = NULL; }
+
+ virtual void init() { /* do nothing yet */ }
+
+ virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> & pixels) {
+ _init(pixels.size());
+
+ uint8_t *p = drawbuffer;
+
+ while(pixels.has(1)) {
+ *p++ = pixels.loadAndScale0();
+ *p++ = pixels.loadAndScale1();
+ *p++ = pixels.loadAndScale2();
+ pixels.stepDithering();
+ pixels.advanceData();
+ }
+ pserial->show();
+ }
+
+};
+
+FASTLED_NAMESPACE_END
+
+#endif // USE_WS2812SERIAL
+#endif // __INC_WS2812SERIAL_CONTROLLER_H
diff --git a/platforms/arm/k66/clockless_arm_k66.h b/src/platforms/arm/k66/clockless_arm_k66.h
index 61021057..e9dcc0cd 100644
--- a/platforms/arm/k66/clockless_arm_k66.h
+++ b/src/platforms/arm/k66/clockless_arm_k66.h
@@ -17,6 +17,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual void init() {
FastPin<DATA_PIN>::setOutput();
@@ -27,18 +28,17 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
+ mWait.wait();
if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- mWait.mark();
- }
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
+ }
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
- for(register uint32_t i = BITS-1; i > 0; i--) {
+ for(register uint32_t i = BITS-1; i > 0; --i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
FastPin<DATA_PIN>::fastset(port, hi);
@@ -74,8 +74,8 @@ protected:
ARM_DWT_CYCCNT = 0;
register data_ptr_t port = FastPin<DATA_PIN>::port();
- register data_t hi = *port | FastPin<DATA_PIN>::mask();;
- register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
+ register data_t hi = *port | FastPin<DATA_PIN>::mask();
+ register data_t lo = *port & ~FastPin<DATA_PIN>::mask();
*port = lo;
// Setup the pixel controller and load/scale the first byte
diff --git a/platforms/arm/k66/clockless_block_arm_k66.h b/src/platforms/arm/k66/clockless_block_arm_k66.h
index 85a8cc71..70f8c7a5 100644
--- a/platforms/arm/k66/clockless_block_arm_k66.h
+++ b/src/platforms/arm/k66/clockless_block_arm_k66.h
@@ -30,6 +30,7 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual int size() { return CLEDController::size() * LANES; }
@@ -107,7 +108,7 @@ public:
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; i < (USED_LANES/2); i++) {
+ for(register uint32_t i = 0; i < (USED_LANES/2); ++i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
@@ -131,7 +132,7 @@ public:
b.bytes[USED_LANES-1] = pixels.template loadAndScale<PX>(pixels,USED_LANES-1,d,scale);
}
- for(register uint32_t i = USED_LANES/2; i < 8; i++) {
+ for(register uint32_t i = USED_LANES/2; i < 8; ++i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
@@ -153,7 +154,7 @@ public:
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, LANE_MASK> &allpixels) {
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, LANE_MASK> &allpixels) {
// Get access to the clock
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
@@ -164,7 +165,7 @@ public:
register Lines b0;
allpixels.preStepFirstByteDithering();
- for(int i = 0; i < USED_LANES; i++) {
+ for(int i = 0; i < USED_LANES; ++i) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
@@ -211,6 +212,7 @@ class SixteenWayInlineBlockClocklessController : public CPixelLEDController<RGB_
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual void init() {
static_assert(LANES <= 16, "Maximum of 16 lanes for Teensy parallel controllers!");
@@ -242,11 +244,11 @@ public:
virtual void showPixels(PixelController<RGB_ORDER, LANES, PMASK> & pixels) {
mWait.wait();
uint32_t clocks = showRGBInternal(pixels);
- #if FASTLED_ALLOW_INTERRUPTS == 0
+ #if FASTLED_ALLOW_INTERRUPTS == 0
// Adjust the timer
long microsTaken = CLKS_TO_MICROS(clocks);
MS_COUNTER += (1 + (microsTaken / 1000));
- #endif
+ #endif
mWait.mark();
}
@@ -264,7 +266,7 @@ public:
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; (i < LANES) && (i < 8); i++) {
+ for(register uint32_t i = 0; (i < LANES) && (i < 8); ++i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<PORTD_FIRST_PIN>::sport() = PMASK_LO;
@@ -286,10 +288,9 @@ public:
}
-
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(PixelController<RGB_ORDER,LANES, PMASK> &allpixels) {
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER,LANES, PMASK> &allpixels) {
// Get access to the clock
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
@@ -300,7 +301,7 @@ public:
register Lines b0;
allpixels.preStepFirstByteDithering();
- for(int i = 0; i < LANES; i++) {
+ for(int i = 0; i < LANES; ++i) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
@@ -309,13 +310,15 @@ public:
while(allpixels.has(1)) {
allpixels.stepDithering();
- #if 0 && (FASTLED_ALLOW_INTERRUPTS == 1)
+ #if 0 && (FASTLED_ALLOW_INTERRUPTS == 1)
cli();
// if interrupts took longer than 45µs, punt on the current frame
if(ARM_DWT_CYCCNT > next_mark) {
- if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; }
+ if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) {
+ sei();
+ return ARM_DWT_CYCCNT; }
}
- #endif
+ #endif
// Write first byte, read next byte
writeBits<8+XTRA0,1>(next_mark, b0, allpixels);
@@ -327,9 +330,9 @@ public:
// Write third byte
writeBits<8+XTRA0,0>(next_mark, b0, allpixels);
- #if 0 && (FASTLED_ALLOW_INTERRUPTS == 1)
+ #if 0 && (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
- #endif
+ #endif
};
sei();
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 a40e5985..f990741b 100644
--- a/platforms/arm/k66/fastspi_arm_k66.h
+++ b/src/platforms/arm/k66/fastspi_arm_k66.h
@@ -37,6 +37,7 @@ template<int VAL, int BIT> class BitWork {
public:
static int highestBit() __attribute__((always_inline)) { return (VAL & 1 << BIT) ? BIT : BitWork<VAL, BIT-1>::highestBit(); }
};
+
template<int VAL> class BitWork<VAL, 0> {
public:
static int highestBit() __attribute__((always_inline)) { return 0; }
@@ -94,7 +95,7 @@ template <int VAL> void getScalars(uint32_t & preScalar, uint32_t & scalar, uint
dbl = 0;
if(scalar == 0) { dbl = 1; }
- else if(scalar < 3) { scalar--; }
+ else if(scalar < 3) { --scalar; }
}
}
return;
@@ -248,7 +249,6 @@ class ARMHardwareSPIOutput {
// CORE_PIN14_CONFIG = gState.pins[3];
}
-
public:
ARMHardwareSPIOutput() { m_pSelect = NULL; }
ARMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
@@ -323,8 +323,8 @@ public:
static void writeWord(uint16_t w) __attribute__((always_inline)) {
if(WAIT_STATE == PRE) { wait(); }
SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) |
- ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
- SPI_PUSHR_CTAS(1) | (w & 0xFFFF);
+ ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
+ SPI_PUSHR_CTAS(1) | (w & 0xFFFF);
SPIX.SR |= SPI_SR_TCF;
if(WAIT_STATE == POST) { wait(); }
}
@@ -332,8 +332,8 @@ public:
static void writeByte(uint8_t b) __attribute__((always_inline)) {
if(WAIT_STATE == PRE) { wait(); }
SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) |
- ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
- SPI_PUSHR_CTAS(0) | (b & 0xFF);
+ ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
+ SPI_PUSHR_CTAS(0) | (b & 0xFF);
SPIX.SR |= SPI_SR_TCF;
if(WAIT_STATE == POST) { wait(); }
}
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/src/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h
new file mode 100644
index 00000000..efc875bc
--- /dev/null
+++ b/src/platforms/arm/mxrt1062/block_clockless_arm_mxrt1062.h
@@ -0,0 +1,214 @@
+#ifndef __INC_BLOCK_CLOCKLESS_ARM_MXRT1062_H
+#define __INC_BLOCK_CLOCKLESS_ARM_MXRT1062_H
+
+FASTLED_NAMESPACE_BEGIN
+
+// Definition for a single channel clockless controller for the teensy4
+// See clockless.h for detailed info on how the template parameters are used.
+#if defined(FASTLED_TEENSY4)
+
+#define __FL_T4_MASK ((1<<(LANES))-1)
+template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
+class FlexibleInlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, __FL_T4_MASK> {
+ uint8_t m_bitOffsets[16];
+ uint8_t m_nActualLanes;
+ uint8_t m_nLowBit;
+ uint8_t m_nHighBit;
+ uint32_t m_nWriteMask;
+ uint8_t m_nOutBlocks;
+ uint32_t m_offsets[3];
+ uint32_t MS_COUNTER;
+ CMinWait<WAIT_TIME> mWait;
+
+public:
+ virtual int size() { return CLEDController::size() * m_nActualLanes; }
+
+ // For each pin, if we've hit our lane count, break, otherwise set the pin to output,
+ // store the bit offset in our offset array, add this pin to the write mask, and if this
+ // pin ends a block sequence, then break out of the switch as well
+ #define _BLOCK_PIN(P) case P: { \
+ if(m_nActualLanes == LANES) break; \
+ FastPin<P>::setOutput(); \
+ m_bitOffsets[m_nActualLanes++] = FastPin<P>::pinbit(); \
+ m_nWriteMask |= FastPin<P>::mask(); \
+ if( P == 27 || P == 7 || P == 30) break; \
+ }
+
+ virtual void init() {
+ // pre-initialize
+ memset(m_bitOffsets,0,16);
+ m_nActualLanes = 0;
+ m_nLowBit = 33;
+ m_nHighBit = 0;
+ m_nWriteMask = 0;
+ MS_COUNTER = 0;
+
+ // setup the bits and data tracking for parallel output
+ switch(FIRST_PIN) {
+ // GPIO6 block output
+ _BLOCK_PIN( 1);
+ _BLOCK_PIN( 0);
+ _BLOCK_PIN(24);
+ _BLOCK_PIN(25);
+ _BLOCK_PIN(19);
+ _BLOCK_PIN(18);
+ _BLOCK_PIN(14);
+ _BLOCK_PIN(15);
+ _BLOCK_PIN(17);
+ _BLOCK_PIN(16);
+ _BLOCK_PIN(22);
+ _BLOCK_PIN(23);
+ _BLOCK_PIN(20);
+ _BLOCK_PIN(21);
+ _BLOCK_PIN(26);
+ _BLOCK_PIN(27);
+ // GPIO7 block output
+ _BLOCK_PIN(10);
+ _BLOCK_PIN(12);
+ _BLOCK_PIN(11);
+ _BLOCK_PIN(13);
+ _BLOCK_PIN( 6);
+ _BLOCK_PIN( 9);
+ _BLOCK_PIN(32);
+ _BLOCK_PIN( 8);
+ _BLOCK_PIN( 7);
+ // GPIO 37 block output
+ _BLOCK_PIN(37);
+ _BLOCK_PIN(36);
+ _BLOCK_PIN(35);
+ _BLOCK_PIN(34);
+ _BLOCK_PIN(39);
+ _BLOCK_PIN(38);
+ _BLOCK_PIN(28);
+ _BLOCK_PIN(31);
+ _BLOCK_PIN(30);
+ }
+
+ for(int i = 0; i < m_nActualLanes; ++i) {
+ if(m_bitOffsets[i] < m_nLowBit) { m_nLowBit = m_bitOffsets[i]; }
+ if(m_bitOffsets[i] > m_nHighBit) { m_nHighBit = m_bitOffsets[i]; }
+ }
+
+ m_nOutBlocks = (m_nHighBit + 8)/8;
+
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+ virtual void showPixels(PixelController<RGB_ORDER, LANES, __FL_T4_MASK> & pixels) {
+ mWait.wait();
+ #if FASTLED_ALLOW_INTERRUPTS == 0
+ uint32_t clocks = showRGBInternal(pixels);
+ // Adjust the timer
+ long microsTaken = CLKS_TO_MICROS(clocks);
+ MS_COUNTER += (1 + (microsTaken / 1000));
+ #else
+ showRGBInternal(pixels);
+ #endif
+ mWait.mark();
+ }
+
+ typedef union {
+ uint8_t bytes[32];
+ uint8_t bg[4][8];
+ uint16_t shorts[16];
+ uint32_t raw[8];
+ } _outlines;
+
+
+ template<int BITS,int PX> __attribute__ ((always_inline)) inline void writeBits(register uint32_t & next_mark, register _outlines & b, PixelController<RGB_ORDER, LANES, __FL_T4_MASK> &pixels) {
+ _outlines b2;
+ transpose8x1(b.bg[3], b2.bg[3]);
+ transpose8x1(b.bg[2], b2.bg[2]);
+ transpose8x1(b.bg[1], b2.bg[1]);
+ transpose8x1(b.bg[0], b2.bg[0]);
+
+ register uint8_t d = pixels.template getd<PX>(pixels);
+ register uint8_t scale = pixels.template getscale<PX>(pixels);
+
+ int x = 0;
+ for(uint32_t i = 8; i > 0;) {
+ --i;
+ while(ARM_DWT_CYCCNT < next_mark);
+ *FastPin<FIRST_PIN>::sport() = m_nWriteMask;
+ next_mark = ARM_DWT_CYCCNT + m_offsets[0];
+
+ uint32_t out = (b2.bg[3][i] << 24) | (b2.bg[2][i] << 16) | (b2.bg[1][i] << 8) | b2.bg[0][i];
+
+ out = ((~out) & m_nWriteMask);
+ while((next_mark - ARM_DWT_CYCCNT) > m_offsets[1]);
+ *FastPin<FIRST_PIN>::cport() = out;
+
+ out = m_nWriteMask;
+ while((next_mark - ARM_DWT_CYCCNT) > m_offsets[2]);
+ *FastPin<FIRST_PIN>::cport() = out;
+
+ // Read and store up to two bytes
+ if (x < m_nActualLanes) {
+ b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale<PX>(pixels, x, d, scale);
+ ++x;
+ if (x < m_nActualLanes) {
+ b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale<PX>(pixels, x, d, scale);
+ ++x;
+ }
+ }
+ }
+ }
+
+ uint32_t showRGBInternal(PixelController<RGB_ORDER,LANES, __FL_T4_MASK> &allpixels) {
+ allpixels.preStepFirstByteDithering();
+ _outlines b0;
+ uint32_t start = ARM_DWT_CYCCNT;
+
+ for(int i = 0; i < m_nActualLanes; ++i) {
+ b0.bytes[m_bitOffsets[i]] = allpixels.loadAndScale0(i);
+ }
+
+ cli();
+
+ m_offsets[0] = _FASTLED_NS_TO_DWT(T1+T2+T3);
+ m_offsets[1] = _FASTLED_NS_TO_DWT(T2+T3);
+ m_offsets[2] = _FASTLED_NS_TO_DWT(T3);
+ uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD));
+
+ uint32_t next_mark = ARM_DWT_CYCCNT + m_offsets[0];
+
+ while(allpixels.has(1)) {
+ allpixels.stepDithering();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ cli();
+ // if interrupts took longer than 45µs, punt on the current frame
+ if(ARM_DWT_CYCCNT > next_mark) {
+ if((ARM_DWT_CYCCNT-next_mark) > wait_off) { sei(); return ARM_DWT_CYCCNT - start; }
+ }
+ #endif
+ // Write first byte, read next byte
+ writeBits<8+XTRA0,1>(next_mark, b0, allpixels);
+
+ // Write second byte, read 3rd byte
+ writeBits<8+XTRA0,2>(next_mark, b0, allpixels);
+ allpixels.advanceData();
+
+ // Write third byte
+ writeBits<8+XTRA0,0>(next_mark, b0, allpixels);
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ sei();
+ #endif
+ }
+
+ sei();
+
+ return ARM_DWT_CYCCNT - start;
+ }
+};
+
+template<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, int NUM_LANES, EOrder RGB_ORDER=GRB>
+class __FIBCC : public FlexibleInlineBlockClocklessController<NUM_LANES,DATA_PIN,CHIPSET<DATA_PIN,RGB_ORDER>::__T1(),CHIPSET<DATA_PIN,RGB_ORDER>::__T2(),CHIPSET<DATA_PIN,RGB_ORDER>::__T3(),RGB_ORDER,CHIPSET<DATA_PIN,RGB_ORDER>::__XTRA0(),CHIPSET<DATA_PIN,RGB_ORDER>::__FLIP(),CHIPSET<DATA_PIN,RGB_ORDER>::__WAIT_TIME()> {};
+
+#define __FASTLED_HAS_FIBCC 1
+
+#endif //defined(FASTLED_TEENSY4)
+
+FASTLED_NAMESPACE_END
+
+#endif
diff --git a/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
index ed72713a..ed3be816 100644
--- a/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h
@@ -35,24 +35,23 @@ public:
FastPin<DATA_PIN>::setOutput();
mPinMask = FastPin<DATA_PIN>::mask();
mPort = FastPin<DATA_PIN>::port();
- FastPin<DATA_PIN>::lo();
+ FastPin<DATA_PIN>::lo();
}
- virtual uint16_t getMaxRefreshRate() const { return 400; }
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
+ mWait.wait();
if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
- mWait.mark();
- }
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
+ }
template<int BITS> __attribute__ ((always_inline)) inline void writeBits(register uint32_t & next_mark, register uint32_t & b) {
- for(register uint32_t i = BITS-1; i > 0; i--) {
+ for(register uint32_t i = BITS-1; i > 0; --i) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + off[0];
FastPin<DATA_PIN>::hi();
@@ -87,12 +86,14 @@ protected:
register uint32_t b = pixels.loadAndScale0();
cli();
- off[0] = _FASTLED_NS_TO_DWT(T1+T2+T3);
- off[1] = _FASTLED_NS_TO_DWT(T2+T3);
+
+ off[0] = _FASTLED_NS_TO_DWT(T1+T2+T3);
+ off[1] = _FASTLED_NS_TO_DWT(T2+T3);
off[2] = _FASTLED_NS_TO_DWT(T3);
- uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD));
- uint32_t next_mark = ARM_DWT_CYCCNT + off[0];
+ uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD));
+
+ uint32_t next_mark = ARM_DWT_CYCCNT + off[0];
while(pixels.has(1)) {
pixels.stepDithering();
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 38c88410..8960a8c9 100644
--- a/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h
@@ -39,7 +39,7 @@ public:
inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO_DR_SET::r(); }
inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO_DR_CLEAR::r(); }
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
- inline static uint32_t pinbit() __attribute__ ((always_inline)) { return _BIT; }
+ inline static uint32_t pinbit() __attribute__ ((always_inline)) { return _BIT; }
};
diff --git a/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h b/src/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h
index fa6b81ff..068c7be1 100644
--- a/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h
+++ b/src/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h
@@ -9,18 +9,18 @@ FASTLED_NAMESPACE_BEGIN
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_RATE, SPIClass & _SPIObject, int _SPI_INDEX>
class Teesy4HardwareSPIOutput {
Selectable *m_pSelect;
- uint32_t m_bitCount;
- uint32_t m_bitData;
- inline IMXRT_LPSPI_t & port() __attribute__((always_inline)) {
- switch(_SPI_INDEX) {
- case 0:
- return IMXRT_LPSPI4_S;
- case 1:
- return IMXRT_LPSPI3_S;
- case 2:
- return IMXRT_LPSPI1_S;
- }
- }
+ uint32_t m_bitCount;
+ uint32_t m_bitData;
+ inline IMXRT_LPSPI_t & port() __attribute__((always_inline)) {
+ switch(_SPI_INDEX) {
+ case 0:
+ return IMXRT_LPSPI4_S;
+ case 1:
+ return IMXRT_LPSPI3_S;
+ case 2:
+ return IMXRT_LPSPI1_S;
+ }
+ }
public:
Teesy4HardwareSPIOutput() { m_pSelect = NULL; m_bitCount = 0;}
@@ -34,42 +34,42 @@ public:
// latch the CS select
void inline select() __attribute__((always_inline)) {
- // begin the SPI transaction
- _SPIObject.beginTransaction(SPISettings(_SPI_CLOCK_RATE, MSBFIRST, SPI_MODE0));
- if(m_pSelect != NULL) { m_pSelect->select(); }
- }
+ // begin the SPI transaction
+ _SPIObject.beginTransaction(SPISettings(_SPI_CLOCK_RATE, MSBFIRST, SPI_MODE0));
+ if(m_pSelect != NULL) { m_pSelect->select(); }
+ }
// release the CS select
void inline release() __attribute__((always_inline)) {
- if(m_pSelect != NULL) { m_pSelect->release(); }
- _SPIObject.endTransaction();
- }
+ if(m_pSelect != NULL) { m_pSelect->release(); }
+ _SPIObject.endTransaction();
+ }
// wait until all queued up data has been written
static void waitFully() { /* TODO */ }
// write a byte out via SPI (returns immediately on writing register) -
void inline writeByte(uint8_t b) __attribute__((always_inline)) {
- if(m_bitCount == 0) {
- _SPIObject.transfer(b);
- } else {
- // There's been a bit of data written, add that to the output as well
- uint32_t outData = (m_bitData << 8) | b;
- uint32_t tcr = port().TCR;
- port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ((8+m_bitCount) - 1); // turn on 9 bit mode
- port().TDR = outData; // output 9 bit data.
- while ((port().RSR & LPSPI_RSR_RXEMPTY)) ; // wait while the RSR fifo is empty...
+ if(m_bitCount == 0) {
+ _SPIObject.transfer(b);
+ } else {
+ // There's been a bit of data written, add that to the output as well
+ uint32_t outData = (m_bitData << 8) | b;
+ uint32_t tcr = port().TCR;
+ port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ((8+m_bitCount) - 1); // turn on 9 bit mode
+ port().TDR = outData; // output 9 bit data.
+ while ((port().RSR & LPSPI_RSR_RXEMPTY)) ; // wait while the RSR fifo is empty...
port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ((8) - 1); // turn back on 8 bit mode
- port().RDR;
- m_bitCount = 0;
- }
- }
+ port().RDR;
+ m_bitCount = 0;
+ }
+ }
// write a word out via SPI (returns immediately on writing register)
void inline writeWord(uint16_t w) __attribute__((always_inline)) {
- writeByte(((w>>8) & 0xFF));
- _SPIObject.transfer(w & 0xFF);
- }
+ writeByte(((w>>8) & 0xFF));
+ _SPIObject.transfer(w & 0xFF);
+ }
// A raw set of writing byte values, assumes setup/init/waiting done elsewhere
static void writeBytesValueRaw(uint8_t value, int len) {
@@ -99,16 +99,16 @@ public:
// write a single bit out, which bit from the passed in byte is determined by template parameter
template <uint8_t BIT> inline void writeBit(uint8_t b) {
- m_bitData = (m_bitData<<1) | ((b&(1<<BIT)) != 0);
- // If this is the 8th bit we've collected, just write it out raw
- register uint32_t bc = m_bitCount;
- bc = (bc + 1) & 0x07;
- if (!bc) {
- m_bitCount = 0;
- _SPIObject.transfer(m_bitData);
- }
- m_bitCount = bc;
- }
+ m_bitData = (m_bitData<<1) | ((b&(1<<BIT)) != 0);
+ // If this is the 8th bit we've collected, just write it out raw
+ register uint32_t bc = m_bitCount;
+ bc = (bc + 1) & 0x07;
+ if (!bc) {
+ m_bitCount = 0;
+ _SPIObject.transfer(m_bitData);
+ }
+ m_bitCount = bc;
+ }
// write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
// parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
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/src/platforms/arm/nrf51/clockless_arm_nrf51.h b/src/platforms/arm/nrf51/clockless_arm_nrf51.h
new file mode 100644
index 00000000..c607e61e
--- /dev/null
+++ b/src/platforms/arm/nrf51/clockless_arm_nrf51.h
@@ -0,0 +1,84 @@
+#ifndef __INC_CLOCKLESS_ARM_NRF51
+#define __INC_CLOCKLESS_ARM_NRF51
+
+#if defined(NRF51)
+
+#include <nrf51_bitfields.h>
+#define FASTLED_HAS_CLOCKLESS 1
+
+#if (FASTLED_ALLOW_INTERRUPTS==1)
+#define SEI_CHK LED_TIMER->CC[0] = (WAIT_TIME * (F_CPU/1000000)); LED_TIMER->TASKS_CLEAR; LED_TIMER->EVENTS_COMPARE[0] = 0;
+#define CLI_CHK cli(); if(LED_TIMER->EVENTS_COMPARE[0]) { LED_TIMER->TASKS_STOP = 1; return 0; }
+#define INNER_SEI sei();
+#else
+#define SEI_CHK
+#define CLI_CHK
+#define INNER_SEI delaycycles<1>();
+#endif
+
+
+#include "../common/m0clockless.h"
+template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 75>
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
+ typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
+ typedef typename FastPinBB<DATA_PIN>::port_t data_t;
+
+ data_t mPinMask;
+ data_ptr_t mPort;
+ CMinWait<WAIT_TIME> mWait;
+
+public:
+ virtual void init() {
+ FastPinBB<DATA_PIN>::setOutput();
+ mPinMask = FastPinBB<DATA_PIN>::mask();
+ mPort = FastPinBB<DATA_PIN>::port();
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ mWait.wait();
+ cli();
+ if(!showRGBInternal(pixels)) {
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ sei();
+ mWait.mark();
+ }
+
+ // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
+ // gcc will use register Y for the this pointer.
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
+ struct M0ClocklessData data;
+ data.d[0] = pixels.d[0];
+ data.d[1] = pixels.d[1];
+ data.d[2] = pixels.d[2];
+ data.s[0] = pixels.mScale[0];
+ data.s[1] = pixels.mScale[1];
+ data.s[2] = pixels.mScale[2];
+ data.e[0] = pixels.e[0];
+ data.e[1] = pixels.e[1];
+ data.e[2] = pixels.e[2];
+ data.adj = pixels.mAdvance;
+
+ typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
+
+ // timer mode w/prescaler of 0
+ LED_TIMER->MODE = TIMER_MODE_MODE_Timer;
+ LED_TIMER->PRESCALER = 0;
+ LED_TIMER->EVENTS_COMPARE[0] = 0;
+ LED_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
+ LED_TIMER->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;
+ LED_TIMER->TASKS_START = 1;
+
+ int ret = showLedData<4,8,T1,T2,T3,RGB_ORDER,WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
+
+ LED_TIMER->TASKS_STOP = 1;
+ return ret; // 0x00FFFFFF - _VAL;
+ }
+};
+
+
+#endif // NRF51
+#endif // __INC_CLOCKLESS_ARM_NRF51
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/src/platforms/arm/nrf51/fastpin_arm_nrf51.h b/src/platforms/arm/nrf51/fastpin_arm_nrf51.h
new file mode 100644
index 00000000..6005c448
--- /dev/null
+++ b/src/platforms/arm/nrf51/fastpin_arm_nrf51.h
@@ -0,0 +1,119 @@
+#ifndef __FASTPIN_ARM_NRF51_H
+#define __FASTPIN_ARM_NRF51_H
+
+#if defined(NRF51)
+/// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this
+/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
+/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
+/// The registers are data output, set output, clear output, toggle output, input, and direction
+#if 0
+template<uint8_t PIN, uint32_t _MASK, typename _DIRSET, typename _DIRCLR, typename _OUTSET, typename _OUTCLR, typename _OUT> class _ARMPIN {
+public:
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ inline static void setOutput() { _DIRSET::r() = _MASK; }
+ inline static void setInput() { _DIRCLR::r() = _MASK; }
+
+ inline static void hi() __attribute__ ((always_inline)) { _OUTSET::r() = _MASK; }
+ inline static void lo() __attribute__ ((always_inline)) { _OUTCLR::r() = _MASK; }
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { _OUT::r() = val; }
+
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+
+ inline static void toggle() __attribute__ ((always_inline)) { _OUT::r() ^= _MASK; }
+
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
+
+ inline static port_t hival() __attribute__ ((always_inline)) { return _OUT::r() | _MASK; }
+ inline static port_t loval() __attribute__ ((always_inline)) { return _OUT::r() & ~_MASK; }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_OUT::r(); }
+ inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
+};
+
+#define ADDR(X) *(volatile uint32_t*)X
+#define NR_GPIO_ADDR(base,offset) (*(volatile uint32_t *))((uint32_t)(base + offset))
+#define NR_DIRSET ADDR(0x50000518UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x518)
+#define NR_DIRCLR ADDR(0x5000051CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x51C)
+#define NR_OUTSET ADDR(0x50000508UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x508)
+#define NR_OUTCLR ADDR(0x5000050CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x50C)
+#define NR_OUT ADDR(0x50000504UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x504)
+
+#define _RD32_NRF(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; }};
+
+_RD32_NRF(NR_DIRSET);
+_RD32_NRF(NR_DIRCLR);
+_RD32_NRF(NR_OUTSET);
+_RD32_NRF(NR_OUTCLR);
+_RD32_NRF(NR_OUT);
+
+#define _FL_DEFPIN(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN, \
+ _R(NR_DIRSET), _R(NR_DIRCLR), _R(NR_OUTSET), _R(NR_OUTCLR), _R(NR_OUT)> {};
+#else
+
+typedef struct { /*!< GPIO Structure */
+ // __I uint32_t RESERVED0[321];
+ __IO uint32_t OUT; /*!< Write GPIO port. */
+ __IO uint32_t OUTSET; /*!< Set individual bits in GPIO port. */
+ __IO uint32_t OUTCLR; /*!< Clear individual bits in GPIO port. */
+ __I uint32_t IN; /*!< Read GPIO port. */
+ __IO uint32_t DIR; /*!< Direction of GPIO pins. */
+ __IO uint32_t DIRSET; /*!< DIR set register. */
+ __IO uint32_t DIRCLR; /*!< DIR clear register. */
+ __I uint32_t RESERVED1[120];
+ __IO uint32_t PIN_CNF[32]; /*!< Configuration of GPIO pins. */
+} FL_NRF_GPIO_Type;
+
+#define FL_NRF_GPIO_BASE 0x50000504UL
+#define FL_NRF_GPIO ((FL_NRF_GPIO_Type *) FL_NRF_GPIO_BASE)
+
+template<uint8_t PIN, uint32_t _MASK> class _ARMPIN {
+public:
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ inline static void setOutput() { FL_NRF_GPIO->DIRSET = _MASK; }
+ inline static void setInput() { FL_NRF_GPIO->DIRCLR = _MASK; }
+
+ inline static void hi() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTSET = _MASK; }
+ inline static void lo() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTCLR= _MASK; }
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT = val; }
+
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+
+ inline static void toggle() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT ^= _MASK; }
+
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
+
+ inline static port_t hival() __attribute__ ((always_inline)) { return FL_NRF_GPIO->OUT | _MASK; }
+ inline static port_t loval() __attribute__ ((always_inline)) { return FL_NRF_GPIO->OUT & ~_MASK; }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { return &FL_NRF_GPIO->OUT; }
+ inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
+
+ inline static bool isset() __attribute__ ((always_inline)) { return (FL_NRF_GPIO->IN & _MASK) != 0; }
+};
+
+
+#define _FL_DEFPIN(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN> {};
+#endif
+
+// Actual pin definitions
+#define MAX_PIN 31
+_FL_DEFPIN(0); _FL_DEFPIN(1); _FL_DEFPIN(2); _FL_DEFPIN(3);
+_FL_DEFPIN(4); _FL_DEFPIN(5); _FL_DEFPIN(6); _FL_DEFPIN(7);
+_FL_DEFPIN(8); _FL_DEFPIN(9); _FL_DEFPIN(10); _FL_DEFPIN(11);
+_FL_DEFPIN(12); _FL_DEFPIN(13); _FL_DEFPIN(14); _FL_DEFPIN(15);
+_FL_DEFPIN(16); _FL_DEFPIN(17); _FL_DEFPIN(18); _FL_DEFPIN(19);
+_FL_DEFPIN(20); _FL_DEFPIN(21); _FL_DEFPIN(22); _FL_DEFPIN(23);
+_FL_DEFPIN(24); _FL_DEFPIN(25); _FL_DEFPIN(26); _FL_DEFPIN(27);
+_FL_DEFPIN(28); _FL_DEFPIN(29); _FL_DEFPIN(30); _FL_DEFPIN(31);
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
+#endif
+
+#endif
diff --git a/src/platforms/arm/nrf51/fastspi_arm_nrf51.h b/src/platforms/arm/nrf51/fastspi_arm_nrf51.h
new file mode 100644
index 00000000..6826ebcb
--- /dev/null
+++ b/src/platforms/arm/nrf51/fastspi_arm_nrf51.h
@@ -0,0 +1,149 @@
+#ifndef __INC_FASTSPI_NRF_H
+#define __INC_FASTSPI_NRF_H
+
+#ifdef NRF51
+
+#ifndef FASTLED_FORCE_SOFTWARE_SPI
+#define FASTLED_ALL_PINS_HARDWARE_SPI
+
+// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should
+// be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the
+// idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead)
+template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
+class NRF51SPIOutput {
+
+ struct saveData {
+ uint32_t sck;
+ uint32_t mosi;
+ uint32_t miso;
+ uint32_t freq;
+ uint32_t enable;
+ } mSavedData;
+
+ void saveSPIData() {
+ mSavedData.sck = NRF_SPI0->PSELSCK;
+ mSavedData.mosi = NRF_SPI0->PSELMOSI;
+ mSavedData.miso = NRF_SPI0->PSELMISO;
+ mSavedData.freq = NRF_SPI0->FREQUENCY;
+ mSavedData.enable = NRF_SPI0->ENABLE;
+ }
+
+ void restoreSPIData() {
+ NRF_SPI0->PSELSCK = mSavedData.sck;
+ NRF_SPI0->PSELMOSI = mSavedData.mosi;
+ NRF_SPI0->PSELMISO = mSavedData.miso;
+ NRF_SPI0->FREQUENCY = mSavedData.freq;
+ mSavedData.enable = NRF_SPI0->ENABLE;
+ }
+
+public:
+ NRF51SPIOutput() { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
+ NRF51SPIOutput(Selectable *pSelect) { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
+
+ // set the object representing the selectable
+ void setSelect(Selectable *pSelect) { /* TODO */ }
+
+ // initialize the SPI subssytem
+ void init() {
+ FastPin<_DATA_PIN>::setOutput();
+ FastPin<_CLOCK_PIN>::setOutput();
+ NRF_SPI0->PSELSCK = _CLOCK_PIN;
+ NRF_SPI0->PSELMOSI = _DATA_PIN;
+ NRF_SPI0->PSELMISO = 0xFFFFFFFF;
+ NRF_SPI0->FREQUENCY = 0x80000000;
+ NRF_SPI0->ENABLE = 1;
+ NRF_SPI0->EVENTS_READY = 0;
+ }
+
+ // latch the CS select
+ void select() { saveSPIData(); init(); }
+
+ // release the CS select
+ void release() { shouldWait(); restoreSPIData(); }
+
+ static bool shouldWait(bool wait = false) __attribute__((always_inline)) __attribute__((always_inline)) {
+ // static bool sWait=false;
+ // bool oldWait = sWait;
+ // sWait = wait;
+ // never going to bother with waiting since we're always running the spi clock at max speed on the rfduino
+ // TODO: When we set clock rate, implement/fix waiting properly, otherwise the world hangs up
+ return false;
+ }
+
+ // wait until all queued up data has been written
+ static void waitFully() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
+ static void wait() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
+
+ // write a byte out via SPI (returns immediately on writing register)
+ static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); NRF_SPI0->TXD = b; NRF_SPI0->INTENCLR; shouldWait(true); }
+
+ // write a word out via SPI (returns immediately on writing register)
+ static void writeWord(uint16_t w) __attribute__((always_inline)){ writeByte(w>>8); writeByte(w & 0xFF); }
+
+ // A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes)
+ static void writeBytesValueRaw(uint8_t value, int len) { while(len--) { writeByte(value); } }
+
+ // A full cycle of writing a value for len bytes, including select, release, and waiting
+ void writeBytesValue(uint8_t value, int len) {
+ select();
+ while(len--) {
+ writeByte(value);
+ }
+ waitFully();
+ release();
+ }
+
+ // A full cycle of writing a raw block of data out, including select, release, and waiting
+ template<class D> void writeBytes(uint8_t *data, int len) {
+ uint8_t *end = data + len;
+ select();
+ while(data != end) {
+ writeByte(D::adjust(*data++));
+ }
+ D::postBlock(len);
+ waitFully();
+ release();
+ }
+
+ void writeBytes(uint8_t *data, int len) {
+ writeBytes<DATA_NOP>(data, len);
+ }
+
+ // write a single bit out, which bit from the passed in byte is determined by template parameter
+ template <uint8_t BIT> inline static void writeBit(uint8_t b) {
+ waitFully();
+ NRF_SPI0->ENABLE = 0;
+ if(b & 1<<BIT) {
+ FastPin<_DATA_PIN>::hi();
+ } else {
+ FastPin<_DATA_PIN>::lo();
+ }
+ FastPin<_CLOCK_PIN>::toggle();
+ FastPin<_CLOCK_PIN>::toggle();
+ NRF_SPI0->ENABLE = 1;
+ }
+
+ template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
+ select();
+ int len = pixels.mLen;
+ while(pixels.has(1)) {
+ if(FLAGS & FLAG_START_BIT) {
+ writeBit<0>(1);
+ }
+ writeByte(D::adjust(pixels.loadAndScale0()));
+ writeByte(D::adjust(pixels.loadAndScale1()));
+ writeByte(D::adjust(pixels.loadAndScale2()));
+
+ pixels.advanceData();
+ pixels.stepDithering();
+ }
+ D::postBlock(len);
+ waitFully();
+ release();
+ }
+};
+
+#endif
+#endif
+
+#endif
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 5a6aa92a..8972d2d2 100644
--- a/platforms/arm/nrf52/arbiter_nrf52.h
+++ b/src/platforms/arm/nrf52/arbiter_nrf52.h
@@ -36,7 +36,6 @@ static_assert(FASTLED_NRF52_PWM_INSTANCE_COUNT > 0, "Instance count must be grea
template <uint32_t _PWM_ID>
class PWM_Arbiter {
-
private:
static_assert(_PWM_ID < 32, "PWM_ID over 31 breaks current arbitration bitmask");
//const uint32_t _ACQUIRE_MASK = (1u << _PWM_ID) ;
diff --git a/platforms/arm/nrf52/clockless_arm_nrf52.h b/src/platforms/arm/nrf52/clockless_arm_nrf52.h
index 56a1dbe0..1dd3cd94 100644
--- a/platforms/arm/nrf52/clockless_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/clockless_arm_nrf52.h
@@ -15,7 +15,6 @@
// NOTE: Update platforms.cpp in root of FastLED library if this changes
#define FASTLED_NRF52_PWM_ID 0
-
extern uint32_t isrCount;
@@ -207,45 +206,45 @@ public:
while (pixels.has(1) && (remainingSequenceElements >= _BITS_PER_PIXEL)) {
uint8_t b0 = pixels.loadAndScale0();
- WriteBitToSequence<7>(b0, e); e++;
- WriteBitToSequence<6>(b0, e); e++;
- WriteBitToSequence<5>(b0, e); e++;
- WriteBitToSequence<4>(b0, e); e++;
- WriteBitToSequence<3>(b0, e); e++;
- WriteBitToSequence<2>(b0, e); e++;
- WriteBitToSequence<1>(b0, e); e++;
- WriteBitToSequence<0>(b0, e); e++;
+ WriteBitToSequence<7>(b0, e); ++e;
+ WriteBitToSequence<6>(b0, e); ++e;
+ WriteBitToSequence<5>(b0, e); ++e;
+ WriteBitToSequence<4>(b0, e); ++e;
+ WriteBitToSequence<3>(b0, e); ++e;
+ WriteBitToSequence<2>(b0, e); ++e;
+ WriteBitToSequence<1>(b0, e); ++e;
+ WriteBitToSequence<0>(b0, e); ++e;
if (_XTRA0 > 0) {
- for (int i = 0; i < _XTRA0; i++) {
- WriteBitToSequence<0>(0,e); e++;
+ for (int i = 0; i < _XTRA0; ++i) {
+ WriteBitToSequence<0>(0,e); ++e;
}
}
uint8_t b1 = pixels.loadAndScale1();
- WriteBitToSequence<7>(b1, e); e++;
- WriteBitToSequence<6>(b1, e); e++;
- WriteBitToSequence<5>(b1, e); e++;
- WriteBitToSequence<4>(b1, e); e++;
- WriteBitToSequence<3>(b1, e); e++;
- WriteBitToSequence<2>(b1, e); e++;
- WriteBitToSequence<1>(b1, e); e++;
- WriteBitToSequence<0>(b1, e); e++;
+ WriteBitToSequence<7>(b1, e); ++e;
+ WriteBitToSequence<6>(b1, e); ++e;
+ WriteBitToSequence<5>(b1, e); ++e;
+ WriteBitToSequence<4>(b1, e); ++e;
+ WriteBitToSequence<3>(b1, e); ++e;
+ WriteBitToSequence<2>(b1, e); ++e;
+ WriteBitToSequence<1>(b1, e); ++e;
+ WriteBitToSequence<0>(b1, e); ++e;
if (_XTRA0 > 0) {
- for (int i = 0; i < _XTRA0; i++) {
- WriteBitToSequence<0>(0,e); e++;
+ for (int i = 0; i < _XTRA0; ++i) {
+ WriteBitToSequence<0>(0,e); ++e;
}
}
uint8_t b2 = pixels.loadAndScale2();
- WriteBitToSequence<7>(b2, e); e++;
- WriteBitToSequence<6>(b2, e); e++;
- WriteBitToSequence<5>(b2, e); e++;
- WriteBitToSequence<4>(b2, e); e++;
- WriteBitToSequence<3>(b2, e); e++;
- WriteBitToSequence<2>(b2, e); e++;
- WriteBitToSequence<1>(b2, e); e++;
- WriteBitToSequence<0>(b2, e); e++;
+ WriteBitToSequence<7>(b2, e); ++e;
+ WriteBitToSequence<6>(b2, e); ++e;
+ WriteBitToSequence<5>(b2, e); ++e;
+ WriteBitToSequence<4>(b2, e); ++e;
+ WriteBitToSequence<3>(b2, e); ++e;
+ WriteBitToSequence<2>(b2, e); ++e;
+ WriteBitToSequence<1>(b2, e); ++e;
+ WriteBitToSequence<0>(b2, e); ++e;
if (_XTRA0 > 0) {
- for (int i = 0; i < _XTRA0; i++) {
- WriteBitToSequence<0>(0,e); e++;
+ for (int i = 0; i < _XTRA0; ++i) {
+ WriteBitToSequence<0>(0,e); ++e;
}
}
@@ -292,22 +291,22 @@ public:
uint8_t * nextByte = arrayOfBytes;
for (uint16_t bytesRemain = bytesToSend;
(remainingSequenceElements >= 8) && (bytesRemain > 0);
- bytesRemain--,
+ --bytesRemain,
remainingSequenceElements -= 8,
s_SequenceBufferValidElements += 8
) {
uint8_t b = *nextByte;
- WriteBitToSequence<7,false>(b, e); e++;
- WriteBitToSequence<6,false>(b, e); e++;
- WriteBitToSequence<5,false>(b, e); e++;
- WriteBitToSequence<4,false>(b, e); e++;
- WriteBitToSequence<3,false>(b, e); e++;
- WriteBitToSequence<2,false>(b, e); e++;
- WriteBitToSequence<1,false>(b, e); e++;
- WriteBitToSequence<0,false>(b, e); e++;
+ WriteBitToSequence<7,false>(b, e); ++e;
+ WriteBitToSequence<6,false>(b, e); ++e;
+ WriteBitToSequence<5,false>(b, e); ++e;
+ WriteBitToSequence<4,false>(b, e); ++e;
+ WriteBitToSequence<3,false>(b, e); ++e;
+ WriteBitToSequence<2,false>(b, e); ++e;
+ WriteBitToSequence<1,false>(b, e); ++e;
+ WriteBitToSequence<0,false>(b, e); ++e;
if (_XTRA0 > 0) {
- for (int i = 0; i < _XTRA0; i++) {
- WriteBitToSequence<0,_FLIP>(0,e); e++;
+ for (int i = 0; i < _XTRA0; ++i) {
+ WriteBitToSequence<0,_FLIP>(0,e); ++e;
}
}
}
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 7a780876..9d0a8ec9 100644
--- a/platforms/arm/nrf52/fastpin_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/fastpin_arm_nrf52.h
@@ -90,54 +90,54 @@ struct __generated_struct_NRF_P1 {
// The actual class template can then use a typename, for what is essentially a constexpr NRF_GPIO_Type*
template <uint32_t _MASK, typename _PORT, uint8_t _PORT_NUMBER, uint8_t _PIN_NUMBER> class _ARMPIN {
public:
- typedef volatile uint32_t * port_ptr_t;
- typedef uint32_t port_t;
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
- FASTLED_NRF52_INLINE_ATTRIBUTE static void setOutput() {
- // OK for this to be more than one instruction, as unusual to quickly switch input/output modes
- nrf_gpio_cfg(
- nrf_pin(),
- NRF_GPIO_PIN_DIR_OUTPUT, // set pin as output
- NRF_GPIO_PIN_INPUT_DISCONNECT, // disconnect the input buffering
- NRF_GPIO_PIN_NOPULL, // neither pull-up nor pull-down resistors enabled
- NRF_GPIO_PIN_H0H1, // high drive mode required for faster speeds
- NRF_GPIO_PIN_NOSENSE // pin sense level disabled
- );
- }
- FASTLED_NRF52_INLINE_ATTRIBUTE static void setInput() {
- // OK for this to be more than one instruction, as unusual to quickly switch input/output modes
- nrf_gpio_cfg(
- nrf_pin(),
- NRF_GPIO_PIN_DIR_INPUT, // set pin as input
- NRF_GPIO_PIN_INPUT_DISCONNECT, // disconnect the input buffering
- NRF_GPIO_PIN_NOPULL, // neither pull-up nor pull-down resistors enabled
- NRF_GPIO_PIN_H0H1, // high drive mode required for faster speeds
- NRF_GPIO_PIN_NOSENSE // pin sense level disabled
- );
- }
- FASTLED_NRF52_INLINE_ATTRIBUTE static void hi() { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTSET = _MASK; } // sets _MASK in the SET OUTPUT register (output set high)
- FASTLED_NRF52_INLINE_ATTRIBUTE static void lo() { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTCLR = _MASK; } // sets _MASK in the CLEAR OUTPUT register (output set low)
- FASTLED_NRF52_INLINE_ATTRIBUTE static void toggle() { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT ^= _MASK; } // toggles _MASK bits in the OUTPUT GPIO port directly
- FASTLED_NRF52_INLINE_ATTRIBUTE static void strobe() { toggle(); toggle(); } // BUGBUG -- Is this used by FastLED? Without knowing (for example) SPI Speed?
- FASTLED_NRF52_INLINE_ATTRIBUTE static port_t hival() { return (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT | _MASK; } // sets all _MASK bit(s) in the OUTPUT GPIO port to 1
- FASTLED_NRF52_INLINE_ATTRIBUTE static port_t loval() { return (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT & ~_MASK; } // sets all _MASK bit(s) in the OUTPUT GPIO port to 0
- FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t port() { return &((reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT); } // gets raw pointer to OUTPUT GPIO port
- FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t cport() { return &((reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTCLR); } // gets raw pointer to SET DIRECTION GPIO port
- FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t sport() { return &((reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTSET); } // gets raw pointer to CLEAR DIRECTION GPIO port
- FASTLED_NRF52_INLINE_ATTRIBUTE static port_t mask() { return _MASK; } // gets the value of _MASK
- FASTLED_NRF52_INLINE_ATTRIBUTE static void hi (register port_ptr_t port) { hi(); } // sets _MASK in the SET OUTPUT register (output set high)
- FASTLED_NRF52_INLINE_ATTRIBUTE static void lo (register port_ptr_t port) { lo(); } // sets _MASK in the CLEAR OUTPUT register (output set low)
- FASTLED_NRF52_INLINE_ATTRIBUTE static void set(register port_t val ) { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT = val; } // sets entire port's value (optimization used by FastLED)
- FASTLED_NRF52_INLINE_ATTRIBUTE static void fastset(register port_ptr_t port, register port_t val) { *port = val; }
- constexpr static uint32_t nrf_pin2() { return NRF_GPIO_PIN_MAP(_PORT_NUMBER, _PIN_NUMBER); }
- constexpr static bool LowSpeedOnlyRecommended() {
- // Caller must always determine if high speed use if allowed on a given pin,
- // because it depends on more than just the chip packaging ... it depends on entire board (and even system) design.
- return false; // choosing default to be FALSE, to allow users to ATTEMPT to use high-speed on pins where support is not known
- }
- // Expose the nrf pin (port/pin combined), port, and pin as properties (e.g., for setting up SPI)
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void setOutput() {
+ // OK for this to be more than one instruction, as unusual to quickly switch input/output modes
+ nrf_gpio_cfg(
+ nrf_pin(),
+ NRF_GPIO_PIN_DIR_OUTPUT, // set pin as output
+ NRF_GPIO_PIN_INPUT_DISCONNECT, // disconnect the input buffering
+ NRF_GPIO_PIN_NOPULL, // neither pull-up nor pull-down resistors enabled
+ NRF_GPIO_PIN_H0H1, // high drive mode required for faster speeds
+ NRF_GPIO_PIN_NOSENSE // pin sense level disabled
+ );
+ }
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void setInput() {
+ // OK for this to be more than one instruction, as unusual to quickly switch input/output modes
+ nrf_gpio_cfg(
+ nrf_pin(),
+ NRF_GPIO_PIN_DIR_INPUT, // set pin as input
+ NRF_GPIO_PIN_INPUT_DISCONNECT, // disconnect the input buffering
+ NRF_GPIO_PIN_NOPULL, // neither pull-up nor pull-down resistors enabled
+ NRF_GPIO_PIN_H0H1, // high drive mode required for faster speeds
+ NRF_GPIO_PIN_NOSENSE // pin sense level disabled
+ );
+ }
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void hi() { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTSET = _MASK; } // sets _MASK in the SET OUTPUT register (output set high)
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void lo() { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTCLR = _MASK; } // sets _MASK in the CLEAR OUTPUT register (output set low)
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void toggle() { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT ^= _MASK; } // toggles _MASK bits in the OUTPUT GPIO port directly
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void strobe() { toggle(); toggle(); } // BUGBUG -- Is this used by FastLED? Without knowing (for example) SPI Speed?
+ FASTLED_NRF52_INLINE_ATTRIBUTE static port_t hival() { return (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT | _MASK; } // sets all _MASK bit(s) in the OUTPUT GPIO port to 1
+ FASTLED_NRF52_INLINE_ATTRIBUTE static port_t loval() { return (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT & ~_MASK; } // sets all _MASK bit(s) in the OUTPUT GPIO port to 0
+ FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t port() { return &((reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT); } // gets raw pointer to OUTPUT GPIO port
+ FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t cport() { return &((reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTCLR); } // gets raw pointer to SET DIRECTION GPIO port
+ FASTLED_NRF52_INLINE_ATTRIBUTE static port_ptr_t sport() { return &((reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUTSET); } // gets raw pointer to CLEAR DIRECTION GPIO port
+ FASTLED_NRF52_INLINE_ATTRIBUTE static port_t mask() { return _MASK; } // gets the value of _MASK
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void hi (register port_ptr_t port) { hi(); } // sets _MASK in the SET OUTPUT register (output set high)
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void lo (register port_ptr_t port) { lo(); } // sets _MASK in the CLEAR OUTPUT register (output set low)
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void set(register port_t val ) { (reinterpret_cast<NRF_GPIO_Type*>(_PORT::r()))->OUT = val; } // sets entire port's value (optimization used by FastLED)
+ FASTLED_NRF52_INLINE_ATTRIBUTE static void fastset(register port_ptr_t port, register port_t val) { *port = val; }
+ constexpr static uint32_t nrf_pin2() { return NRF_GPIO_PIN_MAP(_PORT_NUMBER, _PIN_NUMBER); }
+ constexpr static bool LowSpeedOnlyRecommended() {
+ // Caller must always determine if high speed use if allowed on a given pin,
+ // because it depends on more than just the chip packaging ... it depends on entire board (and even system) design.
+ return false; // choosing default to be FALSE, to allow users to ATTEMPT to use high-speed on pins where support is not known
+ }
+ // Expose the nrf pin (port/pin combined), port, and pin as properties (e.g., for setting up SPI)
- FASTLED_NRF52_INLINE_ATTRIBUTE static uint32_t nrf_pin() { return NRF_GPIO_PIN_MAP(_PORT_NUMBER, _PIN_NUMBER); }
+ FASTLED_NRF52_INLINE_ATTRIBUTE static uint32_t nrf_pin() { return NRF_GPIO_PIN_MAP(_PORT_NUMBER, _PIN_NUMBER); }
};
//
@@ -152,7 +152,7 @@ public:
// _FL_DEFPIN(47, 47, 1);
//
-#define _FL_DEFPIN(ARDUINO_PIN, BOARD_PIN, BOARD_PORT) \
+#define _FL_DEFPIN(ARDUINO_PIN, BOARD_PIN, BOARD_PORT) \
template<> class FastPin<ARDUINO_PIN> : \
public _ARMPIN< \
1u << (BOARD_PIN & 31u), \
diff --git a/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h b/src/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h
index c8aa2e89..9020655c 100644
--- a/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h
+++ b/src/platforms/arm/nrf52/fastpin_arm_nrf52_variants.h
@@ -49,6 +49,41 @@
_DEFPIN_ARM_IDENTITY_P0(31); // A7
#endif // defined (ARDUINO_NRF52832_FEATHER)
+// Adafruit Circuit Playground Bluefruit
+// From https://www.adafruit.com/package_adafruit_index.json
+#if defined (ARDUINO_NRF52840_CIRCUITPLAY)
+ #if defined(__FASTPIN_ARM_NRF52_VARIANT_FOUND)
+ #error "Cannot define more than one board at a time"
+ #else
+ #define __FASTPIN_ARM_NRF52_VARIANT_FOUND
+ #endif
+
+ // This board is a bit of a mess ... as it defines
+ // multiple arduino pins to map to a single Port/Pin
+ // combination.
+
+ // Use PIN_NEOPIXEL (D8) for the ten built-in neopixels
+ _FL_DEFPIN( 8, 13, 0); // P0.13 -- D8 / Neopixels
+
+ // PIN_A0 is connect to an amplifier, and thus *might*
+ // not be suitable for use with FastLED.
+ // Do not enable this pin until can confirm
+ // signal integrity from this pin.
+ //
+ // NOTE: it might also be possible if first disable
+ // the amp using D11 ("speaker shutdown" pin)
+ //
+ // _FL_DEFPIN(14, 26, 0); // P0.26 -- A0 / D12 / Audio Out
+ _FL_DEFPIN(15, 2, 0); // P0.02 -- A1 / D6
+ _FL_DEFPIN(16, 29, 0); // P0.29 -- A2 / D9
+ _FL_DEFPIN(17, 3, 0); // P0.03 -- A3 / D10
+ _FL_DEFPIN(18, 4, 0); // P0.04 -- A4 / D3 / SCL
+ _FL_DEFPIN(19, 5, 0); // P0.05 -- A5 / D2 / SDA
+ _FL_DEFPIN(20, 30, 0); // P0.30 -- A6 / D0 / UART RX
+ _FL_DEFPIN(21, 14, 0); // P0.14 -- AREF / D1 / UART TX
+
+#endif
+
// Adafruit Bluefruit nRF52840 Feather Express
// From https://www.adafruit.com/package_adafruit_index.json
#if defined (ARDUINO_NRF52840_FEATHER)
diff --git a/platforms/arm/nrf52/fastspi_arm_nrf52.h b/src/platforms/arm/nrf52/fastspi_arm_nrf52.h
index 9c1a2198..89d006e3 100644
--- a/platforms/arm/nrf52/fastspi_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/fastspi_arm_nrf52.h
@@ -23,7 +23,6 @@
/// SPI_CLOCK_DIVIDER is number of CPU clock cycles per SPI transmission bit?
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class NRF52SPIOutput {
-
private:
// static variables -- always using same SPIM instance
static bool s_InUse;
diff --git a/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h b/src/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h
index d4e26ce9..3a7ea582 100644
--- a/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h
+++ b/src/platforms/arm/nrf52/led_sysdefs_arm_nrf52.h
@@ -46,14 +46,7 @@ typedef __IO uint32_t RwReg;
#define cli() __disable_irq()
#define sei() __enable_irq()
-#define FASTLED_NRF52_DEBUGPRINT(format, ...)
-/*
#define FASTLED_NRF52_DEBUGPRINT(format, ...)\
- do {\
- FastLED_NRF52_DebugPrint(format, ##__VA_ARGS__);\
- } while(0);
-*/
-
-
+// do { FastLED_NRF52_DebugPrint(format, ##__VA_ARGS__); } while(0);
#endif // __LED_SYSDEFS_ARM_NRF52
diff --git a/platforms/arm/sam/clockless_arm_sam.h b/src/platforms/arm/sam/clockless_arm_sam.h
index 0fc621d2..d7c57940 100644
--- a/platforms/arm/sam/clockless_arm_sam.h
+++ b/src/platforms/arm/sam/clockless_arm_sam.h
@@ -22,6 +22,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual void init() {
FastPinBB<DATA_PIN>::setOutput();
@@ -32,15 +33,14 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
- virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
- mWait.wait();
- if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ mWait.wait();
+ if(!showRGBInternal(pixels)) {
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
}
- mWait.mark();
- }
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register uint8_t & b) {
// Make sure we don't slot into a wrapping spot, this will delay up to 12.5µs for WS2812
@@ -48,7 +48,7 @@ protected:
// while(VAL < (TOTAL*10)) { bShift=true; }
// if(bShift) { next_mark = (VAL-TOTAL); };
- for(register uint32_t i = BITS; i > 0; i--) {
+ for(register uint32_t i = BITS; i > 0; --i) {
// wait to start the bit, then set the pin high
while(DUE_TIMER_VAL < next_mark);
next_mark = (DUE_TIMER_VAL+TOTAL);
@@ -90,7 +90,9 @@ protected:
#if (FASTLED_ALLOW_INTERRUPTS == 1)
cli();
if(DUE_TIMER_VAL > next_mark) {
- if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return 0; }
+ if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) {
+ sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return 0;
+ }
}
#endif
diff --git a/src/platforms/arm/sam/clockless_block_arm_sam.h b/src/platforms/arm/sam/clockless_block_arm_sam.h
new file mode 100644
index 00000000..a1799891
--- /dev/null
+++ b/src/platforms/arm/sam/clockless_block_arm_sam.h
@@ -0,0 +1,183 @@
+ #ifndef __INC_BLOCK_CLOCKLESS_H
+#define __INC_BLOCK_CLOCKLESS_H
+
+FASTLED_NAMESPACE_BEGIN
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point
+// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the
+// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles.
+//
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if defined(__SAM3X8E__)
+#define PORT_MASK (((1<<LANES)-1) & ((FIRST_PIN==2) ? 0xFF : 0xFF))
+
+#define FASTLED_HAS_BLOCKLESS 1
+
+#define PORTD_FIRST_PIN 25
+#define PORTA_FIRST_PIN 69
+#define PORTB_FIRST_PIN 90
+
+typedef union {
+ uint8_t bytes[8];
+ uint32_t raw[2];
+} Lines;
+
+#define TADJUST 0
+#define TOTAL ( (T1+TADJUST) + (T2+TADJUST) + (T3+TADJUST) )
+#define T1_MARK (TOTAL - (T1+TADJUST))
+#define T2_MARK (T1_MARK - (T2+TADJUST))
+template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
+class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PORT_MASK> {
+ typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t;
+ typedef typename FastPin<FIRST_PIN>::port_t data_t;
+
+ data_t mPinMask;
+ data_ptr_t mPort;
+ CMinWait<WAIT_TIME> mWait;
+
+public:
+ virtual int size() { return CLEDController::size() * LANES; }
+ virtual void init() {
+ static_assert(LANES <= 8, "Maximum of 8 lanes for Due parallel controllers!");
+ if(FIRST_PIN == PORTA_FIRST_PIN) {
+ switch(LANES) {
+ case 8: FastPin<31>::setOutput();
+ case 7: FastPin<58>::setOutput();
+ case 6: FastPin<100>::setOutput();
+ case 5: FastPin<59>::setOutput();
+ case 4: FastPin<60>::setOutput();
+ case 3: FastPin<61>::setOutput();
+ case 2: FastPin<68>::setOutput();
+ case 1: FastPin<69>::setOutput();
+ }
+ } else if(FIRST_PIN == PORTD_FIRST_PIN) {
+ switch(LANES) {
+ case 8: FastPin<11>::setOutput();
+ case 7: FastPin<29>::setOutput();
+ case 6: FastPin<15>::setOutput();
+ case 5: FastPin<14>::setOutput();
+ case 4: FastPin<28>::setOutput();
+ case 3: FastPin<27>::setOutput();
+ case 2: FastPin<26>::setOutput();
+ case 1: FastPin<25>::setOutput();
+ }
+ } else if(FIRST_PIN == PORTB_FIRST_PIN) {
+ switch(LANES) {
+ case 8: FastPin<97>::setOutput();
+ case 7: FastPin<96>::setOutput();
+ case 6: FastPin<95>::setOutput();
+ case 5: FastPin<94>::setOutput();
+ case 4: FastPin<93>::setOutput();
+ case 3: FastPin<92>::setOutput();
+ case 2: FastPin<91>::setOutput();
+ case 1: FastPin<90>::setOutput();
+ }
+ }
+ mPinMask = FastPin<FIRST_PIN>::mask();
+ mPort = FastPin<FIRST_PIN>::port();
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+ virtual void showPixels(PixelController<RGB_ORDER, LANES, PORT_MASK> & pixels) {
+ mWait.wait();
+ showRGBInternal(pixels);
+ sei();
+ mWait.mark();
+ }
+
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
+ // Serial.println("Entering show");
+
+ int nLeds = allpixels.mLen;
+
+ // Setup the pixel controller and load/scale the first byte
+ Lines b0,b1,b2;
+
+ allpixels.preStepFirstByteDithering();
+ for(uint8_t i = 0; i < LANES; i++) {
+ b0.bytes[i] = allpixels.loadAndScale0(i);
+ }
+
+ // Setup and start the clock
+ TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1);
+ pmc_enable_periph_clk(DUE_TIMER_ID);
+ TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL);
+
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ cli();
+ #endif
+ uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL));
+ while(nLeds--) {
+ allpixels.stepDithering();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ cli();
+ if(DUE_TIMER_VAL > next_mark) {
+ if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) {
+ sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL;
+ }
+ }
+ #endif
+
+ // Write first byte, read next byte
+ writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels);
+
+ // Write second byte, read 3rd byte
+ writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels);
+
+ allpixels.advanceData();
+ // Write third byte
+ writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels);
+
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ sei();
+ #endif
+ }
+
+ return DUE_TIMER_VAL;
+ }
+
+ template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, PixelController<RGB_ORDER,LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
+ Lines b2;
+ transpose8x1(b.bytes,b2.bytes);
+
+ register uint8_t d = pixels.template getd<PX>(pixels);
+ register uint8_t scale = pixels.template getscale<PX>(pixels);
+
+ for(uint32_t i = 0; (i < LANES) && (i<8); i++) {
+ while(DUE_TIMER_VAL < next_mark);
+ next_mark = (DUE_TIMER_VAL+TOTAL);
+
+ *FastPin<FIRST_PIN>::sport() = PORT_MASK;
+
+ while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
+ *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
+
+ while((next_mark - (DUE_TIMER_VAL)) > T3);
+ *FastPin<FIRST_PIN>::cport() = PORT_MASK;
+
+ b3.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
+ }
+
+ for(uint32_t i = LANES; i < 8; i++) {
+ while(DUE_TIMER_VAL < next_mark);
+ next_mark = (DUE_TIMER_VAL+TOTAL);
+ *FastPin<FIRST_PIN>::sport() = PORT_MASK;
+
+ while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
+ *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
+
+ while((next_mark - DUE_TIMER_VAL) > T3);
+ *FastPin<FIRST_PIN>::cport() = PORT_MASK;
+ }
+ }
+};
+
+#endif
+
+FASTLED_NAMESPACE_END
+
+#endif
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 339c5e75..e1354c73 100644
--- a/platforms/arm/sam/fastpin_arm_sam.h
+++ b/src/platforms/arm/sam/fastpin_arm_sam.h
@@ -92,7 +92,6 @@ _FL_IO(D,3);
#if defined(__SAM3X8E__)
-
#define MAX_PIN 78
_FL_DEFPIN(0, 8, A); _FL_DEFPIN(1, 9, A); _FL_DEFPIN(2, 25, B); _FL_DEFPIN(3, 28, C);
_FL_DEFPIN(4, 26, C); _FL_DEFPIN(5, 25, C); _FL_DEFPIN(6, 24, C); _FL_DEFPIN(7, 23, C);
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/src/platforms/arm/stm32/clockless_arm_stm32.h b/src/platforms/arm/stm32/clockless_arm_stm32.h
new file mode 100644
index 00000000..d87b78c6
--- /dev/null
+++ b/src/platforms/arm/stm32/clockless_arm_stm32.h
@@ -0,0 +1,133 @@
+#ifndef __INC_CLOCKLESS_ARM_STM32_H
+#define __INC_CLOCKLESS_ARM_STM32_H
+
+FASTLED_NAMESPACE_BEGIN
+// Definition for a single channel clockless controller for the stm32 family of chips, like that used in the spark core
+// See clockless.h for detailed info on how the template parameters are used.
+
+#define FASTLED_HAS_CLOCKLESS 1
+
+#if defined(STM32F2XX)
+// The photon runs faster than the others
+#define ADJ 8
+#else
+#define ADJ 20
+#endif
+
+template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
+ typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
+ typedef typename FastPin<DATA_PIN>::port_t data_t;
+
+ data_t mPinMask;
+ data_ptr_t mPort;
+ CMinWait<WAIT_TIME> mWait;
+
+public:
+ virtual void init() {
+ FastPin<DATA_PIN>::setOutput();
+ mPinMask = FastPin<DATA_PIN>::mask();
+ mPort = FastPin<DATA_PIN>::port();
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+protected:
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ mWait.wait();
+ if(!showRGBInternal(pixels)) {
+ sei(); delayMicroseconds(WAIT_TIME); cli();
+ showRGBInternal(pixels);
+ }
+ mWait.mark();
+ }
+
+#define _CYCCNT (*(volatile uint32_t*)(0xE0001004UL))
+
+ template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
+ for(register uint32_t i = BITS-1; i > 0; --i) {
+ while(_CYCCNT < (T1+T2+T3-ADJ));
+ FastPin<DATA_PIN>::fastset(port, hi);
+ _CYCCNT = 4;
+ if(b&0x80) {
+ while(_CYCCNT < (T1+T2-ADJ));
+ FastPin<DATA_PIN>::fastset(port, lo);
+ } else {
+ while(_CYCCNT < (T1-ADJ/2));
+ FastPin<DATA_PIN>::fastset(port, lo);
+ }
+ b <<= 1;
+ }
+
+ while(_CYCCNT < (T1+T2+T3-ADJ));
+ FastPin<DATA_PIN>::fastset(port, hi);
+ _CYCCNT = 4;
+
+ if(b&0x80) {
+ while(_CYCCNT < (T1+T2-ADJ));
+ FastPin<DATA_PIN>::fastset(port, lo);
+ } else {
+ while(_CYCCNT < (T1-ADJ/2));
+ FastPin<DATA_PIN>::fastset(port, lo);
+ }
+ }
+
+ // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
+ // gcc will use register Y for the this pointer.
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
+ // Get access to the clock
+ CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
+ DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
+ DWT->CYCCNT = 0;
+
+ register data_ptr_t port = FastPin<DATA_PIN>::port();
+ register data_t hi = *port | FastPin<DATA_PIN>::mask();;
+ register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
+ *port = lo;
+
+ // Setup the pixel controller and load/scale the first byte
+ pixels.preStepFirstByteDithering();
+ register uint8_t b = pixels.loadAndScale0();
+
+ cli();
+
+ uint32_t next_mark = (T1+T2+T3);
+
+ DWT->CYCCNT = 0;
+ while(pixels.has(1)) {
+ pixels.stepDithering();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ cli();
+ // if interrupts took longer than 45µs, punt on the current frame
+ if(DWT->CYCCNT > next_mark) {
+ if((DWT->CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
+ }
+
+ hi = *port | FastPin<DATA_PIN>::mask();
+ lo = *port & ~FastPin<DATA_PIN>::mask();
+ #endif
+
+ // Write first byte, read next byte
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.loadAndScale1();
+
+ // Write second byte, read 3rd byte
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.loadAndScale2();
+
+ // Write third byte, read 1st byte of next pixel
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.advanceAndLoadAndScale0();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ sei();
+ #endif
+ };
+
+ sei();
+ return DWT->CYCCNT;
+ }
+};
+
+FASTLED_NAMESPACE_END
+
+#endif
diff --git a/src/platforms/arm/stm32/cm3_regs.h b/src/platforms/arm/stm32/cm3_regs.h
new file mode 100644
index 00000000..7bb7f759
--- /dev/null
+++ b/src/platforms/arm/stm32/cm3_regs.h
@@ -0,0 +1,63 @@
+#ifndef __CM3_REGS
+#define __CM3_REGS
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+#define __I volatile /*!< Defines 'read only' permissions */
+#else
+#define __I volatile const /*!< Defines 'read only' permissions */
+#endif
+#define __O volatile /*!< Defines 'write only' permissions */
+#define __IO volatile /*!< Defines 'read / write' permissions */
+
+
+typedef struct
+{
+ __IO uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */
+ __O uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */
+ __IO uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */
+ __IO uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */
+} CoreDebug_Type;
+
+#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */
+#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */
+
+#define CoreDebug_DEMCR_TRCENA_Pos 24 /*!< CoreDebug DEMCR: TRCENA Position */
+#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */
+
+typedef struct
+{
+ __IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */
+ __IO uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */
+ __IO uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */
+ __IO uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */
+ __IO uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */
+ __IO uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */
+ __IO uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */
+ __I uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */
+ __IO uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */
+ __IO uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */
+ __IO uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */
+ uint32_t RESERVED0[1];
+ __IO uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */
+ __IO uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */
+ __IO uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */
+ uint32_t RESERVED1[1];
+ __IO uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */
+ __IO uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */
+ __IO uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */
+ uint32_t RESERVED2[1];
+ __IO uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */
+ __IO uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */
+ __IO uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */
+} DWT_Type;
+
+
+#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */
+#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */
+
+#define DWT_CTRL_CYCCNTENA_Pos 0 /*!< DWT CTRL: CYCCNTENA Position */
+#define DWT_CTRL_CYCCNTENA_Msk (0x1UL << DWT_CTRL_CYCCNTENA_Pos) /*!< DWT CTRL: CYCCNTENA Mask */
+
+#endif // __CM3_REGS
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/src/platforms/arm/stm32/fastpin_arm_stm32.h b/src/platforms/arm/stm32/fastpin_arm_stm32.h
new file mode 100644
index 00000000..548fdc9d
--- /dev/null
+++ b/src/platforms/arm/stm32/fastpin_arm_stm32.h
@@ -0,0 +1,220 @@
+#ifndef __FASTPIN_ARM_STM32_H
+#define __FASTPIN_ARM_STM32_H
+
+FASTLED_NAMESPACE_BEGIN
+
+#if defined(FASTLED_FORCE_SOFTWARE_PINS)
+#warning "Software pin support forced, pin access will be sloightly slower."
+#define NO_HARDWARE_PIN_SUPPORT
+#undef HAS_HARDWARE_PIN_SUPPORT
+
+#else
+
+/// Template definition for STM32 style ARM pins, providing direct access to the various GPIO registers. Note that this
+/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found
+/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning.
+/// The registers are data output, set output, clear output, toggle output, input, and direction
+
+template<uint8_t PIN, uint8_t _BIT, uint32_t _MASK, typename _GPIO> class _ARMPIN {
+
+public:
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ #if 0
+ inline static void setOutput() {
+ if(_BIT<8) {
+ _CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
+ } else {
+ _CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
+ }
+ }
+ inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
+ #endif
+
+ inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; }
+ inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
+
+#if defined(STM32F2XX)
+ inline static void hi() __attribute__ ((always_inline)) { _GPIO::r()->BSRRL = _MASK; }
+ inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BSRRH = _MASK; }
+#else
+ inline static void hi() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = _MASK; }
+ inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BRR = _MASK; }
+ // inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = (_MASK<<16); }
+#endif
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { _GPIO::r()->ODR = val; }
+
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+
+ inline static void toggle() __attribute__ ((always_inline)) { if(_GPIO::r()->ODR & _MASK) { lo(); } else { hi(); } }
+
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
+
+ inline static port_t hival() __attribute__ ((always_inline)) { return _GPIO::r()->ODR | _MASK; }
+ inline static port_t loval() __attribute__ ((always_inline)) { return _GPIO::r()->ODR & ~_MASK; }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_GPIO::r()->ODR; }
+
+#if defined(STM32F2XX)
+ inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRRL; }
+ inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRRH; }
+#else
+ inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRR; }
+ inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO::r()->BRR; }
+#endif
+
+ inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
+};
+
+
+#define _R(T) struct __gen_struct_ ## T
+#define _FL_DEFPIN(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, BIT, 1 << BIT, _R(GPIO ## L)> {};
+
+#if defined(STM32F10X_MD)
+#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile GPIO_TypeDef * r() { return T; } };
+#define _FL_IO(L,C) _RD32(GPIO ## L); _FL_DEFINE_PORT3(L, C, _R(GPIO ## L));
+
+#elif defined(__STM32F1__)
+#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline gpio_reg_map* r() { return T->regs; } };
+#define _FL_IO(L,C) _RD32(GPIO ## L); _FL_DEFINE_PORT3(L, C, _R(GPIO ## L));
+
+#elif defined(STM32F2XX)
+#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile GPIO_TypeDef * r() { return T; } };
+#define _FL_IO(L,C) _RD32(GPIO ## L);
+#else
+#error "Platform not supported"
+#endif
+
+#ifdef GPIOA
+_FL_IO(A,0);
+#endif
+#ifdef GPIOB
+_FL_IO(B,1);
+#endif
+#ifdef GPIOC
+_FL_IO(C,2);
+#endif
+#ifdef GPIOD
+_FL_IO(D,3);
+#endif
+#ifdef GPIOE
+_FL_IO(E,4);
+#endif
+#ifdef GPIOF
+_FL_IO(F,5);
+#endif
+#ifdef GPIOG
+_FL_IO(G,6);
+#endif
+
+// Actual pin definitions
+#if defined(STM32F2XX) // Photon Particle
+
+// https://github.com/focalintent/FastLED-Sparkcore/blob/master/firmware/fastpin_arm_stm32.h
+#define MAX_PIN 20
+_FL_DEFPIN(0, 7, B);
+_FL_DEFPIN(1, 6, B);
+_FL_DEFPIN(2, 5, B);
+_FL_DEFPIN(3, 4, B);
+_FL_DEFPIN(4, 3, B);
+_FL_DEFPIN(5, 15, A);
+_FL_DEFPIN(6, 14, A);
+_FL_DEFPIN(7, 13, A);
+_FL_DEFPIN(10, 5, C);
+_FL_DEFPIN(11, 3, C);
+_FL_DEFPIN(12, 2, C);
+_FL_DEFPIN(13, 5, A);
+_FL_DEFPIN(14, 6, A);
+_FL_DEFPIN(15, 7, A);
+_FL_DEFPIN(16, 4, A);
+_FL_DEFPIN(17, 0, A);
+_FL_DEFPIN(18, 10, A);
+_FL_DEFPIN(19, 9, A);
+_FL_DEFPIN(20, 7, C);
+
+#define SPI_DATA 15
+#define SPI_CLOCK 13
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
+#elif defined(SPARK) // Sparkfun STM32F103 based board
+
+#define MAX_PIN 19
+_FL_DEFPIN(0, 7, B);
+_FL_DEFPIN(1, 6, B);
+_FL_DEFPIN(2, 5, B);
+_FL_DEFPIN(3, 4, B);
+_FL_DEFPIN(4, 3, B);
+_FL_DEFPIN(5, 15, A);
+_FL_DEFPIN(6, 14, A);
+_FL_DEFPIN(7, 13, A);
+_FL_DEFPIN(8, 8, A);
+_FL_DEFPIN(9, 9, A);
+_FL_DEFPIN(10, 0, A);
+_FL_DEFPIN(11, 1, A);
+_FL_DEFPIN(12, 4, A);
+_FL_DEFPIN(13, 5, A);
+_FL_DEFPIN(14, 6, A);
+_FL_DEFPIN(15, 7, A);
+_FL_DEFPIN(16, 0, B);
+_FL_DEFPIN(17, 1, B);
+_FL_DEFPIN(18, 3, A);
+_FL_DEFPIN(19, 2, A);
+
+#define SPI_DATA 15
+#define SPI_CLOCK 13
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
+#elif defined(__STM32F1__) // Generic STM32F103 aka "Blue Pill"
+
+#define MAX_PIN 46
+
+_FL_DEFPIN(10, 0, A); // PA0 - PA7
+_FL_DEFPIN(11, 1, A);
+_FL_DEFPIN(12, 2, A);
+_FL_DEFPIN(13, 3, A);
+_FL_DEFPIN(14, 4, A);
+_FL_DEFPIN(15, 5, A);
+_FL_DEFPIN(16, 6, A);
+_FL_DEFPIN(17, 7, A);
+_FL_DEFPIN(29, 8, A); // PA8 - PA15
+_FL_DEFPIN(30, 9, A);
+_FL_DEFPIN(31, 10, A);
+_FL_DEFPIN(32, 11, A);
+_FL_DEFPIN(33, 12, A);
+_FL_DEFPIN(34, 13, A);
+_FL_DEFPIN(37, 14, A);
+_FL_DEFPIN(38, 15, A);
+
+_FL_DEFPIN(18, 0, B); // PB0 - PB11
+_FL_DEFPIN(19, 1, B);
+_FL_DEFPIN(20, 2, B);
+_FL_DEFPIN(39, 3, B);
+_FL_DEFPIN(40, 4, B);
+_FL_DEFPIN(41, 5, B);
+_FL_DEFPIN(42, 6, B);
+_FL_DEFPIN(43, 7, B);
+_FL_DEFPIN(45, 8, B);
+_FL_DEFPIN(46, 9, B);
+_FL_DEFPIN(21, 10, B);
+_FL_DEFPIN(22, 11, B);
+
+_FL_DEFPIN(2, 13, C); // PC13 - PC15
+_FL_DEFPIN(3, 14, C);
+_FL_DEFPIN(4, 15, C);
+
+#define SPI_DATA BOARD_SPI1_MOSI_PIN
+#define SPI_CLOCK BOARD_SPI1_SCK_PIN
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
+#endif // __STM32F1__
+
+#endif // FASTLED_FORCE_SOFTWARE_PINS
+
+FASTLED_NAMESPACE_END
+
+#endif // __INC_FASTPIN_ARM_STM32
diff --git a/platforms/arm/stm32/led_sysdefs_arm_stm32.h b/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h
index 6b9ce7ca..b58779ff 100644
--- a/platforms/arm/stm32/led_sysdefs_arm_stm32.h
+++ b/src/platforms/arm/stm32/led_sysdefs_arm_stm32.h
@@ -1,27 +1,27 @@
#ifndef __INC_LED_SYSDEFS_ARM_SAM_H
#define __INC_LED_SYSDEFS_ARM_SAM_H
-#if defined(STM32F10X_MD)
+#if defined(STM32F10X_MD) || defined(STM32F2XX)
- #include <application.h>
+#include <application.h>
- #define FASTLED_NAMESPACE_BEGIN namespace NSFastLED {
- #define FASTLED_NAMESPACE_END }
- #define FASTLED_USING_NAMESPACE using namespace NSFastLED;
+#define FASTLED_NAMESPACE_BEGIN namespace NSFastLED {
+#define FASTLED_NAMESPACE_END }
+#define FASTLED_USING_NAMESPACE using namespace NSFastLED;
- // reusing/abusing cli/sei defs for due
- #define cli() __disable_irq(); __disable_fault_irq();
- #define sei() __enable_irq(); __enable_fault_irq();
+// reusing/abusing cli/sei defs for due
+#define cli() __disable_irq(); __disable_fault_irq();
+#define sei() __enable_irq(); __enable_fault_irq();
#elif defined (__STM32F1__)
- #include "cm3_regs.h"
+#include "cm3_regs.h"
- #define cli() nvic_globalirq_disable()
- #define sei() nvic_globalirq_enable()
+#define cli() nvic_globalirq_disable()
+#define sei() nvic_globalirq_enable()
#else
- #error "Platform not supported"
+#error "Platform not supported"
#endif
#define FASTLED_ARM
@@ -55,7 +55,16 @@ typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile u
#define FASTLED_NO_PINMAP
-#ifndef F_CPU
- #define F_CPU 72000000
+#if defined(STM32F2XX)
+#define F_CPU 120000000
+#else
+#define F_CPU 72000000
#endif
+
+#if defined(STM32F2XX)
+// Photon doesn't provide yield
+#define FASTLED_NEEDS_YIELD
+extern "C" void yield();
#endif
+
+#endif // defined(STM32F10X_MD) || defined(STM32F2XX)
diff --git a/platforms/avr/clockless_trinket.h b/src/platforms/avr/clockless_trinket.h
index 824553fe..2cfbef0d 100644
--- a/platforms/avr/clockless_trinket.h
+++ b/src/platforms/avr/clockless_trinket.h
@@ -49,7 +49,11 @@ template<> __attribute__((always_inline)) inline void _dc<-2>(register uint8_t &
template<> __attribute__((always_inline)) inline void _dc<-1>(register uint8_t & ) {}
template<> __attribute__((always_inline)) inline void _dc< 0>(register uint8_t & ) {}
template<> __attribute__((always_inline)) inline void _dc< 1>(register uint8_t & ) {asm __volatile__("mov r0,r0":::);}
+#if defined(__LGT8F__)
+template<> __attribute__((always_inline)) inline void _dc< 2>(register uint8_t & loopvar) { _dc<1>(loopvar); _dc<1>(loopvar); }
+#else
template<> __attribute__((always_inline)) inline void _dc< 2>(register uint8_t & ) {asm __volatile__("rjmp .+0":::);}
+#endif
template<> __attribute__((always_inline)) inline void _dc< 3>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<1>(loopvar); }
template<> __attribute__((always_inline)) inline void _dc< 4>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<2>(loopvar); }
template<> __attribute__((always_inline)) inline void _dc< 5>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<3>(loopvar); }
@@ -97,6 +101,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPin<DATA_PIN>::port_t data_t;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual void init() {
FastPin<DATA_PIN>::setOutput();
@@ -105,7 +110,6 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
@@ -167,6 +171,13 @@ protected:
}
#define USE_ASM_MACROS
+#if defined(__AVR_ATmega4809__)
+// Not used - place holder so existing ASM_VARS macro can remain the same
+#define ASM_VAR_PORT "r" (*FastPin<DATA_PIN>::port())
+#else
+#define ASM_VAR_PORT "M" (FastPin<DATA_PIN>::port() - 0x20)
+#endif
+
// The variables that our various asm statements use. The same block of variables needs to be declared for
// all the asm blocks because GCC is pretty stupid and it would clobber variables happily or optimize code away too aggressively
#define ASM_VARS : /* write variables */ \
@@ -189,19 +200,29 @@ protected:
[e0] "r" (e0), \
[e1] "r" (e1), \
[e2] "r" (e2), \
- [PORT] "M" (FastPin<DATA_PIN>::port()-0x20), \
+ [PORT] ASM_VAR_PORT, \
[O0] "M" (RGB_BYTE0(RGB_ORDER)), \
[O1] "M" (RGB_BYTE1(RGB_ORDER)), \
[O2] "M" (RGB_BYTE2(RGB_ORDER)) \
: "cc" /* clobber registers */
+#if defined(__AVR_ATmega4809__)
-// Note: the code in the else in HI1/LO1 will be turned into an sts (2 cycle, 2 word) opcode
+// 1 cycle, write hi to the port
+#define HI1 do {*FastPin<DATA_PIN>::port()=hi;} while(0);
+// 1 cycle, write lo to the port
+#define LO1 do {*FastPin<DATA_PIN>::port()=lo;} while(0);
+
+#else
+
+// Note: the code in the else in HI1/LO1 will be turned into an sts (2 cycle, 2 word)
// 1 cycle, write hi to the port
#define HI1 FASTLED_SLOW_CLOCK_ADJUST if((int)(FastPin<DATA_PIN>::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[hi]" ASM_VARS ); } else { *FastPin<DATA_PIN>::port()=hi; }
// 1 cycle, write lo to the port
#define LO1 if((int)(FastPin<DATA_PIN>::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[lo]" ASM_VARS ); } else { *FastPin<DATA_PIN>::port()=lo; }
+#endif
+
// 2 cycles, sbrs on flipping the line to lo if we're pushing out a 0
#define QLO2(B, N) asm __volatile__("sbrs %[" #B "], " #N ASM_VARS ); LO1;
// load a byte from ram into the given var with the given offset
@@ -323,10 +344,10 @@ protected:
#define DUSE (0xFF - (DADVANCE-1))
// Silence compiler warnings about switch/case that is explicitly intended to fall through.
-//#define FL_FALLTHROUGH __attribute__ ((fallthrough));
+#define FL_FALLTHROUGH __attribute__ ((fallthrough));
-// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
-// gcc will use register Y for the this pointer.
+ // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
+ // gcc will use register Y for the this pointer.
static void /*__attribute__((optimize("O0")))*/ /*__attribute__ ((always_inline))*/ showRGBInternal(PixelController<RGB_ORDER> & pixels) {
uint8_t *data = (uint8_t*)pixels.mData;
data_ptr_t port = FastPin<DATA_PIN>::port();
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 956e00a9..741d3f34 100644
--- a/platforms/avr/fastpin_avr.h
+++ b/src/platforms/avr/fastpin_avr.h
@@ -37,6 +37,7 @@ public:
inline static port_t hival() __attribute__ ((always_inline)) { return _PORT::r() | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return _PORT::r() & ~_MASK; }
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PORT::r(); }
+
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
};
@@ -46,10 +47,29 @@ public:
/// a custom type for each GPIO register with a single, static, aggressively inlined function that returns that specific GPIO register. A similar
/// trick is used a bit further below for the ARM GPIO registers (of which there are far more than on AVR!)
typedef volatile uint8_t & reg8_t;
+
#define _R(T) struct __gen_struct_ ## T
#define _RD8(T) struct __gen_struct_ ## T { static inline reg8_t r() { return T; }};
+
+// Register name equivalent (using flat names)
+#if defined(AVR_ATtinyxy7) || defined(AVR_ATtinyxy6) || defined(AVR_ATtinyxy4) || defined(AVR_ATtinyxy2)
+
+// ATtiny series 0/1 and ATmega series 0
+#define _FL_IO(L,C) _RD8(PORT ## L ## _DIR); _RD8(PORT ## L ## _OUT); _RD8(PORT ## L ## _IN); _FL_DEFINE_PORT3(L, C, _R(PORT ## L ## _OUT));
+#define _FL_DEFPIN(_PIN, BIT, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, 1<<BIT, _R(PORT ## L ## _OUT), _R(PORT ## L ## _DIR), _R(PORT ## L ## _IN)> {};
+
+#elif defined(__AVR_ATmega4809__)
+
+// Leverage VPORTs instead of PORTs for faster access
+#define _FL_IO(L,C) _RD8(VPORT ## L ## _DIR); _RD8(VPORT ## L ## _OUT); _RD8(VPORT ## L ## _IN); _FL_DEFINE_PORT3(L, C, _R(VPORT ## L ## _OUT));
+#define _FL_DEFPIN(_PIN, BIT, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, 1<<BIT, _R(VPORT ## L ## _OUT), _R(VPORT ## L ## _DIR), _R(VPORT ## L ## _IN)> {};
+
+#else
+
+// Others
#define _FL_IO(L,C) _RD8(DDR ## L); _RD8(PORT ## L); _RD8(PIN ## L); _FL_DEFINE_PORT3(L, C, _R(PORT ## L));
#define _FL_DEFPIN(_PIN, BIT, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, 1<<BIT, _R(PORT ## L), _R(DDR ## L), _R(PIN ## L)> {};
+#endif
// Pre-do all the port definitions
#ifdef PORTA
@@ -195,6 +215,42 @@ _FL_DEFPIN(16, 2, C); _FL_DEFPIN(17, 3, C); _FL_DEFPIN(18, 4, C); _FL_DEFPIN(19,
#define SPI_UART0_CLOCK 12
#endif
+#elif defined(ARDUINO_AVR_NANO_EVERY)
+
+#define MAX_PIN 22
+_FL_DEFPIN(0, 5, C); _FL_DEFPIN(1, 4, C); _FL_DEFPIN(2, 0, A); _FL_DEFPIN(3, 5, F);
+_FL_DEFPIN(4, 6, C); _FL_DEFPIN(5, 2, B); _FL_DEFPIN(6, 4, F); _FL_DEFPIN(7, 1, A);
+_FL_DEFPIN(8, 3, E); _FL_DEFPIN(9, 0, B); _FL_DEFPIN(10, 1, B); _FL_DEFPIN(11, 0, E);
+_FL_DEFPIN(12, 1, E); _FL_DEFPIN(13, 2, E); _FL_DEFPIN(14, 3, D); _FL_DEFPIN(15, 2, D);
+_FL_DEFPIN(16, 1, D); _FL_DEFPIN(17, 0, D); _FL_DEFPIN(18, 2, A); _FL_DEFPIN(19, 3, A);
+_FL_DEFPIN(20, 4, D); _FL_DEFPIN(21, 5, D); _FL_DEFPIN(22, 2, A);
+
+// To confirm for the SPI interfaces
+#define SPI_DATA 11
+#define SPI_CLOCK 13
+#define SPI_SELECT 8
+#define AVR_HARDWARE_SPI 1
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+#elif defined(__AVR_ATmega4809__)
+
+#define MAX_PIN 21
+_FL_DEFPIN(0, 4, C); _FL_DEFPIN(1, 5, C); _FL_DEFPIN(2, 0, A); _FL_DEFPIN(3, 5, F);
+_FL_DEFPIN(4, 6, C); _FL_DEFPIN(5, 2, B); _FL_DEFPIN(6, 4, F); _FL_DEFPIN(7, 1, A);
+_FL_DEFPIN(8, 3, E); _FL_DEFPIN(9, 0, B); _FL_DEFPIN(10, 1, B); _FL_DEFPIN(11, 0, E);
+_FL_DEFPIN(12, 1, E); _FL_DEFPIN(13, 2, E); _FL_DEFPIN(14, 3, D); _FL_DEFPIN(15, 2, D);
+_FL_DEFPIN(16, 1, D); _FL_DEFPIN(17, 0, D); _FL_DEFPIN(18, 2, A); _FL_DEFPIN(19, 3, A);
+_FL_DEFPIN(20, 4, D); _FL_DEFPIN(21, 5, D);
+
+#define SPI_DATA 11
+#define SPI_CLOCK 13
+#define SPI_SELECT 8
+#define AVR_HARDWARE_SPI 1
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+//#define SPI_UART0_DATA 1
+//#define SPI_UART0_CLOCK 4
+
#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega8__)
#define MAX_PIN 19
@@ -215,7 +271,7 @@ _FL_DEFPIN(16, 2, C); _FL_DEFPIN(17, 3, C); _FL_DEFPIN(18, 4, C); _FL_DEFPIN(19,
#define SPI_UART0_CLOCK 4
#endif
-#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega16__)
+#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega16__)
#define MAX_PIN 31
_FL_DEFPIN(0, 0, B); _FL_DEFPIN(1, 1, B); _FL_DEFPIN(2, 2, B); _FL_DEFPIN(3, 3, B);
diff --git a/platforms/avr/fastspi_avr.h b/src/platforms/avr/fastspi_avr.h
index d2edc966..325a24b8 100644
--- a/platforms/avr/fastspi_avr.h
+++ b/src/platforms/avr/fastspi_avr.h
@@ -187,7 +187,6 @@ public:
FastPin<_CLOCK_PIN>::setOutput();
FastPin<_DATA_PIN>::setOutput();
-
// must be done last, see page 206
setSPIRate();
}
@@ -249,12 +248,12 @@ public:
setSPIRate();
}
- void release() {
- if(m_pSelect != NULL) {
- m_pSelect->release();
- }
- disable_pins();
+ void release() {
+ if(m_pSelect != NULL) {
+ m_pSelect->release();
}
+ disable_pins();
+ }
static void writeBytesValueRaw(uint8_t value, int len) {
while(len--) {
@@ -315,6 +314,165 @@ public:
#endif
+#if defined(SPI0_CTRLA)
+
+template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
+class AVRHardwareSPIOutput {
+ Selectable *m_pSelect;
+
+public:
+ AVRHardwareSPIOutput() { m_pSelect = NULL; }
+ AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
+ void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
+
+ void init() {
+ FastPin<_CLOCK_PIN>::setOutput();
+ FastPin<_DATA_PIN>::setOutput();
+
+ // Arduino Nano Every documentation lists SPI pins in ALT2 portmux position
+ PORTMUX_TWISPIROUTEA = PORTMUX_SPI01_bm;
+
+ // Set SPI master mode and clock scaler.
+ SPI0_CTRLA = SPI_MASTER_bm;
+ if(_SPI_CLOCK_DIVIDER >= 128) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 64) { SPI0_CTRLA |= SPI_PRESC1_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 32) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 16) { SPI0_CTRLA |= SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 8) { SPI0_CTRLA |= SPI_PRESC0_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 4) { /* default rate */ }
+ else { SPI0_CTRLA |= SPI_CLK2X_bm; }
+
+ // Set mode 0 and disable slave select.
+ SPI0_CTRLB = SPI_SSD_bm;
+
+ // Enable SPI.
+ SPI0_CTRLA |= SPI_ENABLE_bm;
+ }
+
+ void setSPIRate() {
+ SPI0_CTRLA &= ~ ( (1<<SPI_PRESC1_bp)|(1<<SPI_PRESC0_bp)|(1<<SPI_CLK2X_bp) ); // clear pre-scaler and clock multiplier bits
+
+ if(_SPI_CLOCK_DIVIDER >= 128) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 64) { SPI0_CTRLA |= SPI_PRESC1_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 32) { SPI0_CTRLA |= SPI_PRESC1_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 16) { SPI0_CTRLA |= SPI_PRESC0_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 8) { SPI0_CTRLA |= SPI_PRESC0_bm|SPI_CLK2X_bm; }
+ else if (_SPI_CLOCK_DIVIDER >= 4) { /* default rate */ }
+ else { SPI0_CTRLA |= SPI_CLK2X_bm; }
+ }
+
+ static void stop() {
+ SPI0_CTRLA &= ~(SPI_ENABLE_bm);
+ }
+
+ static bool shouldWait(bool wait = false) __attribute__((always_inline)) {
+ static bool sWait=false;
+ if(sWait) {
+ sWait = wait; return true;
+ } else {
+ sWait = wait; return false;
+ }
+ }
+ static void wait() __attribute__((always_inline)) {
+ if(shouldWait()) {
+ while(!(SPI0_INTFLAGS & SPI_IF_bm));
+ }
+ }
+ static void waitFully() __attribute__((always_inline)) { wait(); }
+
+ static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); }
+
+ static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPI0_DATA=b; shouldWait(true); }
+ static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPI0_DATA=b; shouldWait(true); wait(); }
+ static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPI0_DATA=b; shouldWait(true); }
+
+
+ template <uint8_t BIT> inline static void writeBit(uint8_t b) {
+ if(b && (1 << BIT)) {
+ FastPin<_DATA_PIN>::hi();
+ } else {
+ FastPin<_DATA_PIN>::lo();
+ }
+
+ FastPin<_CLOCK_PIN>::hi();
+ FastPin<_CLOCK_PIN>::lo();
+ }
+
+ void enable_pins() { }
+ void disable_pins() { }
+
+ void select() {
+ if(m_pSelect != NULL) {
+ m_pSelect->select();
+ }
+ enable_pins();
+ setSPIRate();
+ }
+
+ void release() {
+ if(m_pSelect != NULL) {
+ m_pSelect->release();
+ }
+ disable_pins();
+ }
+
+ static void writeBytesValueRaw(uint8_t value, int len) {
+ while(len--) {
+ writeByte(value);
+ }
+ }
+
+ void writeBytesValue(uint8_t value, int len) {
+ //setSPIRate();
+ select();
+ while(len--) {
+ writeByte(value);
+ }
+ release();
+ }
+
+ // Write a block of n uint8_ts out
+ template <class D> void writeBytes(register uint8_t *data, int len) {
+ //setSPIRate();
+ uint8_t *end = data + len;
+ select();
+ while(data != end) {
+ // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM)
+ writeByte(D::adjust(*data++)); delaycycles<3>();
+ }
+ release();
+ }
+
+ void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
+
+ // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
+ // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
+ template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
+ //setSPIRate();
+ int len = pixels.mLen;
+
+ select();
+ while(pixels.has(1)) {
+ if(FLAGS & FLAG_START_BIT) {
+ writeBit<0>(1);
+ writeBytePostWait(D::adjust(pixels.loadAndScale0()));
+ writeBytePostWait(D::adjust(pixels.loadAndScale1()));
+ writeBytePostWait(D::adjust(pixels.loadAndScale2()));
+ } else {
+ writeByte(D::adjust(pixels.loadAndScale0()));
+ writeByte(D::adjust(pixels.loadAndScale1()));
+ writeByte(D::adjust(pixels.loadAndScale2()));
+ }
+
+ pixels.advanceData();
+ pixels.stepDithering();
+ }
+ D::postBlock(len);
+ release();
+ }
+};
+
+#endif
#if defined(SPSR)
@@ -333,6 +491,7 @@ template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class AVRHardwareSPIOutput {
Selectable *m_pSelect;
bool mWait;
+
public:
AVRHardwareSPIOutput() { m_pSelect = NULL; mWait = false;}
AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
@@ -510,6 +669,7 @@ template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class AVRHardwareSPIOutput {
Selectable *m_pSelect;
bool mWait;
+
public:
AVRHardwareSPIOutput() { m_pSelect = NULL; mWait = false;}
AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
diff --git a/platforms/avr/led_sysdefs_avr.h b/src/platforms/avr/led_sysdefs_avr.h
index 2d9722d0..888d75e5 100644
--- a/platforms/avr/led_sysdefs_avr.h
+++ b/src/platforms/avr/led_sysdefs_avr.h
@@ -46,6 +46,9 @@ extern volatile unsigned long timer0_millis_count;
# elif defined(ATTINY_CORE)
extern volatile unsigned long millis_timer_millis;
# define MS_COUNTER millis_timer_millis
+# elif defined(__AVR_ATmega4809__)
+extern volatile unsigned long timer_millis;
+# define MS_COUNTER timer_millis
# else
extern volatile unsigned long timer0_millis;
# define MS_COUNTER timer0_millis
@@ -53,7 +56,7 @@ extern volatile unsigned long timer0_millis;
};
// special defs for the tiny environments
-#if defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny167__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtinyX41__) || defined(__AVR_ATtiny841__) || defined(__AVR_ATtiny441__)
+#if defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny167__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny88__) || defined(__AVR_ATtinyX41__) || defined(__AVR_ATtiny841__) || defined(__AVR_ATtiny441__)
#define LIB8_ATTINY 1
#define FASTLED_NEEDS_YIELD
#endif
diff --git a/platforms/esp/32/clockless_block_esp32.h b/src/platforms/esp/32/clockless_block_esp32.h
index 8ab5807a..45b7671c 100644
--- a/platforms/esp/32/clockless_block_esp32.h
+++ b/src/platforms/esp/32/clockless_block_esp32.h
@@ -24,6 +24,7 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual int size() { return CLEDController::size() * LANES; }
@@ -34,7 +35,7 @@ public:
while(!showRGBInternal(pixels) && cnt--) {
ets_intr_unlock();
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
- _retry_cnt++;
+ ++_retry_cnt;
#endif
delayMicroseconds(WAIT_TIME * 10);
ets_intr_lock();
@@ -85,7 +86,7 @@ public:
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; i < USED_LANES; i++) {
+ for(register uint32_t i = 0; i < USED_LANES; ++i) {
while((__clock_cycles() - last_mark) < (T1+T2+T3));
last_mark = __clock_cycles();
*FastPin<FIRST_PIN>::sport() = PORT_MASK << REAL_FIRST_PIN;
@@ -100,7 +101,7 @@ public:
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
}
- for(register uint32_t i = USED_LANES; i < 8; i++) {
+ for(register uint32_t i = USED_LANES; i < 8; ++i) {
while((__clock_cycles() - last_mark) < (T1+T2+T3));
last_mark = __clock_cycles();
*FastPin<FIRST_PIN>::sport() = PORT_MASK << REAL_FIRST_PIN;
@@ -121,7 +122,7 @@ public:
// Setup the pixel controller and load/scale the first byte
Lines b0;
- for(int i = 0; i < USED_LANES; i++) {
+ for(int i = 0; i < USED_LANES; ++i) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
allpixels.preStepFirstByteDithering();
@@ -158,7 +159,7 @@ public:
ets_intr_unlock();
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
- _frame_cnt++;
+ ++_frame_cnt;
#endif
return __clock_cycles() - _start;
}
diff --git a/platforms/esp/32/clockless_i2s_esp32.h b/src/platforms/esp/32/clockless_i2s_esp32.h
index 6d3241d9..6306ccd2 100644
--- a/platforms/esp/32/clockless_i2s_esp32.h
+++ b/src/platforms/esp/32/clockless_i2s_esp32.h
@@ -86,7 +86,9 @@
#pragma once
+#ifndef FASTLED_INTERNAL
#pragma message "NOTE: ESP32 support using I2S parallel driver. All strips must use the same chipset"
+#endif
FASTLED_NAMESPACE_BEGIN
@@ -103,7 +105,13 @@ extern "C" {
#include "driver/gpio.h"
#include "driver/periph_ctrl.h"
#include "rom/lldesc.h"
+#include "esp_system.h" // Load ESP_IDF_VERSION_MAJOR if exists
+// ESP_IDF_VERSION_MAJOR is defined in ESP-IDF v3.3 or later
+#if defined(ESP_IDF_VERSION_MAJOR) && ESP_IDF_VERSION_MAJOR > 3
+#include "esp_intr_alloc.h"
+#else
#include "esp_intr.h"
+#endif
#include "esp_log.h"
#ifdef __cplusplus
@@ -171,8 +179,8 @@ static DMABuffer * dmaBuffers[NUM_DMA_BUFFERS];
// are global variables.
static int gPulsesPerBit = 0;
-static uint32_t gOneBit[40] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-static uint32_t gZeroBit[40] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static uint32_t gOneBit[40] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static uint32_t gZeroBit[40] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// -- Counters to track progress
static int gCurBuffer = 0;
@@ -202,8 +210,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER>
// -- Make sure we can't call show() too quickly
CMinWait<50> mWait;
- public:
-
+public:
void init()
{
i2sInit();
@@ -214,7 +221,7 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER>
gControllers[gNumControllers] = this;
int my_index = gNumControllers;
- gNumControllers++;
+ ++gNumControllers;
// -- Set up the pin We have to do two things: configure the
// actual GPIO pin, and route the output from the default
@@ -233,11 +240,10 @@ class ClocklessController : public CPixelLEDController<RGB_ORDER>
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
-
static int pgcd(int smallest,int precision,int a,int b,int c)
{
int pgc_=1;
- for( int i=smallest;i>0;i--)
+ for( int i=smallest;i>0;--i)
{
if( a%i<=precision && b%i<=precision && c%i<=precision)
@@ -295,7 +301,7 @@ protected:
//Serial.printf("%f\n",I2S_MAX_CLK/(1000000000L*freq));
while(pgc_==1 || (T1/pgc_ +T2/pgc_ +T3/pgc_)>I2S_MAX_PULSE_PER_BIT) //while(pgc_==1 || (T1/pgc_ +T2/pgc_ +T3/pgc_)>I2S_MAX_CLK/(1000000000L*freq))
{
- precision++;
+ ++precision;
pgc_=pgcd(smallest,precision,T1,T2,T3);
//Serial.printf("%d %d\n",pgc_,(a+b+c)/pgc_);
}
@@ -329,9 +335,9 @@ protected:
int b=0;
CLOCK_DIVIDER_A=1;
CLOCK_DIVIDER_B=0;
- for(a=1;a<64;a++)
+ for(a=1;a<64;++a)
{
- for(b=0;b<a;b++)
+ for(b=0;b<a;++b)
{
//printf("%d %d %f %f %f\n",b,a,v,(double)v*(double)a,fabsf(v-(double)b/a));
if(fabsf(v-(double)b/a) <= prec/2)
@@ -358,7 +364,7 @@ protected:
{
CLOCK_DIVIDER_A=1;
CLOCK_DIVIDER_B=0;
- CLOCK_DIVIDER_N++;
+ ++CLOCK_DIVIDER_N;
}
//printf("%d %d %f %f %d\n",CLOCK_DIVIDER_B,CLOCK_DIVIDER_A,(double)CLOCK_DIVIDER_B/CLOCK_DIVIDER_A,v,CLOCK_DIVIDER_N);
@@ -384,28 +390,28 @@ protected:
int i = 0;
while ( i < ones_for_one ) {
gOneBit[i] = 0xFFFFFF00;
- i++;
+ ++i;
}
while ( i < gPulsesPerBit ) {
gOneBit[i] = 0x00000000;
- i++;
+ ++i;
}
//int ones_for_zero = ((T1ns - 1)/FASTLED_I2S_NS_PER_PULSE) + 1;
ones_for_zero =T1/pgc_ ;
- // Serial.print("Zero bit: target ");
- // Serial.print(T1ns); Serial.print("ns --- ");
+ // Serial.print("Zero bit: target ");
+ // Serial.print(T1ns); Serial.print("ns --- ");
//Serial.print(ones_for_zero); Serial.print(" 1 bits");
//Serial.print(" = "); Serial.print(ones_for_zero * FASTLED_I2S_NS_PER_PULSE); Serial.println("ns");
// Serial.printf("Zero bit : target %d ns --- %d pulses 1 bit = %f ns\n",T1ns,ones_for_zero ,ones_for_zero*pulseduration);
i = 0;
while ( i < ones_for_zero ) {
gZeroBit[i] = 0xFFFFFF00;
- i++;
+ ++i;
}
while ( i < gPulsesPerBit ) {
gZeroBit[i] = 0x00000000;
- i++;
+ ++i;
}
memset(gPixelRow, 0, NUM_COLOR_CHANNELS * 32);
@@ -533,13 +539,13 @@ protected:
*/
static void empty( uint32_t *buf)
{
- for(int i=0;i<8*NUM_COLOR_CHANNELS;i++)
+ for(int i=0;i<8*NUM_COLOR_CHANNELS;++i)
{
int offset=gPulsesPerBit*i;
- for(int j=0;j<ones_for_zero;j++)
+ for(int j=0;j<ones_for_zero;++j)
buf[offset+j]=0xffffffff;
- for(int j=ones_for_one;j<gPulsesPerBit;j++)
+ for(int j=ones_for_one;j<gPulsesPerBit;++j)
buf[offset+j]=0;
}
}
@@ -560,7 +566,7 @@ protected:
(*mPixels) = pixels;
// -- Keep track of the number of strips we've seen
- gNumStarted++;
+ ++gNumStarted;
// Serial.print("Show pixels ");
// Serial.println(gNumStarted);
@@ -628,7 +634,7 @@ protected:
// -- Get the requested pixel from each controller. Store the
// data for each color channel in a separate array.
uint32_t has_data_mask = 0;
- for (int i = 0; i < gNumControllers; i++) {
+ for (int i = 0; i < gNumControllers; ++i) {
// -- Store the pixels in reverse controller order starting at index 23
// This causes the bits to come out in the right position after we
// transpose them.
@@ -654,24 +660,24 @@ protected:
// -- Transpose and encode the pixel data for the DMA buffer
// int buf_index = 0;
- for (int channel = 0; channel < NUM_COLOR_CHANNELS; channel++) {
+ for (int channel = 0; channel < NUM_COLOR_CHANNELS; ++channel) {
// -- Tranpose each array: all the bit 7's, then all the bit 6's, ...
transpose32(gPixelRow[channel], gPixelBits[channel][0] );
//Serial.print("Channel: "); Serial.print(channel); Serial.print(" ");
- for (int bitnum = 0; bitnum < 8; bitnum++) {
+ for (int bitnum = 0; bitnum < 8; ++bitnum) {
uint8_t * row = (uint8_t *) (gPixelBits[channel][bitnum]);
uint32_t bit = (row[0] << 24) | (row[1] << 16) | (row[2] << 8) | row[3];
/* SZG: More general, but too slow:
- for (int pulse_num = 0; pulse_num < gPulsesPerBit; pulse_num++) {
+ for (int pulse_num = 0; pulse_num < gPulsesPerBit; ++pulse_num) {
buf[buf_index++] = has_data_mask & ( (bit & gOneBit[pulse_num]) | (~bit & gZeroBit[pulse_num]) );
}
*/
// -- Only fill in the pulses that are different between the "0" and "1" encodings
- for(int pulse_num = ones_for_zero; pulse_num < ones_for_one; pulse_num++) {
+ for(int pulse_num = ones_for_zero; pulse_num < ones_for_one; ++pulse_num) {
buf[bitnum*gPulsesPerBit+channel*8*gPulsesPerBit+pulse_num] = has_data_mask & bit;
}
}
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..90ca046f
--- /dev/null
+++ b/src/platforms/esp/32/clockless_rmt_esp32.cpp
@@ -0,0 +1,463 @@
+
+#ifdef ESP32
+
+#ifndef FASTLED_ESP32_I2S
+
+#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;
+
+// -- Stored values for FASTLED_RMT_MAX_CHANNELS and FASTLED_RMT_MEM_BLOCKS
+int ESP32RMTController::gMaxChannel;
+int ESP32RMTController::gMemBlocks;
+
+
+ESP32RMTController::ESP32RMTController(int DATA_PIN, int T1, int T2, int T3, int maxChannel, int memBlocks)
+ : mPixelData(0),
+ mSize(0),
+ mCur(0),
+ mBufSize(0),
+ mWhichHalf(0),
+ mBuffer(0),
+ mBufferSize(0),
+ mCurPulse(0)
+{
+ // -- Store the max channel and mem blocks parameters
+ gMaxChannel = maxChannel;
+ gMemBlocks = memBlocks;
+
+ // -- 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.
+uint8_t * ESP32RMTController::getPixelBuffer(int size_in_bytes)
+{
+ // -- Free the old buffer if it will be too small
+ if (mPixelData != 0 and mBufSize < size_in_bytes) {
+ free(mPixelData);
+ mPixelData = 0;
+ }
+
+ if (mPixelData == 0) {
+ mBufSize = size_in_bytes;
+ mPixelData = (uint8_t *) malloc(mBufSize);
+ }
+
+ mSize = size_in_bytes;
+
+ return mPixelData;
+}
+
+// -- Initialize RMT subsystem
+// This only needs to be done once
+void ESP32RMTController::init(gpio_num_t pin)
+{
+ if (gInitialized) return;
+
+ for (int i = 0; i < gMaxChannel; i += gMemBlocks) {
+ 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 = pin;
+ rmt_tx.mem_block_num = gMemBlocks;
+ 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 IRAM_ATTR ESP32RMTController::showPixels()
+{
+ if (gNumStarted == 0) {
+ // -- First controller: make sure everything is set up
+ ESP32RMTController::init(mPin);
+
+#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 < gMaxChannel && 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 += gMemBlocks;
+ }
+
+ // -- 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 IRAM_ATTR 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 IRAM_ATTR 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 IRAM_ATTR ESP32RMTController::tx_start()
+{
+ // rmt_tx_start(mRMT_channel, true);
+ // Inline the code for rmt_tx_start, so it can be placed in IRAM
+ RMT.conf_ch[mRMT_channel].conf1.mem_rd_rst = 1;
+ RMT.conf_ch[mRMT_channel].conf1.mem_rd_rst = 0;
+ RMT.int_ena.val &= ~(1 << (mRMT_channel * 3));
+ RMT.int_ena.val |= (1 << (mRMT_channel * 3));
+ RMT.conf_ch[mRMT_channel].conf1.tx_start = 1;
+ 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 IRAM_ATTR 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);
+ // Inline the code for rmt_tx_stop, so it can be placed in IRAM
+ RMT.int_ena.val &= ~(1 << (channel * 3));
+ RMT.conf_ch[channel].conf1.mem_rd_rst = 1;
+ RMT.conf_ch[channel].conf1.mem_rd_rst = 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 {
+ 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;
+
+ for (channel = 0; channel < gMaxChannel; channel++) {
+ int tx_done_bit = channel * 3;
+ #ifdef CONFIG_IDF_TARGET_ESP32S2
+ int tx_next_bit = channel + 12;
+ #else
+ int tx_next_bit = channel + 24;
+ #endif
+
+ 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);
+ // rmt_tx_stop(mRMT_channel);
+ // Inline the code for rmt_tx_stop, so it can be placed in IRAM
+ /** -- Go back to the original strategy of just setting mCur = mSize
+ and letting the regular 'stop' process happen
+ * mRMT_mem_start = 0;
+ RMT.int_ena.val &= ~(1 << (mRMT_channel * 3));
+ RMT.conf_ch[mRMT_channel].conf1.tx_start = 0;
+ RMT.conf_ch[mRMT_channel].conf1.mem_rd_rst = 1;
+ RMT.conf_ch[mRMT_channel].conf1.mem_rd_rst = 0;
+ */
+ mCur = mSize;
+ }
+ }
+ }
+ 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/8; i++) {
+ if (mCur < mSize) {
+
+ // -- Get the next four bytes of pixel data
+ register uint32_t pixeldata = mPixelData[mCur] << 24;
+ 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 < 8; 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 by filling the
+ // rest of the buffer with zeros
+ *pItem++ = 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 // ! FASTLED_ESP32_I2S
+
+#endif // ESP32
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..8f5690bb
--- /dev/null
+++ b/src/platforms/esp/32/clockless_rmt_esp32.h
@@ -0,0 +1,397 @@
+/*
+ * 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"
+// ESP_IDF_VERSION_MAJOR is defined in ESP-IDF v3.3 or later
+#if defined(ESP_IDF_VERSION_MAJOR) && ESP_IDF_VERSION_MAJOR > 3
+#include "esp_intr_alloc.h"
+#else
+#include "esp_intr.h"
+#endif
+#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
+
+// -- Max RMT channel (default to 8 on ESP32 and 4 on ESP32-S2)
+#ifndef FASTLED_RMT_MAX_CHANNELS
+#ifdef CONFIG_IDF_TARGET_ESP32S2
+#define FASTLED_RMT_MAX_CHANNELS 4
+#else
+#define FASTLED_RMT_MAX_CHANNELS 8
+#endif
+#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
+ uint8_t * mPixelData;
+ int mSize;
+ int mCur;
+ int mBufSize;
+
+ // -- 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;
+
+ // -- These values need to be real variables, so we can access them
+ // in the cpp file
+ static int gMaxChannel;
+ static int gMemBlocks;
+
+public:
+
+ // -- Constructor
+ // Mainly just stores the template parameters from the LEDController as
+ // member variables.
+ ESP32RMTController(int DATA_PIN, int T1, int T2, int T3, int maxChannel, int memBlocks);
+
+ // -- Get max cycles per fill
+ uint32_t IRAM_ATTR getMaxCyclesPerFill() const { return mMaxCyclesPerFill; }
+
+ // -- Get or create the pixel data buffer
+ uint8_t * getPixelBuffer(int size_in_bytes);
+
+ // -- Initialize RMT subsystem
+ // This only needs to be done once. The particular pin is not important,
+ // because we need to configure the RMT channels on the fly.
+ static void init(gpio_num_t pin);
+
+ // -- 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, FASTLED_RMT_MAX_CHANNELS, FASTLED_RMT_MEM_BLOCKS)
+ {}
+
+ void init()
+ {
+ }
+
+ 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;
+ uint8_t * pData = mRMTController.getPixelBuffer(size_in_bytes);
+
+ // -- This might be faster
+ while (pixels.has(1)) {
+ *pData++ = pixels.loadAndScale0();
+ *pData++ = pixels.loadAndScale1();
+ *pData++ = pixels.loadAndScale2();
+ pixels.advanceData();
+ pixels.stepDithering();
+ }
+ }
+
+ // -- 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 6e9a1c59..6e9a1c59 100755
--- 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 d54d7fee..7876b281 100644
--- a/platforms/esp/32/fastpin_esp32.h
+++ b/src/platforms/esp/32/fastpin_esp32.h
@@ -3,7 +3,6 @@
FASTLED_NAMESPACE_BEGIN
template<uint8_t PIN, uint32_t MASK> class _ESPPIN {
-
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
diff --git a/platforms/esp/32/fastspi_esp32.h b/src/platforms/esp/32/fastspi_esp32.h
index 33d620fd..33d620fd 100644
--- a/platforms/esp/32/fastspi_esp32.h
+++ b/src/platforms/esp/32/fastspi_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 40c91612..3eccbe1e 100644
--- a/platforms/esp/8266/clockless_block_esp8266.h
+++ b/src/platforms/esp/8266/clockless_block_esp8266.h
@@ -23,6 +23,7 @@ class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LAN
typedef typename FastPin<FIRST_PIN>::port_t data_t;
CMinWait<WAIT_TIME> mWait;
+
public:
virtual int size() { return CLEDController::size() * LANES; }
@@ -31,13 +32,13 @@ public:
/*uint32_t clocks = */
int cnt=FASTLED_INTERRUPT_RETRY_COUNT;
while(!showRGBInternal(pixels) && cnt--) {
- os_intr_unlock();
+ os_intr_unlock();
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
- _retry_cnt++;
+ ++_retry_cnt;
#endif
- delayMicroseconds(WAIT_TIME * 10);
- os_intr_lock();
- }
+ delayMicroseconds(WAIT_TIME * 10);
+ os_intr_lock();
+ }
// #if FASTLED_ALLOW_INTTERUPTS == 0
// Adjust the timer
// long microsTaken = CLKS_TO_MICROS(clocks);
@@ -47,19 +48,19 @@ public:
// mWait.mark();
}
- template<int PIN> static void initPin() {
- _ESPPIN<PIN, 1<<(PIN & 0xFF)>::setOutput();
- }
+ template<int PIN> static void initPin() {
+ _ESPPIN<PIN, 1<<(PIN & 0xFF)>::setOutput();
+ }
- virtual void init() {
+ virtual void init() {
void (* funcs[])() ={initPin<12>, initPin<13>, initPin<14>, initPin<15>, initPin<4>, initPin<5>};
for (uint8_t i = 0; i < USED_LANES; ++i) {
funcs[i]();
}
- }
+ }
- virtual uint16_t getMaxRefreshRate() const { return 400; }
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
typedef union {
uint8_t bytes[8];
@@ -69,14 +70,14 @@ public:
#define ESP_ADJUST 0 // (2*(F_CPU/24000000))
#define ESP_ADJUST2 0
- template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & last_mark, register Lines & b, PixelController<RGB_ORDER, LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
- Lines b2 = b;
+ template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & last_mark, register Lines & b, PixelController<RGB_ORDER, LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
+ Lines b2 = b;
transpose8x1_noinline(b.bytes,b2.bytes);
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; i < USED_LANES; i++) {
+ for(register uint32_t i = 0; i < USED_LANES; ++i) {
while((__clock_cycles() - last_mark) < (T1+T2+T3));
last_mark = __clock_cycles();
*FastPin<FIRST_PIN>::sport() = PIN_MASK;
@@ -91,7 +92,7 @@ public:
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
}
- for(register uint32_t i = USED_LANES; i < 8; i++) {
+ for(register uint32_t i = USED_LANES; i < 8; ++i) {
while((__clock_cycles() - last_mark) < (T1+T2+T3));
last_mark = __clock_cycles();
*FastPin<FIRST_PIN>::sport() = PIN_MASK;
@@ -105,14 +106,14 @@ public:
}
}
- // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
+ // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
- static uint32_t ICACHE_RAM_ATTR showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
+ static uint32_t ICACHE_RAM_ATTR showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
// Setup the pixel controller and load/scale the first byte
Lines b0;
- for(int i = 0; i < USED_LANES; i++) {
+ for(int i = 0; i < USED_LANES; ++i) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
allpixels.preStepFirstByteDithering();
@@ -132,26 +133,26 @@ public:
// Write third byte
writeBits<8+XTRA0,0>(last_mark, b0, allpixels);
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
os_intr_unlock();
- #endif
+ #endif
allpixels.stepDithering();
- #if (FASTLED_ALLOW_INTERRUPTS == 1)
- os_intr_lock();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ os_intr_lock();
// if interrupts took longer than 45µs, punt on the current frame
if((int32_t)(__clock_cycles()-last_mark) > 0) {
if((int32_t)(__clock_cycles()-last_mark) > (T1+T2+T3+((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US))) { os_intr_unlock(); return 0; }
}
- #endif
+ #endif
};
- os_intr_unlock();
+ os_intr_unlock();
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
- _frame_cnt++;
+ ++_frame_cnt;
#endif
- return __clock_cycles() - _start;
+ return __clock_cycles() - _start;
}
};
diff --git a/platforms/esp/8266/clockless_esp8266.h b/src/platforms/esp/8266/clockless_esp8266.h
index 83d05b3f..131f2467 100644
--- a/platforms/esp/8266/clockless_esp8266.h
+++ b/src/platforms/esp/8266/clockless_esp8266.h
@@ -40,7 +40,7 @@ protected:
int cnt = FASTLED_INTERRUPT_RETRY_COUNT;
while((showRGBInternal(pixels)==0) && cnt--) {
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
- _retry_cnt++;
+ ++_retry_cnt;
#endif
os_intr_unlock();
delayMicroseconds(WAIT_TIME);
@@ -54,7 +54,7 @@ protected:
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & last_mark, register uint32_t b) {
b <<= 24; b = ~b;
- for(register uint32_t i = BITS; i > 0; i--) {
+ for(register uint32_t i = BITS; i > 0; --i) {
while((__clock_cycles() - last_mark) < (T1+T2+T3));
last_mark = __clock_cycles();
FastPin<DATA_PIN>::hi();
@@ -108,7 +108,7 @@ protected:
os_intr_unlock();
#ifdef FASTLED_DEBUG_COUNT_FRAME_RETRIES
- _frame_cnt++;
+ ++_frame_cnt;
#endif
return __clock_cycles() - start;
}
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/src/platforms/esp/8266/fastpin_esp8266.h b/src/platforms/esp/8266/fastpin_esp8266.h
new file mode 100644
index 00000000..d64119f9
--- /dev/null
+++ b/src/platforms/esp/8266/fastpin_esp8266.h
@@ -0,0 +1,100 @@
+#pragma once
+
+FASTLED_NAMESPACE_BEGIN
+
+struct FASTLED_ESP_IO {
+ volatile uint32_t _GPO;
+ volatile uint32_t _GPOS;
+ volatile uint32_t _GPOC;
+};
+
+#define _GPB (*(FASTLED_ESP_IO*)(0x60000000+(0x300)))
+
+
+template<uint8_t PIN, uint32_t MASK> class _ESPPIN {
+public:
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ inline static void setOutput() { pinMode(PIN, OUTPUT); }
+ inline static void setInput() { pinMode(PIN, INPUT); }
+
+ inline static void hi() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOS = MASK; } else { GP16O = 1; } }
+ inline static void lo() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOC = MASK; } else { GP16O = 0; } }
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO = val; } else { GP16O = val; }}
+
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+
+ inline static void toggle() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO ^= MASK; } else { GP16O ^= MASK; } }
+
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
+
+ inline static port_t hival() __attribute__ ((always_inline)) { if (PIN<16) { return GPO | MASK; } else { return GP16O | MASK; } }
+ inline static port_t loval() __attribute__ ((always_inline)) { if (PIN<16) { return GPO & ~MASK; } else { return GP16O & ~MASK; } }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { if(PIN<16) { return &_GPB._GPO; } else { return &GP16O; } }
+ inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPB._GPOS; } // there is no GP160 support for this
+ inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPB._GPOC; }
+ inline static port_t mask() __attribute__ ((always_inline)) { return MASK; }
+
+ inline static bool isset() __attribute__ ((always_inline)) { return (PIN < 16) ? (GPO & MASK) : (GP16O & MASK); }
+};
+
+#define _FL_DEFPIN(PIN, REAL_PIN) template<> class FastPin<PIN> : public _ESPPIN<REAL_PIN, (1<<(REAL_PIN & 0x0F))> {};
+
+
+#ifdef FASTLED_ESP8266_RAW_PIN_ORDER
+#define MAX_PIN 16
+_FL_DEFPIN(0,0); _FL_DEFPIN(1,1); _FL_DEFPIN(2,2); _FL_DEFPIN(3,3);
+_FL_DEFPIN(4,4); _FL_DEFPIN(5,5);
+
+// These pins should be disabled, as they always cause WDT resets
+// _FL_DEFPIN(6,6); _FL_DEFPIN(7,7);
+// _FL_DEFPIN(8,8); _FL_DEFPIN(9,9); _FL_DEFPIN(10,10); _FL_DEFPIN(11,11);
+
+_FL_DEFPIN(12,12); _FL_DEFPIN(13,13); _FL_DEFPIN(14,14); _FL_DEFPIN(15,15);
+_FL_DEFPIN(16,16);
+
+#define PORTA_FIRST_PIN 12
+#elif defined(FASTLED_ESP8266_D1_PIN_ORDER)
+#define MAX_PIN 15
+_FL_DEFPIN(0,3);
+_FL_DEFPIN(1,1);
+_FL_DEFPIN(2,16);
+_FL_DEFPIN(3,5);
+_FL_DEFPIN(4,4);
+_FL_DEFPIN(5,14);
+_FL_DEFPIN(6,12);
+_FL_DEFPIN(7,13);
+_FL_DEFPIN(8,0);
+_FL_DEFPIN(9,2);
+_FL_DEFPIN(10,15);
+_FL_DEFPIN(11,13);
+_FL_DEFPIN(12,12);
+_FL_DEFPIN(13,14);
+_FL_DEFPIN(14,4);
+_FL_DEFPIN(15,5);
+
+#define PORTA_FIRST_PIN 12
+
+#else // if defined(FASTLED_ESP8266_NODEMCU_PIN_ORDER)
+#define MAX_PIN 10
+
+// This seems to be the standard Dxx pin mapping on most of the esp boards that i've found
+_FL_DEFPIN(0,16); _FL_DEFPIN(1,5); _FL_DEFPIN(2,4); _FL_DEFPIN(3,0);
+_FL_DEFPIN(4,2); _FL_DEFPIN(5,14); _FL_DEFPIN(6,12); _FL_DEFPIN(7,13);
+_FL_DEFPIN(8,15); _FL_DEFPIN(9,3); _FL_DEFPIN(10,1);
+
+#define PORTA_FIRST_PIN 6
+
+// The rest of the pins - these are generally not available
+// _FL_DEFPIN(11,6);
+// _FL_DEFPIN(12,7); _FL_DEFPIN(13,8); _FL_DEFPIN(14,9); _FL_DEFPIN(15,10);
+// _FL_DEFPIN(16,11);
+
+#endif
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
+FASTLED_NAMESPACE_END
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/src/platforms/fastspi_ardunio_core.h b/src/platforms/fastspi_ardunio_core.h
new file mode 100644
index 00000000..a0f92288
--- /dev/null
+++ b/src/platforms/fastspi_ardunio_core.h
@@ -0,0 +1,103 @@
+#ifndef __INC_FASTSPI_ARDUNIO_CORE_H
+#define __INC_FASTSPI_ARDUNIO_CORE_H
+
+FASTLED_NAMESPACE_BEGIN
+
+#if defined(ARDUNIO_CORE_SPI)
+#include <SPI.h>
+
+template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_RATE, SPIClass & _SPIObject>
+class ArdunioCoreSPIOutput {
+
+public:
+ ArdunioCoreSPIOutput() {}
+
+ // set the object representing the selectable -- ignore for now
+ void setSelect(Selectable *pSelect) { /* TODO */ }
+
+ // initialize the SPI subssytem
+ void init() { _SPIObject.begin(); }
+
+ // latch the CS select
+ void inline select() __attribute__((always_inline)) {
+ // begin the SPI transaction
+ _SPIObject.beginTransaction(SPISettings(_SPI_CLOCK_RATE, MSBFIRST, SPI_MODE0));
+ }
+
+ // release the CS select
+ void inline release() __attribute__((always_inline)) {
+ _SPIObject.endTransaction();
+ }
+
+ // wait until all queued up data has been written
+ static void waitFully() { /* TODO */ }
+
+ // write a byte out via SPI (returns immediately on writing register) -
+ void inline writeByte(uint8_t b) __attribute__((always_inline)) {
+ _SPIObject.transfer(b);
+ }
+
+ // write a word out via SPI (returns immediately on writing register)
+ void inline writeWord(uint16_t w) __attribute__((always_inline)) {
+ _SPIObject.transfer16(w);
+ }
+
+ // A raw set of writing byte values, assumes setup/init/waiting done elsewhere
+ static void writeBytesValueRaw(uint8_t value, int len) {
+ while(len--) { _SPIObject.transfer(value); }
+ }
+
+ // A full cycle of writing a value for len bytes, including select, release, and waiting
+ void writeBytesValue(uint8_t value, int len) {
+ select(); writeBytesValueRaw(value, len); release();
+ }
+
+ // A full cycle of writing a value for len bytes, including select, release, and waiting
+ template <class D> void writeBytes(register uint8_t *data, int len) {
+ uint8_t *end = data + len;
+ select();
+ // could be optimized to write 16bit words out instead of 8bit bytes
+ while(data != end) {
+ writeByte(D::adjust(*data++));
+ }
+ D::postBlock(len);
+ waitFully();
+ release();
+ }
+
+ // A full cycle of writing a value for len bytes, including select, release, and waiting
+ void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
+
+ // write a single bit out, which bit from the passed in byte is determined by template parameter
+ template <uint8_t BIT> inline void writeBit(uint8_t b) {
+ // todo
+ }
+
+ // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
+ // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
+ template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
+ select();
+ int len = pixels.mLen;
+
+ while(pixels.has(1)) {
+ if(FLAGS & FLAG_START_BIT) {
+ writeBit<0>(1);
+ }
+ writeByte(D::adjust(pixels.loadAndScale0()));
+ writeByte(D::adjust(pixels.loadAndScale1()));
+ writeByte(D::adjust(pixels.loadAndScale2()));
+
+ pixels.advanceData();
+ pixels.stepDithering();
+ }
+ D::postBlock(len);
+ release();
+ }
+
+};
+
+
+#endif
+
+FASTLED_NAMESPACE_END
+#endif
diff --git a/power_mgt.cpp b/src/power_mgt.cpp
index 8e46d93f..e15fa709 100644
--- a/power_mgt.cpp
+++ b/src/power_mgt.cpp
@@ -60,7 +60,7 @@ uint32_t calculate_unscaled_power_mW( const CRGB* ledbuffer, uint16_t numLeds )
red32 += *p++;
green32 += *p++;
blue32 += *p++;
- count--;
+ --count;
}
red32 *= gRed_mW;
@@ -88,7 +88,7 @@ uint8_t calculate_max_brightness_for_power_mW(const CRGB* ledbuffer, uint16_t nu
uint8_t recommended_brightness = target_brightness;
if(requested_power_mW > max_power_mW) {
- recommended_brightness = (uint32_t)((uint8_t)(target_brightness) * (uint32_t)(max_power_mW)) / ((uint32_t)(requested_power_mW));
+ recommended_brightness = (uint32_t)((uint8_t)(target_brightness) * (uint32_t)(max_power_mW)) / ((uint32_t)(requested_power_mW));
}
return recommended_brightness;
@@ -163,23 +163,23 @@ void set_max_power_indicator_LED( uint8_t pinNumber)
void set_max_power_in_volts_and_milliamps( uint8_t volts, uint32_t milliamps)
{
- FastLED.setMaxPowerInVoltsAndMilliamps(volts, milliamps);
+ FastLED.setMaxPowerInVoltsAndMilliamps(volts, milliamps);
}
void set_max_power_in_milliwatts( uint32_t powerInmW)
{
- FastLED.setMaxPowerInMilliWatts(powerInmW);
+ FastLED.setMaxPowerInMilliWatts(powerInmW);
}
void show_at_max_brightness_for_power()
{
- // power management usage is now in FastLED.show, no need for this function
- FastLED.show();
+ // power management usage is now in FastLED.show, no need for this function
+ FastLED.show();
}
void delay_at_max_brightness_for_power( uint16_t ms)
{
- FastLED.delay(ms);
+ FastLED.delay(ms);
}
FASTLED_NAMESPACE_END
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 b2af51cd..744373a1 100644
--- a/wiring.cpp
+++ b/src/wiring.cpp
@@ -71,10 +71,10 @@ unsigned long micros() {
#ifdef TIFR0
if ((TIFR0 & _BV(TOV0)) && (t < 255))
- m++;
+ ++m;
#else
if ((TIFR & _BV(TOV0)) && (t < 255))
- m++;
+ ++m;
#endif
SREG = oldSREG;
@@ -88,7 +88,7 @@ void delay(unsigned long ms)
while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
- ms--;
+ --ms;
start += 1000;
}
}