├── firmware ├── fastspi_dma.h ├── .gitignore ├── FastSPI_LED2.h ├── docs │ ├── .Doxyfile.swp │ └── mainpage.dox ├── platforms │ ├── avr │ │ ├── fastled_avr.h │ │ └── led_sysdefs_avr.h │ └── arm │ │ ├── k26 │ │ ├── fastled_arm_k26.h │ │ ├── led_sysdefs_arm_k26.h │ │ ├── clockless_arm_k26.h │ │ └── fastpin_arm_k26.h │ │ ├── sam │ │ ├── fastled_arm_sam.h │ │ ├── led_sysdefs_arm_sam.h │ │ ├── clockless_arm_sam.h │ │ └── fastspi_arm_sam.h │ │ └── k20 │ │ ├── fastled_arm_k20.h │ │ ├── led_sysdefs_arm_k20.h │ │ ├── smartmatrix_t3.h │ │ ├── octows2811_controller.h │ │ ├── clockless_arm_k20.h │ │ └── fastpin_arm_k20.h ├── fastled_arm_stm32.h ├── platforms.h ├── preview_changes.txt ├── fastled_config.h ├── examples │ ├── Multiple │ │ ├── OctoWS2811Demo │ │ │ └── OctoWS2811Demo.ino │ │ ├── MultipleStripsInOneArray │ │ │ └── MultipleStripsInOneArray.ino │ │ ├── ArrayOfLedArrays │ │ │ └── ArrayOfLedArrays.ino │ │ ├── MirroringSample │ │ │ └── MirroringSample.ino │ │ ├── ParallelOutputDemo │ │ │ └── ParallelOutputDemo.ino │ │ └── MultiArrays │ │ │ └── MultiArrays.ino │ ├── Cylon │ │ └── Cylon.ino │ ├── Blink │ │ └── Blink.ino │ ├── AnalogOutput │ │ └── AnalogOutput.ino │ ├── NoisePlayground │ │ └── NoisePlayground.ino │ ├── Pintest │ │ └── Pintest.ino │ ├── FirstLight │ │ └── FirstLight.ino │ ├── ColorTemperature │ │ └── ColorTemperature.ino │ ├── RGBCalibrate │ │ └── RGBCalibrate.ino │ ├── Fire2012 │ │ └── Fire2012.ino │ ├── Noise │ │ └── Noise.ino │ ├── DemoReel100 │ │ └── DemoReel100.ino │ ├── SmartMatrix │ │ └── SmartMatrix.ino │ ├── Ports │ │ └── PJRCSpectrumAnalyzer │ │ │ └── PJRCSpectrumAnalyzer.ino │ ├── Fire2012WithPalette │ │ └── Fire2012WithPalette.ino │ ├── ColorPalette │ │ └── ColorPalette.ino │ └── XYMatrix │ │ └── XYMatrix.ino ├── led_sysdefs.h ├── LICENSE ├── led_sysdefs_arm_stm32.h ├── fastspi_types.h ├── power_mgt.h ├── colorpalettes.h ├── PORTING.md ├── color.h ├── fastspi_nop.h ├── fastspi.h ├── release_notes.md ├── hsv2rgb.h ├── dmx.h ├── fastspi_ref.h ├── delay.h ├── clockless_arm_stm32.h ├── colorpalettes.cpp ├── fastpin_arm_stm32.h ├── noise.h ├── README.md ├── power_mgt.cpp ├── FastLED.cpp └── bitswap.h ├── spark.json ├── LICENSE └── README.md /firmware/fastspi_dma.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /firmware/.gitignore: -------------------------------------------------------------------------------- 1 | html/ 2 | -------------------------------------------------------------------------------- /firmware/FastSPI_LED2.h: -------------------------------------------------------------------------------- 1 | #warning "This file is going away, please us FastLED.h in the future!" 2 | #include 3 | -------------------------------------------------------------------------------- /firmware/docs/.Doxyfile.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/focalintent/FastLED-Sparkcore/HEAD/firmware/docs/.Doxyfile.swp -------------------------------------------------------------------------------- /firmware/docs/mainpage.dox: -------------------------------------------------------------------------------- 1 | /** 2 | @brief Documentation file for FastLED 3 | @author dgarcia at fastled dot io 4 | @file 5 | */ 6 | /** @defgroup FastLED Sources */ 7 | /** 8 | @mainpage FastLED - let there be light! 9 | */ 10 | EOF 11 | -------------------------------------------------------------------------------- /firmware/platforms/avr/fastled_avr.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTLED_AVR_H 2 | #define __INC_FASTLED_AVR_H 3 | 4 | #include "delay.h" 5 | #include "fastpin_avr.h" 6 | #include "fastspi_avr.h" 7 | #include "clockless_trinket.h" 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /spark.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FastLED", 3 | "author": "Daniel Garcia, Mark Kriegsman", 4 | "license": "MIT", 5 | "version": "3.1.5", 6 | "description": "A packaging of FastLED 3.1 for sparkcore and photon", 7 | "namespace": "NSFastLED" 8 | } 9 | -------------------------------------------------------------------------------- /firmware/fastled_arm_stm32.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTLED_ARM_SAM_H 2 | #define __INC_FASTLED_ARM_SAM_H 3 | 4 | // Include the sam headers 5 | #include "delay.h" 6 | #include "fastpin_arm_stm32.h" 7 | // #include "fastspi_arm_stm32.h" 8 | #include "clockless_arm_stm32.h" 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k26/fastled_arm_k26.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTLED_ARM_K26_H 2 | #define __INC_FASTLED_ARM_K26_H 3 | 4 | // Include the k20 headers 5 | #include "delay.h" 6 | #include "fastpin_arm_k26.h" 7 | #include "fastspi_arm_k26.h" 8 | #include "clockless_arm_k26.h" 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /firmware/platforms/arm/sam/fastled_arm_sam.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTLED_ARM_SAM_H 2 | #define __INC_FASTLED_ARM_SAM_H 3 | 4 | // Include the sam headers 5 | #include "delay.h" 6 | #include "fastpin_arm_sam.h" 7 | #include "fastspi_arm_sam.h" 8 | #include "clockless_arm_sam.h" 9 | #include "clockless_block_arm_sam.h" 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k20/fastled_arm_k20.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTLED_ARM_K20_H 2 | #define __INC_FASTLED_ARM_K20_H 3 | 4 | // Include the k20 headers 5 | #include "bitswap.h" 6 | #include "delay.h" 7 | #include "fastpin_arm_k20.h" 8 | #include "fastspi_arm_k20.h" 9 | #include "octows2811_controller.h" 10 | #include "smartmatrix_t3.h" 11 | #include "clockless_arm_k20.h" 12 | #include "clockless_block_arm_k20.h" 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /firmware/platforms.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_PLATFORMS_H 2 | #define __INC_PLATFORMS_H 3 | 4 | #include "fastled_config.h" 5 | 6 | #if defined(__MK20DX128__) || defined(__MK20DX256__) 7 | // Include k20/T3 headers 8 | #include "platforms/arm/k20/fastled_arm_k20.h" 9 | #elif defined(__MKL26Z64__) 10 | // Include k26/T-LC headers 11 | #include "platforms/arm/k26/fastled_arm_k26.h" 12 | #elif defined(__SAM3X8E__) 13 | // Include sam/due headers 14 | #include "platforms/arm/sam/fastled_arm_sam.h" 15 | #elif defined(STM32F10X_MD) || defined(STM32F2XX) 16 | #include "fastled_arm_stm32.h" 17 | #else 18 | // AVR platforms 19 | #include "platforms/avr/fastled_avr.h" 20 | #endif 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /firmware/preview_changes.txt: -------------------------------------------------------------------------------- 1 | FastLED 3.1 preview changes: 2 | * UART in SPI mode support on AVR 3 | * Support for using both hardware SPI pinsets on the Teensy 3.x - 11/13 and 7/14. 4 | * Added UCS1904 support 5 | * Better AVR cycle counting 6 | * Split WS2812/WS2811 timings 7 | * Added DOTSTAR definition for adafruit dotstar pixels (aka APA102) 8 | * 8-way parallel output on teensy 3, 3.1 (portc,portd), due/digix (porta, portb, portd) 9 | * 12-way parallel output on teensy 3, 3.1 (portc) 10 | * 16-way parallel output on teensy 3, 3.1 (portd & portd paired) 11 | * refresh rate limiting 12 | * interrupt friendly code on teensy 3/3.1 13 | * -interrupt friendly code on AVR- <-- disabled for now 14 | * interrupt friendly code on the due 15 | * code re-org for future wider platform support 16 | -------------------------------------------------------------------------------- /firmware/fastled_config.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTLED_CONFIG_H 2 | #define __INC_FASTLED_CONFIG_H 3 | 4 | // Use this option only for debugging pin access and forcing software pin access. Note that 5 | // software pin access only works in Arduino based environments. Forces use of digitalWrite 6 | // methods for pin access vs. direct hardware port access 7 | // #define FASTLED_FORCE_SOFTWARE_PINS 8 | 9 | // Use this option only for debugging bitbang'd spi access or to work around bugs in hardware 10 | // spi access. Forces use of bit-banged spi, even on pins that has hardware SPI available. 11 | // #define FASTLED_FORCE_SOFTWARE_SPI 12 | 13 | // Use this to force FastLED to allow interrupts in the clockless chipsets (or to force it to 14 | // disallow), overriding the default on platforms that support this. Set the value to 1 to 15 | // allow interrupts or 0 to disallow them. 16 | // #define FASTLED_ALLOW_INTERRUPTS 1 17 | // #define FASTLED_ALLOW_INTERRUPTS 0 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /firmware/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino: -------------------------------------------------------------------------------- 1 | #define USE_OCTOWS2811 2 | #include 3 | #include"FastLED/FastLED.h" 4 | FASTLED_USING_NAMESPACE; 5 | 6 | #define NUM_LEDS_PER_STRIP 64 7 | #define NUM_STRIPS 8 8 | 9 | CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; 10 | 11 | // Pin layouts on the teensy 3: 12 | // OctoWS2811: 2,14,7,8,6,20,21,5 13 | 14 | void setup() { 15 | LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); 16 | LEDS.setBrightness(32); 17 | } 18 | 19 | void loop() { 20 | static uint8_t hue = 0; 21 | for(int i = 0; i < NUM_STRIPS; i++) { 22 | for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) { 23 | leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255); 24 | } 25 | } 26 | 27 | // Set the first n leds on each strip to show which strip it is 28 | for(int i = 0; i < NUM_STRIPS; i++) { 29 | for(int j = 0; j <= i; j++) { 30 | leds[(i*NUM_LEDS_PER_STRIP) + j] = CRGB::Red; 31 | } 32 | } 33 | 34 | hue++; 35 | 36 | LEDS.show(); 37 | LEDS.delay(10); 38 | } 39 | -------------------------------------------------------------------------------- /firmware/led_sysdefs.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_LED_SYSDEFS_H 2 | #define __INC_LED_SYSDEFS_H 3 | 4 | #include "fastled_config.h" 5 | 6 | #if defined(__MK20DX128__) || defined(__MK20DX256__) 7 | // Include k20/T3 headers 8 | #include "platforms/arm/k20/led_sysdefs_arm_k20.h" 9 | #elif defined(__MKL26Z64__) 10 | // Include k26/T-LC headers 11 | #include "platforms/arm/k26/led_sysdefs_arm_k26.h" 12 | #elif defined(__SAM3X8E__) 13 | // Include sam/due headers 14 | #include "platforms/arm/sam/led_sysdefs_arm_sam.h" 15 | #elif defined(STM32F10X_MD) || defined(STM32F2XX) 16 | #include "led_sysdefs_arm_stm32.h" 17 | #else 18 | // AVR platforms 19 | #include "platforms/avr/led_sysdefs_avr.h" 20 | #endif 21 | 22 | #ifndef FASTLED_NAMESPACE_BEGIN 23 | #define FASTLED_NAMESPACE_BEGIN 24 | #define FASTLED_NAMESPACE_END 25 | #define FASTLED_USING_NAMESPACE 26 | #endif 27 | 28 | // Arduino.h needed for convinience functions digitalPinToPort/BitMask/portOutputRegister and the pinMode methods. 29 | #ifdef ARDUINO 30 | #include 31 | #endif 32 | 33 | #define CLKS_PER_US (F_CPU/1000000) 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k20/led_sysdefs_arm_k20.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_LED_SYSDEFS_ARM_K20_H 2 | #define __INC_LED_SYSDEFS_ARM_K20_H 3 | 4 | #define FASTLED_TEENSY3 5 | #define FASTLED_ARM 6 | 7 | #ifndef INTERRUPT_THRESHOLD 8 | #define INTERRUPT_THRESHOLD 1 9 | #endif 10 | 11 | // Default to allowing interrupts 12 | #ifndef FASTLED_ALLOW_INTERRUPTS 13 | #define FASTLED_ALLOW_INTERRUPTS 1 14 | #endif 15 | 16 | #if FASTLED_ALLOW_INTERRUPTS == 1 17 | #define FASTLED_ACCURATE_CLOCK 18 | #endif 19 | 20 | #if (F_CPU == 96000000) 21 | #define CLK_DBL 1 22 | #endif 23 | 24 | // Get some system include files 25 | #include 26 | #include // for cli/se definitions 27 | 28 | // Define the rgister types 29 | #if defined(ARDUINO) // && ARDUINO < 150 30 | typedef volatile uint8_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ 31 | typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ 32 | #endif 33 | 34 | extern volatile uint32_t systick_millis_count; 35 | # define MS_COUNTER systick_millis_count 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k26/led_sysdefs_arm_k26.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_LED_SYSDEFS_ARM_K26_H 2 | #define __INC_LED_SYSDEFS_ARM_K26_H 3 | 4 | #define FASTLED_TEENSYLC 5 | #define FASTLED_ARM 6 | 7 | #ifndef INTERRUPT_THRESHOLD 8 | #define INTERRUPT_THRESHOLD 1 9 | #endif 10 | 11 | // Default to allowing interrupts 12 | #ifndef FASTLED_ALLOW_INTERRUPTS 13 | #define FASTLED_ALLOW_INTERRUPTS 1 14 | #endif 15 | 16 | #if FASTLED_ALLOW_INTERRUPTS == 1 17 | #define FASTLED_ACCURATE_CLOCK 18 | #endif 19 | 20 | #if (F_CPU == 96000000) 21 | #define CLK_DBL 1 22 | #endif 23 | 24 | // Get some system include files 25 | #include 26 | #include // for cli/se definitions 27 | 28 | // Define the rgister types 29 | #if defined(ARDUINO) // && ARDUINO < 150 30 | typedef volatile uint8_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ 31 | typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ 32 | #endif 33 | 34 | extern volatile uint32_t systick_millis_count; 35 | # define MS_COUNTER systick_millis_count 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /firmware/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 FastLED 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Daniel Garcia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /firmware/platforms/arm/sam/led_sysdefs_arm_sam.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_LED_SYSDEFS_ARM_SAM_H 2 | #define __INC_LED_SYSDEFS_ARM_SAM_H 3 | 4 | 5 | #define FASTLED_ARM 6 | 7 | // Setup DUE timer defines/channels/etc... 8 | #ifndef DUE_TIMER_CHANNEL 9 | #define DUE_TIMER_GROUP 0 10 | #endif 11 | 12 | #ifndef DUE_TIMER_CHANNEL 13 | #define DUE_TIMER_CHANNEL 0 14 | #endif 15 | 16 | #define DUE_TIMER ((DUE_TIMER_GROUP==0) ? TC0 : ((DUE_TIMER_GROUP==1) ? TC1 : TC2)) 17 | #define DUE_TIMER_ID (ID_TC0 + (DUE_TIMER_GROUP*3) + DUE_TIMER_CHANNEL) 18 | #define DUE_TIMER_VAL (DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_CV << 1) 19 | #define DUE_TIMER_RUNNING ((DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_SR & TC_SR_CLKSTA) != 0) 20 | 21 | #ifndef INTERRUPT_THRESHOLD 22 | #define INTERRUPT_THRESHOLD 1 23 | #endif 24 | 25 | // Default to allowing interrupts 26 | #ifndef FASTLED_ALLOW_INTERRUPTS 27 | #define FASTLED_ALLOW_INTERRUPTS 1 28 | #endif 29 | 30 | #if FASTLED_ALLOW_INTERRUPTS == 1 31 | #define FASTLED_ACCURATE_CLOCK 32 | #endif 33 | 34 | // reuseing/abusing cli/sei defs for due 35 | #define cli() __disable_irq(); __disable_fault_irq(); 36 | #define sei() __enable_irq(); __enable_fault_irq(); 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /firmware/platforms/avr/led_sysdefs_avr.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_LED_SYSDEFS_AVR_H 2 | #define __INC_LED_SYSDEFS_AVR_H 3 | 4 | #define FASTLED_AVR 5 | 6 | #ifndef INTERRUPT_THRESHOLD 7 | #define INTERRUPT_THRESHOLD 2 8 | #endif 9 | 10 | #include 11 | #include // for cli/se definitions 12 | 13 | // Define the rgister types 14 | #if defined(ARDUINO) // && ARDUINO < 150 15 | typedef volatile uint8_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ 16 | typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ 17 | #endif 18 | 19 | 20 | // Default to disallowing interrupts (may want to gate this on teensy2 vs. other arm platforms, since the 21 | // teensy2 has a good, fast millis interrupt implementation) 22 | #ifndef FASTLED_ALLOW_INTERRUPTS 23 | #define FASTLED_ALLOW_INTERRUPTS 0 24 | #endif 25 | 26 | #if FASTLED_ALLOW_INTERRUPTS == 1 27 | #define FASTLED_ACCURATE_CLOCK 28 | #endif 29 | 30 | # if defined(CORE_TEENSY) 31 | extern volatile unsigned long timer0_millis_count; 32 | # define MS_COUNTER timer0_millis_count 33 | # else 34 | extern volatile unsigned long timer0_millis; 35 | # define MS_COUNTER timer0_millis 36 | # endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /firmware/led_sysdefs_arm_stm32.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_LED_SYSDEFS_ARM_SAM_H 2 | #define __INC_LED_SYSDEFS_ARM_SAM_H 3 | 4 | #include "application.h" 5 | 6 | #define FASTLED_NAMESPACE_BEGIN namespace NSFastLED { 7 | #define FASTLED_NAMESPACE_END } 8 | #define FASTLED_USING_NAMESPACE using namespace NSFastLED; 9 | 10 | #define FASTLED_ARM 11 | 12 | #ifndef INTERRUPT_THRESHOLD 13 | #define INTERRUPT_THRESHOLD 1 14 | #endif 15 | 16 | // Default to allowing interrupts 17 | #ifndef FASTLED_ALLOW_INTERRUPTS 18 | #define FASTLED_ALLOW_INTERRUPTS 0 19 | #endif 20 | 21 | #if FASTLED_ALLOW_INTERRUPTS == 1 22 | #define FASTLED_ACCURATE_CLOCK 23 | #endif 24 | 25 | // reuseing/abusing cli/sei defs for due 26 | #define cli() __disable_irq(); __disable_fault_irq(); 27 | #define sei() __enable_irq(); __enable_fault_irq(); 28 | 29 | // pgmspace definitions 30 | #define PROGMEM 31 | #define pgm_read_dword(addr) (*(const unsigned long *)(addr)) 32 | #define pgm_read_dword_near(addr) pgm_read_dword(addr) 33 | 34 | // data type defs 35 | typedef volatile uint8_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ 36 | typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ 37 | 38 | #define FASTLED_NO_PINMAP 39 | 40 | #if defined(STM32F2XX) 41 | #define F_CPU 120000000 42 | #else 43 | #define F_CPU 72000000 44 | #endif 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /firmware/examples/Multiple/MultipleStripsInOneArray/MultipleStripsInOneArray.ino: -------------------------------------------------------------------------------- 1 | // MultipleStripsInOneArray - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on 2 | // using multiple controllers. In this example, we're going to set up four NEOPIXEL strips on three 3 | // different pins, each strip will be referring to a different part of the single led array 4 | 5 | #include "FastLED/FastLED.h" 6 | FASTLED_USING_NAMESPACE; 7 | 8 | #define NUM_STRIPS 3 9 | #define NUM_LEDS_PER_STRIP 60 10 | #define NUM_LEDS NUM_LEDS_PER_STRIP * NUM_STRIPS 11 | 12 | CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; 13 | 14 | // For mirroring strips, all the "special" stuff happens just in setup. We 15 | // just addLeds multiple times, once for each strip 16 | void setup() { 17 | // tell FastLED there's 60 NEOPIXEL leds on pin 10, starting at index 0 in the led array 18 | FastLED.addLeds(leds, 0, NUM_LEDS_PER_STRIP); 19 | 20 | // tell FastLED there's 60 NEOPIXEL leds on pin 11, starting at index 60 in the led array 21 | FastLED.addLeds(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); 22 | 23 | // tell FastLED there's 60 NEOPIXEL leds on pin 12, starting at index 120 in the led array 24 | FastLED.addLeds(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP); 25 | 26 | } 27 | 28 | void loop() { 29 | for(int i = 0; i < NUM_LEDS; i++) { 30 | leds[i] = CRGB::Red; 31 | FastLED.show(); 32 | leds[i] = CRGB::Black; 33 | delay(100); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /firmware/examples/Multiple/ArrayOfLedArrays/ArrayOfLedArrays.ino: -------------------------------------------------------------------------------- 1 | // ArrayOfLedArrays - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on 2 | // using multiple controllers. In this example, we're going to set up four NEOPIXEL strips on three 3 | // different pins, each strip getting its own CRGB array to be played with, only this time they're going 4 | // to be all parts of an array of arrays. 5 | 6 | #include "FastLED/FastLED.h" 7 | FASTLED_USING_NAMESPACE; 8 | 9 | #define NUM_STRIPS 3 10 | #define NUM_LEDS_PER_STRIP 60 11 | CRGB leds[NUM_STRIPS][NUM_LEDS_PER_STRIP]; 12 | 13 | // For mirroring strips, all the "special" stuff happens just in setup. We 14 | // just addLeds multiple times, once for each strip 15 | void setup() { 16 | // tell FastLED there's 60 NEOPIXEL leds on pin 10 17 | FastLED.addLeds(leds[0], NUM_LEDS_PER_STRIP); 18 | 19 | // tell FastLED there's 60 NEOPIXEL leds on pin 11 20 | FastLED.addLeds(leds[1], NUM_LEDS_PER_STRIP); 21 | 22 | // tell FastLED there's 60 NEOPIXEL leds on pin 12 23 | FastLED.addLeds(leds[2], NUM_LEDS_PER_STRIP); 24 | 25 | } 26 | 27 | void loop() { 28 | // This outer loop will go over each strip, one at a time 29 | for(int x = 0; x < NUM_STRIPS; x++) { 30 | // This inner loop will go over each led in the current strip, one at a time 31 | for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) { 32 | leds[x][i] = CRGB::Red; 33 | FastLED.show(); 34 | leds[x][i] = CRGB::Black; 35 | delay(100); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /firmware/fastspi_types.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTSPI_TYPES_H 2 | #define __INC_FASTSPI_TYPES_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | // Some helper macros for getting at mis-ordered byte values 7 | #define SPI_B0 (RGB_BYTE0(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) 8 | #define SPI_B1 (RGB_BYTE1(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) 9 | #define SPI_B2 (RGB_BYTE2(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) 10 | #define SPI_ADVANCE (3 + (MASK_SKIP_BITS & SKIP)) 11 | 12 | /// Some of the SPI controllers will need to perform a transform on each byte before doing 13 | /// anyting with it. Creating a class of this form and passing it in as a template parameter to 14 | /// writeBytes/writeBytes3 below will ensure that the body of this method will get called on every 15 | /// byte worked on. Recommendation, make the adjust method aggressively inlined. 16 | /// 17 | /// TODO: Convinience macro for building these 18 | class DATA_NOP { 19 | public: 20 | static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data) { return data; } 21 | static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data, register uint8_t scale) { return scale8(data, scale); } 22 | static __attribute__((always_inline)) inline void postBlock(int len) {} 23 | }; 24 | 25 | #define FLAG_START_BIT 0x80 26 | #define MASK_SKIP_BITS 0x3F 27 | 28 | // Clock speed dividers 29 | #define SPEED_DIV_2 2 30 | #define SPEED_DIV_4 4 31 | #define SPEED_DIV_8 8 32 | #define SPEED_DIV_16 16 33 | #define SPEED_DIV_32 32 34 | #define SPEED_DIV_64 64 35 | #define SPEED_DIV_128 128 36 | 37 | #define MAX_DATA_RATE 0 38 | 39 | FASTLED_NAMESPACE_END 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /firmware/examples/Multiple/MirroringSample/MirroringSample.ino: -------------------------------------------------------------------------------- 1 | // MirroringSample - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on 2 | // using multiple controllers. In this example, we're going to set up four NEOPIXEL strips on four 3 | // different pins, and show the same thing on all four of them, a simple bouncing dot/cyclon type pattern 4 | 5 | #include "FastLED/FastLED.h" 6 | FASTLED_USING_NAMESPACE; 7 | 8 | #define NUM_LEDS_PER_STRIP 60 9 | CRGB leds[NUM_LEDS_PER_STRIP]; 10 | 11 | // For mirroring strips, all the "special" stuff happens just in setup. We 12 | // just addLeds multiple times, once for each strip 13 | void setup() { 14 | // tell FastLED there's 60 NEOPIXEL leds on pin 4 15 | FastLED.addLeds(leds, NUM_LEDS_PER_STRIP); 16 | 17 | // tell FastLED there's 60 NEOPIXEL leds on pin 5 18 | FastLED.addLeds(leds, NUM_LEDS_PER_STRIP); 19 | 20 | // tell FastLED there's 60 NEOPIXEL leds on pin 6 21 | FastLED.addLeds(leds, NUM_LEDS_PER_STRIP); 22 | 23 | // tell FastLED there's 60 NEOPIXEL leds on pin 7 24 | FastLED.addLeds(leds, NUM_LEDS_PER_STRIP); 25 | } 26 | 27 | void loop() { 28 | for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) { 29 | // set our current dot to red 30 | leds[i] = CRGB::Red; 31 | FastLED.show(); 32 | // clear our current dot before we move on 33 | leds[i] = CRGB::Black; 34 | delay(100); 35 | } 36 | 37 | for(int i = NUM_LEDS_PER_STRIP-1; i >= 0; i--) { 38 | // set our current dot to red 39 | leds[i] = CRGB::Red; 40 | FastLED.show(); 41 | // clear our current dot before we move on 42 | leds[i] = CRGB::Black; 43 | delay(100); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /firmware/examples/Cylon/Cylon.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | // How many leds in your strip? 5 | #define NUM_LEDS 64 6 | 7 | // For led chips like Neopixels, which have a data line, ground, and power, you just 8 | // need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock, 9 | // ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN 10 | #define DATA_PIN 7 11 | #define CLOCK_PIN 13 12 | 13 | // Define the array of leds 14 | CRGB leds[NUM_LEDS]; 15 | 16 | void setup() { 17 | Serial.begin(57600); 18 | Serial.println("resetting"); 19 | LEDS.addLeds(leds,NUM_LEDS); 20 | LEDS.setBrightness(84); 21 | } 22 | 23 | void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } } 24 | 25 | void loop() { 26 | static uint8_t hue = 0; 27 | Serial.print("x"); 28 | // First slide the led in one direction 29 | for(int i = 0; i < NUM_LEDS; i++) { 30 | // Set the i'th led to red 31 | leds[i] = CHSV(hue++, 255, 255); 32 | // Show the leds 33 | FastLED.show(); 34 | // now that we've shown the leds, reset the i'th led to black 35 | // leds[i] = CRGB::Black; 36 | fadeall(); 37 | // Wait a little bit before we loop around and do it again 38 | delay(10); 39 | } 40 | Serial.print("x"); 41 | 42 | // Now go in the other direction. 43 | for(int i = (NUM_LEDS)-1; i >= 0; i--) { 44 | // Set the i'th led to red 45 | leds[i] = CHSV(hue++, 255, 255); 46 | // Show the leds 47 | FastLED.show(); 48 | // now that we've shown the leds, reset the i'th led to black 49 | // leds[i] = CRGB::Black; 50 | fadeall(); 51 | // Wait a little bit before we loop around and do it again 52 | delay(10); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /firmware/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino: -------------------------------------------------------------------------------- 1 | #include"FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | #define NUM_LEDS_PER_STRIP 64 5 | // Note: this can be 12 if you're using a teensy 3 and don't mind soldering the pads on the back 6 | #define NUM_STRIPS 16 7 | 8 | CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; 9 | 10 | // Pin layouts on the teensy 3/3.1: 11 | // WS2811_PORTD: 2,14,7,8,6,20,21,5 12 | // WS2811_PORTC: 15,22,23,9,10,13,11,12,28,27,29,30 (these last 4 are pads on the bottom of the teensy) 13 | // WS2811_PORTDC: 2,14,7,8,6,20,21,5,15,22,23,9,10,13,11,12 - 16 way parallel 14 | // 15 | // Pin layouts on the due 16 | // WS2811_PORTA: 69,68,61,60,59,100,58,31 (note: pin 100 only available on the digix) 17 | // WS2811_PORTB: 90,91,92,93,94,95,96,97 (note: only available on the digix) 18 | // WS2811_PORTD: 25,26,27,28,14,15,29,11 19 | // 20 | 21 | void setup() { 22 | // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); 23 | // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); 24 | // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip); 25 | LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); 26 | LEDS.setBrightness(32); 27 | } 28 | 29 | void loop() { 30 | static uint8_t hue = 0; 31 | for(int i = 0; i < NUM_STRIPS; i++) { 32 | for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) { 33 | leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255); 34 | } 35 | } 36 | 37 | // Set the first n leds on each strip to show which strip it is 38 | for(int i = 0; i < NUM_STRIPS; i++) { 39 | for(int j = 0; j <= i; j++) { 40 | leds[(i*NUM_LEDS_PER_STRIP) + j] = CRGB::Red; 41 | } 42 | } 43 | 44 | hue++; 45 | 46 | LEDS.show(); 47 | LEDS.delay(10); 48 | } 49 | -------------------------------------------------------------------------------- /firmware/power_mgt.h: -------------------------------------------------------------------------------- 1 | #ifndef POWER_MGT_H 2 | #define POWER_MGT_H 3 | 4 | #include "pixeltypes.h" 5 | 6 | FASTLED_NAMESPACE_BEGIN 7 | 8 | // Power Control setup functions 9 | // 10 | // Example: 11 | // set_max_power_in_volts_and_milliamps( 5, 400); 12 | // 13 | void set_max_power_in_volts_and_milliamps( uint8_t volts, uint32_t milliamps); 14 | void set_max_power_in_milliwatts( uint32_t powerInmW); 15 | 16 | void set_max_power_indicator_LED( uint8_t pinNumber); // zero = no indicator LED 17 | 18 | 19 | // Power Control 'show' and 'delay' functions 20 | // 21 | // These are drop-in replacements for FastLED.show() and FastLED.delay() 22 | // In order to use these, you have to actually replace your calls to 23 | // FastLED.show() and FastLED.delay() with these two functions. 24 | // 25 | // Example: 26 | // // was: FastLED.show(); 27 | // // now is: 28 | // show_at_max_brightness_for_power(); 29 | // 30 | void show_at_max_brightness_for_power(); 31 | void delay_at_max_brightness_for_power( uint16_t ms); 32 | 33 | 34 | // Power Control internal helper functions 35 | // 36 | // calculate_unscaled_power_mW tells you how many milliwatts the current 37 | // LED data would draw at brightness = 255. 38 | // 39 | // calculate_max_brightness_for_power_mW tells you the highest brightness 40 | // level you can use and still stay under the specified power budget. It 41 | // takes a 'target brightness' which is the brightness you'd ideally like 42 | // to use. The result from this function will be no higher than the 43 | // target_brightess you supply, but may be lower. 44 | uint32_t calculate_unscaled_power_mW( const CRGB* ledbuffer, uint16_t numLeds); 45 | 46 | uint8_t calculate_max_brightness_for_power_mW( uint8_t target_brightness, uint32_t max_power_mW); 47 | 48 | FASTLED_NAMESPACE_END 49 | 50 | // POWER_MGT_H 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /firmware/examples/Multiple/MultiArrays/MultiArrays.ino: -------------------------------------------------------------------------------- 1 | // MultiArrays - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on 2 | // using multiple controllers. In this example, we're going to set up four NEOPIXEL strips on three 3 | // different pins, each strip getting its own CRGB array to be played with 4 | 5 | #include "FastLED/FastLED.h" 6 | FASTLED_USING_NAMESPACE; 7 | 8 | #define NUM_LEDS_PER_STRIP 60 9 | CRGB redLeds[NUM_LEDS_PER_STRIP]; 10 | CRGB greenLeds[NUM_LEDS_PER_STRIP]; 11 | CRGB blueLeds[NUM_LEDS_PER_STRIP]; 12 | 13 | // For mirroring strips, all the "special" stuff happens just in setup. We 14 | // just addLeds multiple times, once for each strip 15 | void setup() { 16 | // tell FastLED there's 60 NEOPIXEL leds on pin 10 17 | FastLED.addLeds(redLeds, NUM_LEDS_PER_STRIP); 18 | 19 | // tell FastLED there's 60 NEOPIXEL leds on pin 11 20 | FastLED.addLeds(greenLeds, NUM_LEDS_PER_STRIP); 21 | 22 | // tell FastLED there's 60 NEOPIXEL leds on pin 12 23 | FastLED.addLeds(blueLeds, NUM_LEDS_PER_STRIP); 24 | 25 | } 26 | 27 | void loop() { 28 | for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) { 29 | // set our current dot to red, green, and blue 30 | redLeds[i] = CRGB::Red; 31 | greenLeds[i] = CRGB::Green; 32 | blueLeds[i] = CRGB::Blue; 33 | FastLED.show(); 34 | // clear our current dot before we move on 35 | redLeds[i] = CRGB::Black; 36 | greenLeds[i] = CRGB::Black; 37 | blueLeds[i] = CRGB::Blue; 38 | delay(100); 39 | } 40 | 41 | for(int i = NUM_LEDS_PER_STRIP-1; i >= 0; i--) { 42 | // set our current dot to red, green, and blue 43 | redLeds[i] = CRGB::Red; 44 | greenLeds[i] = CRGB::Green; 45 | blueLeds[i] = CRGB::Blue; 46 | FastLED.show(); 47 | // clear our current dot before we move on 48 | redLeds[i] = CRGB::Black; 49 | greenLeds[i] = CRGB::Black; 50 | blueLeds[i] = CRGB::Blue; 51 | delay(100); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /firmware/examples/Blink/Blink.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | // How many leds in your strip? 5 | #define NUM_LEDS 1 6 | 7 | // For led chips like Neopixels, which have a data line, ground, and power, you just 8 | // need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock, 9 | // ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN 10 | #define DATA_PIN 3 11 | #define CLOCK_PIN 13 12 | 13 | // Define the array of leds 14 | CRGB leds[NUM_LEDS]; 15 | 16 | void setup() { 17 | // Uncomment/edit one of the following lines for your leds arrangement. 18 | // FastLED.addLeds(leds, NUM_LEDS); 19 | // FastLED.addLeds(leds, NUM_LEDS); 20 | // FastLED.addLeds(leds, NUM_LEDS); 21 | // FastLED.addLeds(leds, NUM_LEDS); 22 | // FastLED.addLeds(leds, NUM_LEDS); 23 | // FastLED.addLeds(leds, NUM_LEDS); 24 | FastLED.addLeds(leds, NUM_LEDS); 25 | // FastLED.addLeds(leds, NUM_LEDS); 26 | // FastLED.addLeds(leds, NUM_LEDS); 27 | // FastLED.addLeds(leds, NUM_LEDS); 28 | // FastLED.addLeds(leds, NUM_LEDS); 29 | 30 | // FastLED.addLeds(leds, NUM_LEDS); 31 | // FastLED.addLeds(leds, NUM_LEDS); 32 | // FastLED.addLeds(leds, NUM_LEDS); 33 | 34 | // FastLED.addLeds(leds, NUM_LEDS); 35 | // FastLED.addLeds(leds, NUM_LEDS); 36 | // FastLED.addLeds(leds, NUM_LEDS); 37 | } 38 | 39 | void loop() { 40 | // Turn the LED on, then pause 41 | leds[0] = CRGB::Red; 42 | FastLED.show(); 43 | delay(500); 44 | // Now turn the LED off, then pause 45 | leds[0] = CRGB::Black; 46 | FastLED.show(); 47 | delay(500); 48 | } 49 | -------------------------------------------------------------------------------- /firmware/colorpalettes.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_COLORPALETTES_H 2 | #define __INC_COLORPALETTES_H 3 | 4 | #include "colorutils.h" 5 | 6 | ///@file colorpalettes.h 7 | /// contains definitions for the predefined color palettes supplied by FastLED. 8 | 9 | FASTLED_NAMESPACE_BEGIN 10 | 11 | ///@defgroup Colorpalletes Pre-defined color palletes 12 | /// These schemes are all declared as "PROGMEM", meaning 13 | /// that they won't take up SRAM on AVR chips until used. 14 | /// Furthermore, the compiler won't even include these 15 | /// in your PROGMEM (flash) storage unless you specifically 16 | /// use each one, so you only 'pay for' those you actually use. 17 | 18 | ///@{ 19 | 20 | /// Cloudy color palette 21 | extern const TProgmemRGBPalette16 CloudColors_p PROGMEM; 22 | /// Lava colors 23 | extern const TProgmemRGBPalette16 LavaColors_p PROGMEM; 24 | /// Ocean colors, blues and whites 25 | extern const TProgmemRGBPalette16 OceanColors_p PROGMEM; 26 | /// Forest colors, greens 27 | extern const TProgmemRGBPalette16 ForestColors_p PROGMEM; 28 | 29 | /// HSV Rainbow 30 | extern const TProgmemRGBPalette16 RainbowColors_p PROGMEM; 31 | 32 | #define RainbowStripesColors_p RainbowStripeColors_p 33 | /// HSV Rainbow colors with alternatating stripes of black 34 | extern const TProgmemRGBPalette16 RainbowStripeColors_p PROGMEM; 35 | 36 | /// HSV color ramp: blue purple ping red orange yellow (and back) 37 | /// Basically, everything but the greens, which tend to make 38 | /// people's skin look unhealthy. This palette is good for 39 | /// lighting at a club or party, where it'll be shining on people. 40 | extern const TProgmemRGBPalette16 PartyColors_p PROGMEM; 41 | 42 | /// Approximate "black body radiation" palette, akin to 43 | /// the FastLED 'HeatColor' function. 44 | /// Recommend that you use values 0-240 rather than 45 | /// the usual 0-255, as the last 15 colors will be 46 | /// 'wrapping around' from the hot end to the cold end, 47 | /// which looks wrong. 48 | extern const TProgmemRGBPalette16 HeatColors_p PROGMEM; 49 | 50 | 51 | DECLARE_GRADIENT_PALETTE( Rainbow_gp); 52 | 53 | FASTLED_NAMESPACE_END 54 | 55 | ///@} 56 | #endif 57 | -------------------------------------------------------------------------------- /firmware/examples/AnalogOutput/AnalogOutput.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | // Example showing how to use FastLED color functions 5 | // even when you're NOT using a "pixel-addressible" smart LED strip. 6 | // 7 | // This example is designed to control an "analog" RGB LED strip 8 | // (or a single RGB LED) being driven by Arduino PWM output pins. 9 | // So this code never calls FastLED.addLEDs() or FastLED.show(). 10 | // 11 | // This example illustrates one way you can use just the portions 12 | // of FastLED that you need. In this case, this code uses just the 13 | // fast HSV color conversion code. 14 | // 15 | // In this example, the RGB values are output on three separate 16 | // 'analog' PWM pins, one for red, one for green, and one for blue. 17 | 18 | #define REDPIN 5 19 | #define GREENPIN 6 20 | #define BLUEPIN 3 21 | 22 | // showAnalogRGB: this is like FastLED.show(), but outputs on 23 | // analog PWM output pins instead of sending data to an intelligent, 24 | // pixel-addressable LED strip. 25 | // 26 | // This function takes the incoming RGB values and outputs the values 27 | // on three analog PWM output pins to the r, g, and b values respectively. 28 | void showAnalogRGB( const CRGB& rgb) 29 | { 30 | analogWrite(REDPIN, rgb.r ); 31 | analogWrite(GREENPIN, rgb.g ); 32 | analogWrite(BLUEPIN, rgb.b ); 33 | } 34 | 35 | 36 | 37 | // colorBars: flashes Red, then Green, then Blue, then Black. 38 | // Helpful for diagnosing if you've mis-wired which is which. 39 | void colorBars() 40 | { 41 | showAnalogRGB( CRGB::Red ); delay(500); 42 | showAnalogRGB( CRGB::Green ); delay(500); 43 | showAnalogRGB( CRGB::Blue ); delay(500); 44 | showAnalogRGB( CRGB::Black ); delay(500); 45 | } 46 | 47 | void loop() 48 | { 49 | static uint8_t hue; 50 | hue = hue + 1; 51 | // Use FastLED automatic HSV->RGB conversion 52 | showAnalogRGB( CHSV( hue, 255, 255) ); 53 | 54 | delay(20); 55 | } 56 | 57 | 58 | void setup() { 59 | pinMode(REDPIN, OUTPUT); 60 | pinMode(GREENPIN, OUTPUT); 61 | pinMode(BLUEPIN, OUTPUT); 62 | 63 | // Flash the "hello" color sequence: R, G, B, black. 64 | colorBars(); 65 | } 66 | 67 | -------------------------------------------------------------------------------- /firmware/PORTING.md: -------------------------------------------------------------------------------- 1 | =New platform porting guide= 2 | 3 | == Setting up the basic files/folders == 4 | 5 | * Create platform directory (e.g. platforms/arm/k26) 6 | * Create configuration header led_sysdefs_arm_k26.h: 7 | * Define platform flags (like FASTLED_ARM/FASTLED_TEENSY) 8 | * Define configuration parameters re: interrupts, or clock doubling 9 | * Include extar system header files if needed 10 | * Create main platform include, fastled_arm_k26.h 11 | * Include the various other header files as needed 12 | * Modify led_sysdefs.h to conditionally include platform sysdefs header file 13 | * Modify platforms.h to conditionally include platform fastled header 14 | 15 | == Porting fastpin.h == 16 | 17 | 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. 18 | 19 | There's two low level FastPin classes. There's the base FastPIN template class, and then there is FastPinBB which is for bit-banded access on those MCUs that support bitbanding. Note that the bitband class is optional and primarily useful in the implementation of other functionality internal to the platform. This file is also where you would do the pin to port/bit mapping defines. 20 | 21 | Explaining how the macros work and should be used is currently beyond the scope of this document. 22 | 23 | == Porting fastspi.h == 24 | 25 | 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. 26 | 27 | == Porting clockless.h == 28 | 29 | 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. 30 | -------------------------------------------------------------------------------- /firmware/examples/NoisePlayground/NoisePlayground.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | #define kMatrixWidth 16 5 | #define kMatrixHeight 16 6 | 7 | #define NUM_LEDS (kMatrixWidth * kMatrixHeight) 8 | // Param for different pixel layouts 9 | #define kMatrixSerpentineLayout true 10 | 11 | // led array 12 | CRGB leds[kMatrixWidth * kMatrixHeight]; 13 | 14 | // x,y, & time values 15 | uint32_t x,y,v_time,hue_time,hxy; 16 | 17 | // Play with the values of the variables below and see what kinds of effects they 18 | // have! More octaves will make things slower. 19 | 20 | // how many octaves to use for the brightness and hue functions 21 | uint8_t octaves=1; 22 | uint8_t hue_octaves=3; 23 | 24 | // the 'distance' between points on the x and y axis 25 | int xscale=57771; 26 | int yscale=57771; 27 | 28 | // the 'distance' between x/y points for the hue noise 29 | int hue_scale=1; 30 | 31 | // how fast we move through time & hue noise 32 | int time_speed=1111; 33 | int hue_speed=31; 34 | 35 | // adjust these values to move along the x or y axis between frames 36 | int x_speed=331; 37 | int y_speed=1111; 38 | 39 | void loop() { 40 | // fill the led array 2/16-bit noise values 41 | fill_2dnoise16(LEDS.leds(), kMatrixWidth, kMatrixHeight, kMatrixSerpentineLayout, 42 | octaves,x,xscale,y,yscale,v_time, 43 | hue_octaves,hxy,hue_scale,hxy,hue_scale,hue_time, false); 44 | 45 | LEDS.show(); 46 | 47 | // adjust the intra-frame time values 48 | x += x_speed; 49 | y += y_speed; 50 | v_time += time_speed; 51 | hue_time += hue_speed; 52 | // delay(50); 53 | } 54 | 55 | 56 | void setup() { 57 | // initialize the x/y and time values 58 | random16_set_seed(8934); 59 | random16_add_entropy(analogRead(3)); 60 | 61 | Serial.begin(57600); 62 | Serial.println("resetting!"); 63 | 64 | delay(3000); 65 | LEDS.addLeds(leds,NUM_LEDS); 66 | LEDS.setBrightness(96); 67 | 68 | hxy = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16(); 69 | x = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16(); 70 | y = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16(); 71 | v_time = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16(); 72 | hue_time = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16(); 73 | 74 | } 75 | -------------------------------------------------------------------------------- /firmware/color.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_COLOR_H 2 | #define __INC_COLOR_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | // definitions for color correction and light temperatures 7 | 8 | typedef enum { 9 | // Color correction starting points 10 | 11 | // typical values for SMD5050 LEDs 12 | TypicalSMD5050=0xFFB0F0 /* 255, 176, 240 */, 13 | TypicalLEDStrip=0xFFB0F0 /* 255, 176, 240 */, 14 | 15 | // typical values for 8mm "pixels on a string" 16 | // also for many through-hole 'T' package LEDs 17 | Typical8mmPixel=0xFFE08C /* 255, 224, 140 */, 18 | TypicalPixelString=0xFFE08C /* 255, 224, 140 */, 19 | 20 | // uncorrected color 21 | UncorrectedColor=0xFFFFFF 22 | 23 | } LEDColorCorrection; 24 | 25 | 26 | typedef enum { 27 | // Black-body radiation light sources emit a (relatively) continuous 28 | // spectrum, and can be described as having a Kelvin 'temperature' 29 | Candle=0xFF9329 /* 1900 K, 255, 147, 41 */, 30 | Tungsten40W=0xFFC58F /* 2600 K, 255, 197, 143 */, 31 | Tungsten100W=0xFFD6AA /* 2850 K, 255, 214, 170 */, 32 | Halogen=0xFFF1E0 /* 3200 K, 255, 241, 224 */, 33 | CarbonArc=0xFFFAF4 /* 5200 K, 255, 250, 244 */, 34 | HighNoonSun=0xFFFFFB /* 5400 K, 255, 255, 251 */, 35 | DirectSunlight=0xFFFFFF /* 6000 K, 255, 255, 255 */, 36 | OvercastSky=0xC9E2FF /* 7000 K, 201, 226, 255 */, 37 | ClearBlueSky=0x409CFF /* 20000 K, 64, 156, 255 */, 38 | 39 | // Gaseous light sources emit discrete spectral bands, and while we can 40 | // approximate their aggregate hue with RGB values, they don't actually 41 | // have a proper Kelvin temperature. 42 | WarmFluorescent=0xFFF4E5 /* 0 K, 255, 244, 229 */, 43 | StandardFluorescent=0xF4FFFA /* 0 K, 244, 255, 250 */, 44 | CoolWhiteFluorescent=0xD4EBFF /* 0 K, 212, 235, 255 */, 45 | FullSpectrumFluorescent=0xFFF4F2 /* 0 K, 255, 244, 242 */, 46 | GrowLightFluorescent=0xFFEFF7 /* 0 K, 255, 239, 247 */, 47 | BlackLightFluorescent=0xA700FF /* 0 K, 167, 0, 255 */, 48 | MercuryVapor=0xD8F7FF /* 0 K, 216, 247, 255 */, 49 | SodiumVapor=0xFFD1B2 /* 0 K, 255, 209, 178 */, 50 | MetalHalide=0xF2FCFF /* 0 K, 242, 252, 255 */, 51 | HighPressureSodium=0xFFB74C /* 0 K, 255, 183, 76 */, 52 | 53 | // Uncorrected temperature 0xFFFFFF 54 | UncorrectedTemperature=0xFFFFFF 55 | } ColorTemperature; 56 | 57 | FASTLED_NAMESPACE_END 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /firmware/fastspi_nop.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTSPI_NOP_H 2 | #define __INC_FASTSPI_NOP_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | // A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should 7 | // be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the 8 | // idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead) 9 | template 10 | class NOPSPIOutput { 11 | Selectable *m_pSelect; 12 | 13 | public: 14 | NOPSPIOutput() { m_pSelect = NULL; } 15 | NOPSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } 16 | 17 | // set the object representing the selectable 18 | void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } 19 | 20 | // initialize the SPI subssytem 21 | void init() { /* TODO */ } 22 | 23 | // latch the CS select 24 | void select() { /* TODO */ } 25 | 26 | // release the CS select 27 | void release() { /* TODO */ } 28 | 29 | // wait until all queued up data has been written 30 | void waitFully(); 31 | 32 | // not the most efficient mechanism in the world - but should be enough for sm16716 and friends 33 | template inline static void writeBit(uint8_t b) { /* TODO */ 34 | 35 | // write a byte out via SPI (returns immediately on writing register) 36 | void writeByte(uint8_t b) { /* TODO */ } 37 | // write a word out via SPI (returns immediately on writing register) 38 | void writeWord(uint16_t w) { /* TODO */ } 39 | 40 | // A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes) 41 | static void writeBytesValueRaw(uint8_t value, int len) { /* TODO */ } 42 | 43 | // A full cycle of writing a value for len bytes, including select, release, and waiting 44 | void writeBytesValue(uint8_t value, int len) { /* TODO */ } 45 | 46 | // A full cycle of writing a raw block of data out, including select, release, and waiting 47 | void writeBytes(uint8_t *data, int len) { /* TODO */ } 48 | 49 | // write a single bit out, which bit from the passed in byte is determined by template parameter 50 | template inline static void writeBit(uint8_t b) { /* TODO */ } 51 | 52 | template void writePixels(PixelController pixels) { /* TODO */ } 53 | 54 | }; 55 | 56 | FASTLED_NAMESPACE_END 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k20/smartmatrix_t3.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_SMARTMATRIX_T3_H 2 | #define __INC_SMARTMATRIX_T3_H 3 | 4 | #ifdef SmartMatrix_h 5 | #include 6 | 7 | FASTLED_NAMESPACE_BEGIN 8 | 9 | extern SmartMatrix *pSmartMatrix; 10 | 11 | // note - dmx simple must be included before FastSPI for this code to be enabled 12 | class CSmartMatrixController : public CLEDController { 13 | SmartMatrix matrix; 14 | 15 | public: 16 | // initialize the LED controller 17 | virtual void init() { 18 | // Initialize 32x32 LED Matrix 19 | matrix.begin(); 20 | matrix.setBrightness(255); 21 | matrix.setColorCorrection(ccNone); 22 | 23 | // Clear screen 24 | clearLeds(0); 25 | matrix.swapBuffers(); 26 | pSmartMatrix = &matrix; 27 | } 28 | 29 | // clear out/zero out the given number of leds. 30 | virtual void clearLeds(int nLeds) { 31 | const rgb24 black = {0,0,0}; 32 | matrix.fillScreen(black); 33 | matrix.swapBuffers(); 34 | } 35 | 36 | // set all the leds on the controller to a given color 37 | virtual void showColor(const struct CRGB & data, int nLeds,CRGB scale) { 38 | PixelController pixels(data, nLeds, scale, getDither()); 39 | rgb24 *md = matrix.backBuffer(); 40 | while(nLeds--) { 41 | md->red = pixels.loadAndScale0(); 42 | md->green = pixels.loadAndScale1(); 43 | md->blue = pixels.loadAndScale2(); 44 | md++; 45 | pixels.stepDithering(); 46 | } 47 | matrix.swapBuffers(); 48 | } 49 | 50 | // note that the uint8_ts will be in the order that you want them sent out to the device. 51 | // nLeds is the number of RGB leds being written to 52 | virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { 53 | PixelController pixels(data, nLeds, scale, getDither()); 54 | #ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER 55 | rgb24 *md = matrix.getRealBackBuffer(); 56 | #else 57 | rgb24 *md = matrix.backBuffer(); 58 | #endif 59 | while(nLeds--) { 60 | md->red = pixels.loadAndScale0(); 61 | md->green = pixels.loadAndScale1(); 62 | md->blue = pixels.loadAndScale2(); 63 | md++; 64 | pixels.advanceData(); 65 | pixels.stepDithering(); 66 | } 67 | matrix.swapBuffers(); 68 | #ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER 69 | matrix.setBackBuffer((rgb24*)data); 70 | #endif 71 | } 72 | 73 | #ifdef SUPPORT_ARGB 74 | // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped 75 | virtual void show(const struct CARGB *data, int nLeds, CRGB scale) = 0; 76 | #endif 77 | }; 78 | 79 | FASTLED_NAMESPACE_END 80 | 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k20/octows2811_controller.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_OCTOWS2811_CONTROLLER_H 2 | #define __INC_OCTOWS2811_CONTROLLER_H 3 | 4 | #ifdef USE_OCTOWS2811 5 | 6 | // #include "OctoWS2811.h" 7 | 8 | FASTLED_NAMESPACE_BEGIN 9 | 10 | template 11 | class COctoWS2811Controller : public CLEDController { 12 | OctoWS2811 *pocto; 13 | uint8_t *drawbuffer,*framebuffer; 14 | 15 | void _init(int nLeds) { 16 | if(pocto == NULL) { 17 | drawbuffer = (uint8_t*)malloc(nLeds * 8 * 3); 18 | framebuffer = (uint8_t*)malloc(nLeds * 8 * 3); 19 | switch(RGB_ORDER) { 20 | case RGB: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RGB); break; 21 | case RBG: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RBG); break; 22 | case GBR: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_GBR); break; 23 | case GRB: 24 | default: 25 | pocto = new OctoWS2811(nLeds, framebuffer,drawbuffer, WS2811_GRB); break; 26 | } 27 | pocto->begin(); 28 | } 29 | } 30 | public: 31 | COctoWS2811Controller() { pocto = NULL; } 32 | 33 | 34 | virtual void init() { /* do nothing yet */ } 35 | 36 | virtual void clearLeds(int nLeds) { 37 | _init(nLeds); 38 | showColor(CRGB(0,0,0),nLeds,CRGB(0,0,0)); 39 | } 40 | 41 | virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { 42 | _init(nLeds); 43 | // Get our pixel values 44 | PixelController pixels(data, nLeds, scale, getDither()); 45 | uint8_t ball[3][8]; 46 | memset(ball[0],pixels.loadAndScale0(),8); 47 | memset(ball[1],pixels.loadAndScale1(),8); 48 | memset(ball[2],pixels.loadAndScale2(),8); 49 | 50 | uint8_t bout[24]; 51 | transpose8x1_MSB(ball[0],bout); 52 | transpose8x1_MSB(ball[1],bout+8); 53 | transpose8x1_MSB(ball[2],bout+16); 54 | 55 | uint8_t *pdata = drawbuffer; 56 | while(nLeds--) { 57 | memcpy(pdata,bout,24); 58 | pdata += 24; 59 | } 60 | 61 | pocto->show(); 62 | } 63 | 64 | typedef union { 65 | uint8_t bytes[8]; 66 | uint32_t raw[2]; 67 | } Lines; 68 | 69 | virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { 70 | _init(nLeds); 71 | MultiPixelController<8,0xFF,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() ); 72 | 73 | uint8_t *pData = drawbuffer; 74 | while(nLeds--) { 75 | Lines b; 76 | 77 | for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale0(i); } 78 | transpose8x1_MSB(b.bytes,pData); pData += 8; 79 | for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale1(i); } 80 | transpose8x1_MSB(b.bytes,pData); pData += 8; 81 | for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale2(i); } 82 | transpose8x1_MSB(b.bytes,pData); pData += 8; 83 | pixels.stepDithering(); 84 | pixels.advanceData(); 85 | } 86 | 87 | pocto->show(); 88 | } 89 | }; 90 | 91 | FASTLED_NAMESPACE_END 92 | 93 | #endif 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /firmware/examples/Pintest/Pintest.ino: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | FASTLED_USING_NAMESPACE; 4 | 5 | const char *getPort(void *portPtr) { 6 | #ifdef PORTA 7 | if(portPtr == (void*)&PORTA) { return "PORTA"; } 8 | #endif 9 | #ifdef PORTB 10 | if(portPtr == (void*)&PORTB) { return "PORTB"; } 11 | #endif 12 | #ifdef PORTC 13 | if(portPtr == (void*)&PORTC) { return "PORTC"; } 14 | #endif 15 | #ifdef PORTD 16 | if(portPtr == (void*)&PORTD) { return "PORTD"; } 17 | #endif 18 | #ifdef PORTE 19 | if(portPtr == (void*)&PORTE) { return "PORTE"; } 20 | #endif 21 | #ifdef PORTF 22 | if(portPtr == (void*)&PORTF) { return "PORTF"; } 23 | #endif 24 | #ifdef PORTG 25 | if(portPtr == (void*)&PORTG) { return "PORTG"; } 26 | #endif 27 | #ifdef PORTH 28 | if(portPtr == (void*)&PORTH) { return "PORTH"; } 29 | #endif 30 | #ifdef PORTI 31 | if(portPtr == (void*)&PORTI) { return "PORTI"; } 32 | #endif 33 | #ifdef PORTJ 34 | if(portPtr == (void*)&PORTJ) { return "PORTJ"; } 35 | #endif 36 | #ifdef PORTK 37 | if(portPtr == (void*)&PORTK) { return "PORTK"; } 38 | #endif 39 | #ifdef PORTL 40 | if(portPtr == (void*)&PORTL) { return "PORTL"; } 41 | #endif 42 | #ifdef GPIO_A_PDOR 43 | if(portPtr == (void*)&GPIO_A_PDOR) { return "GPIO_A_PDOR"; } 44 | #endif 45 | #ifdef GPIO_B_PDOR 46 | if(portPtr == (void*)&GPIO_B_PDOR) { return "GPIO_B_PDOR"; } 47 | #endif 48 | #ifdef GPIO_C_PDOR 49 | if(portPtr == (void*)&GPIO_C_PDOR) { return "GPIO_C_PDOR"; } 50 | #endif 51 | #ifdef GPIO_D_PDOR 52 | if(portPtr == (void*)&GPIO_D_PDOR) { return "GPIO_D_PDOR"; } 53 | #endif 54 | #ifdef GPIO_E_PDOR 55 | if(portPtr == (void*)&GPIO_E_PDOR) { return "GPIO_E_PDOR"; } 56 | #endif 57 | #ifdef REG_PIO_A_ODSR 58 | if(portPtr == (void*)®_PIO_A_ODSR) { return "REG_PIO_A_ODSR"; } 59 | #endif 60 | #ifdef REG_PIO_B_ODSR 61 | if(portPtr == (void*)®_PIO_B_ODSR) { return "REG_PIO_B_ODSR"; } 62 | #endif 63 | #ifdef REG_PIO_C_ODSR 64 | if(portPtr == (void*)®_PIO_C_ODSR) { return "REG_PIO_C_ODSR"; } 65 | #endif 66 | #ifdef REG_PIO_D_ODSR 67 | if(portPtr == (void*)®_PIO_D_ODSR) { return "REG_PIO_D_ODSR"; } 68 | #endif 69 | return "unknown"; 70 | } 71 | 72 | template void CheckPin() 73 | { 74 | CheckPin(); 75 | 76 | RwReg *systemThinksPortIs = portOutputRegister(digitalPinToPort(PIN)); 77 | RwReg systemThinksMaskIs = digitalPinToBitMask(PIN); 78 | 79 | Serial.print("Pin "); Serial.print(PIN); Serial.print(": Port "); 80 | 81 | if(systemThinksPortIs == FastPin::port()) { 82 | Serial.print("valid & mask "); 83 | } else { 84 | Serial.print("invalid, is "); Serial.print(getPort((void*)FastPin::port())); Serial.print(" should be "); 85 | Serial.print(getPort((void*)systemThinksPortIs)); 86 | Serial.print(" & mask "); 87 | } 88 | 89 | if(systemThinksMaskIs == FastPin::mask()) { 90 | Serial.println("valid."); 91 | } else { 92 | Serial.print("invalid, is "); Serial.print(FastPin::mask()); Serial.print(" should be "); Serial.println(systemThinksMaskIs); 93 | } 94 | } 95 | 96 | template<> void CheckPin<-1> () {} 97 | 98 | void setup() { 99 | Serial.begin(38400); 100 | Serial.println("resetting!"); 101 | } 102 | 103 | void loop() { 104 | CheckPin(); 105 | delay(10000); 106 | } 107 | -------------------------------------------------------------------------------- /firmware/examples/FirstLight/FirstLight.ino: -------------------------------------------------------------------------------- 1 | // Use if you want to force the software SPI subsystem to be used for some reason (generally, you don't) 2 | // #define FASTLED_FORCE_SOFTWARE_SPI 3 | // Use if you want to force non-accelerated pin access (hint: you really don't, it breaks lots of things) 4 | // #define FASTLED_FORCE_SOFTWARE_SPI 5 | // #define FASTLED_FORCE_SOFTWARE_PINS 6 | #include "FastLED/FastLED.h" 7 | FASTLED_USING_NAMESPACE; 8 | 9 | /////////////////////////////////////////////////////////////////////////////////////////// 10 | // 11 | // Move a white dot along the strip of leds. This program simply shows how to configure the leds, 12 | // and then how to turn a single pixel white and then off, moving down the line of pixels. 13 | // 14 | 15 | // How many leds are in the strip? 16 | #define NUM_LEDS 60 17 | 18 | // Data pin that led data will be written out over 19 | #define DATA_PIN 3 20 | 21 | // Clock pin only needed for SPI based chipsets when not using hardware SPI 22 | //#define CLOCK_PIN 8 23 | 24 | // This is an array of leds. One item for each led in your strip. 25 | CRGB leds[NUM_LEDS]; 26 | 27 | // This function sets up the ledsand tells the controller about them 28 | void setup() { 29 | // sanity check delay - allows reprogramming if accidently blowing power w/leds 30 | delay(2000); 31 | 32 | // Uncomment one of the following lines for your leds arrangement. 33 | // FastLED.addLeds(leds, NUM_LEDS); 34 | // FastLED.addLeds(leds, NUM_LEDS); 35 | // FastLED.addLeds(leds, NUM_LEDS); 36 | FastLED.addLeds(leds, NUM_LEDS); 37 | // FastLED.addLeds(leds, NUM_LEDS); 38 | // FastLED.addLeds(leds, NUM_LEDS); 39 | // FastLED.addLeds(leds, NUM_LEDS); 40 | // FastLED.addLeds(leds, NUM_LEDS); 41 | // FastLED.addLeds(leds, NUM_LEDS); 42 | // FastLED.addLeds(leds, NUM_LEDS); 43 | // FastLED.addLeds(leds, NUM_LEDS); 44 | // FastLED.addLeds(leds, NUM_LEDS); 45 | 46 | // FastLED.addLeds(leds, NUM_LEDS); 47 | // FastLED.addLeds(leds, NUM_LEDS); 48 | // FastLED.addLeds(leds, NUM_LEDS); 49 | // FastLED.addLeds(leds, NUM_LEDS); 50 | 51 | // FastLED.addLeds(leds, NUM_LEDS); 52 | // FastLED.addLeds(leds, NUM_LEDS); 53 | // FastLED.addLeds(leds, NUM_LEDS); 54 | } 55 | 56 | // This function runs over and over, and is where you do the magic to light 57 | // your leds. 58 | void loop() { 59 | // Move a single white led 60 | for(int whiteLed = 0; whiteLed < NUM_LEDS; whiteLed = whiteLed + 1) { 61 | // Turn our current led on to white, then show the leds 62 | leds[whiteLed] = CRGB::White; 63 | 64 | // Show the leds (only one of which is set to white, from above) 65 | FastLED.show(); 66 | 67 | // Wait a little bit 68 | delay(100); 69 | 70 | // Turn our current led back to black for the next loop around 71 | leds[whiteLed] = CRGB::Black; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /firmware/examples/ColorTemperature/ColorTemperature.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | #define LED_PIN 3 5 | 6 | // Information about the LED strip itself 7 | #define NUM_LEDS 60 8 | #define CHIPSET WS2811 9 | #define COLOR_ORDER GRB 10 | CRGB leds[NUM_LEDS]; 11 | 12 | #define BRIGHTNESS 128 13 | 14 | 15 | // FastLED v2.1 provides two color-management controls: 16 | // (1) color correction settings for each LED strip, and 17 | // (2) master control of the overall output 'color temperature' 18 | // 19 | // THIS EXAMPLE demonstrates the second, "color temperature" control. 20 | // It shows a simple rainbow animation first with one temperature profile, 21 | // and a few seconds later, with a different temperature profile. 22 | // 23 | // The first pixel of the strip will show the color temperature. 24 | // 25 | // HELPFUL HINTS for "seeing" the effect in this demo: 26 | // * Don't look directly at the LED pixels. Shine the LEDs aganst 27 | // a white wall, table, or piece of paper, and look at the reflected light. 28 | // 29 | // * If you watch it for a bit, and then walk away, and then come back 30 | // to it, you'll probably be able to "see" whether it's currently using 31 | // the 'redder' or the 'bluer' temperature profile, even not counting 32 | // the lowest 'indicator' pixel. 33 | // 34 | // 35 | // FastLED provides these pre-conigured incandescent color profiles: 36 | // Candle, Tungsten40W, Tungsten100W, Halogen, CarbonArc, 37 | // HighNoonSun, DirectSunlight, OvercastSky, ClearBlueSky, 38 | // FastLED provides these pre-configured gaseous-light color profiles: 39 | // WarmFluorescent, StandardFluorescent, CoolWhiteFluorescent, 40 | // FullSpectrumFluorescent, GrowLightFluorescent, BlackLightFluorescent, 41 | // MercuryVapor, SodiumVapor, MetalHalide, HighPressureSodium, 42 | // FastLED also provides an "Uncorrected temperature" profile 43 | // UncorrectedTemperature; 44 | 45 | #define TEMPERATURE_1 Tungsten100W 46 | #define TEMPERATURE_2 OvercastSky 47 | 48 | // How many seconds to show each temperature before switching 49 | #define DISPLAYTIME 20 50 | // How many seconds to show black between switches 51 | #define BLACKTIME 3 52 | 53 | void loop() 54 | { 55 | // draw a generic, no-name rainbow 56 | static uint8_t starthue = 0; 57 | fill_rainbow( leds + 5, NUM_LEDS - 5, --starthue, 20); 58 | 59 | // Choose which 'color temperature' profile to enable. 60 | uint8_t secs = (millis() / 1000) % (DISPLAYTIME * 2); 61 | if( secs < DISPLAYTIME) { 62 | FastLED.setTemperature( TEMPERATURE_1 ); // first temperature 63 | leds[0] = TEMPERATURE_1; // show indicator pixel 64 | } else { 65 | FastLED.setTemperature( TEMPERATURE_2 ); // second temperature 66 | leds[0] = TEMPERATURE_2; // show indicator pixel 67 | } 68 | 69 | // Black out the LEDs for a few secnds between color changes 70 | // to let the eyes and brains adjust 71 | if( (secs % DISPLAYTIME) < BLACKTIME) { 72 | memset8( leds, 0, NUM_LEDS * sizeof(CRGB)); 73 | } 74 | 75 | FastLED.show(); 76 | FastLED.delay(8); 77 | } 78 | 79 | void setup() { 80 | delay( 3000 ); // power-up safety delay 81 | // It's important to set the color correction for your LED strip here, 82 | // so that colors can be more accurately rendered through the 'temperature' profiles 83 | FastLED.addLeds(leds, NUM_LEDS).setCorrection( TypicalSMD5050 ); 84 | FastLED.setBrightness( BRIGHTNESS ); 85 | } 86 | 87 | -------------------------------------------------------------------------------- /firmware/examples/RGBCalibrate/RGBCalibrate.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | 5 | //////////////////////////////////////////////////////////////////////////////////////////////////// 6 | // 7 | // RGB Calibration code 8 | // 9 | // Use this sketch to determine what the RGB ordering for your chipset should be. Steps for setting up to use: 10 | 11 | // * Uncomment the line in setup that corresponds to the LED chipset that you are using. (Note that they 12 | // all explicitly specify the RGB order as RGB) 13 | // * Define DATA_PIN to the pin that data is connected to. 14 | // * (Optional) if using software SPI for chipsets that are SPI based, define CLOCK_PIN to the clock pin 15 | // * Compile/upload/run the sketch 16 | 17 | // You should see six leds on. If the RGB ordering is correct, you should see 1 red led, 2 green 18 | // leds, and 3 blue leds. If you see different colors, the count of each color tells you what the 19 | // position for that color in the rgb orering should be. So, for example, if you see 1 Blue, and 2 20 | // Red, and 3 Green leds then the rgb ordering should be BRG (Blue, Red, Green). 21 | 22 | // You can then test this ordering by setting the RGB ordering in the addLeds line below to the new ordering 23 | // and it should come out correctly, 1 red, 2 green, and 3 blue. 24 | // 25 | ////////////////////////////////////////////////// 26 | 27 | #define NUM_LEDS 6 28 | 29 | // Data pin that led data will be written out over 30 | #define DATA_PIN 6 31 | // Clock pin only needed for SPI based chipsets when not using hardware SPI 32 | //#define CLOCK_PIN 8 33 | 34 | CRGB leds[NUM_LEDS]; 35 | 36 | void setup() { 37 | // sanity check delay - allows reprogramming if accidently blowing power w/leds 38 | delay(2000); 39 | 40 | // Uncomment one of the following lines for your leds arrangement. 41 | // FastLED.addLeds(leds, NUM_LEDS); 42 | // FastLED.addLeds(leds, NUM_LEDS); 43 | // FastLED.addLeds(leds, NUM_LEDS); 44 | // FastLED.addLeds(leds, NUM_LEDS); 45 | // FastLED.addLeds(leds, NUM_LEDS); 46 | // FastLED.addLeds(leds, NUM_LEDS); 47 | // FastLED.setBrightness(CRGB(255,255,255)); 48 | // FastLED.addLeds(leds, NUM_LEDS); 49 | // FastLED.addLeds(leds, NUM_LEDS); 50 | // FastLED.addLeds(leds, NUM_LEDS); 51 | // FastLED.addLeds(leds, NUM_LEDS); 52 | 53 | // FastLED.addLeds(leds, NUM_LEDS); 54 | // FastLED.addLeds(leds, NUM_LEDS); 55 | FastLED.addLeds(leds, NUM_LEDS); 56 | 57 | // FastLED.addLeds(leds, NUM_LEDS); 58 | // FastLED.addLeds(leds, NUM_LEDS); 59 | // FastLED.addLeds(leds, NUM_LEDS); 60 | } 61 | 62 | void loop() { 63 | leds[0] = CRGB(255,0,0); 64 | leds[1] = CRGB(0,255,0); 65 | leds[2] = CRGB(0,255,0); 66 | leds[3] = CRGB(0,0,255); 67 | leds[4] = CRGB(0,0,255); 68 | leds[5] = CRGB(0,0,255); 69 | // leds[10] = CRGB(0,0,0); 70 | FastLED.show(); 71 | delay(1000); 72 | } 73 | -------------------------------------------------------------------------------- /firmware/examples/Fire2012/Fire2012.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | #define LED_PIN 5 5 | #define COLOR_ORDER GRB 6 | #define CHIPSET WS2811 7 | #define NUM_LEDS 30 8 | 9 | #define BRIGHTNESS 200 10 | #define FRAMES_PER_SECOND 60 11 | 12 | CRGB leds[NUM_LEDS]; 13 | 14 | void setup() { 15 | delay(3000); // sanity delay 16 | FastLED.addLeds(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); 17 | FastLED.setBrightness( BRIGHTNESS ); 18 | } 19 | 20 | void loop() 21 | { 22 | // Add entropy to random number generator; we use a lot of it. 23 | random16_add_entropy( random(256)); 24 | 25 | Fire2012(); // run simulation frame 26 | 27 | FastLED.show(); // display this frame 28 | FastLED.delay(1000 / FRAMES_PER_SECOND); 29 | } 30 | 31 | 32 | // Fire2012 by Mark Kriegsman, July 2012 33 | // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY 34 | //// 35 | // This basic one-dimensional 'fire' simulation works roughly as follows: 36 | // There's a underlying array of 'heat' cells, that model the temperature 37 | // at each point along the line. Every cycle through the simulation, 38 | // four steps are performed: 39 | // 1) All cells cool down a little bit, losing heat to the air 40 | // 2) The heat from each cell drifts 'up' and diffuses a little 41 | // 3) Sometimes randomly new 'sparks' of heat are added at the bottom 42 | // 4) The heat from each cell is rendered as a color into the leds array 43 | // The heat-to-color mapping uses a black-body radiation approximation. 44 | // 45 | // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). 46 | // 47 | // This simulation scales it self a bit depending on NUM_LEDS; it should look 48 | // "OK" on anywhere from 20 to 100 LEDs without too much tweaking. 49 | // 50 | // I recommend running this simulation at anywhere from 30-100 frames per second, 51 | // meaning an interframe delay of about 10-35 milliseconds. 52 | // 53 | // Looks best on a high-density LED setup (60+ pixels/meter). 54 | // 55 | // 56 | // There are two main parameters you can play with to control the look and 57 | // feel of your fire: COOLING (used in step 1 above), and SPARKING (used 58 | // in step 3 above). 59 | // 60 | // COOLING: How much does the air cool as it rises? 61 | // Less cooling = taller flames. More cooling = shorter flames. 62 | // Default 50, suggested range 20-100 63 | #define COOLING 55 64 | 65 | // SPARKING: What chance (out of 255) is there that a new spark will be lit? 66 | // Higher chance = more roaring fire. Lower chance = more flickery fire. 67 | // Default 120, suggested range 50-200. 68 | #define SPARKING 120 69 | 70 | 71 | void Fire2012() 72 | { 73 | // Array of temperature readings at each simulation cell 74 | static byte heat[NUM_LEDS]; 75 | 76 | // Step 1. Cool down every cell a little 77 | for( int i = 0; i < NUM_LEDS; i++) { 78 | heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2)); 79 | } 80 | 81 | // Step 2. Heat from each cell drifts 'up' and diffuses a little 82 | for( int k= NUM_LEDS - 1; k >= 2; k--) { 83 | heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; 84 | } 85 | 86 | // Step 3. Randomly ignite new 'sparks' of heat near the bottom 87 | if( random8() < SPARKING ) { 88 | int y = random8(7); 89 | heat[y] = qadd8( heat[y], random8(160,255) ); 90 | } 91 | 92 | // Step 4. Map from heat cells to LED colors 93 | for( int j = 0; j < NUM_LEDS; j++) { 94 | leds[j] = HeatColor( heat[j]); 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /firmware/fastspi.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTSPI_H 2 | #define __INC_FASTSPI_H 3 | 4 | #include "controller.h" 5 | #include "lib8tion.h" 6 | 7 | #include "fastspi_bitbang.h" 8 | 9 | FASTLED_NAMESPACE_BEGIN 10 | 11 | #if (CLK_DBL == 1) 12 | #define DATA_RATE_MHZ(X) (((F_CPU / 1000000L) / X)/2) 13 | #define DATA_RATE_KHZ(X) (((F_CPU / 1000L) / X)/2) 14 | #else 15 | #define DATA_RATE_MHZ(X) ((F_CPU / 1000000L) / X) 16 | #define DATA_RATE_KHZ(X) ((F_CPU / 1000L) / X) 17 | #endif 18 | 19 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 20 | // 21 | // External SPI template definition with partial instantiation(s) to map to hardware SPI ports on platforms/builds where the pin 22 | // mappings are known at compile time. 23 | // 24 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 25 | 26 | template 27 | class SPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; 28 | 29 | template 30 | class SoftwareSPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; 31 | 32 | #ifndef FASTLED_FORCE_SOFTWARE_SPI 33 | #if defined(SPI_DATA) && defined(SPI_CLOCK) 34 | 35 | #if defined(FASTLED_TEENSY3) && defined(ARM_HARDWARE_SPI) 36 | 37 | template 38 | class SPIOutput : public ARMHardwareSPIOutput {}; 39 | 40 | #if defined(SPI2_DATA) 41 | 42 | template 43 | class SPIOutput : public ARMHardwareSPIOutput {}; 44 | #endif 45 | 46 | #elif defined(FASTLED_TEENSYLC) && defined(ARM_HARDWARE_SPI) 47 | 48 | template 49 | class SPIOutput : public ARMHardwareSPIOutput {}; 50 | 51 | #if defined(SPI2_DATA) 52 | 53 | template 54 | class SPIOutput : public ARMHardwareSPIOutput {}; 55 | #endif 56 | 57 | #elif defined(__SAM3X8E__) 58 | 59 | template 60 | class SPIOutput : public SAMHardwareSPIOutput {}; 61 | 62 | #elif defined(AVR_HARDWARE_SPI) 63 | 64 | template 65 | class SPIOutput : public AVRHardwareSPIOutput {}; 66 | 67 | #if defined(SPI_UART0_DATA) 68 | 69 | template 70 | class SPIOutput : public AVRUSART0SPIOutput {}; 71 | 72 | #endif 73 | 74 | #if defined(SPI_UART1_DATA) 75 | 76 | template 77 | class SPIOutput : public AVRUSART1SPIOutput {}; 78 | 79 | #endif 80 | 81 | #endif 82 | 83 | #else 84 | #warning "No hardware SPI pins defined. All SPI access will default to bitbanged output" 85 | 86 | #endif 87 | 88 | // #if defined(USART_DATA) && defined(USART_CLOCK) 89 | // template 90 | // class AVRSPIOutput : public AVRUSARTSPIOutput {}; 91 | // #endif 92 | 93 | #else 94 | #warning "Forcing software SPI - no hardware SPI for you!" 95 | #endif 96 | 97 | FASTLED_NAMESPACE_END 98 | 99 | #endif 100 | -------------------------------------------------------------------------------- /firmware/release_notes.md: -------------------------------------------------------------------------------- 1 | FastLED3.0 2 | ========== 3 | 4 | * Added support for the following platforms: 5 | * Arduino due 6 | * Teensy 3.1 7 | * Added the following LED chipsets: 8 | * USC1903_400 9 | * GW6205 / GW6205_400 10 | * APA102 11 | * APA104 12 | * LPD1886 13 | * P9813 14 | * SmartMatrix 15 | * Added multiple examples: 16 | * ColorPalette - show off the color palette code 17 | * ColorTemperature - show off the color correction code 18 | * Fire2012 19 | * Fire2012WithPalette 20 | * Multiple led controller examples 21 | * Noise 22 | * NoisePlayground 23 | * NoisePlusPalette 24 | * SmartMatrix - show off SmartMatrix support 25 | * XYMatrix - show how to use a mtrix layout of leds 26 | * Added color correction 27 | * Added dithering 28 | * Added power management support 29 | * Added support for color palettes 30 | * Added easing functions 31 | * Added fast trig functions 32 | * Added simplex noise functions 33 | * Added color utility functions 34 | * Fixed DMXSERIAL/DMXSIMPLE support 35 | * Timing adjustments for existing SPI chipsets 36 | * Cleaned up the code layout to make platform support easier 37 | * Many bug fixes 38 | * A number of performance/memory improvements 39 | * Remove Squant (takes up space!) 40 | 41 | FastLED2 42 | ======== 43 | 44 | ## Full release of the library 45 | 46 | ## Release Candidate 6 47 | * Rename library, offically, to FastLED, move to github 48 | * Update keywords with all the new stuffs 49 | 50 | ## Release Candidate 5 51 | * Gemma and Trinket: supported except for global "setBrightness" 52 | 53 | ## Release Candidate 4 54 | * Added NEOPIXEL as a synonym for WS2811 55 | * Fix WS2811/WS2812B timings, bring it in line to exactly 1.25ns/bit. 56 | * Fix handling of constant color definitions (damn you, gcc!) 57 | 58 | ## Release Candidate 3 59 | * Fixed bug when Clock and Data were on the same port 60 | * Added ability to set pixel color directly from HSV 61 | * Added ability to retrieve current random16 seed 62 | 63 | ## Release Candidate 2 64 | * mostly bug fixes 65 | * Fix SPI macro definitions for latest teensy3 software update 66 | * Teensy 2 compilation fix 67 | * hsv2rgb_rainbow performance fix 68 | 69 | ## Release Candidate 1 70 | * New unified/simplified API for adding/using controllers 71 | * fleshout clockless chip support 72 | * add hsv (spectrum and rainbow style colors) 73 | * high speed memory management operations 74 | * library for interpolation/easing functions 75 | * various api changes, addition of clear and showColor functions 76 | * scale value applied to all show methods 77 | * bug fixes for SM16716 78 | * performance improvements, lpd8806 exceeds 22Mbit now 79 | * hardware def fixes 80 | * allow alternate rgb color orderings 81 | * high speed math methods 82 | * rich CRGB structure 83 | 84 | ## Preview 3 85 | * True hardware SPI support for teensy (up to 20Mbit output!) 86 | * Minor bug fixes/tweaks 87 | 88 | ## Preview 2 89 | * Rename pin class to FastPin 90 | * Replace latch with select, more accurate description of what it does 91 | * Enforce intra-frame timing for ws2801s 92 | * SM16716 support 93 | * Add #define FAST_SPI_INTERRUPTS_WRITE_PINS to make sure world is ok w/interrupts and SPI 94 | * Add #define FASTLED_FORCE_SOFTWARE_SPI for those times when you absolutely don't want to use hardware SPI, ev 95 | en if you're using the hardware SPI pins 96 | * Add pin definitions for the arduino megas - should fix ws2811 support 97 | * Add pin definitions for the leonardo - should fix spi support and pin mappings 98 | * Add warnings when pin definitions are missing 99 | * Added google+ community for fastspi users - https://plus.google.com/communities/109127054924227823508 100 | # Add pin definitions for Teensy++ 2.0 101 | 102 | 103 | ## Preview 1 104 | * Initial release 105 | 106 | 107 | -------------------------------------------------------------------------------- /firmware/examples/Noise/Noise.ino: -------------------------------------------------------------------------------- 1 | #include"FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | // 5 | // Mark's xy coordinate mapping code. See the XYMatrix for more information on it. 6 | // 7 | 8 | // Params for width and height 9 | const uint8_t kMatrixWidth = 16; 10 | const uint8_t kMatrixHeight = 16; 11 | #define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight) 12 | #define NUM_LEDS (kMatrixWidth * kMatrixHeight) 13 | // Param for different pixel layouts 14 | const bool kMatrixSerpentineLayout = true; 15 | 16 | 17 | uint16_t XY( uint8_t x, uint8_t y) 18 | { 19 | uint16_t i; 20 | 21 | if( kMatrixSerpentineLayout == false) { 22 | i = (y * kMatrixWidth) + x; 23 | } 24 | 25 | if( kMatrixSerpentineLayout == true) { 26 | if( y & 0x01) { 27 | // Odd rows run backwards 28 | uint8_t reverseX = (kMatrixWidth - 1) - x; 29 | i = (y * kMatrixWidth) + reverseX; 30 | } else { 31 | // Even rows run forwards 32 | i = (y * kMatrixWidth) + x; 33 | } 34 | } 35 | 36 | return i; 37 | } 38 | 39 | // The leds 40 | CRGB leds[kMatrixWidth * kMatrixHeight]; 41 | 42 | // The 32bit version of our coordinates 43 | static uint16_t x; 44 | static uint16_t y; 45 | static uint16_t z; 46 | 47 | // We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll 48 | // use the z-axis for "time". speed determines how fast time moves forward. Try 49 | // 1 for a very slow moving effect, or 60 for something that ends up looking like 50 | // water. 51 | // uint16_t speed = 1; // almost looks like a painting, moves very slowly 52 | uint16_t speed = 20; // a nice starting speed, mixes well with a scale of 100 53 | // uint16_t speed = 33; 54 | // uint16_t speed = 100; // wicked fast! 55 | 56 | // Scale determines how far apart the pixels in our noise matrix are. Try 57 | // changing these values around to see how it affects the motion of the display. The 58 | // higher the value of scale, the more "zoomed out" the noise iwll be. A value 59 | // of 1 will be so zoomed in, you'll mostly see solid colors. 60 | 61 | // uint16_t scale = 1; // mostly just solid colors 62 | // uint16_t scale = 4011; // very zoomed out and shimmery 63 | uint16_t scale = 311; 64 | 65 | // This is the array that we keep our computed noise values in 66 | uint8_t noise[MAX_DIMENSION][MAX_DIMENSION]; 67 | 68 | void setup() { 69 | // uncomment the following lines if you want to see FPS count information 70 | // Serial.begin(38400); 71 | // Serial.println("resetting!"); 72 | delay(3000); 73 | LEDS.addLeds(leds,NUM_LEDS); 74 | LEDS.setBrightness(96); 75 | 76 | // Initialize our coordinates to some random values 77 | x = random16(); 78 | y = random16(); 79 | z = random16(); 80 | } 81 | 82 | // Fill the x/y array of 8-bit noise values using the inoise8 function. 83 | void fillnoise8() { 84 | for(int i = 0; i < MAX_DIMENSION; i++) { 85 | int ioffset = scale * i; 86 | for(int j = 0; j < MAX_DIMENSION; j++) { 87 | int joffset = scale * j; 88 | noise[i][j] = inoise8(x + ioffset,y + joffset,z); 89 | } 90 | } 91 | z += speed; 92 | } 93 | 94 | 95 | void loop() { 96 | static uint8_t ihue=0; 97 | fillnoise8(); 98 | for(int i = 0; i < kMatrixWidth; i++) { 99 | for(int j = 0; j < kMatrixHeight; j++) { 100 | // We use the value at the (i,j) coordinate in the noise 101 | // array for our brightness, and the flipped value from (j,i) 102 | // for our pixel's hue. 103 | leds[XY(i,j)] = CHSV(noise[j][i],255,noise[i][j]); 104 | 105 | // You can also explore other ways to constrain the hue used, like below 106 | // leds[XY(i,j)] = CHSV(ihue + (noise[j][i]>>2),255,noise[i][j]); 107 | } 108 | } 109 | ihue+=1; 110 | 111 | LEDS.show(); 112 | // delay(10); 113 | } 114 | -------------------------------------------------------------------------------- /firmware/hsv2rgb.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_HSV2RGB_H 2 | #define __INC_HSV2RGB_H 3 | 4 | #include "pixeltypes.h" 5 | 6 | FASTLED_NAMESPACE_BEGIN 7 | 8 | // hsv2rgb_rainbow - convert a hue, saturation, and value to RGB 9 | // using a visually balanced rainbow (vs a straight 10 | // mathematical spectrum). 11 | // This 'rainbow' yields better yellow and orange 12 | // than a straight 'spectrum'. 13 | // 14 | // NOTE: here hue is 0-255, not just 0-191 15 | 16 | void hsv2rgb_rainbow( const struct CHSV& hsv, struct CRGB& rgb); 17 | void hsv2rgb_rainbow( const struct CHSV* phsv, struct CRGB * prgb, int numLeds); 18 | #define HUE_MAX_RAINBOW 255 19 | 20 | 21 | // hsv2rgb_spectrum - convert a hue, saturation, and value to RGB 22 | // using a mathematically straight spectrum (vs 23 | // a visually balanced rainbow). 24 | // This 'spectrum' will have more green & blue 25 | // than a 'rainbow', and less yellow and orange. 26 | // 27 | // NOTE: here hue is 0-255, not just 0-191 28 | 29 | void hsv2rgb_spectrum( const struct CHSV& hsv, struct CRGB& rgb); 30 | void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds); 31 | #define HUE_MAX_SPECTRUM 255 32 | 33 | 34 | // hsv2rgb_raw - convert hue, saturation, and value to RGB. 35 | // This 'spectrum' conversion will be more green & blue 36 | // than a real 'rainbow', and the hue is specified just 37 | // in the range 0-191. Together, these result in a 38 | // slightly faster conversion speed, at the expense of 39 | // color balance. 40 | // 41 | // NOTE: Hue is 0-191 only! 42 | // Saturation & value are 0-255 each. 43 | // 44 | 45 | void hsv2rgb_raw(const struct CHSV& hsv, struct CRGB & rgb); 46 | void hsv2rgb_raw(const struct CHSV* phsv, struct CRGB * prgb, int numLeds); 47 | #define HUE_MAX 191 48 | 49 | 50 | // rgb2hsv_approximate - recover _approximate_ HSV values from RGB. 51 | // 52 | // NOTE 1: This function is a long-term work in process; expect 53 | // results to change slightly over time as this function is 54 | // refined and improved. 55 | // 56 | // NOTE 2: This function is most accurate when the input is an 57 | // RGB color that came from a fully-saturated HSV color to start 58 | // with. E.g. CHSV( hue, 255, 255) -> CRGB -> CHSV will give 59 | // best results. 60 | // 61 | // NOTE 3: This function is not nearly as fast as HSV-to-RGB. 62 | // It is provided for those situations when the need for this 63 | // function cannot be avoided, or when extremely high performance 64 | // is not needed. 65 | // 66 | // NOTE 4: Why is this 'only' an "approximation"? 67 | // Not all RGB colors have HSV equivalents! For example, there 68 | // is no HSV value that will ever convert to RGB(255,255,0) using 69 | // the code provided in this library. So if you try to 70 | // convert RGB(255,255,0) 'back' to HSV, you'll necessarily get 71 | // only an approximation. Emphasis has been placed on getting 72 | // the 'hue' as close as usefully possible, but even that's a bit 73 | // of a challenge. The 8-bit HSV and 8-bit RGB color spaces 74 | // are not a "bijection". 75 | // 76 | // Nevertheless, this function does a pretty good job, particularly 77 | // at recovering the 'hue' from fully saturated RGB colors that 78 | // originally came from HSV rainbow colors. So if you start 79 | // with CHSV(hue_in,255,255), and convert that to RGB, and then 80 | // convert it back to HSV using this function, the resulting output 81 | // hue will either exactly the same, or very close (+/-1). 82 | // The more desaturated the original RGB color is, the rougher the 83 | // approximation, and the less accurate the results. 84 | // 85 | CHSV rgb2hsv_approximate( const CRGB& rgb); 86 | 87 | FASTLED_NAMESPACE_END 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /firmware/examples/DemoReel100/DemoReel100.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | // FastLED "100-lines-of-code" demo reel, showing just a few 5 | // of the kinds of animation patterns you can quickly and easily 6 | // compose using FastLED. 7 | // 8 | // This example also shows one easy way to define multiple 9 | // animations patterns and have them automatically rotate. 10 | // 11 | // -Mark Kriegsman, December 2014 12 | 13 | #if FASTLED_VERSION < 3001000 14 | #error "Requires FastLED 3.1 or later; check github for latest code." 15 | #endif 16 | 17 | #define DATA_PIN 3 18 | //#define CLK_PIN 4 19 | #define LED_TYPE WS2811 20 | #define COLOR_ORDER GRB 21 | #define NUM_LEDS 64 22 | CRGB leds[NUM_LEDS]; 23 | 24 | #define BRIGHTNESS 96 25 | #define FRAMES_PER_SECOND 120 26 | 27 | void setup() { 28 | delay(3000); // 3 second delay for recovery 29 | 30 | // tell FastLED about the LED strip configuration 31 | FastLED.addLeds(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); 32 | //FastLED.addLeds(leds, NUM_LEDS).setCorrection(TypicalLEDStrip); 33 | 34 | // set master brightness control 35 | FastLED.setBrightness(BRIGHTNESS); 36 | } 37 | 38 | 39 | // List of patterns to cycle through. Each is defined as a separate function below. 40 | typedef void (*SimplePatternList[])(); 41 | SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm }; 42 | 43 | uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current 44 | uint8_t gHue = 0; // rotating "base color" used by many of the patterns 45 | 46 | void loop() 47 | { 48 | // Call the current pattern function once, updating the 'leds' array 49 | gPatterns[gCurrentPatternNumber](); 50 | 51 | // send the 'leds' array out to the actual LED strip 52 | FastLED.show(); 53 | // insert a delay to keep the framerate modest 54 | FastLED.delay(1000/FRAMES_PER_SECOND); 55 | 56 | // do some periodic updates 57 | EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the "base color" through the rainbow 58 | EVERY_N_SECONDS( 10 ) { nextPattern(); } // change patterns periodically 59 | } 60 | 61 | #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) 62 | 63 | void nextPattern() 64 | { 65 | // add one to the current pattern number, and wrap around at the end 66 | gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns); 67 | } 68 | 69 | void rainbow() 70 | { 71 | // FastLED's built-in rainbow generator 72 | fill_rainbow( leds, NUM_LEDS, gHue, 7); 73 | } 74 | 75 | void addGlitter( fract8 chanceOfGlitter) 76 | { 77 | if( random8() < chanceOfGlitter) { 78 | leds[ random16(NUM_LEDS) ] += CRGB::White; 79 | } 80 | } 81 | 82 | void rainbowWithGlitter() 83 | { 84 | // built-in FastLED rainbow, plus some random sparkly glitter 85 | rainbow(); 86 | addGlitter(80); 87 | } 88 | 89 | 90 | void confetti() 91 | { 92 | // random colored speckles that blink in and fade smoothly 93 | fadeToBlackBy( leds, NUM_LEDS, 10); 94 | int pos = random16(NUM_LEDS); 95 | leds[pos] += CHSV( gHue + random8(64), 200, 255); 96 | } 97 | 98 | void sinelon() 99 | { 100 | // a colored dot sweeping back and forth, with fading trails 101 | fadeToBlackBy( leds, NUM_LEDS, 20); 102 | int pos = beatsin16(13,0,NUM_LEDS); 103 | leds[pos] += CHSV( gHue, 255, 192); 104 | } 105 | 106 | void bpm() 107 | { 108 | // colored stripes pulsing at a defined Beats-Per-Minute (BPM) 109 | uint8_t BeatsPerMinute = 62; 110 | CRGBPalette16 palette = PartyColors_p; 111 | uint8_t beat = beatsin8( BeatsPerMinute, 64, 255); 112 | for( int i = 0; i < NUM_LEDS; i++) { //9948 113 | leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10)); 114 | } 115 | } 116 | 117 | void juggle() { 118 | // eight colored dots, weaving in and out of sync with each other 119 | fadeToBlackBy( leds, NUM_LEDS, 20); 120 | byte dothue = 0; 121 | for( int i = 0; i < 8; i++) { 122 | leds[beatsin16(i+7,0,NUM_LEDS)] |= CHSV(dothue, 200, 255); 123 | dothue += 32; 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /firmware/examples/SmartMatrix/SmartMatrix.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include"FastLED/FastLED.h" 3 | FASTLED_USING_NAMESPACE; 4 | 5 | #define kMatrixWidth 32 6 | #define kMatrixHeight 32 7 | const bool kMatrixSerpentineLayout = false; 8 | 9 | #define NUM_LEDS (kMatrixWidth * kMatrixHeight) 10 | 11 | CRGB leds[kMatrixWidth * kMatrixHeight]; 12 | 13 | 14 | uint16_t XY( uint8_t x, uint8_t y) 15 | { 16 | uint16_t i; 17 | 18 | if( kMatrixSerpentineLayout == false) { 19 | i = (y * kMatrixWidth) + x; 20 | } 21 | 22 | if( kMatrixSerpentineLayout == true) { 23 | if( y & 0x01) { 24 | // Odd rows run backwards 25 | uint8_t reverseX = (kMatrixWidth - 1) - x; 26 | i = (y * kMatrixWidth) + reverseX; 27 | } else { 28 | // Even rows run forwards 29 | i = (y * kMatrixWidth) + x; 30 | } 31 | } 32 | 33 | return i; 34 | } 35 | 36 | // The 32bit version of our coordinates 37 | static uint16_t x; 38 | static uint16_t y; 39 | static uint16_t z; 40 | 41 | // We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll 42 | // use the z-axis for "time". speed determines how fast time moves forward. Try 43 | // 1 for a very slow moving effect, or 60 for something that ends up looking like 44 | // water. 45 | // uint16_t speed = 1; // almost looks like a painting, moves very slowly 46 | uint16_t speed = 20; // a nice starting speed, mixes well with a scale of 100 47 | // uint16_t speed = 33; 48 | // uint16_t speed = 100; // wicked fast! 49 | 50 | // Scale determines how far apart the pixels in our noise matrix are. Try 51 | // changing these values around to see how it affects the motion of the display. The 52 | // higher the value of scale, the more "zoomed out" the noise iwll be. A value 53 | // of 1 will be so zoomed in, you'll mostly see solid colors. 54 | 55 | // uint16_t scale = 1; // mostly just solid colors 56 | // uint16_t scale = 4011; // very zoomed out and shimmery 57 | uint16_t scale = 31; 58 | 59 | // This is the array that we keep our computed noise values in 60 | uint8_t noise[kMatrixWidth][kMatrixHeight]; 61 | 62 | void setup() { 63 | // uncomment the following lines if you want to see FPS count information 64 | // Serial.begin(38400); 65 | // Serial.println("resetting!"); 66 | delay(3000); 67 | LEDS.addLeds(leds,NUM_LEDS); 68 | LEDS.setBrightness(96); 69 | 70 | // Initialize our coordinates to some random values 71 | x = random16(); 72 | y = random16(); 73 | z = random16(); 74 | 75 | // Show off smart matrix scrolling text 76 | pSmartMatrix->setScrollMode(wrapForward); 77 | pSmartMatrix->setScrollColor({0xff, 0xff, 0xff}); 78 | pSmartMatrix->setScrollSpeed(15); 79 | pSmartMatrix->setScrollFont(font6x10); 80 | pSmartMatrix->scrollText("Smart Matrix & FastLED", -1); 81 | pSmartMatrix->setScrollOffsetFromEdge(10); 82 | } 83 | 84 | // Fill the x/y array of 8-bit noise values using the inoise8 function. 85 | void fillnoise8() { 86 | for(int i = 0; i < kMatrixWidth; i++) { 87 | int ioffset = scale * i; 88 | for(int j = 0; j < kMatrixHeight; j++) { 89 | int joffset = scale * j; 90 | noise[i][j] = inoise8(x + ioffset,y + joffset,z); 91 | } 92 | } 93 | z += speed; 94 | } 95 | 96 | 97 | void loop() { 98 | static uint8_t circlex = 0; 99 | static uint8_t circley = 0; 100 | 101 | static uint8_t ihue=0; 102 | fillnoise8(); 103 | for(int i = 0; i < kMatrixWidth; i++) { 104 | for(int j = 0; j < kMatrixHeight; j++) { 105 | // We use the value at the (i,j) coordinate in the noise 106 | // array for our brightness, and the flipped value from (j,i) 107 | // for our pixel's hue. 108 | leds[XY(i,j)] = CHSV(noise[j][i],255,noise[i][j]); 109 | 110 | // You can also explore other ways to constrain the hue used, like below 111 | // leds[XY(i,j)] = CHSV(ihue + (noise[j][i]>>2),255,noise[i][j]); 112 | } 113 | } 114 | ihue+=1; 115 | 116 | // N.B. this requires SmartMatrix modified w/triple buffering support 117 | pSmartMatrix->fillCircle(circlex % 32,circley % 32,6,CRGB(CHSV(ihue+128,255,255))); 118 | circlex += random16(2); 119 | circley += random16(2); 120 | LEDS.show(); 121 | // delay(10); 122 | } 123 | -------------------------------------------------------------------------------- /firmware/dmx.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_DMX_H 2 | #define __INC_DMX_H 3 | 4 | 5 | #ifdef DmxSimple_h 6 | #include 7 | #define HAS_DMX_SIMPLE 8 | 9 | FASTLED_NAMESPACE_BEGIN 10 | 11 | // note - dmx simple must be included before FastSPI for this code to be enabled 12 | template class DMXSimpleController : public CLEDController { 13 | public: 14 | // initialize the LED controller 15 | virtual void init() { DmxSimple.usePin(DATA_PIN); } 16 | 17 | // clear out/zero out the given number of leds. 18 | virtual void clearLeds(int nLeds) { 19 | int count = min(nLeds * 3, DMX_SIZE); 20 | for(int iChannel = 1; iChannel <= count; iChannel++) { DmxSimple.write(iChannel, 0); } 21 | } 22 | 23 | protected: 24 | // set all the leds on the controller to a given color 25 | virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { 26 | int count = min(nLeds, DMX_SIZE / 3); 27 | int iChannel = 1; 28 | for(int i = 0; i < count; i++) { 29 | DmxSimple.write(iChannel++, scale8(data[RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)])); 30 | DmxSimple.write(iChannel++, scale8(data[RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)])); 31 | DmxSimple.write(iChannel++, scale8(data[RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)])); 32 | } 33 | } 34 | 35 | // note that the uint8_ts will be in the order that you want them sent out to the device. 36 | // nLeds is the number of RGB leds being written to 37 | virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { 38 | int count = min(nLeds, DMX_SIZE / 3); 39 | int iChannel = 1; 40 | for(int i = 0; i < count; i++) { 41 | DmxSimple.write(iChannel++, scale8(data[i][RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)])); 42 | DmxSimple.write(iChannel++, scale8(data[i][RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)])); 43 | DmxSimple.write(iChannel++, scale8(data[i][RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)])); 44 | } 45 | 46 | } 47 | 48 | #ifdef SUPPORT_ARGB 49 | // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped 50 | virtual void show(const struct CARGB *data, int nLeds, uint8_t scale = 255) = 0; 51 | #endif 52 | }; 53 | 54 | FASTLED_NAMESPACE_END 55 | 56 | #endif 57 | 58 | #ifdef DmxSerial_h 59 | #include 60 | 61 | FASTLED_NAMESPACE_BEGIN 62 | 63 | template class DMXSerialController : public CLEDController { 64 | public: 65 | // initialize the LED controller 66 | virtual void init() { DMXSerial.init(DMXController); } 67 | 68 | // clear out/zero out the given number of leds. 69 | virtual void clearLeds(int nLeds) { 70 | int count = min(nLeds * 3, DMXSERIAL_MAX); 71 | for(int iChannel = 0; iChannel < count; iChannel++) { DMXSerial.write(iChannel, 0); } 72 | } 73 | 74 | // set all the leds on the controller to a given color 75 | virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { 76 | int count = min(nLeds, DMXSERIAL_MAX / 3); 77 | int iChannel = 0; 78 | for(int i = 0; i < count; i++) { 79 | DMXSerial.write(iChannel++, scale8(data[RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)])); 80 | DMXSerial.write(iChannel++, scale8(data[RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)])); 81 | DMXSerial.write(iChannel++, scale8(data[RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)])); 82 | } 83 | } 84 | 85 | // note that the uint8_ts will be in the order that you want them sent out to the device. 86 | // nLeds is the number of RGB leds being written to 87 | virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { 88 | int count = min(nLeds, DMXSERIAL_MAX / 3); 89 | int iChannel = 0; 90 | for(int i = 0; i < count; i++) { 91 | DMXSerial.write(iChannel++, scale8(data[i][RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)])); 92 | DMXSerial.write(iChannel++, scale8(data[i][RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)])); 93 | DMXSerial.write(iChannel++, scale8(data[i][RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)])); 94 | } 95 | 96 | } 97 | 98 | #ifdef SUPPORT_ARGB 99 | // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped 100 | virtual void show(const struct CARGB *data, int nLeds, uint8_t scale = 255) = 0; 101 | #endif 102 | }; 103 | 104 | FASTLED_NAMESPACE_END 105 | 106 | #define HAS_DMX_SERIAL 107 | #endif 108 | 109 | #endif 110 | -------------------------------------------------------------------------------- /firmware/fastspi_ref.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTSPI_ARM_SAM_H 2 | #define __INC_FASTSPI_ARM_SAM_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | // A skeletal implementation of hardware SPI support. Fill in the necessary code for init, waiting, and writing. The rest of 7 | // the method implementations should provide a starting point, even if not hte most efficient to start with 8 | template 9 | class REFHardwareSPIOutput { 10 | Selectable *m_pSelect; 11 | public: 12 | SAMHardwareSPIOutput() { m_pSelect = NULL; } 13 | SAMHArdwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } 14 | 15 | // set the object representing the selectable 16 | void setSelect(Selectable *pSelect) { /* TODO */ } 17 | 18 | // initialize the SPI subssytem 19 | void init() { /* TODO */ } 20 | 21 | // latch the CS select 22 | void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } 23 | 24 | // release the CS select 25 | void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } 26 | 27 | // wait until all queued up data has been written 28 | static void waitFully() { /* TODO */ } 29 | 30 | // write a byte out via SPI (returns immediately on writing register) 31 | static void writeByte(uint8_t b) { /* TODO */ } 32 | 33 | // write a word out via SPI (returns immediately on writing register) 34 | static void writeWord(uint16_t w) { /* TODO */ } 35 | 36 | // A raw set of writing byte values, assumes setup/init/waiting done elsewhere 37 | static void writeBytesValueRaw(uint8_t value, int len) { 38 | while(len--) { writeByte(value); } 39 | } 40 | 41 | // A full cycle of writing a value for len bytes, including select, release, and waiting 42 | void writeBytesValue(uint8_t value, int len) { 43 | select(); writeBytesValueRaw(value, len); release(); 44 | } 45 | 46 | // A full cycle of writing a value for len bytes, including select, release, and waiting 47 | template void writeBytes(register uint8_t *data, int len) { 48 | uint8_t *end = data + len; 49 | select(); 50 | // could be optimized to write 16bit words out instead of 8bit bytes 51 | while(data != end) { 52 | writeByte(D::adjust(*data++)); 53 | } 54 | D::postBlock(len); 55 | waitFully(); 56 | release(); 57 | } 58 | 59 | // A full cycle of writing a value for len bytes, including select, release, and waiting 60 | void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } 61 | 62 | // write a single bit out, which bit from the passed in byte is determined by template parameter 63 | template inline static void writeBit(uint8_t b) { /* TODO */ } 64 | 65 | // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template 66 | // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping 67 | template void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { 68 | select(); 69 | while(data != end) { 70 | if(FLAGS & FLAG_START_BIT) { 71 | writeBit<0>(1); 72 | } 73 | writeByte(D::adjust(pixels.loadAndScale0())); 74 | writeByte(D::adjust(pixels.loadAndScale1())); 75 | writeByte(D::adjust(pixels.loadAndScale2())); 76 | 77 | pixels.advanceData(); 78 | pixels.stepDithering(); 79 | data += (3+skip); 80 | } 81 | D::postBlock(len); 82 | release(); 83 | } 84 | 85 | // template instantiations for writeBytes 3 86 | template void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { 87 | writeBytes3(data, len, scale, advance, skip); 88 | } 89 | template void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { 90 | writeBytes3<0, D, RGB_ORDER>(data, len, scale, advance, skip); 91 | } 92 | template void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { 93 | writeBytes3<0, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); 94 | } 95 | void writeBytes3(register uint8_t *data, int len, register CRGB scale, bool advance=true, uint8_t skip=0) { 96 | writeBytes3<0, DATA_NOP, RGB>(data, len, scale, advance, skip); 97 | 98 | }; 99 | 100 | FASTLED_NAMESPACE_END 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /firmware/examples/Ports/PJRCSpectrumAnalyzer/PJRCSpectrumAnalyzer.ino: -------------------------------------------------------------------------------- 1 | // LED Audio Spectrum Analyzer Display 2 | // 3 | // Creates an impressive LED light show to music input 4 | // using Teensy 3.1 with the OctoWS2811 adaptor board 5 | // http://www.pjrc.com/store/teensy31.html 6 | // http://www.pjrc.com/store/octo28_adaptor.html 7 | // 8 | // Line Level Audio Input connects to analog pin A3 9 | // Recommended input circuit: 10 | // http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog 11 | // 12 | // This example code is in the public domain. 13 | 14 | #define USE_OCTOWS2811 15 | #include 16 | #include "FastLED/FastLED.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | FASTLED_USING_NAMESPACE; 22 | 23 | // The display size and color to use 24 | const unsigned int matrix_width = 60; 25 | const unsigned int matrix_height = 32; 26 | const unsigned int myColor = 0x400020; 27 | 28 | // These parameters adjust the vertical thresholds 29 | const float maxLevel = 0.5; // 1.0 = max, lower is more "sensitive" 30 | const float dynamicRange = 40.0; // total range to display, in decibels 31 | const float linearBlend = 0.3; // useful range is 0 to 0.7 32 | 33 | CRGB leds[matrix_width * matrix_height]; 34 | 35 | // Audio library objects 36 | AudioInputAnalog adc1(A3); //xy=99,55 37 | AudioAnalyzeFFT1024 fft; //xy=265,75 38 | AudioConnection patchCord1(adc1, fft); 39 | 40 | 41 | // This array holds the volume level (0 to 1.0) for each 42 | // vertical pixel to turn on. Computed in setup() using 43 | // the 3 parameters above. 44 | float thresholdVertical[matrix_height]; 45 | 46 | // This array specifies how many of the FFT frequency bin 47 | // to use for each horizontal pixel. Because humans hear 48 | // in octaves and FFT bins are linear, the low frequencies 49 | // use a small number of bins, higher frequencies use more. 50 | int frequencyBinsHorizontal[matrix_width] = { 51 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 53 | 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 54 | 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 55 | 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, 56 | 15, 16, 17, 18, 19, 20, 22, 23, 24, 25 57 | }; 58 | 59 | 60 | 61 | // Run setup once 62 | void setup() { 63 | // the audio library needs to be given memory to start working 64 | AudioMemory(12); 65 | 66 | // compute the vertical thresholds before starting 67 | computeVerticalLevels(); 68 | 69 | // turn on the display 70 | FastLED.addLeds(leds,(matrix_width * matrix_height) / 8); 71 | } 72 | 73 | // A simple xy() function to turn display matrix coordinates 74 | // into the index numbers OctoWS2811 requires. If your LEDs 75 | // are arranged differently, edit this code... 76 | unsigned int xy(unsigned int x, unsigned int y) { 77 | if ((y & 1) == 0) { 78 | // even numbered rows (0, 2, 4...) are left to right 79 | return y * matrix_width + x; 80 | } else { 81 | // odd numbered rows (1, 3, 5...) are right to left 82 | return y * matrix_width + matrix_width - 1 - x; 83 | } 84 | } 85 | 86 | // Run repetitively 87 | void loop() { 88 | unsigned int x, y, freqBin; 89 | float level; 90 | 91 | if (fft.available()) { 92 | // freqBin counts which FFT frequency data has been used, 93 | // starting at low frequency 94 | freqBin = 0; 95 | 96 | for (x=0; x < matrix_width; x++) { 97 | // get the volume for each horizontal pixel position 98 | level = fft.read(freqBin, freqBin + frequencyBinsHorizontal[x] - 1); 99 | 100 | // uncomment to see the spectrum in Arduino's Serial Monitor 101 | // Serial.print(level); 102 | // Serial.print(" "); 103 | 104 | for (y=0; y < matrix_height; y++) { 105 | // for each vertical pixel, check if above the threshold 106 | // and turn the LED on or off 107 | if (level >= thresholdVertical[y]) { 108 | leds[xy(x,y)] = CRGB(myColor); 109 | } else { 110 | leds[xy(x,y)] = CRGB::Black; 111 | } 112 | } 113 | // increment the frequency bin count, so we display 114 | // low to higher frequency from left to right 115 | freqBin = freqBin + frequencyBinsHorizontal[x]; 116 | } 117 | // after all pixels set, show them all at the same instant 118 | FastLED.show(); 119 | // Serial.println(); 120 | } 121 | } 122 | 123 | 124 | // Run once from setup, the compute the vertical levels 125 | void computeVerticalLevels() { 126 | unsigned int y; 127 | float n, logLevel, linearLevel; 128 | 129 | for (y=0; y < matrix_height; y++) { 130 | n = (float)y / (float)(matrix_height - 1); 131 | logLevel = pow10f(n * -1.0 * (dynamicRange / 20.0)); 132 | linearLevel = 1.0 - n; 133 | linearLevel = linearLevel * linearBlend; 134 | logLevel = logLevel * (1.0 - linearBlend); 135 | thresholdVertical[y] = (logLevel + linearLevel) * maxLevel; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /firmware/delay.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_DELAY_H 2 | #define __INC_DELAY_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | // Class to ensure that a minimum amount of time has kicked since the last time run - and delay if not enough time has passed yet 7 | // this should make sure that chipsets that have 8 | template class CMinWait { 9 | uint16_t mLastMicros; 10 | public: 11 | CMinWait() { mLastMicros = 0; } 12 | 13 | void wait() { 14 | uint16_t diff; 15 | do { 16 | diff = (micros() & 0xFFFF) - mLastMicros; 17 | } while(diff < WAIT); 18 | } 19 | 20 | void mark() { mLastMicros = micros() & 0xFFFF; } 21 | }; 22 | 23 | 24 | //////////////////////////////////////////////////////////////////////////////////////////// 25 | // 26 | // Clock cycle counted delay loop 27 | // 28 | //////////////////////////////////////////////////////////////////////////////////////////// 29 | 30 | #if defined(__arm__) 31 | # define NOP __asm__ __volatile__ ("nop\n"); 32 | # define NOP2 __asm__ __volatile__ ("nop\n\tnop"); 33 | #else 34 | # define NOP __asm__ __volatile__ ("cp r0,r0\n"); 35 | # define NOP2 __asm__ __volatile__ ("rjmp .+0"); 36 | #endif 37 | 38 | // predeclaration to not upset the compiler 39 | template inline void delaycycles(); 40 | template inline void delaycycles_min1() { 41 | delaycycles<1>(); 42 | delaycycles(); 43 | } 44 | 45 | 46 | // TODO: ARM version of _delaycycles_ 47 | 48 | // usable definition 49 | #if defined(FASTLED_AVR) 50 | // worker template - this will nop for LOOP * 3 + PAD cycles total 51 | template inline void _delaycycles_AVR() { 52 | delaycycles(); 53 | // the loop below is 3 cycles * LOOP. the LDI is one cycle, 54 | // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and 55 | // 1 if not (the LDI balances out the BRNE being 1 cycle on exit) 56 | __asm__ __volatile__ ( 57 | " LDI R16, %0\n" 58 | "L_%=: DEC R16\n" 59 | " BRNE L_%=\n" 60 | : /* no outputs */ 61 | : "M" (LOOP) 62 | : "r16" 63 | ); 64 | } 65 | 66 | template __attribute__((always_inline)) inline void delaycycles() { 67 | if(CYCLES > 0) _delaycycles_AVR(); 68 | } 69 | #else 70 | // template inline void _delaycycles_ARM() { 71 | // delaycycles(); 72 | // // the loop below is 3 cycles * LOOP. the LDI is one cycle, 73 | // // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and 74 | // // 1 if not (the LDI balances out the BRNE being 1 cycle on exit) 75 | // __asm__ __volatile__ ( 76 | // " mov.w r9, %0\n" 77 | // "L_%=: subs.w r9, r9, #1\n" 78 | // " bne.n L_%=\n" 79 | // : /* no outputs */ 80 | // : "M" (LOOP) 81 | // : "r9" 82 | // ); 83 | // } 84 | 85 | 86 | template __attribute__((always_inline)) inline void delaycycles() { 87 | // _delaycycles_ARM(); 88 | if(CYCLES > 0) { NOP; delaycycles(); } 89 | } 90 | #endif 91 | 92 | // pre-instantiations for values small enough to not need the loop, as well as sanity holders 93 | // for some negative values. 94 | template<> __attribute__((always_inline)) inline void delaycycles<-10>() {} 95 | template<> __attribute__((always_inline)) inline void delaycycles<-9>() {} 96 | template<> __attribute__((always_inline)) inline void delaycycles<-8>() {} 97 | template<> __attribute__((always_inline)) inline void delaycycles<-7>() {} 98 | template<> __attribute__((always_inline)) inline void delaycycles<-6>() {} 99 | template<> __attribute__((always_inline)) inline void delaycycles<-5>() {} 100 | template<> __attribute__((always_inline)) inline void delaycycles<-4>() {} 101 | template<> __attribute__((always_inline)) inline void delaycycles<-3>() {} 102 | template<> __attribute__((always_inline)) inline void delaycycles<-2>() {} 103 | template<> __attribute__((always_inline)) inline void delaycycles<-1>() {} 104 | template<> __attribute__((always_inline)) inline void delaycycles<0>() {} 105 | template<> __attribute__((always_inline)) inline void delaycycles<1>() {NOP;} 106 | template<> __attribute__((always_inline)) inline void delaycycles<2>() {NOP2;} 107 | template<> __attribute__((always_inline)) inline void delaycycles<3>() {NOP;NOP2;} 108 | template<> __attribute__((always_inline)) inline void delaycycles<4>() {NOP2;NOP2;} 109 | template<> __attribute__((always_inline)) inline void delaycycles<5>() {NOP2;NOP2;NOP;} 110 | 111 | // Some timing related macros/definitions 112 | 113 | // Macro to convert from nano-seconds to clocks and clocks to nano-seconds 114 | // #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L))) 115 | #if 1 || (F_CPU < 96000000) 116 | #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000 117 | #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L) 118 | #else 119 | #define NS(_NS) ( (_NS * (F_CPU / 2000000L))) / 1000 120 | #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 2000000L) 121 | #endif 122 | 123 | // Macro for making sure there's enough time available 124 | #define NO_TIME(A, B, C) (NS(A) < 3 || NS(B) < 3 || NS(C) < 6) 125 | 126 | FASTLED_NAMESPACE_END 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /firmware/platforms/arm/sam/clockless_arm_sam.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_CLOCKLESS_ARM_SAM_H 2 | #define __INC_CLOCKLESS_ARM_SAM_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | // Definition for a single channel clockless controller for the sam family of arm chips, like that used in the due and rfduino 7 | // See clockless.h for detailed info on how the template parameters are used. 8 | 9 | #if defined(__SAM3X8E__) 10 | 11 | 12 | #define TADJUST 0 13 | #define TOTAL ( (T1+TADJUST) + (T2+TADJUST) + (T3+TADJUST) ) 14 | #define T1_MARK (TOTAL - (T1+TADJUST)) 15 | #define T2_MARK (T1_MARK - (T2+TADJUST)) 16 | 17 | #define SCALE(S,V) scale8_video(S,V) 18 | // #define SCALE(S,V) scale8(S,V) 19 | #define FASTLED_HAS_CLOCKLESS 1 20 | 21 | template 22 | class ClocklessController : public CLEDController { 23 | typedef typename FastPinBB::port_ptr_t data_ptr_t; 24 | typedef typename FastPinBB::port_t data_t; 25 | 26 | data_t mPinMask; 27 | data_ptr_t mPort; 28 | CMinWait mWait; 29 | public: 30 | virtual void init() { 31 | FastPinBB::setOutput(); 32 | mPinMask = FastPinBB::mask(); 33 | mPort = FastPinBB::port(); 34 | } 35 | 36 | virtual void clearLeds(int nLeds) { 37 | showColor(CRGB(0, 0, 0), nLeds, 0); 38 | } 39 | 40 | protected: 41 | 42 | // set all the leds on the controller to a given color 43 | virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { 44 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 45 | mWait.wait(); 46 | showRGBInternal(pixels); 47 | mWait.mark(); 48 | } 49 | 50 | virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { 51 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 52 | mWait.wait(); 53 | showRGBInternal(pixels); 54 | mWait.mark(); 55 | } 56 | 57 | #ifdef SUPPORT_ARGB 58 | virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { 59 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 60 | mWait.wait(); 61 | showRGBInternal(pixels); 62 | sei(); 63 | mWait.mark(); 64 | } 65 | #endif 66 | 67 | 68 | template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register uint8_t & b) { 69 | // Make sure we don't slot into a wrapping spot, this will delay up to 12.5µs for WS2812 70 | // bool bShift=0; 71 | // while(VAL < (TOTAL*10)) { bShift=true; } 72 | // if(bShift) { next_mark = (VAL-TOTAL); }; 73 | 74 | for(register uint32_t i = BITS; i > 0; i--) { 75 | // wait to start the bit, then set the pin high 76 | while(DUE_TIMER_VAL < next_mark); 77 | next_mark = (DUE_TIMER_VAL+TOTAL); 78 | *port = 1; 79 | 80 | // how long we want to wait next depends on whether or not our bit is set to 1 or 0 81 | if(b&0x80) { 82 | // we're a 1, wait until there's less than T3 clocks left 83 | while((next_mark - DUE_TIMER_VAL) > (T3)); 84 | } else { 85 | // we're a 0, wait until there's less than (T2+T3+slop) clocks left in this bit 86 | while((next_mark - DUE_TIMER_VAL) > (T2+T3+6+TADJUST+TADJUST)); 87 | } 88 | *port=0; 89 | b <<= 1; 90 | } 91 | } 92 | 93 | #define FORCE_REFERENCE(var) asm volatile( "" : : "r" (var) ) 94 | // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then 95 | // gcc will use register Y for the this pointer. 96 | static uint32_t showRGBInternal(PixelController & pixels) { 97 | // Setup and start the clock 98 | TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1); 99 | pmc_enable_periph_clk(DUE_TIMER_ID); 100 | TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); 101 | 102 | register data_ptr_t port asm("r7") = FastPinBB::port(); FORCE_REFERENCE(port); 103 | *port = 0; 104 | 105 | // Setup the pixel controller and load/scale the first byte 106 | pixels.preStepFirstByteDithering(); 107 | register uint8_t b = pixels.loadAndScale0(); 108 | 109 | uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); 110 | while(pixels.has(1)) { 111 | pixels.stepDithering(); 112 | 113 | #if (FASTLED_ALLOW_INTERRUPTS == 1) 114 | cli(); 115 | if(DUE_TIMER_VAL > next_mark) { 116 | 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; } 117 | } 118 | #endif 119 | 120 | writeBits<8+XTRA0>(next_mark, port, b); 121 | 122 | b = pixels.loadAndScale1(); 123 | writeBits<8+XTRA0>(next_mark, port,b); 124 | 125 | b = pixels.loadAndScale2(); 126 | writeBits<8+XTRA0>(next_mark, port,b); 127 | 128 | b = pixels.advanceAndLoadAndScale0(); 129 | #if (FASTLED_ALLOW_INTERRUPTS == 1) 130 | sei(); 131 | #endif 132 | }; 133 | 134 | TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); 135 | return DUE_TIMER_VAL; 136 | } 137 | }; 138 | 139 | #endif 140 | 141 | FASTLED_NAMESPACE_END 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k20/clockless_arm_k20.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_CLOCKLESS_ARM_K20_H 2 | #define __INC_CLOCKLESS_ARM_K20_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | // Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 7 | // See clockless.h for detailed info on how the template parameters are used. 8 | #if defined(FASTLED_TEENSY3) 9 | 10 | #define FASTLED_HAS_CLOCKLESS 1 11 | 12 | template 13 | class ClocklessController : public CLEDController { 14 | typedef typename FastPin::port_ptr_t data_ptr_t; 15 | typedef typename FastPin::port_t data_t; 16 | 17 | data_t mPinMask; 18 | data_ptr_t mPort; 19 | CMinWait mWait; 20 | public: 21 | virtual void init() { 22 | FastPin::setOutput(); 23 | mPinMask = FastPin::mask(); 24 | mPort = FastPin::port(); 25 | } 26 | 27 | virtual void clearLeds(int nLeds) { 28 | showColor(CRGB(0, 0, 0), nLeds, 0); 29 | } 30 | 31 | protected: 32 | 33 | // set all the leds on the controller to a given color 34 | virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { 35 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 36 | 37 | mWait.wait(); 38 | showRGBInternal(pixels); 39 | mWait.mark(); 40 | } 41 | 42 | virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { 43 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 44 | 45 | mWait.wait(); 46 | showRGBInternal(pixels); 47 | mWait.mark(); 48 | } 49 | 50 | #ifdef SUPPORT_ARGB 51 | virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { 52 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 53 | mWait.wait(); 54 | showRGBInternal(pixels); 55 | mWait.mark(); 56 | } 57 | #endif 58 | 59 | template __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) { 60 | for(register uint32_t i = BITS-1; i > 0; i--) { 61 | while(ARM_DWT_CYCCNT < next_mark); 62 | next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); 63 | FastPin::fastset(port, hi); 64 | if(b&0x80) { 65 | while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); 66 | FastPin::fastset(port, lo); 67 | } else { 68 | while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); 69 | FastPin::fastset(port, lo); 70 | } 71 | b <<= 1; 72 | } 73 | 74 | while(ARM_DWT_CYCCNT < next_mark); 75 | next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); 76 | FastPin::fastset(port, hi); 77 | 78 | if(b&0x80) { 79 | while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); 80 | FastPin::fastset(port, lo); 81 | } else { 82 | while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); 83 | FastPin::fastset(port, lo); 84 | } 85 | } 86 | 87 | // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then 88 | // gcc will use register Y for the this pointer. 89 | static uint32_t showRGBInternal(PixelController & pixels) { 90 | // Get access to the clock 91 | ARM_DEMCR |= ARM_DEMCR_TRCENA; 92 | ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; 93 | ARM_DWT_CYCCNT = 0; 94 | 95 | register data_ptr_t port = FastPin::port(); 96 | register data_t hi = *port | FastPin::mask();; 97 | register data_t lo = *port & ~FastPin::mask();; 98 | *port = lo; 99 | 100 | // Setup the pixel controller and load/scale the first byte 101 | pixels.preStepFirstByteDithering(); 102 | register uint8_t b = pixels.loadAndScale0(); 103 | 104 | #if (FASTLED_ALLOW_INTERRUPTS == 1) 105 | cli(); 106 | #endif 107 | uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); 108 | 109 | while(pixels.has(1)) { 110 | pixels.stepDithering(); 111 | #if (FASTLED_ALLOW_INTERRUPTS == 1) 112 | cli(); 113 | // if interrupts took longer than 45µs, punt on the current frame 114 | if(ARM_DWT_CYCCNT > next_mark) { 115 | if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } 116 | } 117 | 118 | hi = *port | FastPin::mask(); 119 | lo = *port & ~FastPin::mask(); 120 | #endif 121 | // Write first byte, read next byte 122 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 123 | b = pixels.loadAndScale1(); 124 | 125 | // Write second byte, read 3rd byte 126 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 127 | b = pixels.loadAndScale2(); 128 | 129 | // Write third byte, read 1st byte of next pixel 130 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 131 | b = pixels.advanceAndLoadAndScale0(); 132 | #if (FASTLED_ALLOW_INTERRUPTS == 1) 133 | sei(); 134 | #endif 135 | }; 136 | 137 | return ARM_DWT_CYCCNT; 138 | } 139 | }; 140 | #endif 141 | 142 | FASTLED_NAMESPACE_END 143 | 144 | #endif 145 | -------------------------------------------------------------------------------- /firmware/clockless_arm_stm32.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_CLOCKLESS_ARM_STM32_H 2 | #define __INC_CLOCKLESS_ARM_STM32_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | // Definition for a single channel clockless controller for the stm32 family of chips, like that used in the spark core 6 | // See clockless.h for detailed info on how the template parameters are used. 7 | 8 | #define FASTLED_HAS_CLOCKLESS 1 9 | 10 | #if defined(STM32F2XX) 11 | // The photon runs faster than the 12 | #define ADJ 8 13 | #else 14 | #define ADJ 20 15 | #endif 16 | 17 | template 18 | class ClocklessController : public CLEDController { 19 | typedef typename FastPin::port_ptr_t data_ptr_t; 20 | typedef typename FastPin::port_t data_t; 21 | 22 | data_t mPinMask; 23 | data_ptr_t mPort; 24 | CMinWait mWait; 25 | public: 26 | virtual void init() { 27 | FastPin::setOutput(); 28 | mPinMask = FastPin::mask(); 29 | mPort = FastPin::port(); 30 | } 31 | 32 | virtual void clearLeds(int nLeds) { 33 | showColor(CRGB(0, 0, 0), nLeds, 0); 34 | } 35 | 36 | protected: 37 | 38 | // set all the leds on the controller to a given color 39 | virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { 40 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 41 | 42 | mWait.wait(); 43 | showRGBInternal(pixels); 44 | mWait.mark(); 45 | } 46 | 47 | virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { 48 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 49 | 50 | mWait.wait(); 51 | showRGBInternal(pixels); 52 | mWait.mark(); 53 | } 54 | 55 | #ifdef SUPPORT_ARGB 56 | virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { 57 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 58 | mWait.wait(); 59 | showRGBInternal(pixels); 60 | mWait.mark(); 61 | } 62 | #endif 63 | 64 | #define _CYCCNT (*(volatile uint32_t*)(0xE0001004UL)) 65 | 66 | template __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) { 67 | for(register uint32_t i = BITS-1; i > 0; i--) { 68 | while(_CYCCNT < (T1+T2+T3-ADJ)); 69 | FastPin::fastset(port, hi); 70 | _CYCCNT = 4; 71 | if(b&0x80) { 72 | while(_CYCCNT < (T1+T2-ADJ)); 73 | FastPin::fastset(port, lo); 74 | } else { 75 | while(_CYCCNT < (T1-(ADJ/2))); 76 | FastPin::fastset(port, lo); 77 | } 78 | b <<= 1; 79 | } 80 | 81 | while(_CYCCNT < (T1+T2+T3-ADJ)); 82 | FastPin::fastset(port, hi); 83 | _CYCCNT = 4; 84 | 85 | if(b&0x80) { 86 | while(_CYCCNT < (T1+T2-ADJ)); 87 | FastPin::fastset(port, lo); 88 | } else { 89 | while(_CYCCNT < (T1-(ADJ/2))); 90 | FastPin::fastset(port, lo); 91 | } 92 | } 93 | 94 | // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then 95 | // gcc will use register Y for the this pointer. 96 | static uint32_t showRGBInternal(PixelController & pixels) { 97 | // Get access to the clock 98 | CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 99 | DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; 100 | DWT->CYCCNT = 0; 101 | 102 | register data_ptr_t port = FastPin::port(); 103 | register data_t hi = *port | FastPin::mask();; 104 | register data_t lo = *port & ~FastPin::mask();; 105 | *port = lo; 106 | 107 | // Setup the pixel controller and load/scale the first byte 108 | pixels.preStepFirstByteDithering(); 109 | register uint8_t b = pixels.loadAndScale0(); 110 | 111 | cli(); 112 | 113 | uint32_t next_mark = (T1+T2+T3); 114 | 115 | DWT->CYCCNT = 0; 116 | while(pixels.has(1)) { 117 | pixels.stepDithering(); 118 | #if (FASTLED_ALLOW_INTERRUPTS == 1) 119 | cli(); 120 | // if interrupts took longer than 45µs, punt on the current frame 121 | if(DWT->CYCCNT > next_mark) { 122 | if((DWT->CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return DWT->CYCCNT; } 123 | } 124 | 125 | hi = *port | FastPin::mask(); 126 | lo = *port & ~FastPin::mask(); 127 | #endif 128 | 129 | // Write first byte, read next byte 130 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 131 | b = pixels.loadAndScale1(); 132 | 133 | // Write second byte, read 3rd byte 134 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 135 | b = pixels.loadAndScale2(); 136 | 137 | // Write third byte, read 1st byte of next pixel 138 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 139 | b = pixels.advanceAndLoadAndScale0(); 140 | #if (FASTLED_ALLOW_INTERRUPTS == 1) 141 | sei(); 142 | #endif 143 | }; 144 | 145 | sei(); 146 | return DWT->CYCCNT; 147 | } 148 | }; 149 | 150 | FASTLED_NAMESPACE_END 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /firmware/colorpalettes.cpp: -------------------------------------------------------------------------------- 1 | #ifndef __INC_COLORPALETTES_H 2 | #define __INC_COLORPALETTES_H 3 | #define FASTLED_INTERNAL 4 | #include "FastLED.h" 5 | #include "colorutils.h" 6 | #include "colorpalettes.h" 7 | 8 | FASTLED_NAMESPACE_BEGIN 9 | 10 | // Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734 11 | #ifdef FASTLED_AVR 12 | #ifdef PROGMEM 13 | #undef PROGMEM 14 | #define PROGMEM __attribute__((section(".progmem.data"))) 15 | #endif 16 | #endif 17 | 18 | 19 | 20 | // Preset color schemes, such as they are. 21 | 22 | // These schemes are all declared as "PROGMEM", meaning 23 | // that they won't take up SRAM on AVR chips until used. 24 | // Furthermore, the compiler won't even include these 25 | // in your PROGMEM (flash) storage unless you specifically 26 | // use each one, so you only 'pay for' those you actually use. 27 | 28 | 29 | extern const TProgmemRGBPalette16 CloudColors_p PROGMEM = 30 | { 31 | CRGB::Blue, 32 | CRGB::DarkBlue, 33 | CRGB::DarkBlue, 34 | CRGB::DarkBlue, 35 | 36 | CRGB::DarkBlue, 37 | CRGB::DarkBlue, 38 | CRGB::DarkBlue, 39 | CRGB::DarkBlue, 40 | 41 | CRGB::Blue, 42 | CRGB::DarkBlue, 43 | CRGB::SkyBlue, 44 | CRGB::SkyBlue, 45 | 46 | CRGB::LightBlue, 47 | CRGB::White, 48 | CRGB::LightBlue, 49 | CRGB::SkyBlue 50 | }; 51 | 52 | extern const TProgmemRGBPalette16 LavaColors_p PROGMEM = 53 | { 54 | CRGB::Black, 55 | CRGB::Maroon, 56 | CRGB::Black, 57 | CRGB::Maroon, 58 | 59 | CRGB::DarkRed, 60 | CRGB::Maroon, 61 | CRGB::DarkRed, 62 | 63 | CRGB::DarkRed, 64 | CRGB::DarkRed, 65 | CRGB::Red, 66 | CRGB::Orange, 67 | 68 | CRGB::White, 69 | CRGB::Orange, 70 | CRGB::Red, 71 | CRGB::DarkRed 72 | }; 73 | 74 | 75 | extern const TProgmemRGBPalette16 OceanColors_p PROGMEM = 76 | { 77 | CRGB::MidnightBlue, 78 | CRGB::DarkBlue, 79 | CRGB::MidnightBlue, 80 | CRGB::Navy, 81 | 82 | CRGB::DarkBlue, 83 | CRGB::MediumBlue, 84 | CRGB::SeaGreen, 85 | CRGB::Teal, 86 | 87 | CRGB::CadetBlue, 88 | CRGB::Blue, 89 | CRGB::DarkCyan, 90 | CRGB::CornflowerBlue, 91 | 92 | CRGB::Aquamarine, 93 | CRGB::SeaGreen, 94 | CRGB::Aqua, 95 | CRGB::LightSkyBlue 96 | }; 97 | 98 | extern const TProgmemRGBPalette16 ForestColors_p PROGMEM = 99 | { 100 | CRGB::DarkGreen, 101 | CRGB::DarkGreen, 102 | CRGB::DarkOliveGreen, 103 | CRGB::DarkGreen, 104 | 105 | CRGB::Green, 106 | CRGB::ForestGreen, 107 | CRGB::OliveDrab, 108 | CRGB::Green, 109 | 110 | CRGB::SeaGreen, 111 | CRGB::MediumAquamarine, 112 | CRGB::LimeGreen, 113 | CRGB::YellowGreen, 114 | 115 | CRGB::LightGreen, 116 | CRGB::LawnGreen, 117 | CRGB::MediumAquamarine, 118 | CRGB::ForestGreen 119 | }; 120 | 121 | /// HSV Rainbow 122 | extern const TProgmemRGBPalette16 RainbowColors_p PROGMEM = 123 | { 124 | 0xFF0000, 0xD52A00, 0xAB5500, 0xAB7F00, 125 | 0xABAB00, 0x56D500, 0x00FF00, 0x00D52A, 126 | 0x00AB55, 0x0056AA, 0x0000FF, 0x2A00D5, 127 | 0x5500AB, 0x7F0081, 0xAB0055, 0xD5002B 128 | }; 129 | 130 | /// HSV Rainbow colors with alternatating stripes of black 131 | #define RainbowStripesColors_p RainbowStripeColors_p 132 | extern const TProgmemRGBPalette16 RainbowStripeColors_p PROGMEM = 133 | { 134 | 0xFF0000, 0x000000, 0xAB5500, 0x000000, 135 | 0xABAB00, 0x000000, 0x00FF00, 0x000000, 136 | 0x00AB55, 0x000000, 0x0000FF, 0x000000, 137 | 0x5500AB, 0x000000, 0xAB0055, 0x000000 138 | }; 139 | 140 | /// HSV color ramp: blue purple ping red orange yellow (and back) 141 | /// Basically, everything but the greens, which tend to make 142 | /// people's skin look unhealthy. This palette is good for 143 | /// lighting at a club or party, where it'll be shining on people. 144 | extern const TProgmemRGBPalette16 PartyColors_p PROGMEM = 145 | { 146 | 0x5500AB, 0x84007C, 0xB5004B, 0xE5001B, 147 | 0xE81700, 0xB84700, 0xAB7700, 0xABAB00, 148 | 0xAB5500, 0xDD2200, 0xF2000E, 0xC2003E, 149 | 0x8F0071, 0x5F00A1, 0x2F00D0, 0x0007F9 150 | }; 151 | 152 | /// Approximate "black body radiation" palette, akin to 153 | /// the FastLED 'HeatColor' function. 154 | /// Recommend that you use values 0-240 rather than 155 | /// the usual 0-255, as the last 15 colors will be 156 | /// 'wrapping around' from the hot end to the cold end, 157 | /// which looks wrong. 158 | extern const TProgmemRGBPalette16 HeatColors_p PROGMEM = 159 | { 160 | 0x000000, 161 | 0x330000, 0x660000, 0x990000, 0xCC0000, 0xFF0000, 162 | 0xFF3300, 0xFF6600, 0xFF9900, 0xFFCC00, 0xFFFF00, 163 | 0xFFFF33, 0xFFFF66, 0xFFFF99, 0xFFFFCC, 0xFFFFFF 164 | }; 165 | 166 | 167 | // Gradient palette "Rainbow_gp", 168 | // provided for situations where you're going 169 | // to use a number of other gradient palettes, AND 170 | // you want a 'standard' FastLED rainbow as well. 171 | 172 | DEFINE_GRADIENT_PALETTE( Rainbow_gp ) { 173 | 0, 255, 0, 0, // Red 174 | 32, 171, 85, 0, // Orange 175 | 64, 171,171, 0, // Yellow 176 | 96, 0,255, 0, // Green 177 | 128, 0,171, 85, // Aqua 178 | 160, 0, 0,255, // Blue 179 | 192, 85, 0,171, // Purple 180 | 224, 171, 0, 85, // Pink 181 | 255, 255, 0, 0};// and back to Red 182 | 183 | FASTLED_NAMESPACE_END 184 | 185 | #endif 186 | 187 | -------------------------------------------------------------------------------- /firmware/fastpin_arm_stm32.h: -------------------------------------------------------------------------------- 1 | #ifndef __FASTPIN_ARM_STM32_H 2 | #define __FASTPIN_ARM_STM32_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | #if defined(FASTLED_FORCE_SOFTWARE_PINS) 7 | #warning "Software pin support forced, pin access will be sloightly slower." 8 | #define NO_HARDWARE_PIN_SUPPORT 9 | #undef HAS_HARDWARE_PIN_SUPPORT 10 | 11 | #else 12 | 13 | /// Template definition for STM32 style ARM pins, providing direct access to the various GPIO registers. Note that this 14 | /// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found 15 | /// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. 16 | /// The registers are data output, set output, clear output, toggle output, input, and direction 17 | 18 | template class _ARMPIN { 19 | public: 20 | typedef volatile uint32_t * port_ptr_t; 21 | typedef uint32_t port_t; 22 | 23 | #if 0 24 | inline static void setOutput() { 25 | if(_BIT<8) { 26 | _CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4)); 27 | } else { 28 | _CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4)); 29 | } 30 | } 31 | inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } 32 | #endif 33 | 34 | inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } 35 | inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } 36 | 37 | #if defined(STM32F2XX) 38 | inline static void hi() __attribute__ ((always_inline)) { _GPIO::r()->BSRRL = _MASK; } 39 | inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BSRRH = _MASK; } 40 | #else 41 | inline static void hi() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = _MASK; } 42 | inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BRR = _MASK; } 43 | // inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = (_MASK<<16); } 44 | #endif 45 | inline static void set(register port_t val) __attribute__ ((always_inline)) { _GPIO::r()->ODR = val; } 46 | 47 | inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } 48 | 49 | inline static void toggle() __attribute__ ((always_inline)) { if(_GPIO::r()->ODR & _MASK) { lo(); } else { hi(); } } 50 | 51 | inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } 52 | inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } 53 | inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } 54 | 55 | inline static port_t hival() __attribute__ ((always_inline)) { return _GPIO::r()->ODR | _MASK; } 56 | inline static port_t loval() __attribute__ ((always_inline)) { return _GPIO::r()->ODR & ~_MASK; } 57 | inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_GPIO::r()->ODR; } 58 | #if defined(STM32F2XX) 59 | inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRRL; } 60 | inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRRH; } 61 | #else 62 | inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRR; } 63 | inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO::r()->BRR; } 64 | #endif 65 | inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } 66 | }; 67 | 68 | #define _R(T) struct __gen_struct_ ## T 69 | #define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile GPIO_TypeDef * r() { return T; } }; 70 | 71 | #define _IO32(L) _RD32(GPIO ## L) 72 | 73 | #define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin : public _ARMPIN {}; 74 | 75 | // Actual pin definitions 76 | #if defined(SPARK) 77 | 78 | _IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); _IO32(F); _IO32(G); 79 | 80 | #if defined(STM32F2XX) 81 | #define MAX_PIN 19 82 | _DEFPIN_ARM(0, 7, B); 83 | _DEFPIN_ARM(1, 6, B); 84 | _DEFPIN_ARM(2, 5, B); 85 | _DEFPIN_ARM(3, 4, B); 86 | _DEFPIN_ARM(4, 3, B); 87 | _DEFPIN_ARM(5, 15, A); 88 | _DEFPIN_ARM(6, 14, A); 89 | _DEFPIN_ARM(7, 13, A); 90 | _DEFPIN_ARM(10, 5, C); 91 | _DEFPIN_ARM(11, 3, C); 92 | _DEFPIN_ARM(12, 2, C); 93 | _DEFPIN_ARM(13, 5, A); 94 | _DEFPIN_ARM(14, 6, A); 95 | _DEFPIN_ARM(15, 7, A); 96 | _DEFPIN_ARM(16, 4, A); 97 | _DEFPIN_ARM(17, 0, A); 98 | _DEFPIN_ARM(18, 10, A); 99 | _DEFPIN_ARM(19, 9, A); 100 | _DEFPIN_ARM(20, 7, C); 101 | 102 | #else 103 | #define MAX_PIN 19 104 | _DEFPIN_ARM(0, 7, B); 105 | _DEFPIN_ARM(1, 6, B); 106 | _DEFPIN_ARM(2, 5, B); 107 | _DEFPIN_ARM(3, 4, B); 108 | _DEFPIN_ARM(4, 3, B); 109 | _DEFPIN_ARM(5, 15, A); 110 | _DEFPIN_ARM(6, 14, A); 111 | _DEFPIN_ARM(7, 13, A); 112 | _DEFPIN_ARM(8, 8, A); 113 | _DEFPIN_ARM(9, 9, A); 114 | _DEFPIN_ARM(10, 0, A); 115 | _DEFPIN_ARM(11, 1, A); 116 | _DEFPIN_ARM(12, 4, A); 117 | _DEFPIN_ARM(13, 5, A); 118 | _DEFPIN_ARM(14, 6, A); 119 | _DEFPIN_ARM(15, 7, A); 120 | _DEFPIN_ARM(16, 0, B); 121 | _DEFPIN_ARM(17, 1, B); 122 | _DEFPIN_ARM(18, 3, A); 123 | _DEFPIN_ARM(19, 2, A); 124 | 125 | #endif 126 | 127 | #define SPI_DATA 15 128 | #define SPI_CLOCK 13 129 | 130 | #define HAS_HARDWARE_PIN_SUPPORT 131 | 132 | #endif 133 | 134 | #endif // FASTLED_FORCE_SOFTWARE_PINS 135 | 136 | FASTLED_NAMESPACE_END 137 | 138 | #endif // __INC_FASTPIN_ARM_STM32 139 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k26/clockless_arm_k26.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_CLOCKLESS_ARM_K20_H 2 | #define __INC_CLOCKLESS_ARM_K20_H 3 | 4 | // Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 5 | // See clockless.h for detailed info on how the template parameters are used. 6 | #if defined(FASTLED_TEENSYLC) 7 | FASTLED_NAMESPACE_BEGIN 8 | 9 | #define FASTLED_HAS_CLOCKLESS 1 10 | 11 | #define FASTLED_K26_TIMER_CNT FTM1_CNT 12 | #define FASTLED_K26_TIMER_SC FTM1_SC 13 | 14 | template 15 | class ClocklessController : public CLEDController { 16 | typedef typename FastPin::port_ptr_t data_ptr_t; 17 | typedef typename FastPin::port_t data_t; 18 | 19 | data_t mPinMask; 20 | data_ptr_t mPort; 21 | CMinWait mWait; 22 | public: 23 | virtual void init() { 24 | FastPin::setOutput(); 25 | mPinMask = FastPin::mask(); 26 | mPort = FastPin::port(); 27 | } 28 | 29 | virtual void clearLeds(int nLeds) { 30 | showColor(CRGB(0, 0, 0), nLeds, 0); 31 | } 32 | 33 | protected: 34 | 35 | // set all the leds on the controller to a given color 36 | virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { 37 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 38 | 39 | mWait.wait(); 40 | showRGBInternal(pixels); 41 | mWait.mark(); 42 | } 43 | 44 | virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { 45 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 46 | 47 | mWait.wait(); 48 | showRGBInternal(pixels); 49 | mWait.mark(); 50 | } 51 | 52 | #ifdef SUPPORT_ARGB 53 | virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { 54 | PixelController pixels(rgbdata, nLeds, scale, getDither()); 55 | mWait.wait(); 56 | showRGBInternal(pixels); 57 | mWait.mark(); 58 | } 59 | #endif 60 | 61 | template __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) { 62 | for(register uint32_t i = BITS-1; i > 0; i--) { 63 | while(!(FTM1_STATUS & 0x100)); 64 | FASTLED_K26_TIMER_CNT = 0; 65 | FTM1_STATUS = 0x1FF; 66 | FastPin::fastset(port, hi); 67 | if(b&0x80) { 68 | while(!(FTM1_STATUS & 0x02)); 69 | FastPin::fastset(port, lo); 70 | } else { 71 | while(!(FTM1_STATUS & 0x01)); 72 | FastPin::fastset(port, lo); 73 | } 74 | b <<= 1; 75 | } 76 | 77 | while(!(FTM1_STATUS & 0x100)); 78 | FASTLED_K26_TIMER_CNT = 0; 79 | FTM1_STATUS = 0x1FF; 80 | FastPin::fastset(port, hi); 81 | 82 | if(b&0x80) { 83 | while(!(FTM1_STATUS & 0x02)); 84 | FastPin::fastset(port, lo); 85 | } else { 86 | while(!(FTM1_STATUS & 0x01)); 87 | FastPin::fastset(port, lo); 88 | } 89 | } 90 | 91 | // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then 92 | // gcc will use register Y for the this pointer. 93 | static uint32_t showRGBInternal(PixelController & pixels) { 94 | 95 | register data_ptr_t port = FastPin::port(); 96 | register data_t hi = *port | FastPin::mask();; 97 | register data_t lo = *port & ~FastPin::mask();; 98 | *port = lo; 99 | 100 | // Setup the pixel controller and load/scale the first byte 101 | pixels.preStepFirstByteDithering(); 102 | register uint8_t b = pixels.loadAndScale0(); 103 | 104 | cli(); 105 | // Get access to the clock 106 | FASTLED_K26_TIMER_SC = FTM_SC_PS(0) | FTM_SC_CLKS(0); 107 | FTM1_CONF = 0; 108 | 109 | // Clear the channel modes 110 | FTM1_C0SC = 0; 111 | FTM1_C1SC = 0; 112 | 113 | // Set the channel values for T1 114 | FTM1_C0SC = FTM_CSC_MSA | FTM_CSC_ELSB | FTM_CSC_ELSA; 115 | FTM1_C0V = T1; 116 | 117 | // Set the channel values for T1+T2 118 | FTM1_C1SC = FTM_CSC_MSA | FTM_CSC_ELSB | FTM_CSC_ELSA; 119 | FTM1_C1V = (T1+T2); 120 | 121 | // Set the overflow for the full pixel 122 | FTM1_MOD = (T1 + T2 + T3); 123 | 124 | uint32_t next_mark = 0; // + (T1+T2+T3); 125 | 126 | pixels.stepDithering(); 127 | 128 | FASTLED_K26_TIMER_CNT = 0; 129 | FTM1_STATUS = 0x1FF; 130 | while(pixels.has(1)) { 131 | // #if (FASTLED_ALLOW_INTERRUPTS == 1) 132 | // cli(); 133 | // // if interrupts took longer than 45µs, punt on the current frame 134 | // if(ARM_DWT_CYCCNT > next_mark) { 135 | // if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } 136 | // } 137 | // #endif 138 | 139 | // Write first byte, read next byte 140 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 141 | b = pixels.loadAndScale1(); 142 | 143 | // Write second byte, read 3rd byte 144 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 145 | b = pixels.loadAndScale2(); 146 | 147 | // Write third byte, read 1st byte of next pixel 148 | writeBits<8+XTRA0>(next_mark, port, hi, lo, b); 149 | b = pixels.advanceAndLoadAndScale0(); 150 | // #if (FASTLED_ALLOW_INTERRUPTS == 1) 151 | // sei(); 152 | // #endif 153 | pixels.stepDithering(); 154 | }; 155 | 156 | FASTLED_K26_TIMER_SC = 0; 157 | sei(); 158 | return ARM_DWT_CYCCNT; 159 | } 160 | }; 161 | FASTLED_NAMESPACE_END 162 | 163 | #endif 164 | 165 | #endif 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IMPORTANT NOTE: For AVR based systems, avr-gcc 4.8.x is supported, as is avr-gcc 4.3 and earlier. There are known issues with avr-gcc 4.7 and timing based chipsets like the WS2812B. If you are using a linux system make sure you are using avr-gcc 4.8.x not avr-gcc 4.7.x. 2 | 3 | 4 | FastLED 3.0 5 | =========== 6 | 7 | IMPORTANT NOTE: If you are building for AVR based systems, please do not use any version of the arduino 8 | IDE 1.5.7 or later yet. It messes with some of the asm output which will cause you problems. 9 | 10 | This is a library for easily & efficiently controlling a wide variety of LED chipsets, like the ones 11 | sold by adafruit (Neopixel, LPD8806), Sparkfun (WS2801), and aliexpress. In addition to writing to the 12 | leds, this library also includes a number of functions for high-performing 8bit math for manipulating 13 | your RGB values, as well as low level classes for abstracting out access to pins and SPI hardware, while 14 | still keeping things as fast as possible. 15 | 16 | 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! 17 | 18 | We have multiple goals with this library: 19 | 20 | * Quick start for new developers - hook up your leds and go, no need to think about specifics of the led chipsets being used 21 | * Zero pain switching LED chipsets - you get some new leds that the library supports, just change the definition of LEDs you're using, et. voila! Your code is running with the new leds. 22 | * High performance - with features like zero cost global brightness scaling, high performance 8-bit math for RGB manipulation, and some of the fastest bit-bang'd SPI support around, FastLED wants to keep as many CPU cycles available for your led patterns as possible 23 | 24 | ## Getting help 25 | 26 | If you need help with using the library, please consider going to the google+ community first, which is at http://fastled.io/+ - 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. 27 | 28 | ## Simple example 29 | 30 | How quickly can you get up and running with the library? Here's a simple blink program: 31 | 32 | #include "FastLED.h" 33 | #define NUM_LEDS 60 34 | CRGB leds[NUM_LEDS]; 35 | void setup() { FastLED.addLeds(leds, NUM_LEDS); } 36 | void loop() { 37 | leds[0] = CRGB::White; FastLED.show(); delay(30); 38 | leds[0] = CRGB::Black; FastLED.show(); delay(30); 39 | } 40 | 41 | ## Supported LED chipsets 42 | 43 | Here's a list of all the LED chipsets are supported. More details on the led chipsets are included *TODO: Link to wiki page* 44 | 45 | * Adafruit's Neopixel - aka the WS2812B (also WS2811/WS2812, also suppored in lo-speed mode) - a 3 wire addressable led chipset 46 | * TM1809/4 - 3 wire chipset, cheaply available on aliexpress.com 47 | * TM1803 - 3 wire chipset, sold by radio shack 48 | * UCS1903 - another 3 wire led chipset, cheap 49 | * GW6205 - another 3 wire led chipset 50 | * LPD8806 - SPI based chpiset, very high speed 51 | * WS2801 - SPI based chipset, cheap and widely available 52 | * SM16716 - SPI based chipset 53 | * APA102 - SPI based chipset 54 | * P9813 - aka Cool Neon's Total Control Lighting 55 | * DMX - send rgb data out over DMX using arduino DMX libraries 56 | * SmartMatrix panels - needs the SmartMatrix library - https://github.com/pixelmatix/SmartMatrix 57 | 58 | 59 | LPD6803, HL1606, and "595"-style shift registers are no longer supported by the library. The older Version 1 of the library ("FastSPI_LED") has support for these, but is missing many of the advanced features of current versions and is no longer being maintained. 60 | 61 | 62 | ## Supported platforms 63 | 64 | Right now the library is supported on a variety of arduino compatable platforms. If it's ARM or AVR and uses the arduino software (or a modified version of it to build) then it is likely supported. Note that we have a long list of upcoming platforms to support, so if you don't see what you're looking for here, ask, it may be on the roadmap (or may already be supported). N.B. at the moment we are only supporting the stock compilers that ship with the arduino software. Support for upgraded compilers, as well as using AVR studio and skipping the arduino entirely, should be coming in a near future release. 65 | 66 | * Arduino & compatibles - straight up arduino devices, uno, duo, leonardo, mega, nano, etc... 67 | * Adafruit Trinket & Gemma - Trinket Pro may be supported, but haven't tested to confirm yet 68 | * Teensy 2, Teensy++ 2, Teensy 3.1 - arduino compataible from pjrc.com with some extra goodies (note the teensy 3 is ARM, not AVR!) 69 | * Arduino Due and the digistump DigiX 70 | 71 | What types of platforms are we thinking about supporting in the future? Here's a short list: RFDuino, SparkCore, MSP430, ChipKit32, Maple, Beagleboard 72 | 73 | ## What about that name? 74 | 75 | Wait, what happend to FastSPI_LED and FastSPI_LED2? The library was initially named FastSPI_LED because it was focused on very fast and efficient SPI access. However, since then, the library has expanded to support a number of LED chipsets that don't use SPI, as well as a number of math and utility functions for LED processing across the board. We decided that the name FastLED more accurately represents the totality of what the library provides, everything fast, for LEDs. 76 | 77 | ## For more information 78 | 79 | Check out the official site http://fastled.io for links to documentation, issues, and news 80 | 81 | 82 | *TODO* - get candy 83 | 84 | -------------------------------------------------------------------------------- /firmware/platforms/arm/sam/fastspi_arm_sam.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_FASTSPI_ARM_SAM_H 2 | #define __INC_FASTSPI_ARM_SAM_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | #if defined(__SAM3X8E__) 7 | #define m_SPI ((Spi*)SPI0) 8 | 9 | template 10 | class SAMHardwareSPIOutput { 11 | Selectable *m_pSelect; 12 | 13 | static inline void waitForEmpty() { while ((m_SPI->SPI_SR & SPI_SR_TDRE) == 0); } 14 | 15 | void enableConfig() { m_SPI->SPI_WPMR &= ~SPI_WPMR_WPEN; } 16 | void disableConfig() { m_SPI->SPI_WPMR |= SPI_WPMR_WPEN; } 17 | 18 | void enableSPI() { m_SPI->SPI_CR = SPI_CR_SPIEN; } 19 | void disableSPI() { m_SPI->SPI_CR = SPI_CR_SPIDIS; } 20 | void resetSPI() { m_SPI->SPI_CR = SPI_CR_SWRST; } 21 | 22 | static inline void readyTransferBits(register uint32_t bits) { 23 | bits -= 8; 24 | // don't change the number of transfer bits while data is still being transferred from TDR to the shift register 25 | waitForEmpty(); 26 | m_SPI->SPI_CSR[0] = SPI_CSR_NCPHA | SPI_CSR_CSAAT | (bits << SPI_CSR_BITS_Pos) | SPI_CSR_DLYBCT(1) | SPI_CSR_SCBR(_SPI_CLOCK_DIVIDER); 27 | } 28 | 29 | template static inline void writeBits(uint16_t w) { 30 | waitForEmpty(); 31 | m_SPI->SPI_TDR = (uint32_t)w | SPI_PCS(0); 32 | } 33 | 34 | public: 35 | SAMHardwareSPIOutput() { m_pSelect = NULL; } 36 | SAMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } 37 | 38 | // set the object representing the selectable 39 | void setSelect(Selectable *pSelect) { /* TODO */ } 40 | 41 | // initialize the SPI subssytem 42 | void init() { 43 | // m_SPI = SPI0; 44 | 45 | // set the output pins master out, master in, clock. Note doing this here because I still don't 46 | // know how I want to expose this type of functionality in FastPin. 47 | PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_DATA_PIN>::mask(), PIO_DEFAULT); 48 | PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_DATA_PIN-1>::mask(), PIO_DEFAULT); 49 | PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_CLOCK_PIN>::mask(), PIO_DEFAULT); 50 | 51 | release(); 52 | 53 | // Configure the SPI clock, divider between 1-255 54 | // SCBR = _SPI_CLOCK_DIVIDER 55 | pmc_enable_periph_clk(ID_SPI0); 56 | disableSPI(); 57 | 58 | // reset twice (what the sam code does, not sure why?) 59 | resetSPI(); 60 | resetSPI(); 61 | 62 | // Configure SPI as master, enable 63 | // Bits we want in MR: master, disable mode fault detection, variable peripheral select 64 | m_SPI->SPI_MR = SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PS; 65 | 66 | enableSPI(); 67 | 68 | // Send everything out in 8 bit chunks, other sizes appear to work, poorly... 69 | readyTransferBits(8); 70 | } 71 | 72 | // latch the CS select 73 | void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } 74 | 75 | // release the CS select 76 | void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } 77 | 78 | // wait until all queued up data has been written 79 | void waitFully() { while((m_SPI->SPI_SR & SPI_SR_TXEMPTY) == 0); } 80 | 81 | // write a byte out via SPI (returns immediately on writing register) 82 | static void writeByte(uint8_t b) { 83 | writeBits<8>(b); 84 | } 85 | 86 | // write a word out via SPI (returns immediately on writing register) 87 | static void writeWord(uint16_t w) { 88 | writeBits<16>(w); 89 | } 90 | 91 | // A raw set of writing byte values, assumes setup/init/waiting done elsewhere 92 | static void writeBytesValueRaw(uint8_t value, int len) { 93 | while(len--) { writeByte(value); } 94 | } 95 | 96 | // A full cycle of writing a value for len bytes, including select, release, and waiting 97 | void writeBytesValue(uint8_t value, int len) { 98 | select(); writeBytesValueRaw(value, len); release(); 99 | } 100 | 101 | template void writeBytes(register uint8_t *data, int len) { 102 | uint8_t *end = data + len; 103 | select(); 104 | // could be optimized to write 16bit words out instead of 8bit bytes 105 | while(data != end) { 106 | writeByte(D::adjust(*data++)); 107 | } 108 | D::postBlock(len); 109 | waitFully(); 110 | release(); 111 | } 112 | 113 | void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } 114 | 115 | // write a single bit out, which bit from the passed in byte is determined by template parameter 116 | // not the most efficient mechanism in the world - but should be enough for sm16716 and friends 117 | template inline void writeBit(uint8_t b) { 118 | // need to wait for all exisiting data to go out the door, first 119 | waitFully(); 120 | disableSPI(); 121 | if(b & (1 << BIT)) { 122 | FastPin<_DATA_PIN>::hi(); 123 | } else { 124 | FastPin<_DATA_PIN>::lo(); 125 | } 126 | 127 | FastPin<_CLOCK_PIN>::hi(); 128 | FastPin<_CLOCK_PIN>::lo(); 129 | enableSPI(); 130 | } 131 | 132 | // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template 133 | // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping 134 | template void writePixels(PixelController pixels) { 135 | select(); 136 | int len = pixels.mLen; 137 | 138 | if(FLAGS & FLAG_START_BIT) { 139 | while(pixels.has(1)) { 140 | writeBits<9>((1<<8) | D::adjust(pixels.loadAndScale0())); 141 | writeByte(D::adjust(pixels.loadAndScale1())); 142 | writeByte(D::adjust(pixels.loadAndScale2())); 143 | pixels.advanceData(); 144 | pixels.stepDithering(); 145 | } 146 | } else { 147 | while(pixels.has(1)) { 148 | writeByte(D::adjust(pixels.loadAndScale0())); 149 | writeByte(D::adjust(pixels.loadAndScale1())); 150 | writeByte(D::adjust(pixels.loadAndScale2())); 151 | pixels.advanceData(); 152 | pixels.stepDithering(); 153 | } 154 | } 155 | D::postBlock(len); 156 | release(); 157 | } 158 | }; 159 | 160 | #endif 161 | 162 | FASTLED_NAMESPACE_END 163 | #endif 164 | -------------------------------------------------------------------------------- /firmware/noise.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_NOISE_H 2 | #define __INC_NOISE_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | #if 0 7 | /// Class for accessing 16 bit noise. Provides methods for setting origin, scale, 8 | /// frequency, alplitude, time, octave blurring 9 | class CFastNoise16 { 10 | public: 11 | CFastNoise16 &setOrigin(uint32_t x, uint32_t y, uint32_t z); 12 | CFastNoise16 &setOrigin(uint32_t x, uint32_t y); 13 | CFastNoise16 &setOrigin(uint32_t x); 14 | 15 | uint32_t getX(); 16 | uint32_t getY(); 17 | uint32_t getZ(); 18 | uint32_t getTime(); 19 | 20 | uint32_t getOrigin(uint32_t & x, uint32_t & y, uint32_t & z); 21 | uint32_t getOrigin(uint32_t & x, uint32_t & y); 22 | uint32_t getOrigin(uint32_t & x); 23 | 24 | CFastNoise16 &advance(int32_t x, int32_t y, int32_t z); 25 | CFastNoise16 &advance(int32_t x, int32_t y; 26 | CFastNoise16 &advance(int32_t x); 27 | 28 | CFastNoise16 &advanceTime(int32_t t); 29 | 30 | CFastNoise16 &setScale(int32_t x_scale, int32_t y_scale, int32_t z_scale); 31 | CFastNoise16 &setScale(int32_t x_scale, int32_t y_scale); 32 | CFastNoise16 &setScale(int32_t x_scale); 33 | 34 | int32_t getScaleX(); 35 | int32_t getScaleY(); 36 | int32_t getScaleZ(); 37 | void getScale(int32_t & x, int32_t & y, int32_t & z); 38 | void getScale(int32_t & x, int32_t & y); 39 | void getScale(int32_t & x); 40 | 41 | CFastNoise16 &setAmplitude(fract16 amplitude); 42 | 43 | CFastNoise16 &setFrequency(q88 frequency); 44 | CFastNoise16 &setTime(uint32_t time); 45 | 46 | CFastNoise16 &setOctaves(int octaves); 47 | 48 | CFastNoise16 &setOctaveBlur(bool blurOctaves); 49 | 50 | void getNoise(uint32_t x, uint32_t y, uint32_t z); 51 | void getNoise(uint32_t x, uint32_t y); 52 | void getNoise(uint32_t x); 53 | 54 | void fillNoise(uint16_t *pData, int size); 55 | void fillNoise(uint16_t *pData, int width, int height); 56 | void fillNoise(uint16_t *pData, int width, int height, int depth); 57 | 58 | void fillNoise(uint8_t *pData, int size); 59 | void fillNoise(uint8_t *pData, int width, int height); 60 | void fillNoise(uint8_t *pData, int width, int height, int depth); 61 | }; 62 | #endif 63 | 64 | // 16 bit, fixed point implementation of perlin's Simplex Noise. Coordinates are 65 | // 16.16 fixed point values, 32 bit integers with integral coordinates in the high 16 66 | // bits and fractional in the low 16 bits, and the function takes 1d, 2d, and 3d coordinate 67 | // values. These functions are scaled to return 0-65535 68 | extern uint16_t inoise16(uint32_t x, uint32_t y, uint32_t z); 69 | extern uint16_t inoise16(uint32_t x, uint32_t y); 70 | extern uint16_t inoise16(uint32_t x); 71 | 72 | // 16 bit raw versions of the noise functions. These values are not scaled/altered and have 73 | // output values roughly in the range (-18k,18k) 74 | extern int16_t inoise16_raw(uint32_t x, uint32_t y, uint32_t z); 75 | extern int16_t inoise16_raw(uint32_t x, uint32_t y); 76 | extern int16_t inoise16_raw(uint32_t x); 77 | 78 | // 8 bit, fixed point implementation of perlin's Simplex Noise. Coordinates are 79 | // 8.8 fixed point values, 16 bit integers with integral coordinates in the high 8 80 | // bits and fractional in the low 8 bits, and the function takes 1d, 2d, and 3d coordinate 81 | // values. These functions are scaled to return 0-255 82 | extern uint8_t inoise8(uint16_t x, uint16_t y, uint16_t z); 83 | extern uint8_t inoise8(uint16_t x, uint16_t y); 84 | extern uint8_t inoise8(uint16_t x); 85 | 86 | // 8 bit raw versions of the noise functions. These values are not scaled/altered and have 87 | // output values roughly in the range (-70,70) 88 | extern int8_t inoise8_raw(uint16_t x, uint16_t y, uint16_t z); 89 | extern int8_t inoise8_raw(uint16_t x, uint16_t y); 90 | extern int8_t inoise8_raw(uint16_t x); 91 | 92 | // Raw noise fill functions - fill into a 1d or 2d array of 8-bit values using either 8-bit noise or 16-bit noise 93 | // functions. 94 | void fill_raw_noise8(uint8_t *pData, uint8_t num_points, uint8_t octaves, uint16_t x, int scale, uint16_t time); 95 | void fill_raw_noise16into8(uint8_t *pData, uint8_t num_points, uint8_t octaves, uint32_t x, int scale, uint32_t time); 96 | void fill_raw_2dnoise8(uint8_t *pData, int width, int height, uint8_t octaves, uint16_t x, int scalex, uint16_t y, int scaley, uint16_t time); 97 | void fill_raw_2dnoise16into8(uint8_t *pData, int width, int height, uint8_t octaves, uint32_t x, int scalex, uint32_t y, int scaley, uint32_t time); 98 | 99 | void fill_raw_2dnoise16(uint16_t *pData, int width, int height, uint8_t octaves, q88 freq88, fract16 amplitude, int skip, uint32_t x, int scalex, uint32_t y, int scaley, uint32_t time); 100 | void fill_raw_2dnoise16into8(uint8_t *pData, int width, int height, uint8_t octaves, q44 freq44, fract8 amplitude, int skip, uint32_t x, int scalex, uint32_t y, int scaley, uint32_t time); 101 | 102 | // fill functions to fill leds with values based on noise functions. These functions use the fill_raw_* functions as appropriate. 103 | void fill_noise8(CRGB *leds, int num_leds, 104 | uint8_t octaves, uint16_t x, int scale, 105 | uint8_t hue_octaves, uint16_t hue_x, int hue_scale, 106 | uint16_t time); 107 | void fill_noise16(CRGB *leds, int num_leds, 108 | uint8_t octaves, uint16_t x, int scale, 109 | uint8_t hue_octaves, uint16_t hue_x, int hue_scale, 110 | uint16_t time); 111 | void fill_2dnoise8(CRGB *leds, int width, int height, bool serpentine, 112 | uint8_t octaves, uint16_t x, int xscale, uint16_t y, int yscale, uint16_t time, 113 | uint8_t hue_octaves, uint16_t hue_x, int hue_xscale, uint16_t hue_y, uint16_t hue_yscale,uint16_t hue_time,bool blend); 114 | void fill_2dnoise16(CRGB *leds, int width, int height, bool serpentine, 115 | uint8_t octaves, uint32_t x, int xscale, uint32_t y, int yscale, uint32_t time, 116 | uint8_t hue_octaves, uint16_t hue_x, int hue_xscale, uint16_t hue_y, uint16_t hue_yscale,uint16_t hue_time, bool blend, uint16_t hue_shift=0); 117 | 118 | FASTLED_NAMESPACE_END 119 | 120 | #endif 121 | -------------------------------------------------------------------------------- /firmware/README.md: -------------------------------------------------------------------------------- 1 | SPARKCORE Beta Notes 2 | ==================== 3 | 4 | * Spark Core has a different convention for including header files 5 | * Spark Core requires libraries to be in namespaces. This means that in addition to the include, you need to indicate that you're using the namespace: 6 | 7 | ``` 8 | #include "FastLED/FastLED.h" 9 | FASTLED_USING_NAMESPACE 10 | ``` 11 | * The ```FASTLED_USING_NAMESPACE``` macro will allow your code to work in environments where FastLED is using a namespace vs. places where it isn't. Also, the name of the namespace isn't finalized. 12 | 13 | There may be other tweaks and issues. Please file issues at http://fastled.io/issues 14 | 15 | 16 | FastLED 3.0 17 | =========== 18 | 19 | IMPORTANT NOTE: If you are building for AVR based systems, please do not use any version of the arduino 20 | IDE 1.5.7 or later yet. It messes with some of the asm output which will cause you problems. 21 | 22 | This is a library for easily & efficiently controlling a wide variety of LED chipsets, like the ones 23 | sold by adafruit (Neopixel, LPD8806), Sparkfun (WS2801), and aliexpress. In addition to writing to the 24 | leds, this library also includes a number of functions for high-performing 8bit math for manipulating 25 | your RGB values, as well as low level classes for abstracting out access to pins and SPI hardware, while 26 | still keeping things as fast as possible. 27 | 28 | 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! 29 | 30 | We have multiple goals with this library: 31 | 32 | * Quick start for new developers - hook up your leds and go, no need to think about specifics of the led chipsets being used 33 | * Zero pain switching LED chipsets - you get some new leds that the library supports, just change the definition of LEDs you're using, et. voila! Your code is running with the new leds. 34 | * High performance - with features like zero cost global brightness scaling, high performance 8-bit math for RGB manipulation, and some of the fastest bit-bang'd SPI support around, FastLED wants to keep as many CPU cycles available for your led patterns as possible 35 | 36 | ## Getting help 37 | 38 | If you need help with using the library, please consider going to the google+ community first, which is at http://fastled.io/+ - 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. 39 | 40 | ## Simple example 41 | 42 | How quickly can you get up and running with the library? Here's a simple blink program: 43 | 44 | #include "FastLED.h" 45 | #define NUM_LEDS 60 46 | CRGB leds[NUM_LEDS]; 47 | void setup() { FastLED.addLeds(leds, NUM_LEDS); } 48 | void loop() { 49 | leds[0] = CRGB::White; FastLED.show(); delay(30); 50 | leds[0] = CRGB::Black; FastLED.show(); delay(30); 51 | } 52 | 53 | ## Supported LED chipsets 54 | 55 | Here's a list of all the LED chipsets are supported. More details on the led chipsets are included *TODO: Link to wiki page* 56 | 57 | * Adafruit's Neopixel - aka the WS2812B (also WS2811/WS2812, also suppored in lo-speed mode) - a 3 wire addressable led chipset 58 | * TM1809/4 - 3 wire chipset, cheaply available on aliexpress.com 59 | * TM1803 - 3 wire chipset, sold by radio shack 60 | * UCS1903 - another 3 wire led chipset, cheap 61 | * GW6205 - another 3 wire led chipset 62 | * LPD8806 - SPI based chpiset, very high speed 63 | * WS2801 - SPI based chipset, cheap and widely available 64 | * SM16716 - SPI based chipset 65 | * APA102 - SPI based chipset 66 | * P9813 - aka Cool Neon's Total Control Lighting 67 | * DMX - send rgb data out over DMX using arduino DMX libraries 68 | * SmartMatrix panels - needs the SmartMatrix library - https://github.com/pixelmatix/SmartMatrix 69 | 70 | 71 | LPD6803, HL1606, and "595"-style shift registers are no longer supported by the library. The older Version 1 of the library ("FastSPI_LED") has support for these, but is missing many of the advanced features of current versions and is no longer being maintained. 72 | 73 | 74 | ## Supported platforms 75 | 76 | Right now the library is supported on a variety of arduino compatable platforms. If it's ARM or AVR and uses the arduino software (or a modified version of it to build) then it is likely supported. Note that we have a long list of upcoming platforms to support, so if you don't see what you're looking for here, ask, it may be on the roadmap (or may already be supported). N.B. at the moment we are only supporting the stock compilers that ship with the arduino software. Support for upgraded compilers, as well as using AVR studio and skipping the arduino entirely, should be coming in a near future release. 77 | 78 | * Arduino & compatibles - straight up arduino devices, uno, duo, leonardo, mega, nano, etc... 79 | * Adafruit Trinket & Gemma - Trinket Pro may be supported, but haven't tested to confirm yet 80 | * Teensy 2, Teensy++ 2, Teensy 3.1 - arduino compataible from pjrc.com with some extra goodies (note the teensy 3 is ARM, not AVR!) 81 | * Arduino Due and the digistump DigiX 82 | 83 | What types of platforms are we thinking about supporting in the future? Here's a short list: RFDuino, SparkCore, MSP430, ChipKit32, Maple, Beagleboard 84 | 85 | ## What about that name? 86 | 87 | Wait, what happend to FastSPI_LED and FastSPI_LED2? The library was initially named FastSPI_LED because it was focused on very fast and efficient SPI access. However, since then, the library has expanded to support a number of LED chipsets that don't use SPI, as well as a number of math and utility functions for LED processing across the board. We decided that the name FastLED more accurately represents the totality of what the library provides, everything fast, for LEDs. 88 | 89 | ## For more information 90 | 91 | Check out the official site http://fastled.io for links to documentation, issues, and news 92 | 93 | 94 | *TODO* - get candy 95 | 96 | -------------------------------------------------------------------------------- /firmware/power_mgt.cpp: -------------------------------------------------------------------------------- 1 | #define FASTLED_INTERNAL 2 | #include "FastLED.h" 3 | #include "power_mgt.h" 4 | 5 | FASTLED_NAMESPACE_BEGIN 6 | 7 | //// POWER MANAGEMENT 8 | 9 | // These power usage values are approximate, and your exact readings 10 | // will be slightly (10%?) different from these. 11 | // 12 | // They were arrived at by actually measuing the power draw of a number 13 | // of different LED strips, and a bunch of closed-loop-feedback testing 14 | // to make sure that if we USE these values, we stay at or under 15 | // the target power consumption. 16 | // Actual power consumption is much, much more complicated and has 17 | // to include things like voltage drop, etc., etc. 18 | // However, this is good enough for most cases, and almost certainly better 19 | // than no power management at all. 20 | // 21 | // You're welcome to adjust these values as needed; there may eventually be an API 22 | // for changing these on the fly, but it saves codespace and RAM to have them 23 | // be compile-time constants. 24 | 25 | static const uint8_t gRed_mW = 16 * 5; // 16mA @ 5v = 80mW 26 | static const uint8_t gGreen_mW = 11 * 5; // 11mA @ 5v = 55mW 27 | static const uint8_t gBlue_mW = 15 * 5; // 15mA @ 5v = 75mW 28 | static const uint8_t gDark_mW = 1 * 5; // 1mA @ 5v = 5mW 29 | 30 | // Alternate calibration by RAtkins via pre-PSU wattage measurments; 31 | // these are all probably about 20%-25% too high due to PSU heat losses, 32 | // but if you're measuring wattage on the PSU input side, this may 33 | // be a better set of calibrations. (WS2812B) 34 | // static const uint8_t gRed_mW = 100; 35 | // static const uint8_t gGreen_mW = 48; 36 | // static const uint8_t gBlue_mW = 100; 37 | // static const uint8_t gDark_mW = 12; 38 | 39 | 40 | #define POWER_LED 1 41 | #define POWER_DEBUG_PRINT 0 42 | 43 | 44 | // Power consumed by the MCU 45 | static const uint8_t gMCU_mW = 25 * 5; // 25mA @ 5v = 125 mW 46 | 47 | 48 | static uint32_t gMaxPowerInMilliwatts = (uint32_t)(400) * (uint32_t)(5); // 400mA @ 5v default to avoid USB bricking 49 | static uint8_t gMaxPowerIndicatorLEDPinNumber = 0; // default = Arduino onboard LED pin. set to zero to skip this. 50 | 51 | 52 | uint32_t calculate_unscaled_power_mW( const CRGB* ledbuffer, uint16_t numLeds ) //25354 53 | { 54 | uint32_t red32 = 0, green32 = 0, blue32 = 0; 55 | const CRGB* firstled = &(ledbuffer[0]); 56 | uint8_t* p = (uint8_t*)(firstled); 57 | 58 | uint16_t count = numLeds; 59 | 60 | // This loop might benefit from an AVR assembly version -MEK 61 | while( count) { 62 | red32 += *p++; 63 | green32 += *p++; 64 | blue32 += *p++; 65 | count--; 66 | } 67 | 68 | red32 *= gRed_mW; 69 | green32 *= gGreen_mW; 70 | blue32 *= gBlue_mW; 71 | 72 | red32 >>= 8; 73 | green32 >>= 8; 74 | blue32 >>= 8; 75 | 76 | uint32_t total = red32 + green32 + blue32 + (gDark_mW * numLeds); 77 | 78 | return total; 79 | } 80 | 81 | 82 | 83 | // sets brightness to 84 | // - no more than target_brightness 85 | // - no more than max_mW milliwatts 86 | uint8_t calculate_max_brightness_for_power_mW( uint8_t target_brightness, uint32_t max_power_mW) 87 | { 88 | uint32_t total_mW = gMCU_mW; 89 | 90 | CLEDController *pCur = CLEDController::head(); 91 | while(pCur) { 92 | total_mW += calculate_unscaled_power_mW( pCur->leds(), pCur->size()); 93 | pCur = pCur->next(); 94 | } 95 | 96 | #if POWER_DEBUG_PRINT == 1 97 | Serial.print("power demand at full brightness mW = "); 98 | Serial.println( total_mW); 99 | #endif 100 | 101 | uint32_t requested_power_mW = ((uint32_t)total_mW * target_brightness) / 256; 102 | #if POWER_DEBUG_PRINT == 1 103 | if( target_brightness != 255 ) { 104 | Serial.print("power demand at scaled brightness mW = "); 105 | Serial.println( requested_power_mW); 106 | } 107 | Serial.print("power limit mW = "); 108 | Serial.println( max_power_mW); 109 | #endif 110 | 111 | if( requested_power_mW < max_power_mW) { 112 | #if POWER_LED > 0 113 | if( gMaxPowerIndicatorLEDPinNumber ) { 114 | digitalWrite(gMaxPowerIndicatorLEDPinNumber, LOW); // turn the LED off 115 | } 116 | #endif 117 | #if POWER_DEBUG_PRINT == 1 118 | Serial.print("demand is under the limit"); 119 | #endif 120 | return target_brightness; 121 | } 122 | 123 | uint8_t recommended_brightness = (uint32_t)((uint8_t)(target_brightness) * (uint32_t)(max_power_mW)) / ((uint32_t)(requested_power_mW)); 124 | #if POWER_DEBUG_PRINT == 1 125 | Serial.print("recommended brightness # = "); 126 | Serial.println( recommended_brightness); 127 | 128 | uint32_t resultant_power_mW = (total_mW * recommended_brightness) / 256; 129 | Serial.print("resultant power demand mW = "); 130 | Serial.println( resultant_power_mW); 131 | 132 | Serial.println(); 133 | #endif 134 | 135 | #if POWER_LED > 0 136 | if( gMaxPowerIndicatorLEDPinNumber ) { 137 | digitalWrite( gMaxPowerIndicatorLEDPinNumber, HIGH); // turn the LED on 138 | } 139 | #endif 140 | 141 | return recommended_brightness; 142 | } 143 | 144 | 145 | void set_max_power_indicator_LED( uint8_t pinNumber) 146 | { 147 | gMaxPowerIndicatorLEDPinNumber = pinNumber; 148 | } 149 | 150 | void set_max_power_in_volts_and_milliamps( uint8_t volts, uint32_t milliamps) 151 | { 152 | gMaxPowerInMilliwatts = (uint32_t)((uint32_t)(volts) * milliamps); 153 | } 154 | 155 | void set_max_power_in_milliwatts( uint32_t powerInmW) 156 | { 157 | gMaxPowerInMilliwatts = powerInmW; 158 | } 159 | 160 | void show_at_max_brightness_for_power() 161 | { 162 | uint8_t targetBrightness = FastLED.getBrightness(); 163 | uint8_t max = calculate_max_brightness_for_power_mW( targetBrightness, gMaxPowerInMilliwatts); 164 | 165 | FastLED.setBrightness( max ); 166 | FastLED.show(); 167 | FastLED.setBrightness( targetBrightness ); 168 | } 169 | 170 | void delay_at_max_brightness_for_power( uint16_t ms) 171 | { 172 | uint8_t targetBrightness = FastLED.getBrightness(); 173 | uint8_t max = calculate_max_brightness_for_power_mW( targetBrightness, gMaxPowerInMilliwatts); 174 | 175 | FastLED.setBrightness( max ); 176 | FastLED.delay( ms); 177 | FastLED.setBrightness( targetBrightness ); 178 | } 179 | 180 | FASTLED_NAMESPACE_END 181 | -------------------------------------------------------------------------------- /firmware/examples/Fire2012WithPalette/Fire2012WithPalette.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | #define LED_PIN 5 5 | #define COLOR_ORDER GRB 6 | #define CHIPSET WS2811 7 | #define NUM_LEDS 30 8 | 9 | #define BRIGHTNESS 200 10 | #define FRAMES_PER_SECOND 60 11 | 12 | CRGB leds[NUM_LEDS]; 13 | 14 | // Fire2012 with programmable Color Palette 15 | // 16 | // This code is the same fire simulation as the original "Fire2012", 17 | // but each heat cell's temperature is translated to color through a FastLED 18 | // programmable color palette, instead of through the "HeatColor(...)" function. 19 | // 20 | // Four different static color palettes are provided here, plus one dynamic one. 21 | // 22 | // The three static ones are: 23 | // 1. the FastLED built-in HeatColors_p -- this is the default, and it looks 24 | // pretty much exactly like the original Fire2012. 25 | // 26 | // To use any of the other palettes below, just "uncomment" the corresponding code. 27 | // 28 | // 2. a gradient from black to red to yellow to white, which is 29 | // visually similar to the HeatColors_p, and helps to illustrate 30 | // what the 'heat colors' palette is actually doing, 31 | // 3. a similar gradient, but in blue colors rather than red ones, 32 | // i.e. from black to blue to aqua to white, which results in 33 | // an "icy blue" fire effect, 34 | // 4. a simplified three-step gradient, from black to red to white, just to show 35 | // that these gradients need not have four components; two or 36 | // three are possible, too, even if they don't look quite as nice for fire. 37 | // 38 | // The dynamic palette shows how you can change the basic 'hue' of the 39 | // color palette every time through the loop, producing "rainbow fire". 40 | 41 | CRGBPalette16 gPal; 42 | 43 | void setup() { 44 | delay(3000); // sanity delay 45 | FastLED.addLeds(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); 46 | FastLED.setBrightness( BRIGHTNESS ); 47 | 48 | // This first palette is the basic 'black body radiation' colors, 49 | // which run from black to red to bright yellow to white. 50 | gPal = HeatColors_p; 51 | 52 | // These are other ways to set up the color palette for the 'fire'. 53 | // First, a gradient from black to red to yellow to white -- similar to HeatColors_p 54 | // gPal = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::Yellow, CRGB::White); 55 | 56 | // Second, this palette is like the heat colors, but blue/aqua instead of red/yellow 57 | // gPal = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White); 58 | 59 | // Third, here's a simpler, three-step gradient, from black to red to white 60 | // gPal = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::White); 61 | 62 | } 63 | 64 | void loop() 65 | { 66 | // Add entropy to random number generator; we use a lot of it. 67 | random16_add_entropy( random()); 68 | 69 | // Fourth, the most sophisticated: this one sets up a new palette every 70 | // time through the loop, based on a hue that changes every time. 71 | // The palette is a gradient from black, to a dark color based on the hue, 72 | // to a light color based on the hue, to white. 73 | // 74 | // static uint8_t hue = 0; 75 | // hue++; 76 | // CRGB darkcolor = CHSV(hue,255,192); // pure hue, three-quarters brightness 77 | // CRGB lightcolor = CHSV(hue,128,255); // half 'whitened', full brightness 78 | // gPal = CRGBPalette16( CRGB::Black, darkcolor, lightcolor, CRGB::White); 79 | 80 | 81 | Fire2012WithPalette(); // run simulation frame, using palette colors 82 | 83 | FastLED.show(); // display this frame 84 | FastLED.delay(1000 / FRAMES_PER_SECOND); 85 | } 86 | 87 | 88 | // Fire2012 by Mark Kriegsman, July 2012 89 | // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY 90 | //// 91 | // This basic one-dimensional 'fire' simulation works roughly as follows: 92 | // There's a underlying array of 'heat' cells, that model the temperature 93 | // at each point along the line. Every cycle through the simulation, 94 | // four steps are performed: 95 | // 1) All cells cool down a little bit, losing heat to the air 96 | // 2) The heat from each cell drifts 'up' and diffuses a little 97 | // 3) Sometimes randomly new 'sparks' of heat are added at the bottom 98 | // 4) The heat from each cell is rendered as a color into the leds array 99 | // The heat-to-color mapping uses a black-body radiation approximation. 100 | // 101 | // Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). 102 | // 103 | // This simulation scales it self a bit depending on NUM_LEDS; it should look 104 | // "OK" on anywhere from 20 to 100 LEDs without too much tweaking. 105 | // 106 | // I recommend running this simulation at anywhere from 30-100 frames per second, 107 | // meaning an interframe delay of about 10-35 milliseconds. 108 | // 109 | // Looks best on a high-density LED setup (60+ pixels/meter). 110 | // 111 | // 112 | // There are two main parameters you can play with to control the look and 113 | // feel of your fire: COOLING (used in step 1 above), and SPARKING (used 114 | // in step 3 above). 115 | // 116 | // COOLING: How much does the air cool as it rises? 117 | // Less cooling = taller flames. More cooling = shorter flames. 118 | // Default 55, suggested range 20-100 119 | #define COOLING 55 120 | 121 | // SPARKING: What chance (out of 255) is there that a new spark will be lit? 122 | // Higher chance = more roaring fire. Lower chance = more flickery fire. 123 | // Default 120, suggested range 50-200. 124 | #define SPARKING 120 125 | 126 | 127 | void Fire2012WithPalette() 128 | { 129 | // Array of temperature readings at each simulation cell 130 | static byte heat[NUM_LEDS]; 131 | 132 | // Step 1. Cool down every cell a little 133 | for( int i = 0; i < NUM_LEDS; i++) { 134 | heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2)); 135 | } 136 | 137 | // Step 2. Heat from each cell drifts 'up' and diffuses a little 138 | for( int k= NUM_LEDS - 1; k >= 2; k--) { 139 | heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; 140 | } 141 | 142 | // Step 3. Randomly ignite new 'sparks' of heat near the bottom 143 | if( random8() < SPARKING ) { 144 | int y = random8(7); 145 | heat[y] = qadd8( heat[y], random8(160,255) ); 146 | } 147 | 148 | // Step 4. Map from heat cells to LED colors 149 | for( int j = 0; j < NUM_LEDS; j++) { 150 | // Scale the heat value from 0-255 down to 0-240 151 | // for best results with color palettes. 152 | byte colorindex = scale8( heat[j], 240); 153 | leds[j] = ColorFromPalette( gPal, colorindex); 154 | } 155 | } 156 | 157 | -------------------------------------------------------------------------------- /firmware/FastLED.cpp: -------------------------------------------------------------------------------- 1 | #define FASTLED_INTERNAL 2 | #include "FastLED.h" 3 | 4 | 5 | #if defined(__SAM3X8E__) 6 | volatile uint32_t fuckit; 7 | #endif 8 | 9 | #if defined(ARDUINO) || defined(SPARK) 10 | extern uint32_t millis(); 11 | #endif 12 | 13 | FASTLED_NAMESPACE_BEGIN 14 | 15 | void *pSmartMatrix = NULL; 16 | 17 | CFastLED FastLED; 18 | 19 | CLEDController *CLEDController::m_pHead = NULL; 20 | CLEDController *CLEDController::m_pTail = NULL; 21 | static uint32_t lastshow = 0; 22 | 23 | // uint32_t CRGB::Squant = ((uint32_t)((__TIME__[4]-'0') * 28))<<16 | ((__TIME__[6]-'0')*50)<<8 | ((__TIME__[7]-'0')*28); 24 | 25 | CFastLED::CFastLED() { 26 | // clear out the array of led controllers 27 | // m_nControllers = 0; 28 | m_Scale = 255; 29 | m_nFPS = 0; 30 | setMaxRefreshRate(400); 31 | } 32 | 33 | CLEDController &CFastLED::addLeds(CLEDController *pLed, 34 | struct CRGB *data, 35 | int nLedsOrOffset, int nLedsIfOffset) { 36 | int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0; 37 | int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset; 38 | 39 | pLed->init(); 40 | pLed->setLeds(data + nOffset, nLeds); 41 | return *pLed; 42 | } 43 | 44 | void CFastLED::show(uint8_t scale) { 45 | // guard against showing too rapidly 46 | while(m_nMinMicros && ((micros()-lastshow) < m_nMinMicros)); 47 | lastshow = micros(); 48 | 49 | CLEDController *pCur = CLEDController::head(); 50 | while(pCur) { 51 | uint8_t d = pCur->getDither(); 52 | if(m_nFPS < 100) { pCur->setDither(0); } 53 | pCur->showLeds(scale); 54 | pCur->setDither(d); 55 | pCur = pCur->next(); 56 | } 57 | countFPS(); 58 | } 59 | 60 | int CFastLED::count() { 61 | int x = 0; 62 | CLEDController *pCur = CLEDController::head(); 63 | while( pCur) { 64 | x++; 65 | pCur = pCur->next(); 66 | } 67 | return x; 68 | } 69 | 70 | CLEDController & CFastLED::operator[](int x) { 71 | CLEDController *pCur = CLEDController::head(); 72 | while(x-- && pCur) { 73 | pCur = pCur->next(); 74 | } 75 | if(pCur == NULL) { 76 | return *(CLEDController::head()); 77 | } else { 78 | return *pCur; 79 | } 80 | } 81 | 82 | void CFastLED::showColor(const struct CRGB & color, uint8_t scale) { 83 | while(m_nMinMicros && ((micros()-lastshow) < m_nMinMicros)); 84 | lastshow = micros(); 85 | 86 | CLEDController *pCur = CLEDController::head(); 87 | while(pCur) { 88 | uint8_t d = pCur->getDither(); 89 | if(m_nFPS < 100) { pCur->setDither(0); } 90 | pCur->showColor(color, scale); 91 | pCur->setDither(d); 92 | pCur = pCur->next(); 93 | } 94 | countFPS(); 95 | } 96 | 97 | void CFastLED::clear(boolean writeData) { 98 | if(writeData) { 99 | showColor(CRGB(0,0,0), 0); 100 | } 101 | clearData(); 102 | } 103 | 104 | void CFastLED::clearData() { 105 | CLEDController *pCur = CLEDController::head(); 106 | while(pCur) { 107 | pCur->clearLedData(); 108 | pCur = pCur->next(); 109 | } 110 | } 111 | 112 | void CFastLED::delay(unsigned long ms) { 113 | unsigned long start = ::millis(); 114 | while((::millis()-start) < ms) { 115 | #ifndef FASTLED_ACCURATE_CLOCK 116 | // make sure to allow at least one ms to pass to ensure the clock moves 117 | // forward 118 | ::delay(1); 119 | #endif 120 | show(); 121 | } 122 | } 123 | 124 | void CFastLED::setTemperature(const struct CRGB & temp) { 125 | CLEDController *pCur = CLEDController::head(); 126 | while(pCur) { 127 | pCur->setTemperature(temp); 128 | pCur = pCur->next(); 129 | } 130 | } 131 | 132 | void CFastLED::setCorrection(const struct CRGB & correction) { 133 | CLEDController *pCur = CLEDController::head(); 134 | while(pCur) { 135 | pCur->setCorrection(correction); 136 | pCur = pCur->next(); 137 | } 138 | } 139 | 140 | void CFastLED::setDither(uint8_t ditherMode) { 141 | CLEDController *pCur = CLEDController::head(); 142 | while(pCur) { 143 | pCur->setDither(ditherMode); 144 | pCur = pCur->next(); 145 | } 146 | } 147 | 148 | // 149 | // template void transpose8(unsigned char A[8], unsigned char B[8]) { 150 | // uint32_t x, y, t; 151 | // 152 | // // Load the array and pack it into x and y. 153 | // y = *(unsigned int*)(A); 154 | // x = *(unsigned int*)(A+4); 155 | // 156 | // // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m]; 157 | // // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m]; 158 | // 159 | // // pre-transform x 160 | // t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); 161 | // t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); 162 | // 163 | // // pre-transform y 164 | // t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); 165 | // t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); 166 | // 167 | // // final transform 168 | // t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); 169 | // y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); 170 | // x = t; 171 | // 172 | // B[7*n] = y; y >>= 8; 173 | // B[6*n] = y; y >>= 8; 174 | // B[5*n] = y; y >>= 8; 175 | // B[4*n] = y; 176 | // 177 | // B[3*n] = x; x >>= 8; 178 | // B[2*n] = x; x >>= 8; 179 | // B[n] = x; x >>= 8; 180 | // B[0] = x; 181 | // // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; 182 | // // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; 183 | // } 184 | // 185 | // void transposeLines(Lines & out, Lines & in) { 186 | // transpose8<1,2>(in.bytes, out.bytes); 187 | // transpose8<1,2>(in.bytes + 8, out.bytes + 1); 188 | // } 189 | 190 | extern int noise_min; 191 | extern int noise_max; 192 | 193 | void CFastLED::countFPS(int nFrames) { 194 | static int br = 0; 195 | static uint32_t lastframe = 0; // ::millis(); 196 | 197 | if(br++ >= nFrames) { 198 | uint32_t now = ::millis(); 199 | now -= lastframe; 200 | m_nFPS = (br * 1000) / now; 201 | br = 0; 202 | lastframe = ::millis(); 203 | } 204 | } 205 | 206 | void CFastLED::setMaxRefreshRate(uint16_t refresh) { 207 | if(refresh > 0) { 208 | m_nMinMicros = 1000000 / refresh; 209 | } else { 210 | m_nMinMicros = 0; 211 | } 212 | } 213 | 214 | 215 | #ifdef NEED_CXX_BITS 216 | namespace __cxxabiv1 217 | { 218 | extern "C" void __cxa_pure_virtual (void) {} 219 | /* guard variables */ 220 | 221 | /* The ABI requires a 64-bit type. */ 222 | __extension__ typedef int __guard __attribute__((mode(__DI__))); 223 | 224 | extern "C" int __cxa_guard_acquire (__guard *); 225 | extern "C" void __cxa_guard_release (__guard *); 226 | extern "C" void __cxa_guard_abort (__guard *); 227 | 228 | extern "C" int __cxa_guard_acquire (__guard *g) 229 | { 230 | return !*(char *)(g); 231 | } 232 | 233 | extern "C" void __cxa_guard_release (__guard *g) 234 | { 235 | *(char *)g = 1; 236 | } 237 | 238 | extern "C" void __cxa_guard_abort (__guard *) 239 | { 240 | 241 | } 242 | } 243 | #endif 244 | 245 | FASTLED_NAMESPACE_END 246 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k26/fastpin_arm_k26.h: -------------------------------------------------------------------------------- 1 | #ifndef __FASTPIN_ARM_K20_H 2 | #define __FASTPIN_ARM_K20_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | #if defined(FASTLED_FORCE_SOFTWARE_PINS) 7 | #warning "Software pin support forced, pin access will be sloightly slower." 8 | #define NO_HARDWARE_PIN_SUPPORT 9 | #undef HAS_HARDWARE_PIN_SUPPORT 10 | 11 | #else 12 | 13 | 14 | /// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this 15 | /// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found 16 | /// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. 17 | /// The registers are data output, set output, clear output, toggle output, input, and direction 18 | template class _ARMPIN { 19 | public: 20 | typedef volatile uint32_t * port_ptr_t; 21 | typedef uint32_t port_t; 22 | 23 | inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } 24 | inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } 25 | 26 | inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } 27 | inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } 28 | inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } 29 | 30 | inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } 31 | 32 | inline static void toggle() __attribute__ ((always_inline)) { _PTOR::r() = _MASK; } 33 | 34 | inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } 35 | inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } 36 | inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } 37 | 38 | inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } 39 | inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } 40 | inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } 41 | inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } 42 | inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } 43 | inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } 44 | }; 45 | 46 | #if 0 47 | /// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC 48 | /// does a poor job of optimizing around these accesses so they are not being used just yet. 49 | template class _ARMPIN_BITBAND { 50 | public: 51 | typedef volatile uint32_t * port_ptr_t; 52 | typedef uint32_t port_t; 53 | 54 | inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } 55 | inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } 56 | 57 | inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } 58 | inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } 59 | inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } 60 | 61 | inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } 62 | 63 | inline static void toggle() __attribute__ ((always_inline)) { *_PTOR::template rx<_BIT>() = 1; } 64 | 65 | inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } 66 | inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } 67 | inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } 68 | 69 | inline static port_t hival() __attribute__ ((always_inline)) { return 1; } 70 | inline static port_t loval() __attribute__ ((always_inline)) { return 0; } 71 | inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } 72 | inline static port_t mask() __attribute__ ((always_inline)) { return 1; } 73 | }; 74 | #endif 75 | 76 | // Macros for k20 pin access/definition 77 | #define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) 78 | #define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) 79 | 80 | #define _R(T) struct __gen_struct_ ## T 81 | #define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } \ 82 | template static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } }; 83 | #define _IO32(L) _RD32(FGPIO ## L ## _PDOR); _RD32(FGPIO ## L ## _PSOR); _RD32(FGPIO ## L ## _PCOR); _RD32(GPIO ## L ## _PTOR); _RD32(FGPIO ## L ## _PDIR); _RD32(FGPIO ## L ## _PDDR); 84 | 85 | #define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin : public _ARMPIN {}; \ 87 | /* template<> class FastPinBB : public _ARMPIN_BITBAND {}; */ 89 | 90 | // Actual pin definitions 91 | #if defined(FASTLED_TEENSYLC) && defined(CORE_TEENSY) 92 | 93 | _IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); 94 | 95 | #define MAX_PIN 26 96 | _DEFPIN_ARM(0, 16, B); _DEFPIN_ARM(1, 17, B); _DEFPIN_ARM(2, 0, D); _DEFPIN_ARM(3, 1, A); 97 | _DEFPIN_ARM(4, 2, A); _DEFPIN_ARM(5, 7, D); _DEFPIN_ARM(6, 4, D); _DEFPIN_ARM(7, 2, D); 98 | _DEFPIN_ARM(8, 3, D); _DEFPIN_ARM(9, 3, C); _DEFPIN_ARM(10, 4, C); _DEFPIN_ARM(11, 6, C); 99 | _DEFPIN_ARM(12, 7, C); _DEFPIN_ARM(13, 5, C); _DEFPIN_ARM(14, 1, D); _DEFPIN_ARM(15, 0, C); 100 | _DEFPIN_ARM(16, 0, B); _DEFPIN_ARM(17, 1, B); _DEFPIN_ARM(18, 3, B); _DEFPIN_ARM(19, 2, B); 101 | _DEFPIN_ARM(20, 5, D); _DEFPIN_ARM(21, 6, D); _DEFPIN_ARM(22, 1, C); _DEFPIN_ARM(23, 2, C); 102 | _DEFPIN_ARM(24, 20, E); _DEFPIN_ARM(25, 21, E); _DEFPIN_ARM(26, 30, E); 103 | 104 | #define SPI_DATA 11 105 | #define SPI_CLOCK 13 106 | // #define SPI1 (*(SPI_t *)0x4002D000) 107 | 108 | #define SPI2_DATA 0 109 | #define SPI2_CLOCK 20 110 | 111 | #define HAS_HARDWARE_PIN_SUPPORT 112 | #endif 113 | 114 | #endif // FASTLED_FORCE_SOFTWARE_PINS 115 | 116 | FASTLED_NAMESPACE_END 117 | 118 | #endif // __INC_FASTPIN_ARM_K20 119 | -------------------------------------------------------------------------------- /firmware/platforms/arm/k20/fastpin_arm_k20.h: -------------------------------------------------------------------------------- 1 | #ifndef __FASTPIN_ARM_K20_H 2 | #define __FASTPIN_ARM_K20_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | #if defined(FASTLED_FORCE_SOFTWARE_PINS) 7 | #warning "Software pin support forced, pin access will be sloightly slower." 8 | #define NO_HARDWARE_PIN_SUPPORT 9 | #undef HAS_HARDWARE_PIN_SUPPORT 10 | 11 | #else 12 | 13 | 14 | /// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this 15 | /// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found 16 | /// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. 17 | /// The registers are data output, set output, clear output, toggle output, input, and direction 18 | template class _ARMPIN { 19 | public: 20 | typedef volatile uint32_t * port_ptr_t; 21 | typedef uint32_t port_t; 22 | 23 | inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } 24 | inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } 25 | 26 | inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } 27 | inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } 28 | inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } 29 | 30 | inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } 31 | 32 | inline static void toggle() __attribute__ ((always_inline)) { _PTOR::r() = _MASK; } 33 | 34 | inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } 35 | inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } 36 | inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } 37 | 38 | inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } 39 | inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } 40 | inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } 41 | inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } 42 | inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } 43 | inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } 44 | }; 45 | 46 | /// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC 47 | /// does a poor job of optimizing around these accesses so they are not being used just yet. 48 | template class _ARMPIN_BITBAND { 49 | public: 50 | typedef volatile uint32_t * port_ptr_t; 51 | typedef uint32_t port_t; 52 | 53 | inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } 54 | inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } 55 | 56 | inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } 57 | inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } 58 | inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } 59 | 60 | inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } 61 | 62 | inline static void toggle() __attribute__ ((always_inline)) { *_PTOR::template rx<_BIT>() = 1; } 63 | 64 | inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } 65 | inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } 66 | inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } 67 | 68 | inline static port_t hival() __attribute__ ((always_inline)) { return 1; } 69 | inline static port_t loval() __attribute__ ((always_inline)) { return 0; } 70 | inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } 71 | inline static port_t mask() __attribute__ ((always_inline)) { return 1; } 72 | }; 73 | 74 | // Macros for k20 pin access/definition 75 | #define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) 76 | #define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) 77 | 78 | #define _R(T) struct __gen_struct_ ## T 79 | #define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } \ 80 | template static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } }; 81 | #define _IO32(L) _RD32(GPIO ## L ## _PDOR); _RD32(GPIO ## L ## _PSOR); _RD32(GPIO ## L ## _PCOR); _RD32(GPIO ## L ## _PTOR); _RD32(GPIO ## L ## _PDIR); _RD32(GPIO ## L ## _PDDR); 82 | 83 | #define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin : public _ARMPIN {}; \ 85 | template<> class FastPinBB : public _ARMPIN_BITBAND {}; 87 | 88 | // Actual pin definitions 89 | #if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY) 90 | 91 | _IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); 92 | 93 | #define MAX_PIN 33 94 | _DEFPIN_ARM(0, 16, B); _DEFPIN_ARM(1, 17, B); _DEFPIN_ARM(2, 0, D); _DEFPIN_ARM(3, 12, A); 95 | _DEFPIN_ARM(4, 13, A); _DEFPIN_ARM(5, 7, D); _DEFPIN_ARM(6, 4, D); _DEFPIN_ARM(7, 2, D); 96 | _DEFPIN_ARM(8, 3, D); _DEFPIN_ARM(9, 3, C); _DEFPIN_ARM(10, 4, C); _DEFPIN_ARM(11, 6, C); 97 | _DEFPIN_ARM(12, 7, C); _DEFPIN_ARM(13, 5, C); _DEFPIN_ARM(14, 1, D); _DEFPIN_ARM(15, 0, C); 98 | _DEFPIN_ARM(16, 0, B); _DEFPIN_ARM(17, 1, B); _DEFPIN_ARM(18, 3, B); _DEFPIN_ARM(19, 2, B); 99 | _DEFPIN_ARM(20, 5, D); _DEFPIN_ARM(21, 6, D); _DEFPIN_ARM(22, 1, C); _DEFPIN_ARM(23, 2, C); 100 | _DEFPIN_ARM(24, 5, A); _DEFPIN_ARM(25, 19, B); _DEFPIN_ARM(26, 1, E); _DEFPIN_ARM(27, 9, C); 101 | _DEFPIN_ARM(28, 8, C); _DEFPIN_ARM(29, 10, C); _DEFPIN_ARM(30, 11, C); _DEFPIN_ARM(31, 0, E); 102 | _DEFPIN_ARM(32, 18, B); _DEFPIN_ARM(33, 4, A); 103 | 104 | #define SPI_DATA 11 105 | #define SPI_CLOCK 13 106 | #define SPI1 (*(SPI_t *)0x4002D000) 107 | 108 | #define SPI2_DATA 7 109 | #define SPI2_CLOCK 14 110 | 111 | #define FASTLED_TEENSY3 112 | #define ARM_HARDWARE_SPI 113 | #define HAS_HARDWARE_PIN_SUPPORT 114 | #endif 115 | 116 | #endif // FASTLED_FORCE_SOFTWARE_PINS 117 | 118 | FASTLED_NAMESPACE_END 119 | 120 | #endif // __INC_FASTPIN_ARM_K20 121 | -------------------------------------------------------------------------------- /firmware/examples/ColorPalette/ColorPalette.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | #define LED_PIN 5 5 | #define NUM_LEDS 50 6 | #define BRIGHTNESS 64 7 | #define LED_TYPE WS2811 8 | #define COLOR_ORDER GRB 9 | CRGB leds[NUM_LEDS]; 10 | 11 | #define UPDATES_PER_SECOND 100 12 | 13 | // This example shows several ways to set up and use 'palettes' of colors 14 | // with FastLED. 15 | // 16 | // These compact palettes provide an easy way to re-colorize your 17 | // animation on the fly, quickly, easily, and with low overhead. 18 | // 19 | // USING palettes is MUCH simpler in practice than in theory, so first just 20 | // run this sketch, and watch the pretty lights as you then read through 21 | // the code. Although this sketch has eight (or more) different color schemes, 22 | // the entire sketch compiles down to about 6.5K on AVR. 23 | // 24 | // FastLED provides a few pre-configured color palettes, and makes it 25 | // extremely easy to make up your own color schemes with palettes. 26 | // 27 | // Some notes on the more abstract 'theory and practice' of 28 | // FastLED compact palettes are at the bottom of this file. 29 | 30 | 31 | 32 | CRGBPalette16 currentPalette; 33 | TBlendType currentBlending; 34 | 35 | extern CRGBPalette16 myRedWhiteBluePalette; 36 | extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM; 37 | 38 | 39 | void setup() { 40 | delay( 3000 ); // power-up safety delay 41 | FastLED.addLeds(leds, NUM_LEDS).setCorrection( TypicalLEDStrip ); 42 | FastLED.setBrightness( BRIGHTNESS ); 43 | 44 | currentPalette = RainbowColors_p; 45 | currentBlending = BLEND; 46 | } 47 | 48 | 49 | void loop() 50 | { 51 | ChangePalettePeriodically(); 52 | 53 | static uint8_t startIndex = 0; 54 | startIndex = startIndex + 1; /* motion speed */ 55 | 56 | FillLEDsFromPaletteColors( startIndex); 57 | 58 | FastLED.show(); 59 | FastLED.delay(1000 / UPDATES_PER_SECOND); 60 | } 61 | 62 | void FillLEDsFromPaletteColors( uint8_t colorIndex) 63 | { 64 | uint8_t brightness = 255; 65 | 66 | for( int i = 0; i < NUM_LEDS; i++) { 67 | leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending); 68 | colorIndex += 3; 69 | } 70 | } 71 | 72 | 73 | // There are several different palettes of colors demonstrated here. 74 | // 75 | // FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p, 76 | // OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p. 77 | // 78 | // Additionally, you can manually define your own color palettes, or you can write 79 | // code that creates color palettes on the fly. All are shown here. 80 | 81 | void ChangePalettePeriodically() 82 | { 83 | uint8_t secondHand = (millis() / 1000) % 60; 84 | static uint8_t lastSecond = 99; 85 | 86 | if( lastSecond != secondHand) { 87 | lastSecond = secondHand; 88 | if( secondHand == 0) { currentPalette = RainbowColors_p; currentBlending = BLEND; } 89 | if( secondHand == 10) { currentPalette = RainbowStripeColors_p; currentBlending = NOBLEND; } 90 | if( secondHand == 15) { currentPalette = RainbowStripeColors_p; currentBlending = BLEND; } 91 | if( secondHand == 20) { SetupPurpleAndGreenPalette(); currentBlending = BLEND; } 92 | if( secondHand == 25) { SetupTotallyRandomPalette(); currentBlending = BLEND; } 93 | if( secondHand == 30) { SetupBlackAndWhiteStripedPalette(); currentBlending = NOBLEND; } 94 | if( secondHand == 35) { SetupBlackAndWhiteStripedPalette(); currentBlending = BLEND; } 95 | if( secondHand == 40) { currentPalette = CloudColors_p; currentBlending = BLEND; } 96 | if( secondHand == 45) { currentPalette = PartyColors_p; currentBlending = BLEND; } 97 | if( secondHand == 50) { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND; } 98 | if( secondHand == 55) { currentPalette = myRedWhiteBluePalette_p; currentBlending = BLEND; } 99 | } 100 | } 101 | 102 | // This function fills the palette with totally random colors. 103 | void SetupTotallyRandomPalette() 104 | { 105 | for( int i = 0; i < 16; i++) { 106 | currentPalette[i] = CHSV( random8(), 255, random8()); 107 | } 108 | } 109 | 110 | // This function sets up a palette of black and white stripes, 111 | // using code. Since the palette is effectively an array of 112 | // sixteen CRGB colors, the various fill_* functions can be used 113 | // to set them up. 114 | void SetupBlackAndWhiteStripedPalette() 115 | { 116 | // 'black out' all 16 palette entries... 117 | fill_solid( currentPalette, 16, CRGB::Black); 118 | // and set every fourth one to white. 119 | currentPalette[0] = CRGB::White; 120 | currentPalette[4] = CRGB::White; 121 | currentPalette[8] = CRGB::White; 122 | currentPalette[12] = CRGB::White; 123 | 124 | } 125 | 126 | // This function sets up a palette of purple and green stripes. 127 | void SetupPurpleAndGreenPalette() 128 | { 129 | CRGB purple = CHSV( HUE_PURPLE, 255, 255); 130 | CRGB green = CHSV( HUE_GREEN, 255, 255); 131 | CRGB black = CRGB::Black; 132 | 133 | currentPalette = CRGBPalette16( 134 | green, green, black, black, 135 | purple, purple, black, black, 136 | green, green, black, black, 137 | purple, purple, black, black ); 138 | } 139 | 140 | 141 | // This example shows how to set up a static color palette 142 | // which is stored in PROGMEM (flash), which is almost always more 143 | // plentiful than RAM. A static PROGMEM palette like this 144 | // takes up 64 bytes of flash. 145 | const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM = 146 | { 147 | CRGB::Red, 148 | CRGB::Gray, // 'white' is too bright compared to red and blue 149 | CRGB::Blue, 150 | CRGB::Black, 151 | 152 | CRGB::Red, 153 | CRGB::Gray, 154 | CRGB::Blue, 155 | CRGB::Black, 156 | 157 | CRGB::Red, 158 | CRGB::Red, 159 | CRGB::Gray, 160 | CRGB::Gray, 161 | CRGB::Blue, 162 | CRGB::Blue, 163 | CRGB::Black, 164 | CRGB::Black 165 | }; 166 | 167 | 168 | 169 | // Additionl notes on FastLED compact palettes: 170 | // 171 | // Normally, in computer graphics, the palette (or "color lookup table") 172 | // has 256 entries, each containing a specific 24-bit RGB color. You can then 173 | // index into the color palette using a simple 8-bit (one byte) value. 174 | // A 256-entry color palette takes up 768 bytes of RAM, which on Arduino 175 | // is quite possibly "too many" bytes. 176 | // 177 | // FastLED does offer traditional 256-element palettes, for setups that 178 | // can afford the 768-byte cost in RAM. 179 | // 180 | // However, FastLED also offers a compact alternative. FastLED offers 181 | // palettes that store 16 distinct entries, but can be accessed AS IF 182 | // they actually have 256 entries; this is accomplished by interpolating 183 | // between the 16 explicit entries to create fifteen intermediate palette 184 | // entries between each pair. 185 | // 186 | // So for example, if you set the first two explicit entries of a compact 187 | // palette to Green (0,255,0) and Blue (0,0,255), and then retrieved 188 | // the first sixteen entries from the virtual palette (of 256), you'd get 189 | // Green, followed by a smooth gradient from green-to-blue, and then Blue. 190 | 191 | -------------------------------------------------------------------------------- /firmware/examples/XYMatrix/XYMatrix.ino: -------------------------------------------------------------------------------- 1 | #include "FastLED/FastLED.h" 2 | FASTLED_USING_NAMESPACE; 3 | 4 | #define LED_PIN 3 5 | 6 | #define COLOR_ORDER GRB 7 | #define CHIPSET WS2811 8 | 9 | #define BRIGHTNESS 64 10 | 11 | // Helper functions for an two-dimensional XY matrix of pixels. 12 | // Simple 2-D demo code is included as well. 13 | // 14 | // XY(x,y) takes x and y coordinates and returns an LED index number, 15 | // for use like this: leds[ XY(x,y) ] == CRGB::Red; 16 | // No error checking is performed on the ranges of x and y. 17 | // 18 | // XYsafe(x,y) takes x and y coordinates and returns an LED index number, 19 | // for use like this: leds[ XY(x,y) ] == CRGB::Red; 20 | // Error checking IS performed on the ranges of x and y, and an 21 | // index of "-1" is returned. Special instructions below 22 | // explain how to use this without having to do your own error 23 | // checking every time you use this function. 24 | // This is a slightly more advanced technique, and 25 | // it REQUIRES SPECIAL ADDITIONAL setup, described below. 26 | 27 | 28 | // Params for width and height 29 | const uint8_t kMatrixWidth = 16; 30 | const uint8_t kMatrixHeight = 16; 31 | 32 | // Param for different pixel layouts 33 | const bool kMatrixSerpentineLayout = true; 34 | // Set 'kMatrixSerpentineLayout' to false if your pixels are 35 | // laid out all running the same way, like this: 36 | // 37 | // 0 > 1 > 2 > 3 > 4 38 | // | 39 | // .----<----<----<----' 40 | // | 41 | // 5 > 6 > 7 > 8 > 9 42 | // | 43 | // .----<----<----<----' 44 | // | 45 | // 10 > 11 > 12 > 13 > 14 46 | // | 47 | // .----<----<----<----' 48 | // | 49 | // 15 > 16 > 17 > 18 > 19 50 | // 51 | // Set 'kMatrixSerpentineLayout' to true if your pixels are 52 | // laid out back-and-forth, like this: 53 | // 54 | // 0 > 1 > 2 > 3 > 4 55 | // | 56 | // | 57 | // 9 < 8 < 7 < 6 < 5 58 | // | 59 | // | 60 | // 10 > 11 > 12 > 13 > 14 61 | // | 62 | // | 63 | // 19 < 18 < 17 < 16 < 15 64 | // 65 | // Bonus vocabulary word: anything that goes one way 66 | // in one row, and then backwards in the next row, and so on 67 | // is call "boustrophedon", meaning "as the ox plows." 68 | 69 | 70 | // This function will return the right 'led index number' for 71 | // a given set of X and Y coordinates on your matrix. 72 | // IT DOES NOT CHECK THE COORDINATE BOUNDARIES. 73 | // That's up to you. Don't pass it bogus values. 74 | // 75 | // Use the "XY" function like this: 76 | // 77 | // for( uint8_t x = 0; x < kMatrixWidth; x++) { 78 | // for( uint8_t y = 0; y < kMatrixHeight; y++) { 79 | // 80 | // // Here's the x, y to 'led index' in action: 81 | // leds[ XY( x, y) ] = CHSV( random8(), 255, 255); 82 | // 83 | // } 84 | // } 85 | // 86 | // 87 | uint16_t XY( uint8_t x, uint8_t y) 88 | { 89 | uint16_t i; 90 | 91 | if( kMatrixSerpentineLayout == false) { 92 | i = (y * kMatrixWidth) + x; 93 | } 94 | 95 | if( kMatrixSerpentineLayout == true) { 96 | if( y & 0x01) { 97 | // Odd rows run backwards 98 | uint8_t reverseX = (kMatrixWidth - 1) - x; 99 | i = (y * kMatrixWidth) + reverseX; 100 | } else { 101 | // Even rows run forwards 102 | i = (y * kMatrixWidth) + x; 103 | } 104 | } 105 | 106 | return i; 107 | } 108 | 109 | 110 | // Once you've gotten the basics working (AND NOT UNTIL THEN!) 111 | // here's a helpful technique that can be tricky to set up, but 112 | // then helps you avoid the needs for sprinkling array-bound-checking 113 | // throughout your code. 114 | // 115 | // It requires a careful attention to get it set up correctly, but 116 | // can potentially make your code smaller and faster. 117 | // 118 | // Suppose you have an 8 x 5 matrix of 40 LEDs. Normally, you'd 119 | // delcare your leds array like this: 120 | // CRGB leds[40]; 121 | // But instead of that, declare an LED buffer with one extra pixel in 122 | // it, "leds_plus_safety_pixel". Then declare "leds" as a pointer to 123 | // that array, but starting with the 2nd element (id=1) of that array: 124 | // CRGB leds_with_safety_pixel[41]; 125 | // const CRGB* leds( leds_plus_safety_pixel + 1); 126 | // Then you use the "leds" array as you normally would. 127 | // Now "leds[0..N]" are aliases for "leds_plus_safety_pixel[1..(N+1)]", 128 | // AND leds[-1] is now a legitimate and safe alias for leds_plus_safety_pixel[0]. 129 | // leds_plus_safety_pixel[0] aka leds[-1] is now your "safety pixel". 130 | // 131 | // Now instead of using the XY function above, use the one below, "XYsafe". 132 | // 133 | // If the X and Y values are 'in bounds', this function will return an index 134 | // into the visible led array, same as "XY" does. 135 | // HOWEVER -- and this is the trick -- if the X or Y values 136 | // are out of bounds, this function will return an index of -1. 137 | // And since leds[-1] is actually just an alias for leds_plus_safety_pixel[0], 138 | // it's a totally safe and legal place to access. And since the 'safety pixel' 139 | // falls 'outside' the visible part of the LED array, anything you write 140 | // there is hidden from view automatically. 141 | // Thus, this line of code is totally safe, regardless of the actual size of 142 | // your matrix: 143 | // leds[ XYsafe( random8(), random8() ) ] = CHSV( random8(), 255, 255); 144 | // 145 | // The only catch here is that while this makes it safe to read from and 146 | // write to 'any pixel', there's really only ONE 'safety pixel'. No matter 147 | // what out-of-bounds coordinates you write to, you'll really be writing to 148 | // that one safety pixel. And if you try to READ from the safety pixel, 149 | // you'll read whatever was written there last, reglardless of what coordinates 150 | // were supplied. 151 | 152 | #define NUM_LEDS (kMatrixWidth * kMatrixHeight) 153 | CRGB leds_plus_safety_pixel[ NUM_LEDS + 1]; 154 | CRGB* leds( leds_plus_safety_pixel + 1); 155 | 156 | uint16_t XYsafe( uint8_t x, uint8_t y) 157 | { 158 | if( x >= kMatrixWidth) return -1; 159 | if( y >= kMatrixHeight) return -1; 160 | return XY(x,y); 161 | } 162 | 163 | 164 | // Demo that USES "XY" follows code below 165 | 166 | void loop() 167 | { 168 | uint32_t ms = millis(); 169 | int32_t yHueDelta32 = ((int32_t)cos16( ms * (27/1) ) * (350 / kMatrixWidth)); 170 | int32_t xHueDelta32 = ((int32_t)cos16( ms * (39/1) ) * (310 / kMatrixHeight)); 171 | DrawOneFrame( ms / 65536, yHueDelta32 / 32768, xHueDelta32 / 32768); 172 | if( ms < 5000 ) { 173 | FastLED.setBrightness( scale8( BRIGHTNESS, (ms * 256) / 5000)); 174 | } else { 175 | FastLED.setBrightness(BRIGHTNESS); 176 | } 177 | FastLED.show(); 178 | } 179 | 180 | void DrawOneFrame( byte startHue8, int8_t yHueDelta8, int8_t xHueDelta8) 181 | { 182 | byte lineStartHue = startHue8; 183 | for( byte y = 0; y < kMatrixHeight; y++) { 184 | lineStartHue += yHueDelta8; 185 | byte pixelHue = lineStartHue; 186 | for( byte x = 0; x < kMatrixWidth; x++) { 187 | pixelHue += xHueDelta8; 188 | leds[ XY(x, y)] = CHSV( pixelHue, 255, 255); 189 | } 190 | } 191 | } 192 | 193 | 194 | void setup() { 195 | FastLED.addLeds(leds, NUM_LEDS).setCorrection(TypicalSMD5050); 196 | FastLED.setBrightness( BRIGHTNESS ); 197 | } 198 | 199 | -------------------------------------------------------------------------------- /firmware/bitswap.h: -------------------------------------------------------------------------------- 1 | #ifndef __INC_BITSWAP_H 2 | #define __INC_BITSWAP_H 3 | 4 | FASTLED_NAMESPACE_BEGIN 5 | 6 | #ifdef FASTLED_ARM 7 | // structure representing 8 bits of access 8 | typedef union { 9 | uint8_t raw; 10 | struct { 11 | uint32_t a0:1; 12 | uint32_t a1:1; 13 | uint32_t a2:1; 14 | uint32_t a3:1; 15 | uint32_t a4:1; 16 | uint32_t a5:1; 17 | uint32_t a6:1; 18 | uint32_t a7:1; 19 | }; 20 | } just8bits; 21 | 22 | // structure representing 32 bits of access 23 | typedef struct { 24 | uint32_t a0:1; 25 | uint32_t a1:1; 26 | uint32_t a2:1; 27 | uint32_t a3:1; 28 | uint32_t a4:1; 29 | uint32_t a5:1; 30 | uint32_t a6:1; 31 | uint32_t a7:1; 32 | uint32_t b0:1; 33 | uint32_t b1:1; 34 | uint32_t b2:1; 35 | uint32_t b3:1; 36 | uint32_t b4:1; 37 | uint32_t b5:1; 38 | uint32_t b6:1; 39 | uint32_t b7:1; 40 | uint32_t c0:1; 41 | uint32_t c1:1; 42 | uint32_t c2:1; 43 | uint32_t c3:1; 44 | uint32_t c4:1; 45 | uint32_t c5:1; 46 | uint32_t c6:1; 47 | uint32_t c7:1; 48 | uint32_t d0:1; 49 | uint32_t d1:1; 50 | uint32_t d2:1; 51 | uint32_t d3:1; 52 | uint32_t d4:1; 53 | uint32_t d5:1; 54 | uint32_t d6:1; 55 | uint32_t d7:1; 56 | } sub4; 57 | 58 | // union containing a full 8 bytes to swap the bit orientation on 59 | typedef union { 60 | uint32_t word[2]; 61 | uint8_t bytes[8]; 62 | struct { 63 | sub4 a; 64 | sub4 b; 65 | }; 66 | } bitswap_type; 67 | 68 | 69 | #define SWAPSA(X,N) out. X ## 0 = in.a.a ## N; \ 70 | out. X ## 1 = in.a.b ## N; \ 71 | out. X ## 2 = in.a.c ## N; \ 72 | out. X ## 3 = in.a.d ## N; 73 | 74 | #define SWAPSB(X,N) out. X ## 0 = in.b.a ## N; \ 75 | out. X ## 1 = in.b.b ## N; \ 76 | out. X ## 2 = in.b.c ## N; \ 77 | out. X ## 3 = in.b.d ## N; 78 | 79 | #define SWAPS(X,N) out. X ## 0 = in.a.a ## N; \ 80 | out. X ## 1 = in.a.b ## N; \ 81 | out. X ## 2 = in.a.c ## N; \ 82 | out. X ## 3 = in.a.d ## N; \ 83 | out. X ## 4 = in.b.a ## N; \ 84 | out. X ## 5 = in.b.b ## N; \ 85 | out. X ## 6 = in.b.c ## N; \ 86 | out. X ## 7 = in.b.d ## N; 87 | 88 | 89 | __attribute__((always_inline)) inline void swapbits8(bitswap_type in, bitswap_type & out) { 90 | 91 | // SWAPS(a.a,7); 92 | // SWAPS(a.b,6); 93 | // SWAPS(a.c,5); 94 | // SWAPS(a.d,4); 95 | // SWAPS(b.a,3); 96 | // SWAPS(b.b,2); 97 | // SWAPS(b.c,1); 98 | // SWAPS(b.d,0); 99 | 100 | // SWAPSA(a.a,7); 101 | // SWAPSA(a.b,6); 102 | // SWAPSA(a.c,5); 103 | // SWAPSA(a.d,4); 104 | // 105 | // SWAPSB(a.a,7); 106 | // SWAPSB(a.b,6); 107 | // SWAPSB(a.c,5); 108 | // SWAPSB(a.d,4); 109 | // 110 | // SWAPSA(b.a,3); 111 | // SWAPSA(b.b,2); 112 | // SWAPSA(b.c,1); 113 | // SWAPSA(b.d,0); 114 | // // 115 | // SWAPSB(b.a,3); 116 | // SWAPSB(b.b,2); 117 | // SWAPSB(b.c,1); 118 | // SWAPSB(b.d,0); 119 | 120 | for(int i = 0; i < 8; i++) { 121 | just8bits work; 122 | work.a3 = in.word[0] >> 31; 123 | work.a2 = in.word[0] >> 23; 124 | work.a1 = in.word[0] >> 15; 125 | work.a0 = in.word[0] >> 7; 126 | in.word[0] <<= 1; 127 | work.a7 = in.word[1] >> 31; 128 | work.a6 = in.word[1] >> 23; 129 | work.a5 = in.word[1] >> 15; 130 | work.a4 = in.word[1] >> 7; 131 | in.word[1] <<= 1; 132 | out.bytes[i] = work.raw; 133 | } 134 | } 135 | 136 | __attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned char *B) { 137 | 138 | for(int row = 0; row < 7; row++) { 139 | uint8_t x = A[row]; 140 | 141 | uint8_t bit = (1<>= 1) { 144 | if(x & mask) { 145 | *p++ |= bit; 146 | } else { 147 | *p++ &= ~bit; 148 | } 149 | } 150 | // B[7] |= (x & 0x01) << row; x >>= 1; 151 | // B[6] |= (x & 0x01) << row; x >>= 1; 152 | // B[5] |= (x & 0x01) << row; x >>= 1; 153 | // B[4] |= (x & 0x01) << row; x >>= 1; 154 | // B[3] |= (x & 0x01) << row; x >>= 1; 155 | // B[2] |= (x & 0x01) << row; x >>= 1; 156 | // B[1] |= (x & 0x01) << row; x >>= 1; 157 | // B[0] |= (x & 0x01) << row; x >>= 1; 158 | } 159 | } 160 | 161 | // Simplified form of bits rotating function found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating 162 | // data into LSB for a faster write (the code using this data can happily walk the array backwards) 163 | __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsigned char *B) { 164 | uint32_t x, y, t; 165 | 166 | // Load the array and pack it into x and y. 167 | y = *(unsigned int*)(A); 168 | x = *(unsigned int*)(A+4); 169 | 170 | // pre-transform x 171 | t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); 172 | t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); 173 | 174 | // pre-transform y 175 | t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); 176 | t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); 177 | 178 | // final transform 179 | t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); 180 | y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); 181 | x = t; 182 | 183 | *((uint32_t*)B) = y; 184 | *((uint32_t*)(B+4)) = x; 185 | } 186 | 187 | // Simplified form of bits rotating function found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt 188 | __attribute__((always_inline)) inline void transpose8x1_MSB(unsigned char *A, unsigned char *B) { 189 | uint32_t x, y, t; 190 | 191 | // Load the array and pack it into x and y. 192 | y = *(unsigned int*)(A); 193 | x = *(unsigned int*)(A+4); 194 | 195 | // pre-transform x 196 | t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); 197 | t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); 198 | 199 | // pre-transform y 200 | t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); 201 | t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); 202 | 203 | // final transform 204 | t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); 205 | y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); 206 | x = t; 207 | 208 | B[7] = y; y >>= 8; 209 | B[6] = y; y >>= 8; 210 | B[5] = y; y >>= 8; 211 | B[4] = y; 212 | 213 | B[3] = x; x >>= 8; 214 | B[2] = x; x >>= 8; 215 | B[1] = x; x >>= 8; 216 | B[0] = x; /* */ 217 | } 218 | 219 | // templated bit-rotating function based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt 220 | template 221 | __attribute__((always_inline)) inline void transpose8(unsigned char *A, unsigned char *B) { 222 | uint32_t x, y, t; 223 | 224 | // Load the array and pack it into x and y. 225 | if(m == 1) { 226 | y = *(unsigned int*)(A); 227 | x = *(unsigned int*)(A+4); 228 | } else { 229 | x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m]; 230 | y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m]; 231 | } 232 | 233 | // pre-transform x 234 | t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); 235 | t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); 236 | 237 | // pre-transform y 238 | t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); 239 | t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); 240 | 241 | // final transform 242 | t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); 243 | y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); 244 | x = t; 245 | 246 | B[7*n] = y; y >>= 8; 247 | B[6*n] = y; y >>= 8; 248 | B[5*n] = y; y >>= 8; 249 | B[4*n] = y; 250 | 251 | B[3*n] = x; x >>= 8; 252 | B[2*n] = x; x >>= 8; 253 | B[n] = x; x >>= 8; 254 | B[0] = x; 255 | // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; 256 | // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; 257 | } 258 | #endif 259 | 260 | FASTLED_NAMESPACE_END 261 | 262 | #endif 263 | --------------------------------------------------------------------------------