no message
This commit is contained in:
commit
413c83b4cf
132
LED-Mesh.ino
Normal file
132
LED-Mesh.ino
Normal file
@ -0,0 +1,132 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#include <LEDMatrix.h>
|
||||
#include <LEDText.h>
|
||||
#include <Font4x5.h>
|
||||
|
||||
// Change the next 6 defines to match your matrix type and size
|
||||
|
||||
#define LED_PIN 5
|
||||
#define COLOR_ORDER RGB
|
||||
#define CHIPSET PL9823
|
||||
|
||||
#define NUM_LEDS 90
|
||||
|
||||
#define MATRIX_WIDTH 18
|
||||
#define MATRIX_HEIGHT 5
|
||||
#define MATRIX_TYPE VERTICAL_ZIGZAG_MATRIX
|
||||
cLEDMatrix < -MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_TYPE > leds;
|
||||
CRGB leds2[NUM_LEDS];
|
||||
|
||||
cLEDText ScrollingMsg;
|
||||
|
||||
const unsigned char TxtDemo[] = { /*
|
||||
EFFECT_FRAME_RATE "\x06" EFFECT_BACKGND_DIMMING "\x20"
|
||||
EFFECT_SCROLL_LEFT " LEEFT SCROLL "
|
||||
EFFECT_SCROLL_RIGHT " LLORCS THGIR"
|
||||
EFFECT_CHAR_UP EFFECT_SCROLL_LEFT " UP"
|
||||
EFFECT_SCROLL_LEFT " Magande 2811 ABCDEFGHIJK "
|
||||
EFFECT_FRAME_RATE "\x10"
|
||||
EFFECT_SCROLL_LEFT " LMNOPQRSTUVWXYZ 0123456789 +*~,;:.-_!$%&/()=\" {[]}`^^#<>"
|
||||
EFFECT_FRAME_RATE "\x06"
|
||||
EFFECT_CHAR_RIGHT " RIGHT"
|
||||
EFFECT_CHAR_DOWN " DOWN"
|
||||
EFFECT_CHAR_LEFT " LEFT"
|
||||
EFFECT_HSV_CV "\x00\xff\xff\x40\xff\xff" EFFECT_CHAR_UP " HSV_CV 00-40"
|
||||
EFFECT_HSV_CH "\x00\xff\xff\x40\xff\xff" "HSV_CH 00-40"
|
||||
EFFECT_HSV_AV "\x00\xff\xff\x40\xff\xff" "HSV_AV 00-40"
|
||||
EFFECT_HSV_AH "\x00\xff\xff\xff\xff\xff" "HSV_AH 00-FF"
|
||||
EFFECT_HSV "\x00\xff\xff" "R" EFFECT_HSV "\x20\xff\xff" "A" EFFECT_HSV "\x40\xff\xff" "I" EFFECT_HSV "\x60\xff\xff" "N" EFFECT_HSV "\xe0\xff\xff" "B" EFFECT_HSV "\xc0\xff\xff" "O"
|
||||
EFFECT_HSV "\xa0\xff\xff" "W" EFFECT_HSV "\x80\xff\xff" "S " EFFECT_DELAY_FRAMES "\x00\x96" EFFECT_RGB "\xff\xff\xff"
|
||||
*/
|
||||
EFFECT_FRAME_RATE "\x05"
|
||||
EFFECT_SCROLL_LEFT EFFECT_RGB "\x52\xff\xa3" " KIESELSTEIN "
|
||||
//EFFECT_RGB "\xbb\xff\x44" " IM "
|
||||
EFFECT_HSV_AV "\xaa\xff\xff\x2c\xaa\xb9" " INTERNATIONAL "
|
||||
EFFECT_HSV_CH "\x03\xff\xff\xaf\xff\xff" " GMBH "
|
||||
EFFECT_RGB "\xaa\xaa\xf0" " --"
|
||||
EFFECT_HSV_CH "\x00\xff\xff\xd0\xff\xff" " STRUCTWIRE "
|
||||
// EFFECT_HSV_CH "\xaa\xff\xff\xe2\xff\xff" " DIE ZWEITE "
|
||||
|
||||
};
|
||||
int demo2;
|
||||
/*
|
||||
String StringRead =
|
||||
EFFECT_FRAME_RATE "\x06"
|
||||
EFFECT_SCROLL_LEFT EFFECT_RGB "\x52\xff\xa3" "Hallo weLT:";
|
||||
*/
|
||||
static uint8_t hue;
|
||||
int16_t x, y;
|
||||
uint8_t h;
|
||||
|
||||
int UPDATES_PER_SECOND;
|
||||
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
//StringRead.reserve(100);
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds[0], leds.Size());
|
||||
FastLED.setBrightness(63);
|
||||
FastLED.clear(true);
|
||||
|
||||
delay(500);
|
||||
FastLED.showColor(CRGB::Red);
|
||||
delay(1000);
|
||||
FastLED.showColor(CRGB::Lime);
|
||||
delay(1000);
|
||||
FastLED.showColor(CRGB::Blue);
|
||||
delay(1000);
|
||||
FastLED.showColor(CRGB::White);
|
||||
delay(1000);
|
||||
FastLED.show();
|
||||
|
||||
ScrollingMsg.SetFont(MatriseFontData);
|
||||
ScrollingMsg.Init(&leds, leds.Width(), ScrollingMsg.FontHeight() + 1, 0, 0);
|
||||
ScrollingMsg.SetText((unsigned char *)TxtDemo, sizeof(TxtDemo) - 1);
|
||||
ScrollingMsg.SetTextColrOptions(COLR_RGB | COLR_SINGLE, 0xff, 0x00, 0xff);
|
||||
//ScrollingMsg.SetBackgroundMode(BACKGND_DIMMING, 0x05);
|
||||
//ScrollingMsg.SetFrameRate(FrameRate);
|
||||
|
||||
// currentPalette = RainbowColors_p;
|
||||
// currentBlending = LINEARBLEND;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
h = hue;
|
||||
if (ScrollingMsg.UpdateText() == -1) {
|
||||
ScrollingMsg.SetText((unsigned char *)TxtDemo, sizeof(TxtDemo) - 1);
|
||||
//ScrollingMsg.SetText((unsigned char *) StringRead.c_str(), StringRead.length());
|
||||
// demo2=40;
|
||||
}
|
||||
else {
|
||||
FastLED.show();
|
||||
//delay(3);
|
||||
//FastLED.clear();
|
||||
}
|
||||
delay(8);
|
||||
|
||||
/* if (Serial.available()) {
|
||||
if (Serial.available() != 0) {
|
||||
StringRead = Serial.readString();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* if(demo2>=20){
|
||||
for (x=0; x<leds.Width(); ++x)
|
||||
{
|
||||
leds.DrawLine(x, 0, x, leds.Height() - 1, CHSV(h, 255, 255));
|
||||
h+=16;
|
||||
}
|
||||
hue+=4;
|
||||
FastLED.show();
|
||||
FastLED.delay(1000/UPDATES_PER_SECOND);
|
||||
demo2--;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
272
libraries/FastLED/FastLED.cpp
Normal file
272
libraries/FastLED/FastLED.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
#define FASTLED_INTERNAL
|
||||
#include "FastLED.h"
|
||||
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
volatile uint32_t fuckit;
|
||||
#endif
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
void *pSmartMatrix = NULL;
|
||||
|
||||
CFastLED FastLED;
|
||||
|
||||
CLEDController *CLEDController::m_pHead = NULL;
|
||||
CLEDController *CLEDController::m_pTail = NULL;
|
||||
static uint32_t lastshow = 0;
|
||||
|
||||
uint32_t _frame_cnt=0;
|
||||
uint32_t _retry_cnt=0;
|
||||
|
||||
// uint32_t CRGB::Squant = ((uint32_t)((__TIME__[4]-'0') * 28))<<16 | ((__TIME__[6]-'0')*50)<<8 | ((__TIME__[7]-'0')*28);
|
||||
|
||||
CFastLED::CFastLED() {
|
||||
// clear out the array of led controllers
|
||||
// m_nControllers = 0;
|
||||
m_Scale = 255;
|
||||
m_nFPS = 0;
|
||||
m_pPowerFunc = NULL;
|
||||
m_nPowerData = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
CLEDController &CFastLED::addLeds(CLEDController *pLed,
|
||||
struct CRGB *data,
|
||||
int nLedsOrOffset, int nLedsIfOffset) {
|
||||
int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0;
|
||||
int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset;
|
||||
|
||||
pLed->init();
|
||||
pLed->setLeds(data + nOffset, nLeds);
|
||||
FastLED.setMaxRefreshRate(pLed->getMaxRefreshRate(),true);
|
||||
return *pLed;
|
||||
}
|
||||
|
||||
void CFastLED::show(uint8_t scale) {
|
||||
// guard against showing too rapidly
|
||||
while(m_nMinMicros && ((micros()-lastshow) < m_nMinMicros));
|
||||
lastshow = micros();
|
||||
|
||||
// If we have a function for computing power, use it!
|
||||
if(m_pPowerFunc) {
|
||||
scale = (*m_pPowerFunc)(scale, m_nPowerData);
|
||||
}
|
||||
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while(pCur) {
|
||||
uint8_t d = pCur->getDither();
|
||||
if(m_nFPS < 100) { pCur->setDither(0); }
|
||||
pCur->showLeds(scale);
|
||||
pCur->setDither(d);
|
||||
pCur = pCur->next();
|
||||
}
|
||||
countFPS();
|
||||
}
|
||||
|
||||
int CFastLED::count() {
|
||||
int x = 0;
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while( pCur) {
|
||||
x++;
|
||||
pCur = pCur->next();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
CLEDController & CFastLED::operator[](int x) {
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while(x-- && pCur) {
|
||||
pCur = pCur->next();
|
||||
}
|
||||
if(pCur == NULL) {
|
||||
return *(CLEDController::head());
|
||||
} else {
|
||||
return *pCur;
|
||||
}
|
||||
}
|
||||
|
||||
void CFastLED::showColor(const struct CRGB & color, uint8_t scale) {
|
||||
while(m_nMinMicros && ((micros()-lastshow) < m_nMinMicros));
|
||||
lastshow = micros();
|
||||
|
||||
// If we have a function for computing power, use it!
|
||||
if(m_pPowerFunc) {
|
||||
scale = (*m_pPowerFunc)(scale, m_nPowerData);
|
||||
}
|
||||
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while(pCur) {
|
||||
uint8_t d = pCur->getDither();
|
||||
if(m_nFPS < 100) { pCur->setDither(0); }
|
||||
pCur->showColor(color, scale);
|
||||
pCur->setDither(d);
|
||||
pCur = pCur->next();
|
||||
}
|
||||
countFPS();
|
||||
}
|
||||
|
||||
void CFastLED::clear(bool writeData) {
|
||||
if(writeData) {
|
||||
showColor(CRGB(0,0,0), 0);
|
||||
}
|
||||
clearData();
|
||||
}
|
||||
|
||||
void CFastLED::clearData() {
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while(pCur) {
|
||||
pCur->clearLedData();
|
||||
pCur = pCur->next();
|
||||
}
|
||||
}
|
||||
|
||||
void CFastLED::delay(unsigned long ms) {
|
||||
unsigned long start = millis();
|
||||
do {
|
||||
#ifndef FASTLED_ACCURATE_CLOCK
|
||||
// make sure to allow at least one ms to pass to ensure the clock moves
|
||||
// forward
|
||||
::delay(1);
|
||||
#endif
|
||||
show();
|
||||
yield();
|
||||
}
|
||||
while((millis()-start) < ms);
|
||||
}
|
||||
|
||||
void CFastLED::setTemperature(const struct CRGB & temp) {
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while(pCur) {
|
||||
pCur->setTemperature(temp);
|
||||
pCur = pCur->next();
|
||||
}
|
||||
}
|
||||
|
||||
void CFastLED::setCorrection(const struct CRGB & correction) {
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while(pCur) {
|
||||
pCur->setCorrection(correction);
|
||||
pCur = pCur->next();
|
||||
}
|
||||
}
|
||||
|
||||
void CFastLED::setDither(uint8_t ditherMode) {
|
||||
CLEDController *pCur = CLEDController::head();
|
||||
while(pCur) {
|
||||
pCur->setDither(ditherMode);
|
||||
pCur = pCur->next();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// template<int m, int n> void transpose8(unsigned char A[8], unsigned char B[8]) {
|
||||
// uint32_t x, y, t;
|
||||
//
|
||||
// // Load the array and pack it into x and y.
|
||||
// y = *(unsigned int*)(A);
|
||||
// x = *(unsigned int*)(A+4);
|
||||
//
|
||||
// // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m];
|
||||
// // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m];
|
||||
//
|
||||
// // pre-transform x
|
||||
// t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
|
||||
// t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
|
||||
//
|
||||
// // pre-transform y
|
||||
// t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
|
||||
// t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
|
||||
//
|
||||
// // final transform
|
||||
// t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
|
||||
// y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
|
||||
// x = t;
|
||||
//
|
||||
// B[7*n] = y; y >>= 8;
|
||||
// B[6*n] = y; y >>= 8;
|
||||
// B[5*n] = y; y >>= 8;
|
||||
// B[4*n] = y;
|
||||
//
|
||||
// B[3*n] = x; x >>= 8;
|
||||
// B[2*n] = x; x >>= 8;
|
||||
// B[n] = x; x >>= 8;
|
||||
// B[0] = x;
|
||||
// // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0;
|
||||
// // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0;
|
||||
// }
|
||||
//
|
||||
// void transposeLines(Lines & out, Lines & in) {
|
||||
// transpose8<1,2>(in.bytes, out.bytes);
|
||||
// transpose8<1,2>(in.bytes + 8, out.bytes + 1);
|
||||
// }
|
||||
|
||||
extern int noise_min;
|
||||
extern int noise_max;
|
||||
|
||||
void CFastLED::countFPS(int nFrames) {
|
||||
static int br = 0;
|
||||
static uint32_t lastframe = 0; // millis();
|
||||
|
||||
if(br++ >= nFrames) {
|
||||
uint32_t now = millis();
|
||||
now -= lastframe;
|
||||
m_nFPS = (br * 1000) / now;
|
||||
br = 0;
|
||||
lastframe = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void CFastLED::setMaxRefreshRate(uint16_t refresh, bool constrain) {
|
||||
if(constrain) {
|
||||
// if we're constraining, the new value of m_nMinMicros _must_ be higher than previously (because we're only
|
||||
// allowed to slow things down if constraining)
|
||||
if(refresh > 0) {
|
||||
m_nMinMicros = ( (1000000/refresh) > m_nMinMicros) ? (1000000/refresh) : m_nMinMicros;
|
||||
}
|
||||
} else if(refresh > 0) {
|
||||
m_nMinMicros = 1000000 / refresh;
|
||||
} else {
|
||||
m_nMinMicros = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" int atexit(void (* /*func*/ )()) { return 0; }
|
||||
|
||||
#ifdef FASTLED_NEEDS_YIELD
|
||||
extern "C" void yield(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef NEED_CXX_BITS
|
||||
namespace __cxxabiv1
|
||||
{
|
||||
#if !defined(ESP8266) && !defined(ESP32)
|
||||
extern "C" void __cxa_pure_virtual (void) {}
|
||||
#endif
|
||||
|
||||
/* guard variables */
|
||||
|
||||
/* The ABI requires a 64-bit type. */
|
||||
__extension__ typedef int __guard __attribute__((mode(__DI__)));
|
||||
|
||||
extern "C" int __cxa_guard_acquire (__guard *) __attribute__((weak));
|
||||
extern "C" void __cxa_guard_release (__guard *) __attribute__((weak));
|
||||
extern "C" void __cxa_guard_abort (__guard *) __attribute__((weak));
|
||||
|
||||
extern "C" int __cxa_guard_acquire (__guard *g)
|
||||
{
|
||||
return !*(char *)(g);
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_release (__guard *g)
|
||||
{
|
||||
*(char *)g = 1;
|
||||
}
|
||||
|
||||
extern "C" void __cxa_guard_abort (__guard *)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
FASTLED_NAMESPACE_END
|
584
libraries/FastLED/FastLED.h
Normal file
584
libraries/FastLED/FastLED.h
Normal file
@ -0,0 +1,584 @@
|
||||
#ifndef __INC_FASTSPI_LED2_H
|
||||
#define __INC_FASTSPI_LED2_H
|
||||
|
||||
///@file FastLED.h
|
||||
/// central include file for FastLED, defines the CFastLED class/object
|
||||
|
||||
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
|
||||
#define FASTLED_HAS_PRAGMA_MESSAGE
|
||||
#endif
|
||||
|
||||
#define FASTLED_VERSION 3002006
|
||||
#ifndef FASTLED_INTERNAL
|
||||
# ifdef FASTLED_HAS_PRAGMA_MESSAGE
|
||||
# pragma message "FastLED version 3.002.006"
|
||||
# else
|
||||
# warning FastLED version 3.002.006 (Not really a warning, just telling you here.)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __PROG_TYPES_COMPAT__
|
||||
#define __PROG_TYPES_COMPAT__
|
||||
#endif
|
||||
|
||||
#ifdef SmartMatrix_h
|
||||
#include <SmartMatrix.h>
|
||||
#endif
|
||||
|
||||
#ifdef DmxSimple_h
|
||||
#include <DmxSimple.h>
|
||||
#endif
|
||||
|
||||
#ifdef DmxSerial_h
|
||||
#include <DMXSerial.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpp_compat.h"
|
||||
|
||||
#include "fastled_config.h"
|
||||
#include "led_sysdefs.h"
|
||||
|
||||
// Utility functions
|
||||
#include "fastled_delay.h"
|
||||
#include "bitswap.h"
|
||||
|
||||
#include "controller.h"
|
||||
#include "fastpin.h"
|
||||
#include "fastspi_types.h"
|
||||
#include "dmx.h"
|
||||
|
||||
#include "platforms.h"
|
||||
#include "fastled_progmem.h"
|
||||
|
||||
#include "lib8tion.h"
|
||||
#include "pixeltypes.h"
|
||||
#include "hsv2rgb.h"
|
||||
#include "colorutils.h"
|
||||
#include "pixelset.h"
|
||||
#include "colorpalettes.h"
|
||||
|
||||
#include "noise.h"
|
||||
#include "power_mgt.h"
|
||||
|
||||
#include "fastspi.h"
|
||||
#include "chipsets.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
/// definitions for the spi chipset constants
|
||||
enum ESPIChipsets {
|
||||
LPD6803,
|
||||
LPD8806,
|
||||
WS2801,
|
||||
WS2803,
|
||||
SM16716,
|
||||
P9813,
|
||||
APA102,
|
||||
SK9822,
|
||||
DOTSTAR
|
||||
};
|
||||
|
||||
enum ESM { SMART_MATRIX };
|
||||
enum OWS2811 { OCTOWS2811,OCTOWS2811_400, OCTOWS2813};
|
||||
enum SWS2812 { WS2812SERIAL };
|
||||
|
||||
#ifdef HAS_PIXIE
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class PIXIE : public PixieController<DATA_PIN, RGB_ORDER> {};
|
||||
#endif
|
||||
|
||||
#ifdef FASTLED_HAS_CLOCKLESS
|
||||
template<uint8_t DATA_PIN> class NEOPIXEL : public WS2812Controller800Khz<DATA_PIN, GRB> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SM16703 : public SM16703Controller<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1829 : public TM1829Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1812 : public TM1809Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1809 : public TM1809Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1804 : public TM1809Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class TM1803 : public TM1803Controller400Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1903 : public UCS1903Controller400Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1903B : public UCS1903BController800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS1904 : public UCS1904Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class UCS2903 : public UCS2903Controller<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2812 : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2852 : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2812B : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GS1903 : public WS2812Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SK6812 : public SK6812Controller<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class SK6822 : public SK6822Controller<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class APA106 : public SK6822Controller<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class PL9823 : public PL9823Controller<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2811 : public WS2811Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2813 : public WS2813Controller<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class APA104 : public WS2811Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class WS2811_400 : public WS2811Controller400Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GE8822 : public GE8822Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GW6205 : public GW6205Controller800Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class GW6205_400 : public GW6205Controller400Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class LPD1886 : public LPD1886Controller1250Khz<DATA_PIN, RGB_ORDER> {};
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class LPD1886_8BIT : public LPD1886Controller1250Khz_8bit<DATA_PIN, RGB_ORDER> {};
|
||||
#ifdef DmxSimple_h
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER> class DMXSIMPLE : public DMXSimpleController<DATA_PIN, RGB_ORDER> {};
|
||||
#endif
|
||||
#ifdef DmxSerial_h
|
||||
template<EOrder RGB_ORDER> class DMXSERIAL : public DMXSerialController<RGB_ORDER> {};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum EBlockChipsets {
|
||||
#ifdef PORTA_FIRST_PIN
|
||||
WS2811_PORTA,
|
||||
WS2813_PORTA,
|
||||
WS2811_400_PORTA,
|
||||
TM1803_PORTA,
|
||||
UCS1903_PORTA,
|
||||
#endif
|
||||
#ifdef PORTB_FIRST_PIN
|
||||
WS2811_PORTB,
|
||||
WS2813_PORTB,
|
||||
WS2811_400_PORTB,
|
||||
TM1803_PORTB,
|
||||
UCS1903_PORTB,
|
||||
#endif
|
||||
#ifdef PORTC_FIRST_PIN
|
||||
WS2811_PORTC,
|
||||
WS2813_PORTC,
|
||||
WS2811_400_PORTC,
|
||||
TM1803_PORTC,
|
||||
UCS1903_PORTC,
|
||||
#endif
|
||||
#ifdef PORTD_FIRST_PIN
|
||||
WS2811_PORTD,
|
||||
WS2813_PORTD,
|
||||
WS2811_400_PORTD,
|
||||
TM1803_PORTD,
|
||||
UCS1903_PORTD,
|
||||
#endif
|
||||
#ifdef HAS_PORTDC
|
||||
WS2811_PORTDC,
|
||||
WS2813_PORTDC,
|
||||
WS2811_400_PORTDC,
|
||||
TM1803_PORTDC,
|
||||
UCS1903_PORTDC,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(LIB8_ATTINY)
|
||||
#define NUM_CONTROLLERS 2
|
||||
#else
|
||||
#define NUM_CONTROLLERS 8
|
||||
#endif
|
||||
|
||||
typedef uint8_t (*power_func)(uint8_t scale, uint32_t data);
|
||||
|
||||
/// High level controller interface for FastLED. This class manages controllers, global settings and trackings
|
||||
/// such as brightness, and refresh rates, and provides access functions for driving led data to controllers
|
||||
/// via the show/showColor/clear methods.
|
||||
/// @nosubgrouping
|
||||
class CFastLED {
|
||||
// int m_nControllers;
|
||||
uint8_t m_Scale; ///< The current global brightness scale setting
|
||||
uint16_t m_nFPS; ///< Tracking for current FPS value
|
||||
uint32_t m_nMinMicros; ///< minimum µs between frames, used for capping frame rates.
|
||||
uint32_t m_nPowerData; ///< max power use parameter
|
||||
power_func m_pPowerFunc; ///< function for overriding brightness when using FastLED.show();
|
||||
|
||||
public:
|
||||
CFastLED();
|
||||
|
||||
|
||||
/// Add a CLEDController instance to the world. Exposed to the public to allow people to implement their own
|
||||
/// CLEDController objects or instances. There are two ways to call this method (as well as the other addLeds)
|
||||
/// variations. The first is with 3 arguments, in which case the arguments are the controller, a pointer to
|
||||
/// led data, and the number of leds used by this controller. The second is with 4 arguments, in which case
|
||||
/// the first two arguments are the same, the third argument is an offset into the CRGB data where this controller's
|
||||
/// CRGB data begins, and the fourth argument is the number of leds for this controller object.
|
||||
/// @param pLed - the led controller being added
|
||||
/// @param data - base point to an array of CRGB data structures
|
||||
/// @param nLedsOrOffset - number of leds (3 argument version) or offset into the data array
|
||||
/// @param nLedsIfOffset - number of leds (4 argument version)
|
||||
/// @returns a reference to the added controller
|
||||
static CLEDController &addLeds(CLEDController *pLed, struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0);
|
||||
|
||||
/// @name Adding SPI based controllers
|
||||
//@{
|
||||
/// Add an SPI based CLEDController instance to the world.
|
||||
/// There are two ways to call this method (as well as the other addLeds)
|
||||
/// variations. The first is with 2 arguments, in which case the arguments are a pointer to
|
||||
/// led data, and the number of leds used by this controller. The second is with 3 arguments, in which case
|
||||
/// the first argument is the same, the second argument is an offset into the CRGB data where this controller's
|
||||
/// CRGB data begins, and the third argument is the number of leds for this controller object.
|
||||
///
|
||||
/// This method also takes a 1 to 5 template parameters for identifying the specific chipset, data and clock pins,
|
||||
/// RGB ordering, and SPI data rate
|
||||
/// @param data - base point to an array of CRGB data structures
|
||||
/// @param nLedsOrOffset - number of leds (3 argument version) or offset into the data array
|
||||
/// @param nLedsIfOffset - number of leds (4 argument version)
|
||||
/// @tparam CHIPSET - the chipset type
|
||||
/// @tparam DATA_PIN - the optional data pin for the leds (if omitted, will default to the first hardware SPI MOSI pin)
|
||||
/// @tparam CLOCK_PIN - the optional clock pin for the leds (if omitted, will default to the first hardware SPI clock pin)
|
||||
/// @tparam RGB_ORDER - the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
|
||||
/// @tparam SPI_DATA_RATE - the data rate to drive the SPI clock at, defined using DATA_RATE_MHZ or DATA_RATE_KHZ macros
|
||||
/// @returns a reference to the added controller
|
||||
template<ESPIChipsets CHIPSET, uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER, uint8_t SPI_DATA_RATE > CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
switch(CHIPSET) {
|
||||
case LPD6803: { static LPD6803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case LPD8806: { static LPD8806Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case WS2801: { static WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case WS2803: { static WS2803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case SM16716: { static SM16716Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case P9813: { static P9813Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case DOTSTAR:
|
||||
case APA102: { static APA102Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case SK9822: { static SK9822Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_DATA_RATE> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
}
|
||||
}
|
||||
|
||||
template<ESPIChipsets CHIPSET, uint8_t DATA_PIN, uint8_t CLOCK_PIN > static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
switch(CHIPSET) {
|
||||
case LPD6803: { static LPD6803Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case LPD8806: { static LPD8806Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case WS2801: { static WS2801Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case WS2803: { static WS2803Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case SM16716: { static SM16716Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case P9813: { static P9813Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case DOTSTAR:
|
||||
case APA102: { static APA102Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case SK9822: { static SK9822Controller<DATA_PIN, CLOCK_PIN> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
}
|
||||
}
|
||||
|
||||
template<ESPIChipsets CHIPSET, uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER > static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
switch(CHIPSET) {
|
||||
case LPD6803: { static LPD6803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case LPD8806: { static LPD8806Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case WS2801: { static WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case WS2803: { static WS2803Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case SM16716: { static SM16716Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case P9813: { static P9813Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case DOTSTAR:
|
||||
case APA102: { static APA102Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case SK9822: { static SK9822Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER> c; return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SPI_DATA
|
||||
template<ESPIChipsets CHIPSET> static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
return addLeds<CHIPSET, SPI_DATA, SPI_CLOCK, RGB>(data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
template<ESPIChipsets CHIPSET, EOrder RGB_ORDER> static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
return addLeds<CHIPSET, SPI_DATA, SPI_CLOCK, RGB_ORDER>(data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
template<ESPIChipsets CHIPSET, EOrder RGB_ORDER, uint8_t SPI_DATA_RATE> static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
return addLeds<CHIPSET, SPI_DATA, SPI_CLOCK, RGB_ORDER, SPI_DATA_RATE>(data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
#endif
|
||||
//@}
|
||||
|
||||
#ifdef FASTLED_HAS_CLOCKLESS
|
||||
/// @name Adding 3-wire led controllers
|
||||
//@{
|
||||
/// Add a clockless (aka 3wire, also DMX) based CLEDController instance to the world.
|
||||
/// There are two ways to call this method (as well as the other addLeds)
|
||||
/// variations. The first is with 2 arguments, in which case the arguments are a pointer to
|
||||
/// led data, and the number of leds used by this controller. The second is with 3 arguments, in which case
|
||||
/// the first argument is the same, the second argument is an offset into the CRGB data where this controller's
|
||||
/// CRGB data begins, and the third argument is the number of leds for this controller object.
|
||||
///
|
||||
/// This method also takes a 2 to 3 template parameters for identifying the specific chipset, data pin, and rgb ordering
|
||||
/// RGB ordering, and SPI data rate
|
||||
/// @param data - base point to an array of CRGB data structures
|
||||
/// @param nLedsOrOffset - number of leds (3 argument version) or offset into the data array
|
||||
/// @param nLedsIfOffset - number of leds (4 argument version)
|
||||
/// @tparam CHIPSET - the chipset type (required)
|
||||
/// @tparam DATA_PIN - the optional data pin for the leds (required)
|
||||
/// @tparam RGB_ORDER - the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
|
||||
/// @returns a reference to the added controller
|
||||
template<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, EOrder RGB_ORDER>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
static CHIPSET<DATA_PIN, RGB_ORDER> c;
|
||||
return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
template<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
static CHIPSET<DATA_PIN, RGB> c;
|
||||
return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
template<template<uint8_t DATA_PIN> class CHIPSET, uint8_t DATA_PIN>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
static CHIPSET<DATA_PIN> c;
|
||||
return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
#ifdef FASTSPI_USE_DMX_SIMPLE
|
||||
template<EClocklessChipsets CHIPSET, uint8_t DATA_PIN, EOrder RGB_ORDER=RGB>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
|
||||
{
|
||||
switch(CHIPSET) {
|
||||
case DMX: { static DMXController<DATA_PIN> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//@}
|
||||
#endif
|
||||
|
||||
/// @name Adding 3rd party library controllers
|
||||
//@{
|
||||
/// Add a 3rd party library based CLEDController instance to the world.
|
||||
/// There are two ways to call this method (as well as the other addLeds)
|
||||
/// variations. The first is with 2 arguments, in which case the arguments are a pointer to
|
||||
/// led data, and the number of leds used by this controller. The second is with 3 arguments, in which case
|
||||
/// the first argument is the same, the second argument is an offset into the CRGB data where this controller's
|
||||
/// CRGB data begins, and the third argument is the number of leds for this controller object. This class includes the SmartMatrix
|
||||
/// and OctoWS2811 based controllers
|
||||
///
|
||||
/// This method also takes a 1 to 2 template parameters for identifying the specific chipset and rgb ordering
|
||||
/// RGB ordering, and SPI data rate
|
||||
/// @param data - base point to an array of CRGB data structures
|
||||
/// @param nLedsOrOffset - number of leds (3 argument version) or offset into the data array
|
||||
/// @param nLedsIfOffset - number of leds (4 argument version)
|
||||
/// @tparam CHIPSET - the chipset type (required)
|
||||
/// @tparam RGB_ORDER - the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
|
||||
/// @returns a reference to the added controller
|
||||
template<template<EOrder RGB_ORDER> class CHIPSET, EOrder RGB_ORDER>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
static CHIPSET<RGB_ORDER> c;
|
||||
return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
template<template<EOrder RGB_ORDER> class CHIPSET>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
static CHIPSET<RGB> c;
|
||||
return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
|
||||
#ifdef USE_OCTOWS2811
|
||||
template<OWS2811 CHIPSET, EOrder RGB_ORDER>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
|
||||
{
|
||||
switch(CHIPSET) {
|
||||
case OCTOWS2811: { static COctoWS2811Controller<RGB_ORDER,WS2811_800kHz> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
case OCTOWS2811_400: { static COctoWS2811Controller<RGB_ORDER,WS2811_400kHz> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
#ifdef WS2813_800kHz
|
||||
case OCTOWS2813: { static COctoWS2811Controller<RGB_ORDER,WS2813_800kHz> controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template<OWS2811 CHIPSET>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
|
||||
{
|
||||
return addLeds<CHIPSET,GRB>(data,nLedsOrOffset,nLedsIfOffset);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_WS2812SERIAL
|
||||
template<SWS2812 CHIPSET, int DATA_PIN, EOrder RGB_ORDER>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
|
||||
{
|
||||
static CWS2812SerialController<DATA_PIN,RGB_ORDER> controller;
|
||||
return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SmartMatrix_h
|
||||
template<ESM CHIPSET>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0)
|
||||
{
|
||||
switch(CHIPSET) {
|
||||
case SMART_MATRIX: { static CSmartMatrixController controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//@}
|
||||
|
||||
|
||||
#ifdef FASTLED_HAS_BLOCKLESS
|
||||
|
||||
/// @name adding parallel output controllers
|
||||
//@{
|
||||
/// Add a block based CLEDController instance to the world.
|
||||
/// There are two ways to call this method (as well as the other addLeds)
|
||||
/// variations. The first is with 2 arguments, in which case the arguments are a pointer to
|
||||
/// led data, and the number of leds used by this controller. The second is with 3 arguments, in which case
|
||||
/// the first argument is the same, the second argument is an offset into the CRGB data where this controller's
|
||||
/// CRGB data begins, and the third argument is the number of leds for this controller object.
|
||||
///
|
||||
/// This method also takes a 2 to 3 template parameters for identifying the specific chipset and rgb ordering
|
||||
/// RGB ordering, and SPI data rate
|
||||
/// @param data - base point to an array of CRGB data structures
|
||||
/// @param nLedsOrOffset - number of leds (3 argument version) or offset into the data array
|
||||
/// @param nLedsIfOffset - number of leds (4 argument version)
|
||||
/// @tparam CHIPSET - the chipset/port type (required)
|
||||
/// @tparam NUM_LANES - how many parallel lanes of output to write
|
||||
/// @tparam RGB_ORDER - the rgb ordering for the leds (e.g. what order red, green, and blue data is written out in)
|
||||
/// @returns a reference to the added controller
|
||||
template<EBlockChipsets CHIPSET, int NUM_LANES, EOrder RGB_ORDER>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
switch(CHIPSET) {
|
||||
#ifdef PORTA_FIRST_PIN
|
||||
case WS2811_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2811_400_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2813_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case TM1803_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case UCS1903_PORTA: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTA_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
#endif
|
||||
#ifdef PORTB_FIRST_PIN
|
||||
case WS2811_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2811_400_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2813_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case TM1803_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case UCS1903_PORTB: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTB_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
#endif
|
||||
#ifdef PORTC_FIRST_PIN
|
||||
case WS2811_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2811_400_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2813_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case TM1803_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case UCS1903_PORTC: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTC_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
#endif
|
||||
#ifdef PORTD_FIRST_PIN
|
||||
case WS2811_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2811_400_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2813_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case TM1803_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case UCS1903_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
#endif
|
||||
#ifdef HAS_PORTDC
|
||||
case WS2811_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES,NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2811_400_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES,NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case WS2813_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES, NS(320), NS(320), NS(640), RGB_ORDER, 0, false, 300>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case TM1803_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES, NS(700), NS(1100), NS(700), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
case UCS1903_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<NUM_LANES, NS(500), NS(1500), NS(500), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template<EBlockChipsets CHIPSET, int NUM_LANES>
|
||||
static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {
|
||||
return addLeds<CHIPSET,NUM_LANES,GRB>(data,nLedsOrOffset,nLedsIfOffset);
|
||||
}
|
||||
//@}
|
||||
#endif
|
||||
|
||||
/// Set the global brightness scaling
|
||||
/// @param scale a 0-255 value for how much to scale all leds before writing them out
|
||||
void setBrightness(uint8_t scale) { m_Scale = scale; }
|
||||
|
||||
/// Get the current global brightness setting
|
||||
/// @returns the current global brightness value
|
||||
uint8_t getBrightness() { return m_Scale; }
|
||||
|
||||
/// Set the maximum power to be used, given in volts and milliamps.
|
||||
/// @param volts - how many volts the leds are being driven at (usually 5)
|
||||
/// @param milliamps - the maximum milliamps of power draw you want
|
||||
inline void setMaxPowerInVoltsAndMilliamps(uint8_t volts, uint32_t milliamps) { setMaxPowerInMilliWatts(volts * milliamps); }
|
||||
|
||||
/// Set the maximum power to be used, given in milliwatts
|
||||
/// @param milliwatts - the max power draw desired, in milliwatts
|
||||
inline void setMaxPowerInMilliWatts(uint32_t milliwatts) { m_pPowerFunc = &calculate_max_brightness_for_power_mW; m_nPowerData = milliwatts; }
|
||||
|
||||
/// Update all our controllers with the current led colors, using the passed in brightness
|
||||
/// @param scale temporarily override the scale
|
||||
void show(uint8_t scale);
|
||||
|
||||
/// Update all our controllers with the current led colors
|
||||
void show() { show(m_Scale); }
|
||||
|
||||
/// clear the leds, wiping the local array of data, optionally black out the leds as well
|
||||
/// @param writeData whether or not to write out to the leds as well
|
||||
void clear(bool writeData = false);
|
||||
|
||||
/// clear out the local data array
|
||||
void clearData();
|
||||
|
||||
/// Set all leds on all controllers to the given color/scale
|
||||
/// @param color what color to set the leds to
|
||||
/// @param scale what brightness scale to show at
|
||||
void showColor(const struct CRGB & color, uint8_t scale);
|
||||
|
||||
/// Set all leds on all controllers to the given color
|
||||
/// @param color what color to set the leds to
|
||||
void showColor(const struct CRGB & color) { showColor(color, m_Scale); }
|
||||
|
||||
/// Delay for the given number of milliseconds. Provided to allow the library to be used on platforms
|
||||
/// that don't have a delay function (to allow code to be more portable). Note: this will call show
|
||||
/// constantly to drive the dithering engine (and will call show at least once).
|
||||
/// @param ms the number of milliseconds to pause for
|
||||
void delay(unsigned long ms);
|
||||
|
||||
/// Set a global color temperature. Sets the color temperature for all added led strips, overriding whatever
|
||||
/// previous color temperature those controllers may have had
|
||||
/// @param temp A CRGB structure describing the color temperature
|
||||
void setTemperature(const struct CRGB & temp);
|
||||
|
||||
/// Set a global color correction. Sets the color correction for all added led strips,
|
||||
/// overriding whatever previous color correction those controllers may have had.
|
||||
/// @param correction A CRGB structure describin the color correction.
|
||||
void setCorrection(const struct CRGB & correction);
|
||||
|
||||
/// Set the dithering mode. Sets the dithering mode for all added led strips, overriding
|
||||
/// whatever previous dithering option those controllers may have had.
|
||||
/// @param ditherMode - what type of dithering to use, either BINARY_DITHER or DISABLE_DITHER
|
||||
void setDither(uint8_t ditherMode = BINARY_DITHER);
|
||||
|
||||
/// Set the maximum refresh rate. This is global for all leds. Attempts to
|
||||
/// call show faster than this rate will simply wait. Note that the refresh rate
|
||||
/// defaults to the slowest refresh rate of all the leds added through addLeds. If
|
||||
/// you wish to set/override this rate, be sure to call setMaxRefreshRate _after_
|
||||
/// adding all of your leds.
|
||||
/// @param refresh - maximum refresh rate in hz
|
||||
/// @param constrain - constrain refresh rate to the slowest speed yet set
|
||||
void setMaxRefreshRate(uint16_t refresh, bool constrain=false);
|
||||
|
||||
/// for debugging, will keep track of time between calls to countFPS, and every
|
||||
/// nFrames calls, it will update an internal counter for the current FPS.
|
||||
/// @todo make this a rolling counter
|
||||
/// @param nFrames - how many frames to time for determining FPS
|
||||
void countFPS(int nFrames=25);
|
||||
|
||||
/// Get the number of frames/second being written out
|
||||
/// @returns the most recently computed FPS value
|
||||
uint16_t getFPS() { return m_nFPS; }
|
||||
|
||||
/// Get how many controllers have been registered
|
||||
/// @returns the number of controllers (strips) that have been added with addLeds
|
||||
int count();
|
||||
|
||||
/// Get a reference to a registered controller
|
||||
/// @returns a reference to the Nth controller
|
||||
CLEDController & operator[](int x);
|
||||
|
||||
/// Get the number of leds in the first controller
|
||||
/// @returns the number of LEDs in the first controller
|
||||
int size() { return (*this)[0].size(); }
|
||||
|
||||
/// Get a pointer to led data for the first controller
|
||||
/// @returns pointer to the CRGB buffer for the first controller
|
||||
CRGB *leds() { return (*this)[0].leds(); }
|
||||
};
|
||||
|
||||
#define FastSPI_LED FastLED
|
||||
#define FastSPI_LED2 FastLED
|
||||
#ifndef LEDS
|
||||
#define LEDS FastLED
|
||||
#endif
|
||||
|
||||
extern CFastLED FastLED;
|
||||
|
||||
// Warnings for undefined things
|
||||
#ifndef HAS_HARDWARE_PIN_SUPPORT
|
||||
#warning "No pin/port mappings found, pin access will be slightly slower. See fastpin.h for info."
|
||||
#define NO_HARDWARE_PIN_SUPPORT
|
||||
#endif
|
||||
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
20
libraries/FastLED/LICENSE
Normal file
20
libraries/FastLED/LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 FastLED
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
29
libraries/FastLED/PORTING.md
Normal file
29
libraries/FastLED/PORTING.md
Normal file
@ -0,0 +1,29 @@
|
||||
=New platform porting guide=
|
||||
|
||||
== Setting up the basic files/folders ==
|
||||
|
||||
* Create platform directory (e.g. platforms/arm/kl26)
|
||||
* Create configuration header led_sysdefs_arm_kl26.h:
|
||||
* Define platform flags (like FASTLED_ARM/FASTLED_TEENSY)
|
||||
* Define configuration parameters re: interrupts, or clock doubling
|
||||
* Include extar system header files if needed
|
||||
* Create main platform include, fastled_arm_kl26.h
|
||||
* Include the various other header files as needed
|
||||
* Modify led_sysdefs.h to conditionally include platform sysdefs header file
|
||||
* Modify platforms.h to conditionally include platform fastled header
|
||||
|
||||
== Porting fastpin.h ==
|
||||
|
||||
The heart of the FastLED library is the fast pin accesss. This is a templated class that provides 1-2 cycle pin access, bypassing digital write and other such things. As such, this will usually be the first bit of the library that you will want to port when moving to a new platform. Once you have FastPIN up and running then you can do some basic work like testing toggles or running bit-bang'd SPI output.
|
||||
|
||||
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.
|
||||
|
||||
Explaining how the macros work and should be used is currently beyond the scope of this document.
|
||||
|
||||
== Porting fastspi.h ==
|
||||
|
||||
This is where you define the low level interface to the hardware SPI system (including a writePixels method that does a bunch of housekeeping for writing led data). Use the fastspi_nop.h file as a reference for the methods that need to be implemented. There are ofteh other useful methods that can help with the internals of the SPI code, I recommend taking a look at how the various platforms implement their SPI classes.
|
||||
|
||||
== Porting clockless.h ==
|
||||
|
||||
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.
|
90
libraries/FastLED/README.md
Normal file
90
libraries/FastLED/README.md
Normal file
@ -0,0 +1,90 @@
|
||||
[](https://gitter.im/FastLED/public)
|
||||
[](https://www.ardu-badge.com/FastLED)
|
||||
|
||||
IMPORTANT NOTE: For AVR based systems, avr-gcc 4.8.x is supported and tested. This means Arduino 1.6.5 and later.
|
||||
|
||||
|
||||
FastLED 3.2
|
||||
===========
|
||||
|
||||
This is a library for easily & efficiently controlling a wide variety of LED chipsets, like the ones
|
||||
sold by adafruit (Neopixel, DotStar, LPD8806), Sparkfun (WS2801), and aliexpress. In addition to writing to the
|
||||
leds, this library also includes a number of functions for high-performing 8bit math for manipulating
|
||||
your RGB values, as well as low level classes for abstracting out access to pins and SPI hardware, while
|
||||
still keeping things as fast as possible. Tested with Arduino up to 1.6.5 from arduino.cc.
|
||||
|
||||
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!
|
||||
|
||||
We have multiple goals with this library:
|
||||
|
||||
* Quick start for new developers - hook up your leds and go, no need to think about specifics of the led chipsets being used
|
||||
* 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.
|
||||
* 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
|
||||
|
||||
## Getting help
|
||||
|
||||
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.
|
||||
|
||||
## Simple example
|
||||
|
||||
How quickly can you get up and running with the library? Here's a simple blink program:
|
||||
|
||||
#include "FastLED.h"
|
||||
#define NUM_LEDS 60
|
||||
CRGB leds[NUM_LEDS];
|
||||
void setup() { FastLED.addLeds<NEOPIXEL, 6>(leds, NUM_LEDS); }
|
||||
void loop() {
|
||||
leds[0] = CRGB::White; FastLED.show(); delay(30);
|
||||
leds[0] = CRGB::Black; FastLED.show(); delay(30);
|
||||
}
|
||||
|
||||
## Supported LED chipsets
|
||||
|
||||
Here's a list of all the LED chipsets are supported. More details on the led chipsets are included *TODO: Link to wiki page*
|
||||
|
||||
* Adafruit's DotStars - AKA the APA102
|
||||
* Adafruit's Neopixel - aka the WS2812B (also WS2811/WS2812/WS2813, also supported in lo-speed mode) - a 3 wire addressable led chipset
|
||||
* TM1809/4 - 3 wire chipset, cheaply available on aliexpress.com
|
||||
* TM1803 - 3 wire chipset, sold by radio shack
|
||||
* UCS1903 - another 3 wire led chipset, cheap
|
||||
* GW6205 - another 3 wire led chipset
|
||||
* LPD8806 - SPI based chpiset, very high speed
|
||||
* WS2801 - SPI based chipset, cheap and widely available
|
||||
* SM16716 - SPI based chipset
|
||||
* APA102 - SPI based chipset
|
||||
* P9813 - aka Cool Neon's Total Control Lighting
|
||||
* DMX - send rgb data out over DMX using arduino DMX libraries
|
||||
* SmartMatrix panels - needs the SmartMatrix library - https://github.com/pixelmatix/SmartMatrix
|
||||
* LPD6803 - SPI based chpiset, chip CMODE pin must be set to 1 (inside oscillator mode)
|
||||
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Supported platforms
|
||||
|
||||
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.
|
||||
|
||||
* Arduino & compatibles - straight up arduino devices, uno, duo, leonardo, mega, nano, etc...
|
||||
* Arduino Yún
|
||||
* Adafruit Trinket & Gemma - Trinket Pro may be supported, but haven't tested to confirm yet
|
||||
* Teensy 2, Teensy++ 2, Teensy 3.0, Teensy 3.1/3.2, Teensy LC - arduino compataible from pjrc.com with some extra goodies (note the teensy 3, 3.1, and LC are ARM, not AVR!)
|
||||
* Arduino Due and the digistump DigiX
|
||||
* RFDuino
|
||||
* SparkCore
|
||||
* Arduino Zero
|
||||
* ESP8266 using the arduino board definitions from http://arduino.esp8266.com/stable/package_esp8266com_index.json - please be sure to also read https://github.com/FastLED/FastLED/wiki/ESP8266-notes for information specific to the 8266.
|
||||
* The wino board - http://wino-board.com
|
||||
|
||||
What types of platforms are we thinking about supporting in the future? Here's a short list: ChipKit32, Maple, Beagleboard
|
||||
|
||||
## What about that name?
|
||||
|
||||
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.
|
||||
|
||||
## For more information
|
||||
|
||||
Check out the official site http://fastled.io for links to documentation, issues, and news
|
||||
|
||||
|
||||
*TODO* - get candy
|
28
libraries/FastLED/bitswap.cpp
Normal file
28
libraries/FastLED/bitswap.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#define FASTLED_INTERNAL
|
||||
#include "FastLED.h"
|
||||
|
||||
/// Simplified form of bits rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating
|
||||
/// data into LSB for a faster write (the code using this data can happily walk the array backwards)
|
||||
void transpose8x1_noinline(unsigned char *A, unsigned char *B) {
|
||||
uint32_t x, y, t;
|
||||
|
||||
// Load the array and pack it into x and y.
|
||||
y = *(unsigned int*)(A);
|
||||
x = *(unsigned int*)(A+4);
|
||||
|
||||
// pre-transform x
|
||||
t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
|
||||
t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
|
||||
|
||||
// pre-transform y
|
||||
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
|
||||
t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
|
||||
|
||||
// final transform
|
||||
t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
|
||||
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
|
||||
x = t;
|
||||
|
||||
*((uint32_t*)B) = y;
|
||||
*((uint32_t*)(B+4)) = x;
|
||||
}
|
276
libraries/FastLED/bitswap.h
Normal file
276
libraries/FastLED/bitswap.h
Normal file
@ -0,0 +1,276 @@
|
||||
#ifndef __INC_BITSWAP_H
|
||||
#define __INC_BITSWAP_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
///@file bitswap.h
|
||||
///Functions for rotating bits/bytes
|
||||
|
||||
///@defgroup Bitswap Bit swapping/rotate
|
||||
///Functions for doing a rotation of bits/bytes used by parallel output
|
||||
///@{
|
||||
#if defined(FASTLED_ARM) || defined(FASTLED_ESP8266)
|
||||
/// structure representing 8 bits of access
|
||||
typedef union {
|
||||
uint8_t raw;
|
||||
struct {
|
||||
uint32_t a0:1;
|
||||
uint32_t a1:1;
|
||||
uint32_t a2:1;
|
||||
uint32_t a3:1;
|
||||
uint32_t a4:1;
|
||||
uint32_t a5:1;
|
||||
uint32_t a6:1;
|
||||
uint32_t a7:1;
|
||||
};
|
||||
} just8bits;
|
||||
|
||||
/// structure representing 32 bits of access
|
||||
typedef struct {
|
||||
uint32_t a0:1;
|
||||
uint32_t a1:1;
|
||||
uint32_t a2:1;
|
||||
uint32_t a3:1;
|
||||
uint32_t a4:1;
|
||||
uint32_t a5:1;
|
||||
uint32_t a6:1;
|
||||
uint32_t a7:1;
|
||||
uint32_t b0:1;
|
||||
uint32_t b1:1;
|
||||
uint32_t b2:1;
|
||||
uint32_t b3:1;
|
||||
uint32_t b4:1;
|
||||
uint32_t b5:1;
|
||||
uint32_t b6:1;
|
||||
uint32_t b7:1;
|
||||
uint32_t c0:1;
|
||||
uint32_t c1:1;
|
||||
uint32_t c2:1;
|
||||
uint32_t c3:1;
|
||||
uint32_t c4:1;
|
||||
uint32_t c5:1;
|
||||
uint32_t c6:1;
|
||||
uint32_t c7:1;
|
||||
uint32_t d0:1;
|
||||
uint32_t d1:1;
|
||||
uint32_t d2:1;
|
||||
uint32_t d3:1;
|
||||
uint32_t d4:1;
|
||||
uint32_t d5:1;
|
||||
uint32_t d6:1;
|
||||
uint32_t d7:1;
|
||||
} sub4;
|
||||
|
||||
/// union containing a full 8 bytes to swap the bit orientation on
|
||||
typedef union {
|
||||
uint32_t word[2];
|
||||
uint8_t bytes[8];
|
||||
struct {
|
||||
sub4 a;
|
||||
sub4 b;
|
||||
};
|
||||
} bitswap_type;
|
||||
|
||||
|
||||
#define SWAPSA(X,N) out. X ## 0 = in.a.a ## N; \
|
||||
out. X ## 1 = in.a.b ## N; \
|
||||
out. X ## 2 = in.a.c ## N; \
|
||||
out. X ## 3 = in.a.d ## N;
|
||||
|
||||
#define SWAPSB(X,N) out. X ## 0 = in.b.a ## N; \
|
||||
out. X ## 1 = in.b.b ## N; \
|
||||
out. X ## 2 = in.b.c ## N; \
|
||||
out. X ## 3 = in.b.d ## N;
|
||||
|
||||
#define SWAPS(X,N) out. X ## 0 = in.a.a ## N; \
|
||||
out. X ## 1 = in.a.b ## N; \
|
||||
out. X ## 2 = in.a.c ## N; \
|
||||
out. X ## 3 = in.a.d ## N; \
|
||||
out. X ## 4 = in.b.a ## N; \
|
||||
out. X ## 5 = in.b.b ## N; \
|
||||
out. X ## 6 = in.b.c ## N; \
|
||||
out. X ## 7 = in.b.d ## N;
|
||||
|
||||
|
||||
/// Do an 8byte by 8bit rotation
|
||||
__attribute__((always_inline)) inline void swapbits8(bitswap_type in, bitswap_type & out) {
|
||||
|
||||
// SWAPS(a.a,7);
|
||||
// SWAPS(a.b,6);
|
||||
// SWAPS(a.c,5);
|
||||
// SWAPS(a.d,4);
|
||||
// SWAPS(b.a,3);
|
||||
// SWAPS(b.b,2);
|
||||
// SWAPS(b.c,1);
|
||||
// SWAPS(b.d,0);
|
||||
|
||||
// SWAPSA(a.a,7);
|
||||
// SWAPSA(a.b,6);
|
||||
// SWAPSA(a.c,5);
|
||||
// SWAPSA(a.d,4);
|
||||
//
|
||||
// SWAPSB(a.a,7);
|
||||
// SWAPSB(a.b,6);
|
||||
// SWAPSB(a.c,5);
|
||||
// SWAPSB(a.d,4);
|
||||
//
|
||||
// SWAPSA(b.a,3);
|
||||
// SWAPSA(b.b,2);
|
||||
// SWAPSA(b.c,1);
|
||||
// SWAPSA(b.d,0);
|
||||
// //
|
||||
// SWAPSB(b.a,3);
|
||||
// SWAPSB(b.b,2);
|
||||
// SWAPSB(b.c,1);
|
||||
// SWAPSB(b.d,0);
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
just8bits work;
|
||||
work.a3 = in.word[0] >> 31;
|
||||
work.a2 = in.word[0] >> 23;
|
||||
work.a1 = in.word[0] >> 15;
|
||||
work.a0 = in.word[0] >> 7;
|
||||
in.word[0] <<= 1;
|
||||
work.a7 = in.word[1] >> 31;
|
||||
work.a6 = in.word[1] >> 23;
|
||||
work.a5 = in.word[1] >> 15;
|
||||
work.a4 = in.word[1] >> 7;
|
||||
in.word[1] <<= 1;
|
||||
out.bytes[i] = work.raw;
|
||||
}
|
||||
}
|
||||
|
||||
/// Slow version of the 8 byte by 8 bit rotation
|
||||
__attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned char *B) {
|
||||
|
||||
for(int row = 0; row < 7; row++) {
|
||||
uint8_t x = A[row];
|
||||
|
||||
uint8_t bit = (1<<row);
|
||||
unsigned char *p = B;
|
||||
for(uint32_t mask = 1<<7 ; mask ; mask >>= 1) {
|
||||
if(x & mask) {
|
||||
*p++ |= bit;
|
||||
} else {
|
||||
*p++ &= ~bit;
|
||||
}
|
||||
}
|
||||
// B[7] |= (x & 0x01) << row; x >>= 1;
|
||||
// B[6] |= (x & 0x01) << row; x >>= 1;
|
||||
// B[5] |= (x & 0x01) << row; x >>= 1;
|
||||
// B[4] |= (x & 0x01) << row; x >>= 1;
|
||||
// B[3] |= (x & 0x01) << row; x >>= 1;
|
||||
// B[2] |= (x & 0x01) << row; x >>= 1;
|
||||
// B[1] |= (x & 0x01) << row; x >>= 1;
|
||||
// B[0] |= (x & 0x01) << row; x >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void transpose8x1_noinline(unsigned char *A, unsigned char *B);
|
||||
|
||||
/// Simplified form of bits rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating
|
||||
/// data into LSB for a faster write (the code using this data can happily walk the array backwards)
|
||||
__attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsigned char *B) {
|
||||
uint32_t x, y, t;
|
||||
|
||||
// Load the array and pack it into x and y.
|
||||
y = *(unsigned int*)(A);
|
||||
x = *(unsigned int*)(A+4);
|
||||
|
||||
// pre-transform x
|
||||
t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
|
||||
t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
|
||||
|
||||
// pre-transform y
|
||||
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
|
||||
t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
|
||||
|
||||
// final transform
|
||||
t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
|
||||
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
|
||||
x = t;
|
||||
|
||||
*((uint32_t*)B) = y;
|
||||
*((uint32_t*)(B+4)) = x;
|
||||
}
|
||||
|
||||
/// Simplified form of bits rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt
|
||||
__attribute__((always_inline)) inline void transpose8x1_MSB(unsigned char *A, unsigned char *B) {
|
||||
uint32_t x, y, t;
|
||||
|
||||
// Load the array and pack it into x and y.
|
||||
y = *(unsigned int*)(A);
|
||||
x = *(unsigned int*)(A+4);
|
||||
|
||||
// pre-transform x
|
||||
t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
|
||||
t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
|
||||
|
||||
// pre-transform y
|
||||
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
|
||||
t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
|
||||
|
||||
// final transform
|
||||
t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
|
||||
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
|
||||
x = t;
|
||||
|
||||
B[7] = y; y >>= 8;
|
||||
B[6] = y; y >>= 8;
|
||||
B[5] = y; y >>= 8;
|
||||
B[4] = y;
|
||||
|
||||
B[3] = x; x >>= 8;
|
||||
B[2] = x; x >>= 8;
|
||||
B[1] = x; x >>= 8;
|
||||
B[0] = x; /* */
|
||||
}
|
||||
|
||||
/// templated bit-rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt
|
||||
template<int m, int n>
|
||||
__attribute__((always_inline)) inline void transpose8(unsigned char *A, unsigned char *B) {
|
||||
uint32_t x, y, t;
|
||||
|
||||
// Load the array and pack it into x and y.
|
||||
if(m == 1) {
|
||||
y = *(unsigned int*)(A);
|
||||
x = *(unsigned int*)(A+4);
|
||||
} else {
|
||||
x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m];
|
||||
y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m];
|
||||
}
|
||||
|
||||
// pre-transform x
|
||||
t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7);
|
||||
t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14);
|
||||
|
||||
// pre-transform y
|
||||
t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7);
|
||||
t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14);
|
||||
|
||||
// final transform
|
||||
t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F);
|
||||
y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
|
||||
x = t;
|
||||
|
||||
B[7*n] = y; y >>= 8;
|
||||
B[6*n] = y; y >>= 8;
|
||||
B[5*n] = y; y >>= 8;
|
||||
B[4*n] = y;
|
||||
|
||||
B[3*n] = x; x >>= 8;
|
||||
B[2*n] = x; x >>= 8;
|
||||
B[n] = x; x >>= 8;
|
||||
B[0] = x;
|
||||
// B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0;
|
||||
// B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
///@}
|
||||
#endif
|
591
libraries/FastLED/chipsets.h
Normal file
591
libraries/FastLED/chipsets.h
Normal file
@ -0,0 +1,591 @@
|
||||
#ifndef __INC_CHIPSETS_H
|
||||
#define __INC_CHIPSETS_H
|
||||
|
||||
#include "FastLED.h"
|
||||
#include "pixeltypes.h"
|
||||
|
||||
///@file chipsets.h
|
||||
/// contains the bulk of the definitions for the various LED chipsets supported.
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
///@defgroup chipsets
|
||||
/// Implementations of CLEDController classes for various led chipsets.
|
||||
///
|
||||
///@{
|
||||
|
||||
#if defined(ARDUINO) //&& defined(SoftwareSerial_h)
|
||||
|
||||
|
||||
#if defined(SoftwareSerial_h)
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#define HAS_PIXIE
|
||||
|
||||
/// Adafruit Pixie controller class
|
||||
/// @tparam DATAPIN the pin to write data out on
|
||||
/// @tparam RGB_ORDER the RGB ordering for the led data
|
||||
template<uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class PixieController : public CPixelLEDController<RGB_ORDER> {
|
||||
SoftwareSerial Serial;
|
||||
CMinWait<2000> mWait;
|
||||
public:
|
||||
PixieController() : Serial(-1, DATA_PIN) {}
|
||||
|
||||
protected:
|
||||
virtual void init() {
|
||||
Serial.begin(115200);
|
||||
mWait.mark();
|
||||
}
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mWait.wait();
|
||||
while(pixels.has(1)) {
|
||||
uint8_t r = pixels.loadAndScale0();
|
||||
Serial.write(r);
|
||||
uint8_t g = pixels.loadAndScale1();
|
||||
Serial.write(g);
|
||||
uint8_t b = pixels.loadAndScale2();
|
||||
Serial.write(b);
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
}
|
||||
mWait.mark();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// template<SoftwareSerial & STREAM, EOrder RGB_ORDER = RGB>
|
||||
// class PixieController : public PixieBaseController<STREAM, RGB_ORDER> {
|
||||
// public:
|
||||
// virtual void init() {
|
||||
// STREAM.begin(115200);
|
||||
// }
|
||||
// };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///@name Clocked chipsets - nominally SPI based these chipsets have a data and a clock line.
|
||||
///@{
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// LPD8806 controller class - takes data/clock/select pin values (N.B. should take an SPI definition?)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// LPD8806 controller class.
|
||||
/// @tparam DATA_PIN the data pin for these leds
|
||||
/// @tparam CLOCK_PIN the clock pin for these leds
|
||||
/// @tparam RGB_ORDER the RGB ordering for these leds
|
||||
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12)
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(12) >
|
||||
class LPD8806Controller : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
|
||||
|
||||
class LPD8806_ADJUST {
|
||||
public:
|
||||
// LPD8806 spec wants the high bit of every rgb data byte sent out to be set.
|
||||
__attribute__((always_inline)) inline static uint8_t adjust(register uint8_t data) { return ((data>>1) | 0x80) + ((data && (data<254)) & 0x01); }
|
||||
__attribute__((always_inline)) inline static void postBlock(int len) {
|
||||
SPI::writeBytesValueRaw(0, ((len*3+63)>>6));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SPI mSPI;
|
||||
public:
|
||||
|
||||
LPD8806Controller() {}
|
||||
virtual void init() {
|
||||
mSPI.init();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(pixels);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WS2801 definition - takes data/clock/select pin values (N.B. should take an SPI definition?)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// WS2801 controller class.
|
||||
/// @tparam DATA_PIN the data pin for these leds
|
||||
/// @tparam CLOCK_PIN the clock pin for these leds
|
||||
/// @tparam RGB_ORDER the RGB ordering for these leds
|
||||
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(1)
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(1)>
|
||||
class WS2801Controller : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
|
||||
SPI mSPI;
|
||||
CMinWait<1000> mWaitDelay;
|
||||
public:
|
||||
WS2801Controller() {}
|
||||
|
||||
virtual void init() {
|
||||
mSPI.init();
|
||||
mWaitDelay.mark();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mWaitDelay.wait();
|
||||
mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(pixels);
|
||||
mWaitDelay.mark();
|
||||
}
|
||||
};
|
||||
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(25)>
|
||||
class WS2803Controller : public WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_SPEED> {};
|
||||
|
||||
/// LPD6803 controller class (LPD1101).
|
||||
/// 16 bit (1 bit - const "1", 5 bit - red, 5 bit - green, 5 bit blue).
|
||||
/// In chip CMODE pin must be set to 1 (inside oscillator mode).
|
||||
/// Datasheet: https://cdn-shop.adafruit.com/datasheets/LPD6803.pdf
|
||||
/// @tparam DATA_PIN the data pin for these leds
|
||||
/// @tparam CLOCK_PIN the clock pin for these leds
|
||||
/// @tparam RGB_ORDER the RGB ordering for these leds
|
||||
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12)
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(12)>
|
||||
class LPD6803Controller : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
|
||||
SPI mSPI;
|
||||
|
||||
void startBoundary() { mSPI.writeByte(0); mSPI.writeByte(0); mSPI.writeByte(0); mSPI.writeByte(0); }
|
||||
|
||||
public:
|
||||
LPD6803Controller() {}
|
||||
|
||||
virtual void init() {
|
||||
mSPI.init();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mSPI.select();
|
||||
|
||||
startBoundary();
|
||||
while(pixels.has(1)) {
|
||||
register uint16_t command;
|
||||
command = 0x8000;
|
||||
command |= (pixels.loadAndScale0() & 0xF8) << 7; // red is the high 5 bits
|
||||
command |= (pixels.loadAndScale1() & 0xF8) << 2; // green is the middle 5 bits
|
||||
mSPI.writeByte((command >> 8) & 0xFF);
|
||||
command |= pixels.loadAndScale2() >> 3 ; // blue is the low 5 bits
|
||||
mSPI.writeByte(command & 0xFF);
|
||||
|
||||
pixels.stepDithering();
|
||||
pixels.advanceData();
|
||||
}
|
||||
//endBoundary(pixels.size());
|
||||
mSPI.waitFully();
|
||||
mSPI.release();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// APA102 definition - takes data/clock/select pin values (N.B. should take an SPI definition?)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// APA102 controller class.
|
||||
/// @tparam DATA_PIN the data pin for these leds
|
||||
/// @tparam CLOCK_PIN the clock pin for these leds
|
||||
/// @tparam RGB_ORDER the RGB ordering for these leds
|
||||
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12)
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(12)>
|
||||
class APA102Controller : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
|
||||
SPI mSPI;
|
||||
|
||||
void startBoundary() { mSPI.writeWord(0); mSPI.writeWord(0); }
|
||||
void endBoundary(int nLeds) { int nDWords = (nLeds/32); do { mSPI.writeByte(0xFF); mSPI.writeByte(0x00); mSPI.writeByte(0x00); mSPI.writeByte(0x00); } while(nDWords--); }
|
||||
|
||||
inline void writeLed(uint8_t brightness, uint8_t b0, uint8_t b1, uint8_t b2) __attribute__((always_inline)) {
|
||||
#ifdef FASTLED_SPI_BYTE_ONLY
|
||||
mSPI.writeByte(0xE0 | brightness);
|
||||
mSPI.writeByte(b0);
|
||||
mSPI.writeByte(b1);
|
||||
mSPI.writeByte(b2);
|
||||
#else
|
||||
uint16_t b = 0xE000 | (brightness << 8) | (uint16_t)b0;
|
||||
mSPI.writeWord(b);
|
||||
uint16_t w = b1 << 8;
|
||||
w |= b2;
|
||||
mSPI.writeWord(w);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
APA102Controller() {}
|
||||
|
||||
virtual void init() {
|
||||
mSPI.init();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mSPI.select();
|
||||
|
||||
uint8_t s0 = pixels.getScale0(), s1 = pixels.getScale1(), s2 = pixels.getScale2();
|
||||
#if FASTLED_USE_GLOBAL_BRIGHTNESS == 1
|
||||
const uint16_t maxBrightness = 0x1F;
|
||||
uint16_t brightness = ((((uint16_t)max(max(s0, s1), s2) + 1) * maxBrightness - 1) >> 8) + 1;
|
||||
s0 = (maxBrightness * s0 + (brightness >> 1)) / brightness;
|
||||
s1 = (maxBrightness * s1 + (brightness >> 1)) / brightness;
|
||||
s2 = (maxBrightness * s2 + (brightness >> 1)) / brightness;
|
||||
#else
|
||||
const uint8_t brightness = 0x1F;
|
||||
#endif
|
||||
|
||||
startBoundary();
|
||||
while (pixels.has(1)) {
|
||||
writeLed(brightness, pixels.loadAndScale0(0, s0), pixels.loadAndScale1(0, s1), pixels.loadAndScale2(0, s2));
|
||||
pixels.stepDithering();
|
||||
pixels.advanceData();
|
||||
}
|
||||
endBoundary(pixels.size());
|
||||
|
||||
mSPI.waitFully();
|
||||
mSPI.release();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// SK9822 controller class.
|
||||
/// @tparam DATA_PIN the data pin for these leds
|
||||
/// @tparam CLOCK_PIN the clock pin for these leds
|
||||
/// @tparam RGB_ORDER the RGB ordering for these leds
|
||||
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(24)
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(24)>
|
||||
class SK9822Controller : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
|
||||
SPI mSPI;
|
||||
|
||||
void startBoundary() { mSPI.writeWord(0); mSPI.writeWord(0); }
|
||||
void endBoundary(int nLeds) { int nLongWords = (nLeds/32); do { mSPI.writeByte(0x00); mSPI.writeByte(0x00); mSPI.writeByte(0x00); mSPI.writeByte(0x00); } while(nLongWords--); }
|
||||
|
||||
inline void writeLed(uint8_t brightness, uint8_t b0, uint8_t b1, uint8_t b2) __attribute__((always_inline)) {
|
||||
#ifdef FASTLED_SPI_BYTE_ONLY
|
||||
mSPI.writeByte(0xE0 | brightness);
|
||||
mSPI.writeByte(b0);
|
||||
mSPI.writeByte(b1);
|
||||
mSPI.writeByte(b2);
|
||||
#else
|
||||
uint16_t b = 0xE000 | (brightness << 8) | (uint16_t)b0;
|
||||
mSPI.writeWord(b);
|
||||
uint16_t w = b1 << 8;
|
||||
w |= b2;
|
||||
mSPI.writeWord(w);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
SK9822Controller() {}
|
||||
|
||||
virtual void init() {
|
||||
mSPI.init();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mSPI.select();
|
||||
|
||||
uint8_t s0 = pixels.getScale0(), s1 = pixels.getScale1(), s2 = pixels.getScale2();
|
||||
#if FASTLED_USE_GLOBAL_BRIGHTNESS == 1
|
||||
const uint16_t maxBrightness = 0x1F;
|
||||
uint16_t brightness = ((((uint16_t)max(max(s0, s1), s2) + 1) * maxBrightness - 1) >> 8) + 1;
|
||||
s0 = (maxBrightness * s0 + (brightness >> 1)) / brightness;
|
||||
s1 = (maxBrightness * s1 + (brightness >> 1)) / brightness;
|
||||
s2 = (maxBrightness * s2 + (brightness >> 1)) / brightness;
|
||||
#else
|
||||
const uint8_t brightness = 0x1F;
|
||||
#endif
|
||||
|
||||
startBoundary();
|
||||
while (pixels.has(1)) {
|
||||
writeLed(brightness, pixels.loadAndScale0(0, s0), pixels.loadAndScale1(0, s1), pixels.loadAndScale2(0, s2));
|
||||
pixels.stepDithering();
|
||||
pixels.advanceData();
|
||||
}
|
||||
|
||||
endBoundary(pixels.size());
|
||||
|
||||
mSPI.waitFully();
|
||||
mSPI.release();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// P9813 definition - takes data/clock/select pin values (N.B. should take an SPI definition?)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// P9813 controller class.
|
||||
/// @tparam DATA_PIN the data pin for these leds
|
||||
/// @tparam CLOCK_PIN the clock pin for these leds
|
||||
/// @tparam RGB_ORDER the RGB ordering for these leds
|
||||
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(10)
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(10)>
|
||||
class P9813Controller : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
|
||||
SPI mSPI;
|
||||
|
||||
void writeBoundary() { mSPI.writeWord(0); mSPI.writeWord(0); }
|
||||
|
||||
inline void writeLed(uint8_t r, uint8_t g, uint8_t b) __attribute__((always_inline)) {
|
||||
register uint8_t top = 0xC0 | ((~b & 0xC0) >> 2) | ((~g & 0xC0) >> 4) | ((~r & 0xC0) >> 6);
|
||||
mSPI.writeByte(top); mSPI.writeByte(b); mSPI.writeByte(g); mSPI.writeByte(r);
|
||||
}
|
||||
|
||||
public:
|
||||
P9813Controller() {}
|
||||
|
||||
virtual void init() {
|
||||
mSPI.init();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mSPI.select();
|
||||
|
||||
writeBoundary();
|
||||
while(pixels.has(1)) {
|
||||
writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2());
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
}
|
||||
writeBoundary();
|
||||
mSPI.waitFully();
|
||||
|
||||
mSPI.release();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// SM16716 definition - takes data/clock/select pin values (N.B. should take an SPI definition?)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// SM16716 controller class.
|
||||
/// @tparam DATA_PIN the data pin for these leds
|
||||
/// @tparam CLOCK_PIN the clock pin for these leds
|
||||
/// @tparam RGB_ORDER the RGB ordering for these leds
|
||||
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(16)
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(16)>
|
||||
class SM16716Controller : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
|
||||
SPI mSPI;
|
||||
|
||||
void writeHeader() {
|
||||
// Write out 50 zeros to the spi line (6 blocks of 8 followed by two single bit writes)
|
||||
mSPI.select();
|
||||
mSPI.writeBytesValueRaw(0, 6);
|
||||
mSPI.waitFully();
|
||||
mSPI.template writeBit<0>(0);
|
||||
mSPI.template writeBit<0>(0);
|
||||
mSPI.release();
|
||||
}
|
||||
|
||||
public:
|
||||
SM16716Controller() {}
|
||||
|
||||
virtual void init() {
|
||||
mSPI.init();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
// Make sure the FLAG_START_BIT flag is set to ensure that an extra 1 bit is sent at the start
|
||||
// of each triplet of bytes for rgb data
|
||||
// writeHeader();
|
||||
mSPI.template writePixels<FLAG_START_BIT, DATA_NOP, RGB_ORDER>( pixels );
|
||||
writeHeader();
|
||||
}
|
||||
|
||||
};
|
||||
/// @}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Clockless template instantiations - see clockless.h for how the timing values are used
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef FASTLED_HAS_CLOCKLESS
|
||||
/// @name clockless controllers
|
||||
/// Provides timing definitions for the variety of clockless controllers supplied by the library.
|
||||
/// @{
|
||||
|
||||
// We want to force all avr's to use the Trinket controller when running at 8Mhz, because even the 328's at 8Mhz
|
||||
// need the more tightly defined timeframes.
|
||||
#if (F_CPU == 8000000 || F_CPU == 16000000 || F_CPU == 24000000) // || F_CPU == 48000000 || F_CPU == 96000000) // 125ns/clock
|
||||
#define FMUL (F_CPU/8000000)
|
||||
|
||||
// GE8822
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class GE8822Controller800Khz : public ClocklessController<DATA_PIN, 3 * FMUL, 5 * FMUL, 3 * FMUL, RGB_ORDER, 4> {};
|
||||
|
||||
// LPD1886
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class LPD1886Controller1250Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 3 * FMUL, 2 * FMUL, RGB_ORDER, 4> {};
|
||||
|
||||
// LPD1886
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class LPD1886Controller1250Khz_8bit : public ClocklessController<DATA_PIN, 2 * FMUL, 3 * FMUL, 2 * FMUL, RGB_ORDER> {};
|
||||
|
||||
// WS2811@800khz 2 clocks, 5 clocks, 3 clocks
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class WS2812Controller800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 5 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class WS2811Controller800Khz : public ClocklessController<DATA_PIN, 3 * FMUL, 4 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> //not tested
|
||||
class WS2813Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 4 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class WS2811Controller400Khz : public ClocklessController<DATA_PIN, 4 * FMUL, 10 * FMUL, 6 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class SK6822Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 8 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class SM16703Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 4 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class SK6812Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 3 * FMUL, 4 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS1903Controller400Khz : public ClocklessController<DATA_PIN, 4 * FMUL, 12 * FMUL, 4 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS1903BController800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 4 * FMUL, 4 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS1904Controller800Khz : public ClocklessController<DATA_PIN, 3 * FMUL, 3 * FMUL, 4 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS2903Controller : public ClocklessController<DATA_PIN, 2 * FMUL, 6 * FMUL, 2 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class TM1809Controller800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 5 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class TM1803Controller400Khz : public ClocklessController<DATA_PIN, 6 * FMUL, 9 * FMUL, 6 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class TM1829Controller800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 5 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class GW6205Controller400Khz : public ClocklessController<DATA_PIN, 6 * FMUL, 7 * FMUL, 6 * FMUL, RGB_ORDER, 4> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class GW6205Controller800Khz : public ClocklessController<DATA_PIN, 2 * FMUL, 4 * FMUL, 4 * FMUL, RGB_ORDER, 4> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class PL9823Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 8 * FMUL, 3 * FMUL, RGB_ORDER> {};
|
||||
|
||||
#else
|
||||
// GE8822 - 350ns 660ns 350ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class GE8822Controller800Khz : public ClocklessController<DATA_PIN, NS(350), NS(660), NS(350), RGB_ORDER, 4> {};
|
||||
|
||||
// GW6205@400khz - 800ns, 800ns, 800ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class GW6205Controller400Khz : public ClocklessController<DATA_PIN, NS(800), NS(800), NS(800), RGB_ORDER, 4> {};
|
||||
|
||||
// GW6205@400khz - 400ns, 400ns, 400ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class GW6205Controller800Khz : public ClocklessController<DATA_PIN, NS(400), NS(400), NS(400), RGB_ORDER, 4> {};
|
||||
|
||||
// UCS1903 - 500ns, 1500ns, 500ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS1903Controller400Khz : public ClocklessController<DATA_PIN, NS(500), NS(1500), NS(500), RGB_ORDER> {};
|
||||
|
||||
// UCS1903B - 400ns, 450ns, 450ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS1903BController800Khz : public ClocklessController<DATA_PIN, NS(400), NS(450), NS(450), RGB_ORDER> {};
|
||||
|
||||
// UCS1904 - 400ns, 400ns, 450ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS1904Controller800Khz : public ClocklessController<DATA_PIN, NS(400), NS(400), NS(450), RGB_ORDER> {};
|
||||
|
||||
// UCS2903 - 250ns, 750ns, 250ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class UCS2903Controller : public ClocklessController<DATA_PIN, NS(250), NS(750), NS(250), RGB_ORDER> {};
|
||||
|
||||
// TM1809 - 350ns, 350ns, 550ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class TM1809Controller800Khz : public ClocklessController<DATA_PIN, NS(350), NS(350), NS(450), RGB_ORDER> {};
|
||||
|
||||
// WS2811 - 320ns, 320ns, 640ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class WS2811Controller800Khz : public ClocklessController<DATA_PIN, NS(320), NS(320), NS(640), RGB_ORDER> {};
|
||||
|
||||
// WS2813 - 320ns, 320ns, 640ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class WS2813Controller : public ClocklessController<DATA_PIN, NS(320), NS(320), NS(640), RGB_ORDER> {};
|
||||
|
||||
// WS2812 - 250ns, 625ns, 375ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class WS2812Controller800Khz : public ClocklessController<DATA_PIN, NS(250), NS(625), NS(375), RGB_ORDER> {};
|
||||
|
||||
// WS2811@400khz - 800ns, 800ns, 900ns
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class WS2811Controller400Khz : public ClocklessController<DATA_PIN, NS(800), NS(800), NS(900), RGB_ORDER> {};
|
||||
|
||||
// 750NS, 750NS, 750NS
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class TM1803Controller400Khz : public ClocklessController<DATA_PIN, NS(700), NS(1100), NS(700), RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class TM1829Controller800Khz : public ClocklessController<DATA_PIN, NS(340), NS(340), NS(550), RGB_ORDER, 0, true, 500> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class TM1829Controller1600Khz : public ClocklessController<DATA_PIN, NS(100), NS(300), NS(200), RGB_ORDER, 0, true, 500> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class LPD1886Controller1250Khz : public ClocklessController<DATA_PIN, NS(200), NS(400), NS(200), RGB_ORDER, 4> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class LPD1886Controller1250Khz_8bit : public ClocklessController<DATA_PIN, NS(200), NS(400), NS(200), RGB_ORDER> {};
|
||||
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class SK6822Controller : public ClocklessController<DATA_PIN, NS(375), NS(1000), NS(375), RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class SK6812Controller : public ClocklessController<DATA_PIN, NS(300), NS(300), NS(600), RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class SM16703Controller : public ClocklessController<DATA_PIN, NS(300), NS(600), NS(300), RGB_ORDER> {};
|
||||
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
|
||||
class PL9823Controller : public ClocklessController<DATA_PIN, NS(350), NS(1010), NS(350), RGB_ORDER> {};
|
||||
#endif
|
||||
///@}
|
||||
|
||||
#endif
|
||||
///@}
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
84
libraries/FastLED/color.h
Normal file
84
libraries/FastLED/color.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef __INC_COLOR_H
|
||||
#define __INC_COLOR_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
///@file color.h
|
||||
/// contains definitions for color correction and temperature
|
||||
///@defgroup ColorEnums Color correction/temperature
|
||||
/// definitions for color correction and light temperatures
|
||||
///@{
|
||||
typedef enum {
|
||||
// Color correction starting points
|
||||
|
||||
/// typical values for SMD5050 LEDs
|
||||
///@{
|
||||
TypicalSMD5050=0xFFB0F0 /* 255, 176, 240 */,
|
||||
TypicalLEDStrip=0xFFB0F0 /* 255, 176, 240 */,
|
||||
///@}
|
||||
|
||||
/// typical values for 8mm "pixels on a string"
|
||||
/// also for many through-hole 'T' package LEDs
|
||||
///@{
|
||||
Typical8mmPixel=0xFFE08C /* 255, 224, 140 */,
|
||||
TypicalPixelString=0xFFE08C /* 255, 224, 140 */,
|
||||
///@}
|
||||
|
||||
/// uncorrected color
|
||||
UncorrectedColor=0xFFFFFF
|
||||
|
||||
} LEDColorCorrection;
|
||||
|
||||
|
||||
typedef enum {
|
||||
/// @name Black-body radiation light sources
|
||||
/// Black-body radiation light sources emit a (relatively) continuous
|
||||
/// spectrum, and can be described as having a Kelvin 'temperature'
|
||||
///@{
|
||||
/// 1900 Kelvin
|
||||
Candle=0xFF9329 /* 1900 K, 255, 147, 41 */,
|
||||
/// 2600 Kelvin
|
||||
Tungsten40W=0xFFC58F /* 2600 K, 255, 197, 143 */,
|
||||
/// 2850 Kelvin
|
||||
Tungsten100W=0xFFD6AA /* 2850 K, 255, 214, 170 */,
|
||||
/// 3200 Kelvin
|
||||
Halogen=0xFFF1E0 /* 3200 K, 255, 241, 224 */,
|
||||
/// 5200 Kelvin
|
||||
CarbonArc=0xFFFAF4 /* 5200 K, 255, 250, 244 */,
|
||||
/// 5400 Kelvin
|
||||
HighNoonSun=0xFFFFFB /* 5400 K, 255, 255, 251 */,
|
||||
/// 6000 Kelvin
|
||||
DirectSunlight=0xFFFFFF /* 6000 K, 255, 255, 255 */,
|
||||
/// 7000 Kelvin
|
||||
OvercastSky=0xC9E2FF /* 7000 K, 201, 226, 255 */,
|
||||
/// 20000 Kelvin
|
||||
ClearBlueSky=0x409CFF /* 20000 K, 64, 156, 255 */,
|
||||
///@}
|
||||
|
||||
/// @name Gaseous light sources
|
||||
/// Gaseous light sources emit discrete spectral bands, and while we can
|
||||
/// approximate their aggregate hue with RGB values, they don't actually
|
||||
/// have a proper Kelvin temperature.
|
||||
///@{
|
||||
WarmFluorescent=0xFFF4E5 /* 0 K, 255, 244, 229 */,
|
||||
StandardFluorescent=0xF4FFFA /* 0 K, 244, 255, 250 */,
|
||||
CoolWhiteFluorescent=0xD4EBFF /* 0 K, 212, 235, 255 */,
|
||||
FullSpectrumFluorescent=0xFFF4F2 /* 0 K, 255, 244, 242 */,
|
||||
GrowLightFluorescent=0xFFEFF7 /* 0 K, 255, 239, 247 */,
|
||||
BlackLightFluorescent=0xA700FF /* 0 K, 167, 0, 255 */,
|
||||
MercuryVapor=0xD8F7FF /* 0 K, 216, 247, 255 */,
|
||||
SodiumVapor=0xFFD1B2 /* 0 K, 255, 209, 178 */,
|
||||
MetalHalide=0xF2FCFF /* 0 K, 242, 252, 255 */,
|
||||
HighPressureSodium=0xFFB74C /* 0 K, 255, 183, 76 */,
|
||||
///@}
|
||||
|
||||
/// Uncorrected temperature 0xFFFFFF
|
||||
UncorrectedTemperature=0xFFFFFF
|
||||
} ColorTemperature;
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
///@}
|
||||
#endif
|
174
libraries/FastLED/colorpalettes.cpp
Normal file
174
libraries/FastLED/colorpalettes.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
#ifndef __INC_COLORPALETTES_H
|
||||
#define __INC_COLORPALETTES_H
|
||||
#define FASTLED_INTERNAL
|
||||
#include "FastLED.h"
|
||||
#include "colorutils.h"
|
||||
#include "colorpalettes.h"
|
||||
|
||||
FASTLED_USING_NAMESPACE
|
||||
|
||||
|
||||
// Preset color schemes, such as they are.
|
||||
|
||||
// These schemes are all declared as "PROGMEM", meaning
|
||||
// that they won't take up SRAM on AVR chips until used.
|
||||
// Furthermore, the compiler won't even include these
|
||||
// in your PROGMEM (flash) storage unless you specifically
|
||||
// use each one, so you only 'pay for' those you actually use.
|
||||
|
||||
|
||||
extern const TProgmemRGBPalette16 CloudColors_p FL_PROGMEM =
|
||||
{
|
||||
CRGB::Blue,
|
||||
CRGB::DarkBlue,
|
||||
CRGB::DarkBlue,
|
||||
CRGB::DarkBlue,
|
||||
|
||||
CRGB::DarkBlue,
|
||||
CRGB::DarkBlue,
|
||||
CRGB::DarkBlue,
|
||||
CRGB::DarkBlue,
|
||||
|
||||
CRGB::Blue,
|
||||
CRGB::DarkBlue,
|
||||
CRGB::SkyBlue,
|
||||
CRGB::SkyBlue,
|
||||
|
||||
CRGB::LightBlue,
|
||||
CRGB::White,
|
||||
CRGB::LightBlue,
|
||||
CRGB::SkyBlue
|
||||
};
|
||||
|
||||
extern const TProgmemRGBPalette16 LavaColors_p FL_PROGMEM =
|
||||
{
|
||||
CRGB::Black,
|
||||
CRGB::Maroon,
|
||||
CRGB::Black,
|
||||
CRGB::Maroon,
|
||||
|
||||
CRGB::DarkRed,
|
||||
CRGB::Maroon,
|
||||
CRGB::DarkRed,
|
||||
|
||||
CRGB::DarkRed,
|
||||
CRGB::DarkRed,
|
||||
CRGB::Red,
|
||||
CRGB::Orange,
|
||||
|
||||
CRGB::White,
|
||||
CRGB::Orange,
|
||||
CRGB::Red,
|
||||
CRGB::DarkRed
|
||||
};
|
||||
|
||||
|
||||
extern const TProgmemRGBPalette16 OceanColors_p FL_PROGMEM =
|
||||
{
|
||||
CRGB::MidnightBlue,
|
||||
CRGB::DarkBlue,
|
||||
CRGB::MidnightBlue,
|
||||
CRGB::Navy,
|
||||
|
||||
CRGB::DarkBlue,
|
||||
CRGB::MediumBlue,
|
||||
CRGB::SeaGreen,
|
||||
CRGB::Teal,
|
||||
|
||||
CRGB::CadetBlue,
|
||||
CRGB::Blue,
|
||||
CRGB::DarkCyan,
|
||||
CRGB::CornflowerBlue,
|
||||
|
||||
CRGB::Aquamarine,
|
||||
CRGB::SeaGreen,
|
||||
CRGB::Aqua,
|
||||
CRGB::LightSkyBlue
|
||||
};
|
||||
|
||||
extern const TProgmemRGBPalette16 ForestColors_p FL_PROGMEM =
|
||||
{
|
||||
CRGB::DarkGreen,
|
||||
CRGB::DarkGreen,
|
||||
CRGB::DarkOliveGreen,
|
||||
CRGB::DarkGreen,
|
||||
|
||||
CRGB::Green,
|
||||
CRGB::ForestGreen,
|
||||
CRGB::OliveDrab,
|
||||
CRGB::Green,
|
||||
|
||||
CRGB::SeaGreen,
|
||||
CRGB::MediumAquamarine,
|
||||
CRGB::LimeGreen,
|
||||
CRGB::YellowGreen,
|
||||
|
||||
CRGB::LightGreen,
|
||||
CRGB::LawnGreen,
|
||||
CRGB::MediumAquamarine,
|
||||
CRGB::ForestGreen
|
||||
};
|
||||
|
||||
/// HSV Rainbow
|
||||
extern const TProgmemRGBPalette16 RainbowColors_p FL_PROGMEM =
|
||||
{
|
||||
0xFF0000, 0xD52A00, 0xAB5500, 0xAB7F00,
|
||||
0xABAB00, 0x56D500, 0x00FF00, 0x00D52A,
|
||||
0x00AB55, 0x0056AA, 0x0000FF, 0x2A00D5,
|
||||
0x5500AB, 0x7F0081, 0xAB0055, 0xD5002B
|
||||
};
|
||||
|
||||
/// HSV Rainbow colors with alternatating stripes of black
|
||||
#define RainbowStripesColors_p RainbowStripeColors_p
|
||||
extern const TProgmemRGBPalette16 RainbowStripeColors_p FL_PROGMEM =
|
||||
{
|
||||
0xFF0000, 0x000000, 0xAB5500, 0x000000,
|
||||
0xABAB00, 0x000000, 0x00FF00, 0x000000,
|
||||
0x00AB55, 0x000000, 0x0000FF, 0x000000,
|
||||
0x5500AB, 0x000000, 0xAB0055, 0x000000
|
||||
};
|
||||
|
||||
/// HSV color ramp: blue purple ping red orange yellow (and back)
|
||||
/// Basically, everything but the greens, which tend to make
|
||||
/// people's skin look unhealthy. This palette is good for
|
||||
/// lighting at a club or party, where it'll be shining on people.
|
||||
extern const TProgmemRGBPalette16 PartyColors_p FL_PROGMEM =
|
||||
{
|
||||
0x5500AB, 0x84007C, 0xB5004B, 0xE5001B,
|
||||
0xE81700, 0xB84700, 0xAB7700, 0xABAB00,
|
||||
0xAB5500, 0xDD2200, 0xF2000E, 0xC2003E,
|
||||
0x8F0071, 0x5F00A1, 0x2F00D0, 0x0007F9
|
||||
};
|
||||
|
||||
/// Approximate "black body radiation" palette, akin to
|
||||
/// the FastLED 'HeatColor' function.
|
||||
/// Recommend that you use values 0-240 rather than
|
||||
/// the usual 0-255, as the last 15 colors will be
|
||||
/// 'wrapping around' from the hot end to the cold end,
|
||||
/// which looks wrong.
|
||||
extern const TProgmemRGBPalette16 HeatColors_p FL_PROGMEM =
|
||||
{
|
||||
0x000000,
|
||||
0x330000, 0x660000, 0x990000, 0xCC0000, 0xFF0000,
|
||||
0xFF3300, 0xFF6600, 0xFF9900, 0xFFCC00, 0xFFFF00,
|
||||
0xFFFF33, 0xFFFF66, 0xFFFF99, 0xFFFFCC, 0xFFFFFF
|
||||
};
|
||||
|
||||
|
||||
// Gradient palette "Rainbow_gp",
|
||||
// provided for situations where you're going
|
||||
// to use a number of other gradient palettes, AND
|
||||
// you want a 'standard' FastLED rainbow as well.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Rainbow_gp ) {
|
||||
0, 255, 0, 0, // Red
|
||||
32, 171, 85, 0, // Orange
|
||||
64, 171,171, 0, // Yellow
|
||||
96, 0,255, 0, // Green
|
||||
128, 0,171, 85, // Aqua
|
||||
160, 0, 0,255, // Blue
|
||||
192, 85, 0,171, // Purple
|
||||
224, 171, 0, 85, // Pink
|
||||
255, 255, 0, 0};// and back to Red
|
||||
|
||||
#endif
|
57
libraries/FastLED/colorpalettes.h
Normal file
57
libraries/FastLED/colorpalettes.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef __INC_COLORPALETTES_H
|
||||
#define __INC_COLORPALETTES_H
|
||||
|
||||
#include "FastLED.h"
|
||||
#include "colorutils.h"
|
||||
|
||||
///@file colorpalettes.h
|
||||
/// contains definitions for the predefined color palettes supplied by FastLED.
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
///@defgroup Colorpalletes Pre-defined color palletes
|
||||
/// These schemes are all declared as "PROGMEM", meaning
|
||||
/// that they won't take up SRAM on AVR chips until used.
|
||||
/// Furthermore, the compiler won't even include these
|
||||
/// in your PROGMEM (flash) storage unless you specifically
|
||||
/// use each one, so you only 'pay for' those you actually use.
|
||||
|
||||
///@{
|
||||
|
||||
/// Cloudy color pallete
|
||||
extern const TProgmemRGBPalette16 CloudColors_p FL_PROGMEM;
|
||||
/// Lava colors
|
||||
extern const TProgmemRGBPalette16 LavaColors_p FL_PROGMEM;
|
||||
/// Ocean colors, blues and whites
|
||||
extern const TProgmemRGBPalette16 OceanColors_p FL_PROGMEM;
|
||||
/// Forest colors, greens
|
||||
extern const TProgmemRGBPalette16 ForestColors_p FL_PROGMEM;
|
||||
|
||||
/// HSV Rainbow
|
||||
extern const TProgmemRGBPalette16 RainbowColors_p FL_PROGMEM;
|
||||
|
||||
#define RainbowStripesColors_p RainbowStripeColors_p
|
||||
/// HSV Rainbow colors with alternatating stripes of black
|
||||
extern const TProgmemRGBPalette16 RainbowStripeColors_p FL_PROGMEM;
|
||||
|
||||
/// HSV color ramp: blue purple ping red orange yellow (and back)
|
||||
/// Basically, everything but the greens, which tend to make
|
||||
/// people's skin look unhealthy. This palette is good for
|
||||
/// lighting at a club or party, where it'll be shining on people.
|
||||
extern const TProgmemRGBPalette16 PartyColors_p FL_PROGMEM;
|
||||
|
||||
/// Approximate "black body radiation" palette, akin to
|
||||
/// the FastLED 'HeatColor' function.
|
||||
/// Recommend that you use values 0-240 rather than
|
||||
/// the usual 0-255, as the last 15 colors will be
|
||||
/// 'wrapping around' from the hot end to the cold end,
|
||||
/// which looks wrong.
|
||||
extern const TProgmemRGBPalette16 HeatColors_p FL_PROGMEM;
|
||||
|
||||
|
||||
DECLARE_GRADIENT_PALETTE( Rainbow_gp);
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
///@}
|
||||
#endif
|
1198
libraries/FastLED/colorutils.cpp
Normal file
1198
libraries/FastLED/colorutils.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1706
libraries/FastLED/colorutils.h
Normal file
1706
libraries/FastLED/colorutils.h
Normal file
File diff suppressed because it is too large
Load Diff
1
libraries/FastLED/component.mk
Normal file
1
libraries/FastLED/component.mk
Normal file
@ -0,0 +1 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
418
libraries/FastLED/controller.h
Normal file
418
libraries/FastLED/controller.h
Normal file
@ -0,0 +1,418 @@
|
||||
#ifndef __INC_CONTROLLER_H
|
||||
#define __INC_CONTROLLER_H
|
||||
|
||||
///@file controller.h
|
||||
/// base definitions used by led controllers for writing out led data
|
||||
|
||||
#include "FastLED.h"
|
||||
#include "led_sysdefs.h"
|
||||
#include "pixeltypes.h"
|
||||
#include "color.h"
|
||||
#include <stddef.h>
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
#define RO(X) RGB_BYTE(RGB_ORDER, X)
|
||||
#define RGB_BYTE(RO,X) (((RO)>>(3*(2-(X)))) & 0x3)
|
||||
|
||||
#define RGB_BYTE0(RO) ((RO>>6) & 0x3)
|
||||
#define RGB_BYTE1(RO) ((RO>>3) & 0x3)
|
||||
#define RGB_BYTE2(RO) ((RO) & 0x3)
|
||||
|
||||
// operator byte *(struct CRGB[] arr) { return (byte*)arr; }
|
||||
|
||||
#define DISABLE_DITHER 0x00
|
||||
#define BINARY_DITHER 0x01
|
||||
typedef uint8_t EDitherMode;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// LED Controller interface definition
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Base definition for an LED controller. Pretty much the methods that every LED controller object will make available.
|
||||
/// Note that the showARGB method is not impelemented for all controllers yet. Note also the methods for eventual checking
|
||||
/// of background writing of data (I'm looking at you, teensy 3.0 DMA controller!). If you want to pass LED controllers around
|
||||
/// to methods, make them references to this type, keeps your code saner. However, most people won't be seeing/using these objects
|
||||
/// directly at all
|
||||
class CLEDController {
|
||||
protected:
|
||||
friend class CFastLED;
|
||||
CRGB *m_Data;
|
||||
CLEDController *m_pNext;
|
||||
CRGB m_ColorCorrection;
|
||||
CRGB m_ColorTemperature;
|
||||
EDitherMode m_DitherMode;
|
||||
int m_nLeds;
|
||||
static CLEDController *m_pHead;
|
||||
static CLEDController *m_pTail;
|
||||
|
||||
/// set all the leds on the controller to a given color
|
||||
///@param data the crgb color to set the leds to
|
||||
///@param nLeds the numner of leds to set to this color
|
||||
///@param scale the rgb scaling value for outputting color
|
||||
virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) = 0;
|
||||
|
||||
/// write the passed in rgb data out to the leds managed by this controller
|
||||
///@param data the rgb data to write out to the strip
|
||||
///@param nLeds the number of leds being written out
|
||||
///@param scale the rgb scaling to apply to each led before writing it out
|
||||
virtual void show(const struct CRGB *data, int nLeds, CRGB scale) = 0;
|
||||
|
||||
public:
|
||||
/// create an led controller object, add it to the chain of controllers
|
||||
CLEDController() : m_Data(NULL), m_ColorCorrection(UncorrectedColor), m_ColorTemperature(UncorrectedTemperature), m_DitherMode(BINARY_DITHER), m_nLeds(0) {
|
||||
m_pNext = NULL;
|
||||
if(m_pHead==NULL) { m_pHead = this; }
|
||||
if(m_pTail != NULL) { m_pTail->m_pNext = this; }
|
||||
m_pTail = this;
|
||||
}
|
||||
|
||||
///initialize the LED controller
|
||||
virtual void init() = 0;
|
||||
|
||||
///clear out/zero out the given number of leds.
|
||||
virtual void clearLeds(int nLeds) { showColor(CRGB::Black, nLeds, CRGB::Black); }
|
||||
|
||||
/// show function w/integer brightness, will scale for color correction and temperature
|
||||
void show(const struct CRGB *data, int nLeds, uint8_t brightness) {
|
||||
show(data, nLeds, getAdjustment(brightness));
|
||||
}
|
||||
|
||||
/// show function w/integer brightness, will scale for color correction and temperature
|
||||
void showColor(const struct CRGB &data, int nLeds, uint8_t brightness) {
|
||||
showColor(data, nLeds, getAdjustment(brightness));
|
||||
}
|
||||
|
||||
/// show function using the "attached to this controller" led data
|
||||
void showLeds(uint8_t brightness=255) {
|
||||
show(m_Data, m_nLeds, getAdjustment(brightness));
|
||||
}
|
||||
|
||||
/// show the given color on the led strip
|
||||
void showColor(const struct CRGB & data, uint8_t brightness=255) {
|
||||
showColor(data, m_nLeds, getAdjustment(brightness));
|
||||
}
|
||||
|
||||
/// get the first led controller in the chain of controllers
|
||||
static CLEDController *head() { return m_pHead; }
|
||||
/// get the next controller in the chain after this one. will return NULL at the end of the chain
|
||||
CLEDController *next() { return m_pNext; }
|
||||
|
||||
/// set the default array of leds to be used by this controller
|
||||
CLEDController & setLeds(CRGB *data, int nLeds) {
|
||||
m_Data = data;
|
||||
m_nLeds = nLeds;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// zero out the led data managed by this controller
|
||||
void clearLedData() {
|
||||
if(m_Data) {
|
||||
memset8((void*)m_Data, 0, sizeof(struct CRGB) * m_nLeds);
|
||||
}
|
||||
}
|
||||
|
||||
/// How many leds does this controller manage?
|
||||
virtual int size() { return m_nLeds; }
|
||||
|
||||
/// Pointer to the CRGB array for this controller
|
||||
CRGB* leds() { return m_Data; }
|
||||
|
||||
/// Reference to the n'th item in the controller
|
||||
CRGB &operator[](int x) { return m_Data[x]; }
|
||||
|
||||
/// set the dithering mode for this controller to use
|
||||
inline CLEDController & setDither(uint8_t ditherMode = BINARY_DITHER) { m_DitherMode = ditherMode; return *this; }
|
||||
/// get the dithering option currently set for this controller
|
||||
inline uint8_t getDither() { return m_DitherMode; }
|
||||
|
||||
/// the the color corrction to use for this controller, expressed as an rgb object
|
||||
CLEDController & setCorrection(CRGB correction) { m_ColorCorrection = correction; return *this; }
|
||||
/// set the color correction to use for this controller
|
||||
CLEDController & setCorrection(LEDColorCorrection correction) { m_ColorCorrection = correction; return *this; }
|
||||
/// get the correction value used by this controller
|
||||
CRGB getCorrection() { return m_ColorCorrection; }
|
||||
|
||||
/// set the color temperature, aka white point, for this controller
|
||||
CLEDController & setTemperature(CRGB temperature) { m_ColorTemperature = temperature; return *this; }
|
||||
/// set the color temperature, aka white point, for this controller
|
||||
CLEDController & setTemperature(ColorTemperature temperature) { m_ColorTemperature = temperature; return *this; }
|
||||
/// get the color temperature, aka whipe point, for this controller
|
||||
CRGB getTemperature() { return m_ColorTemperature; }
|
||||
|
||||
/// Get the combined brightness/color adjustment for this controller
|
||||
CRGB getAdjustment(uint8_t scale) {
|
||||
return computeAdjustment(scale, m_ColorCorrection, m_ColorTemperature);
|
||||
}
|
||||
|
||||
static CRGB computeAdjustment(uint8_t scale, const CRGB & colorCorrection, const CRGB & colorTemperature) {
|
||||
#if defined(NO_CORRECTION) && (NO_CORRECTION==1)
|
||||
return CRGB(scale,scale,scale);
|
||||
#else
|
||||
CRGB adj(0,0,0);
|
||||
|
||||
if(scale > 0) {
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
uint8_t cc = colorCorrection.raw[i];
|
||||
uint8_t ct = colorTemperature.raw[i];
|
||||
if(cc > 0 && ct > 0) {
|
||||
uint32_t work = (((uint32_t)cc)+1) * (((uint32_t)ct)+1) * scale;
|
||||
work /= 0x10000L;
|
||||
adj.raw[i] = work & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return adj;
|
||||
#endif
|
||||
}
|
||||
virtual uint16_t getMaxRefreshRate() const { return 0; }
|
||||
};
|
||||
|
||||
// Pixel controller class. This is the class that we use to centralize pixel access in a block of data, including
|
||||
// support for things like RGB reordering, scaling, dithering, skipping (for ARGB data), and eventually, we will
|
||||
// centralize 8/12/16 conversions here as well.
|
||||
template<EOrder RGB_ORDER, int LANES=1, uint32_t MASK=0xFFFFFFFF>
|
||||
struct PixelController {
|
||||
const uint8_t *mData;
|
||||
int mLen,mLenRemaining;
|
||||
uint8_t d[3];
|
||||
uint8_t e[3];
|
||||
CRGB mScale;
|
||||
int8_t mAdvance;
|
||||
int mOffsets[LANES];
|
||||
|
||||
PixelController(const PixelController & other) {
|
||||
d[0] = other.d[0];
|
||||
d[1] = other.d[1];
|
||||
d[2] = other.d[2];
|
||||
e[0] = other.e[0];
|
||||
e[1] = other.e[1];
|
||||
e[2] = other.e[2];
|
||||
mData = other.mData;
|
||||
mScale = other.mScale;
|
||||
mAdvance = other.mAdvance;
|
||||
mLenRemaining = mLen = other.mLen;
|
||||
for(int i = 0; i < LANES; i++) { mOffsets[i] = other.mOffsets[i]; }
|
||||
|
||||
}
|
||||
|
||||
void initOffsets(int len) {
|
||||
int nOffset = 0;
|
||||
for(int i = 0; i < LANES; i++) {
|
||||
mOffsets[i] = nOffset;
|
||||
if((1<<i) & MASK) { nOffset += (len * mAdvance); }
|
||||
}
|
||||
}
|
||||
|
||||
PixelController(const uint8_t *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER, bool advance=true, uint8_t skip=0) : mData(d), mLen(len), mLenRemaining(len), mScale(s) {
|
||||
enable_dithering(dither);
|
||||
mData += skip;
|
||||
mAdvance = (advance) ? 3+skip : 0;
|
||||
initOffsets(len);
|
||||
}
|
||||
|
||||
PixelController(const CRGB *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)d), mLen(len), mLenRemaining(len), mScale(s) {
|
||||
enable_dithering(dither);
|
||||
mAdvance = 3;
|
||||
initOffsets(len);
|
||||
}
|
||||
|
||||
PixelController(const CRGB &d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)&d), mLen(len), mLenRemaining(len), mScale(s) {
|
||||
enable_dithering(dither);
|
||||
mAdvance = 0;
|
||||
initOffsets(len);
|
||||
}
|
||||
|
||||
void init_binary_dithering() {
|
||||
#if !defined(NO_DITHERING) || (NO_DITHERING != 1)
|
||||
|
||||
// Set 'virtual bits' of dithering to the highest level
|
||||
// that is not likely to cause excessive flickering at
|
||||
// low brightness levels + low update rates.
|
||||
// These pre-set values are a little ambitious, since
|
||||
// a 400Hz update rate for WS2811-family LEDs is only
|
||||
// possible with 85 pixels or fewer.
|
||||
// Once we have a 'number of milliseconds since last update'
|
||||
// value available here, we can quickly calculate the correct
|
||||
// number of 'virtual bits' on the fly with a couple of 'if'
|
||||
// statements -- no division required. At this point,
|
||||
// the division is done at compile time, so there's no runtime
|
||||
// cost, but the values are still hard-coded.
|
||||
#define MAX_LIKELY_UPDATE_RATE_HZ 400
|
||||
#define MIN_ACCEPTABLE_DITHER_RATE_HZ 50
|
||||
#define UPDATES_PER_FULL_DITHER_CYCLE (MAX_LIKELY_UPDATE_RATE_HZ / MIN_ACCEPTABLE_DITHER_RATE_HZ)
|
||||
#define RECOMMENDED_VIRTUAL_BITS ((UPDATES_PER_FULL_DITHER_CYCLE>1) + \
|
||||
(UPDATES_PER_FULL_DITHER_CYCLE>2) + \
|
||||
(UPDATES_PER_FULL_DITHER_CYCLE>4) + \
|
||||
(UPDATES_PER_FULL_DITHER_CYCLE>8) + \
|
||||
(UPDATES_PER_FULL_DITHER_CYCLE>16) + \
|
||||
(UPDATES_PER_FULL_DITHER_CYCLE>32) + \
|
||||
(UPDATES_PER_FULL_DITHER_CYCLE>64) + \
|
||||
(UPDATES_PER_FULL_DITHER_CYCLE>128) )
|
||||
#define VIRTUAL_BITS RECOMMENDED_VIRTUAL_BITS
|
||||
|
||||
// R is the digther signal 'counter'.
|
||||
static uint8_t R = 0;
|
||||
R++;
|
||||
|
||||
// R is wrapped around at 2^ditherBits,
|
||||
// so if ditherBits is 2, R will cycle through (0,1,2,3)
|
||||
uint8_t ditherBits = VIRTUAL_BITS;
|
||||
R &= (0x01 << ditherBits) - 1;
|
||||
|
||||
// Q is the "unscaled dither signal" itself.
|
||||
// It's initialized to the reversed bits of R.
|
||||
// If 'ditherBits' is 2, Q here will cycle through (0,128,64,192)
|
||||
uint8_t Q = 0;
|
||||
|
||||
// Reverse bits in a byte
|
||||
{
|
||||
if(R & 0x01) { Q |= 0x80; }
|
||||
if(R & 0x02) { Q |= 0x40; }
|
||||
if(R & 0x04) { Q |= 0x20; }
|
||||
if(R & 0x08) { Q |= 0x10; }
|
||||
if(R & 0x10) { Q |= 0x08; }
|
||||
if(R & 0x20) { Q |= 0x04; }
|
||||
if(R & 0x40) { Q |= 0x02; }
|
||||
if(R & 0x80) { Q |= 0x01; }
|
||||
}
|
||||
|
||||
// Now we adjust Q to fall in the center of each range,
|
||||
// instead of at the start of the range.
|
||||
// If ditherBits is 2, Q will be (0, 128, 64, 192) at first,
|
||||
// and this adjustment makes it (31, 159, 95, 223).
|
||||
if( ditherBits < 8) {
|
||||
Q += 0x01 << (7 - ditherBits);
|
||||
}
|
||||
|
||||
// D and E form the "scaled dither signal"
|
||||
// which is added to pixel values to affect the
|
||||
// actual dithering.
|
||||
|
||||
// Setup the initial D and E values
|
||||
for(int i = 0; i < 3; i++) {
|
||||
uint8_t s = mScale.raw[i];
|
||||
e[i] = s ? (256/s) + 1 : 0;
|
||||
d[i] = scale8(Q, e[i]);
|
||||
#if (FASTLED_SCALE8_FIXED == 1)
|
||||
if(d[i]) (d[i]--);
|
||||
#endif
|
||||
if(e[i]) e[i]--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Do we have n pixels left to process?
|
||||
__attribute__((always_inline)) inline bool has(int n) {
|
||||
return mLenRemaining >= n;
|
||||
}
|
||||
|
||||
// toggle dithering enable
|
||||
void enable_dithering(EDitherMode dither) {
|
||||
switch(dither) {
|
||||
case BINARY_DITHER: init_binary_dithering(); break;
|
||||
default: d[0]=d[1]=d[2]=e[0]=e[1]=e[2]=0; break;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) inline int size() { return mLen; }
|
||||
|
||||
// get the amount to advance the pointer by
|
||||
__attribute__((always_inline)) inline int advanceBy() { return mAdvance; }
|
||||
|
||||
// advance the data pointer forward, adjust position counter
|
||||
__attribute__((always_inline)) inline void advanceData() { mData += mAdvance; mLenRemaining--;}
|
||||
|
||||
// step the dithering forward
|
||||
__attribute__((always_inline)) inline void stepDithering() {
|
||||
// IF UPDATING HERE, BE SURE TO UPDATE THE ASM VERSION IN
|
||||
// clockless_trinket.h!
|
||||
d[0] = e[0] - d[0];
|
||||
d[1] = e[1] - d[1];
|
||||
d[2] = e[2] - d[2];
|
||||
}
|
||||
|
||||
// Some chipsets pre-cycle the first byte, which means we want to cycle byte 0's dithering separately
|
||||
__attribute__((always_inline)) inline void preStepFirstByteDithering() {
|
||||
d[RO(0)] = e[RO(0)] - d[RO(0)];
|
||||
}
|
||||
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t loadByte(PixelController & pc) { return pc.mData[RO(SLOT)]; }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t loadByte(PixelController & pc, int lane) { return pc.mData[pc.mOffsets[lane] + RO(SLOT)]; }
|
||||
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t dither(PixelController & pc, uint8_t b) { return b ? qadd8(b, pc.d[RO(SLOT)]) : 0; }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t dither(PixelController & , uint8_t b, uint8_t d) { return b ? qadd8(b,d) : 0; }
|
||||
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t scale(PixelController & pc, uint8_t b) { return scale8(b, pc.mScale.raw[RO(SLOT)]); }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t scale(PixelController & , uint8_t b, uint8_t scale) { return scale8(b, scale); }
|
||||
|
||||
// composite shortcut functions for loading, dithering, and scaling
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t loadAndScale(PixelController & pc) { return scale<SLOT>(pc, pc.dither<SLOT>(pc, pc.loadByte<SLOT>(pc))); }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t loadAndScale(PixelController & pc, int lane) { return scale<SLOT>(pc, pc.dither<SLOT>(pc, pc.loadByte<SLOT>(pc, lane))); }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t loadAndScale(PixelController & pc, int lane, uint8_t d, uint8_t scale) { return scale8(pc.dither<SLOT>(pc, pc.loadByte<SLOT>(pc, lane), d), scale); }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t loadAndScale(PixelController & pc, int lane, uint8_t scale) { return scale8(pc.loadByte<SLOT>(pc, lane), scale); }
|
||||
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(PixelController & pc) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc); }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(PixelController & pc, int lane) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc, lane); }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(PixelController & pc, int lane, uint8_t scale) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc, lane, scale); }
|
||||
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t getd(PixelController & pc) { return pc.d[RO(SLOT)]; }
|
||||
template<int SLOT> __attribute__((always_inline)) inline static uint8_t getscale(PixelController & pc) { return pc.mScale.raw[RO(SLOT)]; }
|
||||
|
||||
// Helper functions to get around gcc stupidities
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale0(int lane, uint8_t scale) { return loadAndScale<0>(*this, lane, scale); }
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale1(int lane, uint8_t scale) { return loadAndScale<1>(*this, lane, scale); }
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale2(int lane, uint8_t scale) { return loadAndScale<2>(*this, lane, scale); }
|
||||
__attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0(int lane, uint8_t scale) { return advanceAndLoadAndScale<0>(*this, lane, scale); }
|
||||
__attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0(int lane, uint8_t scale) { stepDithering(); return advanceAndLoadAndScale<0>(*this, lane, scale); }
|
||||
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale0(int lane) { return loadAndScale<0>(*this, lane); }
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale1(int lane) { return loadAndScale<1>(*this, lane); }
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale2(int lane) { return loadAndScale<2>(*this, lane); }
|
||||
__attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0(int lane) { return advanceAndLoadAndScale<0>(*this, lane); }
|
||||
__attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0(int lane) { stepDithering(); return advanceAndLoadAndScale<0>(*this, lane); }
|
||||
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale0() { return loadAndScale<0>(*this); }
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale1() { return loadAndScale<1>(*this); }
|
||||
__attribute__((always_inline)) inline uint8_t loadAndScale2() { return loadAndScale<2>(*this); }
|
||||
__attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0() { return advanceAndLoadAndScale<0>(*this); }
|
||||
__attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0() { stepDithering(); return advanceAndLoadAndScale<0>(*this); }
|
||||
|
||||
__attribute__((always_inline)) inline uint8_t getScale0() { return getscale<0>(*this); }
|
||||
__attribute__((always_inline)) inline uint8_t getScale1() { return getscale<1>(*this); }
|
||||
__attribute__((always_inline)) inline uint8_t getScale2() { return getscale<2>(*this); }
|
||||
};
|
||||
|
||||
template<EOrder RGB_ORDER, int LANES=1, uint32_t MASK=0xFFFFFFFF> class CPixelLEDController : public CLEDController {
|
||||
protected:
|
||||
virtual void showPixels(PixelController<RGB_ORDER,LANES,MASK> & pixels) = 0;
|
||||
|
||||
/// set all the leds on the controller to a given color
|
||||
///@param data the crgb color to set the leds to
|
||||
///@param nLeds the numner of leds to set to this color
|
||||
///@param scale the rgb scaling value for outputting color
|
||||
virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
|
||||
PixelController<RGB_ORDER, LANES, MASK> pixels(data, nLeds, scale, getDither());
|
||||
showPixels(pixels);
|
||||
}
|
||||
|
||||
/// write the passed in rgb data out to the leds managed by this controller
|
||||
///@param data the rgb data to write out to the strip
|
||||
///@param nLeds the number of leds being written out
|
||||
///@param scale the rgb scaling to apply to each led before writing it out
|
||||
virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
|
||||
PixelController<RGB_ORDER, LANES, MASK> pixels(data, nLeds, scale, getDither());
|
||||
showPixels(pixels);
|
||||
}
|
||||
|
||||
public:
|
||||
CPixelLEDController() : CLEDController() {}
|
||||
};
|
||||
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
16
libraries/FastLED/cpp_compat.h
Normal file
16
libraries/FastLED/cpp_compat.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef __INC_CPP_COMPAT_H
|
||||
#define __INC_CPP_COMPAT_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
#if __cplusplus <= 199711L
|
||||
|
||||
#define static_assert(expression, message)
|
||||
#define constexpr const
|
||||
|
||||
#else
|
||||
|
||||
// things that we can turn on if we're in a C++11 environment
|
||||
#endif
|
||||
|
||||
#endif
|
65
libraries/FastLED/dmx.h
Normal file
65
libraries/FastLED/dmx.h
Normal file
@ -0,0 +1,65 @@
|
||||
#ifndef __INC_DMX_H
|
||||
#define __INC_DMX_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
#ifdef DmxSimple_h
|
||||
#include <DmxSimple.h>
|
||||
#define HAS_DMX_SIMPLE
|
||||
|
||||
///@ingroup chipsets
|
||||
///@{
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
// note - dmx simple must be included before FastSPI for this code to be enabled
|
||||
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> class DMXSimpleController : public CPixelLEDController<RGB_ORDER> {
|
||||
public:
|
||||
// initialize the LED controller
|
||||
virtual void init() { DmxSimple.usePin(DATA_PIN); }
|
||||
|
||||
protected:
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
int iChannel = 1;
|
||||
while(pixels.has(1)) {
|
||||
DmxSimple.write(iChannel++, pixels.loadAndScale0());
|
||||
DmxSimple.write(iChannel++, pixels.loadAndScale1());
|
||||
DmxSimple.write(iChannel++, pixels.loadAndScale2());
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef DmxSerial_h
|
||||
#include <DMXSerial.h>
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
template <EOrder RGB_ORDER = RGB> class DMXSerialController : public CPixelLEDController<RGB_ORDER> {
|
||||
public:
|
||||
// initialize the LED controller
|
||||
virtual void init() { DMXSerial.init(DMXController); }
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
int iChannel = 1;
|
||||
while(pixels.has(1)) {
|
||||
DMXSerial.write(iChannel++, pixels.loadAndScale0());
|
||||
DMXSerial.write(iChannel++, pixels.loadAndScale1());
|
||||
DMXSerial.write(iChannel++, pixels.loadAndScale2());
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
///@}
|
||||
|
||||
#define HAS_DMX_SERIAL
|
||||
#endif
|
||||
|
||||
#endif
|
2331
libraries/FastLED/docs/Doxyfile
Normal file
2331
libraries/FastLED/docs/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
10
libraries/FastLED/docs/mainpage.dox
Normal file
10
libraries/FastLED/docs/mainpage.dox
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
@brief Documentation file for FastLED
|
||||
@author dgarcia at fastled dot io
|
||||
@file
|
||||
*/
|
||||
/** @defgroup FastLED Sources */
|
||||
/**
|
||||
@mainpage FastLED - let there be light!
|
||||
*/
|
||||
EOF
|
65
libraries/FastLED/examples/AnalogOutput/AnalogOutput.ino
Normal file
65
libraries/FastLED/examples/AnalogOutput/AnalogOutput.ino
Normal file
@ -0,0 +1,65 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
// Example showing how to use FastLED color functions
|
||||
// even when you're NOT using a "pixel-addressible" smart LED strip.
|
||||
//
|
||||
// This example is designed to control an "analog" RGB LED strip
|
||||
// (or a single RGB LED) being driven by Arduino PWM output pins.
|
||||
// So this code never calls FastLED.addLEDs() or FastLED.show().
|
||||
//
|
||||
// This example illustrates one way you can use just the portions
|
||||
// of FastLED that you need. In this case, this code uses just the
|
||||
// fast HSV color conversion code.
|
||||
//
|
||||
// In this example, the RGB values are output on three separate
|
||||
// 'analog' PWM pins, one for red, one for green, and one for blue.
|
||||
|
||||
#define REDPIN 5
|
||||
#define GREENPIN 6
|
||||
#define BLUEPIN 3
|
||||
|
||||
// showAnalogRGB: this is like FastLED.show(), but outputs on
|
||||
// analog PWM output pins instead of sending data to an intelligent,
|
||||
// pixel-addressable LED strip.
|
||||
//
|
||||
// This function takes the incoming RGB values and outputs the values
|
||||
// on three analog PWM output pins to the r, g, and b values respectively.
|
||||
void showAnalogRGB( const CRGB& rgb)
|
||||
{
|
||||
analogWrite(REDPIN, rgb.r );
|
||||
analogWrite(GREENPIN, rgb.g );
|
||||
analogWrite(BLUEPIN, rgb.b );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// colorBars: flashes Red, then Green, then Blue, then Black.
|
||||
// Helpful for diagnosing if you've mis-wired which is which.
|
||||
void colorBars()
|
||||
{
|
||||
showAnalogRGB( CRGB::Red ); delay(500);
|
||||
showAnalogRGB( CRGB::Green ); delay(500);
|
||||
showAnalogRGB( CRGB::Blue ); delay(500);
|
||||
showAnalogRGB( CRGB::Black ); delay(500);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
static uint8_t hue;
|
||||
hue = hue + 1;
|
||||
// Use FastLED automatic HSV->RGB conversion
|
||||
showAnalogRGB( CHSV( hue, 255, 255) );
|
||||
|
||||
delay(20);
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
pinMode(REDPIN, OUTPUT);
|
||||
pinMode(GREENPIN, OUTPUT);
|
||||
pinMode(BLUEPIN, OUTPUT);
|
||||
|
||||
// Flash the "hello" color sequence: R, G, B, black.
|
||||
colorBars();
|
||||
}
|
||||
|
54
libraries/FastLED/examples/Blink/Blink.ino
Normal file
54
libraries/FastLED/examples/Blink/Blink.ino
Normal file
@ -0,0 +1,54 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
// How many leds in your strip?
|
||||
#define NUM_LEDS 1
|
||||
|
||||
// For led chips like Neopixels, which have a data line, ground, and power, you just
|
||||
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
|
||||
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
|
||||
#define DATA_PIN 3
|
||||
#define CLOCK_PIN 13
|
||||
|
||||
// Define the array of leds
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
void setup() {
|
||||
// Uncomment/edit one of the following lines for your leds arrangement.
|
||||
// FastLED.addLeds<TM1803, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<TM1804, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<TM1809, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<APA104, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<UCS1903, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<UCS1903B, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<GW6205, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<GW6205_400, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
|
||||
// FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<SM16716, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<LPD8806, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<P9813, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<APA102, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<DOTSTAR, RGB>(leds, NUM_LEDS);
|
||||
|
||||
// FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<SM16716, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<P9813, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<DOTSTAR, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Turn the LED on, then pause
|
||||
leds[0] = CRGB::Red;
|
||||
FastLED.show();
|
||||
delay(500);
|
||||
// Now turn the LED off, then pause
|
||||
leds[0] = CRGB::Black;
|
||||
FastLED.show();
|
||||
delay(500);
|
||||
}
|
188
libraries/FastLED/examples/ColorPalette/ColorPalette.ino
Normal file
188
libraries/FastLED/examples/ColorPalette/ColorPalette.ino
Normal file
@ -0,0 +1,188 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define LED_PIN 5
|
||||
#define NUM_LEDS 50
|
||||
#define BRIGHTNESS 64
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#define UPDATES_PER_SECOND 100
|
||||
|
||||
// This example shows several ways to set up and use 'palettes' of colors
|
||||
// with FastLED.
|
||||
//
|
||||
// These compact palettes provide an easy way to re-colorize your
|
||||
// animation on the fly, quickly, easily, and with low overhead.
|
||||
//
|
||||
// USING palettes is MUCH simpler in practice than in theory, so first just
|
||||
// run this sketch, and watch the pretty lights as you then read through
|
||||
// the code. Although this sketch has eight (or more) different color schemes,
|
||||
// the entire sketch compiles down to about 6.5K on AVR.
|
||||
//
|
||||
// FastLED provides a few pre-configured color palettes, and makes it
|
||||
// extremely easy to make up your own color schemes with palettes.
|
||||
//
|
||||
// Some notes on the more abstract 'theory and practice' of
|
||||
// FastLED compact palettes are at the bottom of this file.
|
||||
|
||||
|
||||
|
||||
CRGBPalette16 currentPalette;
|
||||
TBlendType currentBlending;
|
||||
|
||||
extern CRGBPalette16 myRedWhiteBluePalette;
|
||||
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;
|
||||
|
||||
|
||||
void setup() {
|
||||
delay( 3000 ); // power-up safety delay
|
||||
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
|
||||
FastLED.setBrightness( BRIGHTNESS );
|
||||
|
||||
currentPalette = RainbowColors_p;
|
||||
currentBlending = LINEARBLEND;
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
ChangePalettePeriodically();
|
||||
|
||||
static uint8_t startIndex = 0;
|
||||
startIndex = startIndex + 1; /* motion speed */
|
||||
|
||||
FillLEDsFromPaletteColors( startIndex);
|
||||
|
||||
FastLED.show();
|
||||
FastLED.delay(1000 / UPDATES_PER_SECOND);
|
||||
}
|
||||
|
||||
void FillLEDsFromPaletteColors( uint8_t colorIndex)
|
||||
{
|
||||
uint8_t brightness = 255;
|
||||
|
||||
for( int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
|
||||
colorIndex += 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// There are several different palettes of colors demonstrated here.
|
||||
//
|
||||
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
|
||||
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
|
||||
//
|
||||
// Additionally, you can manually define your own color palettes, or you can write
|
||||
// code that creates color palettes on the fly. All are shown here.
|
||||
|
||||
void ChangePalettePeriodically()
|
||||
{
|
||||
uint8_t secondHand = (millis() / 1000) % 60;
|
||||
static uint8_t lastSecond = 99;
|
||||
|
||||
if( lastSecond != secondHand) {
|
||||
lastSecond = secondHand;
|
||||
if( secondHand == 0) { currentPalette = RainbowColors_p; currentBlending = LINEARBLEND; }
|
||||
if( secondHand == 10) { currentPalette = RainbowStripeColors_p; currentBlending = NOBLEND; }
|
||||
if( secondHand == 15) { currentPalette = RainbowStripeColors_p; currentBlending = LINEARBLEND; }
|
||||
if( secondHand == 20) { SetupPurpleAndGreenPalette(); currentBlending = LINEARBLEND; }
|
||||
if( secondHand == 25) { SetupTotallyRandomPalette(); currentBlending = LINEARBLEND; }
|
||||
if( secondHand == 30) { SetupBlackAndWhiteStripedPalette(); currentBlending = NOBLEND; }
|
||||
if( secondHand == 35) { SetupBlackAndWhiteStripedPalette(); currentBlending = LINEARBLEND; }
|
||||
if( secondHand == 40) { currentPalette = CloudColors_p; currentBlending = LINEARBLEND; }
|
||||
if( secondHand == 45) { currentPalette = PartyColors_p; currentBlending = LINEARBLEND; }
|
||||
if( secondHand == 50) { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND; }
|
||||
if( secondHand == 55) { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
|
||||
}
|
||||
}
|
||||
|
||||
// This function fills the palette with totally random colors.
|
||||
void SetupTotallyRandomPalette()
|
||||
{
|
||||
for( int i = 0; i < 16; i++) {
|
||||
currentPalette[i] = CHSV( random8(), 255, random8());
|
||||
}
|
||||
}
|
||||
|
||||
// This function sets up a palette of black and white stripes,
|
||||
// using code. Since the palette is effectively an array of
|
||||
// sixteen CRGB colors, the various fill_* functions can be used
|
||||
// to set them up.
|
||||
void SetupBlackAndWhiteStripedPalette()
|
||||
{
|
||||
// 'black out' all 16 palette entries...
|
||||
fill_solid( currentPalette, 16, CRGB::Black);
|
||||
// and set every fourth one to white.
|
||||
currentPalette[0] = CRGB::White;
|
||||
currentPalette[4] = CRGB::White;
|
||||
currentPalette[8] = CRGB::White;
|
||||
currentPalette[12] = CRGB::White;
|
||||
|
||||
}
|
||||
|
||||
// This function sets up a palette of purple and green stripes.
|
||||
void SetupPurpleAndGreenPalette()
|
||||
{
|
||||
CRGB purple = CHSV( HUE_PURPLE, 255, 255);
|
||||
CRGB green = CHSV( HUE_GREEN, 255, 255);
|
||||
CRGB black = CRGB::Black;
|
||||
|
||||
currentPalette = CRGBPalette16(
|
||||
green, green, black, black,
|
||||
purple, purple, black, black,
|
||||
green, green, black, black,
|
||||
purple, purple, black, black );
|
||||
}
|
||||
|
||||
|
||||
// This example shows how to set up a static color palette
|
||||
// which is stored in PROGMEM (flash), which is almost always more
|
||||
// plentiful than RAM. A static PROGMEM palette like this
|
||||
// takes up 64 bytes of flash.
|
||||
const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
|
||||
{
|
||||
CRGB::Red,
|
||||
CRGB::Gray, // 'white' is too bright compared to red and blue
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
|
||||
CRGB::Red,
|
||||
CRGB::Gray,
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
|
||||
CRGB::Red,
|
||||
CRGB::Red,
|
||||
CRGB::Gray,
|
||||
CRGB::Gray,
|
||||
CRGB::Blue,
|
||||
CRGB::Blue,
|
||||
CRGB::Black,
|
||||
CRGB::Black
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Additional notes on FastLED compact palettes:
|
||||
//
|
||||
// Normally, in computer graphics, the palette (or "color lookup table")
|
||||
// has 256 entries, each containing a specific 24-bit RGB color. You can then
|
||||
// index into the color palette using a simple 8-bit (one byte) value.
|
||||
// A 256-entry color palette takes up 768 bytes of RAM, which on Arduino
|
||||
// is quite possibly "too many" bytes.
|
||||
//
|
||||
// FastLED does offer traditional 256-element palettes, for setups that
|
||||
// can afford the 768-byte cost in RAM.
|
||||
//
|
||||
// However, FastLED also offers a compact alternative. FastLED offers
|
||||
// palettes that store 16 distinct entries, but can be accessed AS IF
|
||||
// they actually have 256 entries; this is accomplished by interpolating
|
||||
// between the 16 explicit entries to create fifteen intermediate palette
|
||||
// entries between each pair.
|
||||
//
|
||||
// So for example, if you set the first two explicit entries of a compact
|
||||
// palette to Green (0,255,0) and Blue (0,0,255), and then retrieved
|
||||
// the first sixteen entries from the virtual palette (of 256), you'd get
|
||||
// Green, followed by a smooth gradient from green-to-blue, and then Blue.
|
@ -0,0 +1,85 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define LED_PIN 3
|
||||
|
||||
// Information about the LED strip itself
|
||||
#define NUM_LEDS 60
|
||||
#define CHIPSET WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#define BRIGHTNESS 128
|
||||
|
||||
|
||||
// FastLED v2.1 provides two color-management controls:
|
||||
// (1) color correction settings for each LED strip, and
|
||||
// (2) master control of the overall output 'color temperature'
|
||||
//
|
||||
// THIS EXAMPLE demonstrates the second, "color temperature" control.
|
||||
// It shows a simple rainbow animation first with one temperature profile,
|
||||
// and a few seconds later, with a different temperature profile.
|
||||
//
|
||||
// The first pixel of the strip will show the color temperature.
|
||||
//
|
||||
// HELPFUL HINTS for "seeing" the effect in this demo:
|
||||
// * Don't look directly at the LED pixels. Shine the LEDs aganst
|
||||
// a white wall, table, or piece of paper, and look at the reflected light.
|
||||
//
|
||||
// * If you watch it for a bit, and then walk away, and then come back
|
||||
// to it, you'll probably be able to "see" whether it's currently using
|
||||
// the 'redder' or the 'bluer' temperature profile, even not counting
|
||||
// the lowest 'indicator' pixel.
|
||||
//
|
||||
//
|
||||
// FastLED provides these pre-conigured incandescent color profiles:
|
||||
// Candle, Tungsten40W, Tungsten100W, Halogen, CarbonArc,
|
||||
// HighNoonSun, DirectSunlight, OvercastSky, ClearBlueSky,
|
||||
// FastLED provides these pre-configured gaseous-light color profiles:
|
||||
// WarmFluorescent, StandardFluorescent, CoolWhiteFluorescent,
|
||||
// FullSpectrumFluorescent, GrowLightFluorescent, BlackLightFluorescent,
|
||||
// MercuryVapor, SodiumVapor, MetalHalide, HighPressureSodium,
|
||||
// FastLED also provides an "Uncorrected temperature" profile
|
||||
// UncorrectedTemperature;
|
||||
|
||||
#define TEMPERATURE_1 Tungsten100W
|
||||
#define TEMPERATURE_2 OvercastSky
|
||||
|
||||
// How many seconds to show each temperature before switching
|
||||
#define DISPLAYTIME 20
|
||||
// How many seconds to show black between switches
|
||||
#define BLACKTIME 3
|
||||
|
||||
void loop()
|
||||
{
|
||||
// draw a generic, no-name rainbow
|
||||
static uint8_t starthue = 0;
|
||||
fill_rainbow( leds + 5, NUM_LEDS - 5, --starthue, 20);
|
||||
|
||||
// Choose which 'color temperature' profile to enable.
|
||||
uint8_t secs = (millis() / 1000) % (DISPLAYTIME * 2);
|
||||
if( secs < DISPLAYTIME) {
|
||||
FastLED.setTemperature( TEMPERATURE_1 ); // first temperature
|
||||
leds[0] = TEMPERATURE_1; // show indicator pixel
|
||||
} else {
|
||||
FastLED.setTemperature( TEMPERATURE_2 ); // second temperature
|
||||
leds[0] = TEMPERATURE_2; // show indicator pixel
|
||||
}
|
||||
|
||||
// Black out the LEDs for a few secnds between color changes
|
||||
// to let the eyes and brains adjust
|
||||
if( (secs % DISPLAYTIME) < BLACKTIME) {
|
||||
memset8( leds, 0, NUM_LEDS * sizeof(CRGB));
|
||||
}
|
||||
|
||||
FastLED.show();
|
||||
FastLED.delay(8);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
delay( 3000 ); // power-up safety delay
|
||||
// It's important to set the color correction for your LED strip here,
|
||||
// so that colors can be more accurately rendered through the 'temperature' profiles
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalSMD5050 );
|
||||
FastLED.setBrightness( BRIGHTNESS );
|
||||
}
|
||||
|
53
libraries/FastLED/examples/Cylon/Cylon.ino
Normal file
53
libraries/FastLED/examples/Cylon/Cylon.ino
Normal file
@ -0,0 +1,53 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
// How many leds in your strip?
|
||||
#define NUM_LEDS 64
|
||||
|
||||
// For led chips like Neopixels, which have a data line, ground, and power, you just
|
||||
// need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock,
|
||||
// ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN
|
||||
#define DATA_PIN 7
|
||||
#define CLOCK_PIN 13
|
||||
|
||||
// Define the array of leds
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
void setup() {
|
||||
Serial.begin(57600);
|
||||
Serial.println("resetting");
|
||||
LEDS.addLeds<WS2812,DATA_PIN,RGB>(leds,NUM_LEDS);
|
||||
LEDS.setBrightness(84);
|
||||
}
|
||||
|
||||
void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } }
|
||||
|
||||
void loop() {
|
||||
static uint8_t hue = 0;
|
||||
Serial.print("x");
|
||||
// First slide the led in one direction
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
// Set the i'th led to red
|
||||
leds[i] = CHSV(hue++, 255, 255);
|
||||
// Show the leds
|
||||
FastLED.show();
|
||||
// now that we've shown the leds, reset the i'th led to black
|
||||
// leds[i] = CRGB::Black;
|
||||
fadeall();
|
||||
// Wait a little bit before we loop around and do it again
|
||||
delay(10);
|
||||
}
|
||||
Serial.print("x");
|
||||
|
||||
// Now go in the other direction.
|
||||
for(int i = (NUM_LEDS)-1; i >= 0; i--) {
|
||||
// Set the i'th led to red
|
||||
leds[i] = CHSV(hue++, 255, 255);
|
||||
// Show the leds
|
||||
FastLED.show();
|
||||
// now that we've shown the leds, reset the i'th led to black
|
||||
// leds[i] = CRGB::Black;
|
||||
fadeall();
|
||||
// Wait a little bit before we loop around and do it again
|
||||
delay(10);
|
||||
}
|
||||
}
|
126
libraries/FastLED/examples/DemoReel100/DemoReel100.ino
Normal file
126
libraries/FastLED/examples/DemoReel100/DemoReel100.ino
Normal file
@ -0,0 +1,126 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
FASTLED_USING_NAMESPACE
|
||||
|
||||
// FastLED "100-lines-of-code" demo reel, showing just a few
|
||||
// of the kinds of animation patterns you can quickly and easily
|
||||
// compose using FastLED.
|
||||
//
|
||||
// This example also shows one easy way to define multiple
|
||||
// animations patterns and have them automatically rotate.
|
||||
//
|
||||
// -Mark Kriegsman, December 2014
|
||||
|
||||
#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3001000)
|
||||
#warning "Requires FastLED 3.1 or later; check github for latest code."
|
||||
#endif
|
||||
|
||||
#define DATA_PIN 3
|
||||
//#define CLK_PIN 4
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
#define NUM_LEDS 64
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#define BRIGHTNESS 96
|
||||
#define FRAMES_PER_SECOND 120
|
||||
|
||||
void setup() {
|
||||
delay(3000); // 3 second delay for recovery
|
||||
|
||||
// tell FastLED about the LED strip configuration
|
||||
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
|
||||
//FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
|
||||
|
||||
// set master brightness control
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
}
|
||||
|
||||
|
||||
// List of patterns to cycle through. Each is defined as a separate function below.
|
||||
typedef void (*SimplePatternList[])();
|
||||
SimplePatternList gPatterns = { rainbow, rainbowWithGlitter, confetti, sinelon, juggle, bpm };
|
||||
|
||||
uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
|
||||
uint8_t gHue = 0; // rotating "base color" used by many of the patterns
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Call the current pattern function once, updating the 'leds' array
|
||||
gPatterns[gCurrentPatternNumber]();
|
||||
|
||||
// send the 'leds' array out to the actual LED strip
|
||||
FastLED.show();
|
||||
// insert a delay to keep the framerate modest
|
||||
FastLED.delay(1000/FRAMES_PER_SECOND);
|
||||
|
||||
// do some periodic updates
|
||||
EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the "base color" through the rainbow
|
||||
EVERY_N_SECONDS( 10 ) { nextPattern(); } // change patterns periodically
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
|
||||
|
||||
void nextPattern()
|
||||
{
|
||||
// add one to the current pattern number, and wrap around at the end
|
||||
gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
|
||||
}
|
||||
|
||||
void rainbow()
|
||||
{
|
||||
// FastLED's built-in rainbow generator
|
||||
fill_rainbow( leds, NUM_LEDS, gHue, 7);
|
||||
}
|
||||
|
||||
void rainbowWithGlitter()
|
||||
{
|
||||
// built-in FastLED rainbow, plus some random sparkly glitter
|
||||
rainbow();
|
||||
addGlitter(80);
|
||||
}
|
||||
|
||||
void addGlitter( fract8 chanceOfGlitter)
|
||||
{
|
||||
if( random8() < chanceOfGlitter) {
|
||||
leds[ random16(NUM_LEDS) ] += CRGB::White;
|
||||
}
|
||||
}
|
||||
|
||||
void confetti()
|
||||
{
|
||||
// random colored speckles that blink in and fade smoothly
|
||||
fadeToBlackBy( leds, NUM_LEDS, 10);
|
||||
int pos = random16(NUM_LEDS);
|
||||
leds[pos] += CHSV( gHue + random8(64), 200, 255);
|
||||
}
|
||||
|
||||
void sinelon()
|
||||
{
|
||||
// a colored dot sweeping back and forth, with fading trails
|
||||
fadeToBlackBy( leds, NUM_LEDS, 20);
|
||||
int pos = beatsin16( 13, 0, NUM_LEDS-1 );
|
||||
leds[pos] += CHSV( gHue, 255, 192);
|
||||
}
|
||||
|
||||
void bpm()
|
||||
{
|
||||
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
|
||||
uint8_t BeatsPerMinute = 62;
|
||||
CRGBPalette16 palette = PartyColors_p;
|
||||
uint8_t beat = beatsin8( BeatsPerMinute, 64, 255);
|
||||
for( int i = 0; i < NUM_LEDS; i++) { //9948
|
||||
leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10));
|
||||
}
|
||||
}
|
||||
|
||||
void juggle() {
|
||||
// eight colored dots, weaving in and out of sync with each other
|
||||
fadeToBlackBy( leds, NUM_LEDS, 20);
|
||||
byte dothue = 0;
|
||||
for( int i = 0; i < 8; i++) {
|
||||
leds[beatsin16( i+7, 0, NUM_LEDS-1 )] |= CHSV(dothue, 200, 255);
|
||||
dothue += 32;
|
||||
}
|
||||
}
|
||||
|
105
libraries/FastLED/examples/Fire2012/Fire2012.ino
Normal file
105
libraries/FastLED/examples/Fire2012/Fire2012.ino
Normal file
@ -0,0 +1,105 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define LED_PIN 5
|
||||
#define COLOR_ORDER GRB
|
||||
#define CHIPSET WS2811
|
||||
#define NUM_LEDS 30
|
||||
|
||||
#define BRIGHTNESS 200
|
||||
#define FRAMES_PER_SECOND 60
|
||||
|
||||
bool gReverseDirection = false;
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
void setup() {
|
||||
delay(3000); // sanity delay
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
|
||||
FastLED.setBrightness( BRIGHTNESS );
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Add entropy to random number generator; we use a lot of it.
|
||||
// random16_add_entropy( random());
|
||||
|
||||
Fire2012(); // run simulation frame
|
||||
|
||||
FastLED.show(); // display this frame
|
||||
FastLED.delay(1000 / FRAMES_PER_SECOND);
|
||||
}
|
||||
|
||||
|
||||
// Fire2012 by Mark Kriegsman, July 2012
|
||||
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
|
||||
////
|
||||
// This basic one-dimensional 'fire' simulation works roughly as follows:
|
||||
// There's a underlying array of 'heat' cells, that model the temperature
|
||||
// at each point along the line. Every cycle through the simulation,
|
||||
// four steps are performed:
|
||||
// 1) All cells cool down a little bit, losing heat to the air
|
||||
// 2) The heat from each cell drifts 'up' and diffuses a little
|
||||
// 3) Sometimes randomly new 'sparks' of heat are added at the bottom
|
||||
// 4) The heat from each cell is rendered as a color into the leds array
|
||||
// The heat-to-color mapping uses a black-body radiation approximation.
|
||||
//
|
||||
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
|
||||
//
|
||||
// This simulation scales it self a bit depending on NUM_LEDS; it should look
|
||||
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
|
||||
//
|
||||
// I recommend running this simulation at anywhere from 30-100 frames per second,
|
||||
// meaning an interframe delay of about 10-35 milliseconds.
|
||||
//
|
||||
// Looks best on a high-density LED setup (60+ pixels/meter).
|
||||
//
|
||||
//
|
||||
// There are two main parameters you can play with to control the look and
|
||||
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
|
||||
// in step 3 above).
|
||||
//
|
||||
// COOLING: How much does the air cool as it rises?
|
||||
// Less cooling = taller flames. More cooling = shorter flames.
|
||||
// Default 50, suggested range 20-100
|
||||
#define COOLING 55
|
||||
|
||||
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
|
||||
// Higher chance = more roaring fire. Lower chance = more flickery fire.
|
||||
// Default 120, suggested range 50-200.
|
||||
#define SPARKING 120
|
||||
|
||||
|
||||
void Fire2012()
|
||||
{
|
||||
// Array of temperature readings at each simulation cell
|
||||
static byte heat[NUM_LEDS];
|
||||
|
||||
// Step 1. Cool down every cell a little
|
||||
for( int i = 0; i < NUM_LEDS; i++) {
|
||||
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
for( int k= NUM_LEDS - 1; k >= 2; k--) {
|
||||
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
|
||||
}
|
||||
|
||||
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
|
||||
if( random8() < SPARKING ) {
|
||||
int y = random8(7);
|
||||
heat[y] = qadd8( heat[y], random8(160,255) );
|
||||
}
|
||||
|
||||
// Step 4. Map from heat cells to LED colors
|
||||
for( int j = 0; j < NUM_LEDS; j++) {
|
||||
CRGB color = HeatColor( heat[j]);
|
||||
int pixelnumber;
|
||||
if( gReverseDirection ) {
|
||||
pixelnumber = (NUM_LEDS-1) - j;
|
||||
} else {
|
||||
pixelnumber = j;
|
||||
}
|
||||
leds[pixelnumber] = color;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,164 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define LED_PIN 5
|
||||
#define COLOR_ORDER GRB
|
||||
#define CHIPSET WS2811
|
||||
#define NUM_LEDS 30
|
||||
|
||||
#define BRIGHTNESS 200
|
||||
#define FRAMES_PER_SECOND 60
|
||||
|
||||
bool gReverseDirection = false;
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
// Fire2012 with programmable Color Palette
|
||||
//
|
||||
// This code is the same fire simulation as the original "Fire2012",
|
||||
// but each heat cell's temperature is translated to color through a FastLED
|
||||
// programmable color palette, instead of through the "HeatColor(...)" function.
|
||||
//
|
||||
// Four different static color palettes are provided here, plus one dynamic one.
|
||||
//
|
||||
// The three static ones are:
|
||||
// 1. the FastLED built-in HeatColors_p -- this is the default, and it looks
|
||||
// pretty much exactly like the original Fire2012.
|
||||
//
|
||||
// To use any of the other palettes below, just "uncomment" the corresponding code.
|
||||
//
|
||||
// 2. a gradient from black to red to yellow to white, which is
|
||||
// visually similar to the HeatColors_p, and helps to illustrate
|
||||
// what the 'heat colors' palette is actually doing,
|
||||
// 3. a similar gradient, but in blue colors rather than red ones,
|
||||
// i.e. from black to blue to aqua to white, which results in
|
||||
// an "icy blue" fire effect,
|
||||
// 4. a simplified three-step gradient, from black to red to white, just to show
|
||||
// that these gradients need not have four components; two or
|
||||
// three are possible, too, even if they don't look quite as nice for fire.
|
||||
//
|
||||
// The dynamic palette shows how you can change the basic 'hue' of the
|
||||
// color palette every time through the loop, producing "rainbow fire".
|
||||
|
||||
CRGBPalette16 gPal;
|
||||
|
||||
void setup() {
|
||||
delay(3000); // sanity delay
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
|
||||
FastLED.setBrightness( BRIGHTNESS );
|
||||
|
||||
// This first palette is the basic 'black body radiation' colors,
|
||||
// which run from black to red to bright yellow to white.
|
||||
gPal = HeatColors_p;
|
||||
|
||||
// These are other ways to set up the color palette for the 'fire'.
|
||||
// First, a gradient from black to red to yellow to white -- similar to HeatColors_p
|
||||
// gPal = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::Yellow, CRGB::White);
|
||||
|
||||
// Second, this palette is like the heat colors, but blue/aqua instead of red/yellow
|
||||
// gPal = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White);
|
||||
|
||||
// Third, here's a simpler, three-step gradient, from black to red to white
|
||||
// gPal = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::White);
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// Add entropy to random number generator; we use a lot of it.
|
||||
random16_add_entropy( random());
|
||||
|
||||
// Fourth, the most sophisticated: this one sets up a new palette every
|
||||
// time through the loop, based on a hue that changes every time.
|
||||
// The palette is a gradient from black, to a dark color based on the hue,
|
||||
// to a light color based on the hue, to white.
|
||||
//
|
||||
// static uint8_t hue = 0;
|
||||
// hue++;
|
||||
// CRGB darkcolor = CHSV(hue,255,192); // pure hue, three-quarters brightness
|
||||
// CRGB lightcolor = CHSV(hue,128,255); // half 'whitened', full brightness
|
||||
// gPal = CRGBPalette16( CRGB::Black, darkcolor, lightcolor, CRGB::White);
|
||||
|
||||
|
||||
Fire2012WithPalette(); // run simulation frame, using palette colors
|
||||
|
||||
FastLED.show(); // display this frame
|
||||
FastLED.delay(1000 / FRAMES_PER_SECOND);
|
||||
}
|
||||
|
||||
|
||||
// Fire2012 by Mark Kriegsman, July 2012
|
||||
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
|
||||
////
|
||||
// This basic one-dimensional 'fire' simulation works roughly as follows:
|
||||
// There's a underlying array of 'heat' cells, that model the temperature
|
||||
// at each point along the line. Every cycle through the simulation,
|
||||
// four steps are performed:
|
||||
// 1) All cells cool down a little bit, losing heat to the air
|
||||
// 2) The heat from each cell drifts 'up' and diffuses a little
|
||||
// 3) Sometimes randomly new 'sparks' of heat are added at the bottom
|
||||
// 4) The heat from each cell is rendered as a color into the leds array
|
||||
// The heat-to-color mapping uses a black-body radiation approximation.
|
||||
//
|
||||
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
|
||||
//
|
||||
// This simulation scales it self a bit depending on NUM_LEDS; it should look
|
||||
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
|
||||
//
|
||||
// I recommend running this simulation at anywhere from 30-100 frames per second,
|
||||
// meaning an interframe delay of about 10-35 milliseconds.
|
||||
//
|
||||
// Looks best on a high-density LED setup (60+ pixels/meter).
|
||||
//
|
||||
//
|
||||
// There are two main parameters you can play with to control the look and
|
||||
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
|
||||
// in step 3 above).
|
||||
//
|
||||
// COOLING: How much does the air cool as it rises?
|
||||
// Less cooling = taller flames. More cooling = shorter flames.
|
||||
// Default 55, suggested range 20-100
|
||||
#define COOLING 55
|
||||
|
||||
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
|
||||
// Higher chance = more roaring fire. Lower chance = more flickery fire.
|
||||
// Default 120, suggested range 50-200.
|
||||
#define SPARKING 120
|
||||
|
||||
|
||||
void Fire2012WithPalette()
|
||||
{
|
||||
// Array of temperature readings at each simulation cell
|
||||
static byte heat[NUM_LEDS];
|
||||
|
||||
// Step 1. Cool down every cell a little
|
||||
for( int i = 0; i < NUM_LEDS; i++) {
|
||||
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
for( int k= NUM_LEDS - 1; k >= 2; k--) {
|
||||
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
|
||||
}
|
||||
|
||||
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
|
||||
if( random8() < SPARKING ) {
|
||||
int y = random8(7);
|
||||
heat[y] = qadd8( heat[y], random8(160,255) );
|
||||
}
|
||||
|
||||
// Step 4. Map from heat cells to LED colors
|
||||
for( int j = 0; j < NUM_LEDS; j++) {
|
||||
// Scale the heat value from 0-255 down to 0-240
|
||||
// for best results with color palettes.
|
||||
byte colorindex = scale8( heat[j], 240);
|
||||
CRGB color = ColorFromPalette( gPal, colorindex);
|
||||
int pixelnumber;
|
||||
if( gReverseDirection ) {
|
||||
pixelnumber = (NUM_LEDS-1) - j;
|
||||
} else {
|
||||
pixelnumber = j;
|
||||
}
|
||||
leds[pixelnumber] = color;
|
||||
}
|
||||
}
|
||||
|
78
libraries/FastLED/examples/FirstLight/FirstLight.ino
Normal file
78
libraries/FastLED/examples/FirstLight/FirstLight.ino
Normal file
@ -0,0 +1,78 @@
|
||||
// Use if you want to force the software SPI subsystem to be used for some reason (generally, you don't)
|
||||
// #define FASTLED_FORCE_SOFTWARE_SPI
|
||||
// Use if you want to force non-accelerated pin access (hint: you really don't, it breaks lots of things)
|
||||
// #define FASTLED_FORCE_SOFTWARE_SPI
|
||||
// #define FASTLED_FORCE_SOFTWARE_PINS
|
||||
#include <FastLED.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Move a white dot along the strip of leds. This program simply shows how to configure the leds,
|
||||
// and then how to turn a single pixel white and then off, moving down the line of pixels.
|
||||
//
|
||||
|
||||
// How many leds are in the strip?
|
||||
#define NUM_LEDS 60
|
||||
|
||||
// Data pin that led data will be written out over
|
||||
#define DATA_PIN 3
|
||||
|
||||
// Clock pin only needed for SPI based chipsets when not using hardware SPI
|
||||
//#define CLOCK_PIN 8
|
||||
|
||||
// This is an array of leds. One item for each led in your strip.
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
// This function sets up the ledsand tells the controller about them
|
||||
void setup() {
|
||||
// sanity check delay - allows reprogramming if accidently blowing power w/leds
|
||||
delay(2000);
|
||||
|
||||
// Uncomment one of the following lines for your leds arrangement.
|
||||
// FastLED.addLeds<TM1803, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<TM1804, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<TM1809, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<APA104, DATA_PIN>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2811_400, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<GW6205, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<GW6205_400, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<UCS1903, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<UCS1903B, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
|
||||
// FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<SM16716, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<LPD8806, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<P9813, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<APA102, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<DOTSTAR, RGB>(leds, NUM_LEDS);
|
||||
|
||||
// FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<SM16716, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<P9813, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<APA102, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<DOTSTAR, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
}
|
||||
|
||||
// This function runs over and over, and is where you do the magic to light
|
||||
// your leds.
|
||||
void loop() {
|
||||
// Move a single white led
|
||||
for(int whiteLed = 0; whiteLed < NUM_LEDS; whiteLed = whiteLed + 1) {
|
||||
// Turn our current led on to white, then show the leds
|
||||
leds[whiteLed] = CRGB::White;
|
||||
|
||||
// Show the leds (only one of which is set to white, from above)
|
||||
FastLED.show();
|
||||
|
||||
// Wait a little bit
|
||||
delay(100);
|
||||
|
||||
// Turn our current led back to black for the next loop around
|
||||
leds[whiteLed] = CRGB::Black;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
// ArrayOfLedArrays - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on
|
||||
// using multiple controllers. In this example, we're going to set up three NEOPIXEL strips on three
|
||||
// different pins, each strip getting its own CRGB array to be played with, only this time they're going
|
||||
// to be all parts of an array of arrays.
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#define NUM_STRIPS 3
|
||||
#define NUM_LEDS_PER_STRIP 60
|
||||
CRGB leds[NUM_STRIPS][NUM_LEDS_PER_STRIP];
|
||||
|
||||
// For mirroring strips, all the "special" stuff happens just in setup. We
|
||||
// just addLeds multiple times, once for each strip
|
||||
void setup() {
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 10
|
||||
FastLED.addLeds<NEOPIXEL, 10>(leds[0], NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 11
|
||||
FastLED.addLeds<NEOPIXEL, 11>(leds[1], NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 12
|
||||
FastLED.addLeds<NEOPIXEL, 12>(leds[2], NUM_LEDS_PER_STRIP);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// This outer loop will go over each strip, one at a time
|
||||
for(int x = 0; x < NUM_STRIPS; x++) {
|
||||
// This inner loop will go over each led in the current strip, one at a time
|
||||
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
|
||||
leds[x][i] = CRGB::Red;
|
||||
FastLED.show();
|
||||
leds[x][i] = CRGB::Black;
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
// MirroringSample - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on
|
||||
// using multiple controllers. In this example, we're going to set up four NEOPIXEL strips on four
|
||||
// different pins, and show the same thing on all four of them, a simple bouncing dot/cyclon type pattern
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#define NUM_LEDS_PER_STRIP 60
|
||||
CRGB leds[NUM_LEDS_PER_STRIP];
|
||||
|
||||
// For mirroring strips, all the "special" stuff happens just in setup. We
|
||||
// just addLeds multiple times, once for each strip
|
||||
void setup() {
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 4
|
||||
FastLED.addLeds<NEOPIXEL, 4>(leds, NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 5
|
||||
FastLED.addLeds<NEOPIXEL, 5>(leds, NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 6
|
||||
FastLED.addLeds<NEOPIXEL, 6>(leds, NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 7
|
||||
FastLED.addLeds<NEOPIXEL, 7>(leds, NUM_LEDS_PER_STRIP);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
|
||||
// set our current dot to red
|
||||
leds[i] = CRGB::Red;
|
||||
FastLED.show();
|
||||
// clear our current dot before we move on
|
||||
leds[i] = CRGB::Black;
|
||||
delay(100);
|
||||
}
|
||||
|
||||
for(int i = NUM_LEDS_PER_STRIP-1; i >= 0; i--) {
|
||||
// set our current dot to red
|
||||
leds[i] = CRGB::Red;
|
||||
FastLED.show();
|
||||
// clear our current dot before we move on
|
||||
leds[i] = CRGB::Black;
|
||||
delay(100);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
// MultiArrays - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on
|
||||
// using multiple controllers. In this example, we're going to set up three NEOPIXEL strips on three
|
||||
// different pins, each strip getting its own CRGB array to be played with
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#define NUM_LEDS_PER_STRIP 60
|
||||
CRGB redLeds[NUM_LEDS_PER_STRIP];
|
||||
CRGB greenLeds[NUM_LEDS_PER_STRIP];
|
||||
CRGB blueLeds[NUM_LEDS_PER_STRIP];
|
||||
|
||||
// For mirroring strips, all the "special" stuff happens just in setup. We
|
||||
// just addLeds multiple times, once for each strip
|
||||
void setup() {
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 10
|
||||
FastLED.addLeds<NEOPIXEL, 10>(redLeds, NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 11
|
||||
FastLED.addLeds<NEOPIXEL, 11>(greenLeds, NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 12
|
||||
FastLED.addLeds<NEOPIXEL, 12>(blueLeds, NUM_LEDS_PER_STRIP);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for(int i = 0; i < NUM_LEDS_PER_STRIP; i++) {
|
||||
// set our current dot to red, green, and blue
|
||||
redLeds[i] = CRGB::Red;
|
||||
greenLeds[i] = CRGB::Green;
|
||||
blueLeds[i] = CRGB::Blue;
|
||||
FastLED.show();
|
||||
// clear our current dot before we move on
|
||||
redLeds[i] = CRGB::Black;
|
||||
greenLeds[i] = CRGB::Black;
|
||||
blueLeds[i] = CRGB::Blue;
|
||||
delay(100);
|
||||
}
|
||||
|
||||
for(int i = NUM_LEDS_PER_STRIP-1; i >= 0; i--) {
|
||||
// set our current dot to red, green, and blue
|
||||
redLeds[i] = CRGB::Red;
|
||||
greenLeds[i] = CRGB::Green;
|
||||
blueLeds[i] = CRGB::Blue;
|
||||
FastLED.show();
|
||||
// clear our current dot before we move on
|
||||
redLeds[i] = CRGB::Black;
|
||||
greenLeds[i] = CRGB::Black;
|
||||
blueLeds[i] = CRGB::Blue;
|
||||
delay(100);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
// MultipleStripsInOneArray - see https://github.com/FastLED/FastLED/wiki/Multiple-Controller-Examples for more info on
|
||||
// using multiple controllers. In this example, we're going to set up four NEOPIXEL strips on three
|
||||
// different pins, each strip will be referring to a different part of the single led array
|
||||
|
||||
#include <FastLED.h>
|
||||
|
||||
#define NUM_STRIPS 3
|
||||
#define NUM_LEDS_PER_STRIP 60
|
||||
#define NUM_LEDS NUM_LEDS_PER_STRIP * NUM_STRIPS
|
||||
|
||||
CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];
|
||||
|
||||
// For mirroring strips, all the "special" stuff happens just in setup. We
|
||||
// just addLeds multiple times, once for each strip
|
||||
void setup() {
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 10, starting at index 0 in the led array
|
||||
FastLED.addLeds<NEOPIXEL, 10>(leds, 0, NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 11, starting at index 60 in the led array
|
||||
FastLED.addLeds<NEOPIXEL, 11>(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
|
||||
|
||||
// tell FastLED there's 60 NEOPIXEL leds on pin 12, starting at index 120 in the led array
|
||||
FastLED.addLeds<NEOPIXEL, 12>(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = CRGB::Red;
|
||||
FastLED.show();
|
||||
leds[i] = CRGB::Black;
|
||||
delay(100);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
#define USE_OCTOWS2811
|
||||
#include <OctoWS2811.h>
|
||||
#include <FastLED.h>
|
||||
|
||||
#define NUM_LEDS_PER_STRIP 64
|
||||
#define NUM_STRIPS 8
|
||||
|
||||
CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];
|
||||
|
||||
// Pin layouts on the teensy 3:
|
||||
// OctoWS2811: 2,14,7,8,6,20,21,5
|
||||
|
||||
void setup() {
|
||||
LEDS.addLeds<OCTOWS2811>(leds, NUM_LEDS_PER_STRIP);
|
||||
LEDS.setBrightness(32);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint8_t hue = 0;
|
||||
for(int i = 0; i < NUM_STRIPS; i++) {
|
||||
for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) {
|
||||
leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the first n leds on each strip to show which strip it is
|
||||
for(int i = 0; i < NUM_STRIPS; i++) {
|
||||
for(int j = 0; j <= i; j++) {
|
||||
leds[(i*NUM_LEDS_PER_STRIP) + j] = CRGB::Red;
|
||||
}
|
||||
}
|
||||
|
||||
hue++;
|
||||
|
||||
LEDS.show();
|
||||
LEDS.delay(10);
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define NUM_LEDS_PER_STRIP 64
|
||||
// Note: this can be 12 if you're using a teensy 3 and don't mind soldering the pads on the back
|
||||
#define NUM_STRIPS 16
|
||||
|
||||
CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];
|
||||
|
||||
// Pin layouts on the teensy 3/3.1:
|
||||
// WS2811_PORTD: 2,14,7,8,6,20,21,5
|
||||
// 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)
|
||||
// WS2811_PORTDC: 2,14,7,8,6,20,21,5,15,22,23,9,10,13,11,12 - 16 way parallel
|
||||
//
|
||||
// Pin layouts on the due
|
||||
// WS2811_PORTA: 69,68,61,60,59,100,58,31 (note: pin 100 only available on the digix)
|
||||
// WS2811_PORTB: 90,91,92,93,94,95,96,97 (note: only available on the digix)
|
||||
// WS2811_PORTD: 25,26,27,28,14,15,29,11
|
||||
//
|
||||
|
||||
void setup() {
|
||||
// LEDS.addLeds<WS2811_PORTA,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
|
||||
// LEDS.addLeds<WS2811_PORTB,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
|
||||
// LEDS.addLeds<WS2811_PORTD,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip);
|
||||
LEDS.addLeds<WS2811_PORTDC,NUM_STRIPS>(leds, NUM_LEDS_PER_STRIP);
|
||||
LEDS.setBrightness(32);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint8_t hue = 0;
|
||||
for(int i = 0; i < NUM_STRIPS; i++) {
|
||||
for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) {
|
||||
leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255);
|
||||
}
|
||||
}
|
||||
|
||||
// Set the first n leds on each strip to show which strip it is
|
||||
for(int i = 0; i < NUM_STRIPS; i++) {
|
||||
for(int j = 0; j <= i; j++) {
|
||||
leds[(i*NUM_LEDS_PER_STRIP) + j] = CRGB::Red;
|
||||
}
|
||||
}
|
||||
|
||||
hue++;
|
||||
|
||||
LEDS.show();
|
||||
LEDS.delay(10);
|
||||
}
|
112
libraries/FastLED/examples/Noise/Noise.ino
Normal file
112
libraries/FastLED/examples/Noise/Noise.ino
Normal file
@ -0,0 +1,112 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
//
|
||||
// Mark's xy coordinate mapping code. See the XYMatrix for more information on it.
|
||||
//
|
||||
|
||||
// Params for width and height
|
||||
const uint8_t kMatrixWidth = 16;
|
||||
const uint8_t kMatrixHeight = 16;
|
||||
#define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight)
|
||||
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
|
||||
// Param for different pixel layouts
|
||||
const bool kMatrixSerpentineLayout = true;
|
||||
|
||||
|
||||
uint16_t XY( uint8_t x, uint8_t y)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if( kMatrixSerpentineLayout == false) {
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
|
||||
if( kMatrixSerpentineLayout == true) {
|
||||
if( y & 0x01) {
|
||||
// Odd rows run backwards
|
||||
uint8_t reverseX = (kMatrixWidth - 1) - x;
|
||||
i = (y * kMatrixWidth) + reverseX;
|
||||
} else {
|
||||
// Even rows run forwards
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// The leds
|
||||
CRGB leds[kMatrixWidth * kMatrixHeight];
|
||||
|
||||
// The 32bit version of our coordinates
|
||||
static uint16_t x;
|
||||
static uint16_t y;
|
||||
static uint16_t z;
|
||||
|
||||
// We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll
|
||||
// use the z-axis for "time". speed determines how fast time moves forward. Try
|
||||
// 1 for a very slow moving effect, or 60 for something that ends up looking like
|
||||
// water.
|
||||
// uint16_t speed = 1; // almost looks like a painting, moves very slowly
|
||||
uint16_t speed = 20; // a nice starting speed, mixes well with a scale of 100
|
||||
// uint16_t speed = 33;
|
||||
// uint16_t speed = 100; // wicked fast!
|
||||
|
||||
// Scale determines how far apart the pixels in our noise matrix are. Try
|
||||
// changing these values around to see how it affects the motion of the display. The
|
||||
// higher the value of scale, the more "zoomed out" the noise iwll be. A value
|
||||
// of 1 will be so zoomed in, you'll mostly see solid colors.
|
||||
|
||||
// uint16_t scale = 1; // mostly just solid colors
|
||||
// uint16_t scale = 4011; // very zoomed out and shimmery
|
||||
uint16_t scale = 311;
|
||||
|
||||
// This is the array that we keep our computed noise values in
|
||||
uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];
|
||||
|
||||
void setup() {
|
||||
// uncomment the following lines if you want to see FPS count information
|
||||
// Serial.begin(38400);
|
||||
// Serial.println("resetting!");
|
||||
delay(3000);
|
||||
LEDS.addLeds<WS2811,5,RGB>(leds,NUM_LEDS);
|
||||
LEDS.setBrightness(96);
|
||||
|
||||
// Initialize our coordinates to some random values
|
||||
x = random16();
|
||||
y = random16();
|
||||
z = random16();
|
||||
}
|
||||
|
||||
// Fill the x/y array of 8-bit noise values using the inoise8 function.
|
||||
void fillnoise8() {
|
||||
for(int i = 0; i < MAX_DIMENSION; i++) {
|
||||
int ioffset = scale * i;
|
||||
for(int j = 0; j < MAX_DIMENSION; j++) {
|
||||
int joffset = scale * j;
|
||||
noise[i][j] = inoise8(x + ioffset,y + joffset,z);
|
||||
}
|
||||
}
|
||||
z += speed;
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
static uint8_t ihue=0;
|
||||
fillnoise8();
|
||||
for(int i = 0; i < kMatrixWidth; i++) {
|
||||
for(int j = 0; j < kMatrixHeight; j++) {
|
||||
// We use the value at the (i,j) coordinate in the noise
|
||||
// array for our brightness, and the flipped value from (j,i)
|
||||
// for our pixel's hue.
|
||||
leds[XY(i,j)] = CHSV(noise[j][i],255,noise[i][j]);
|
||||
|
||||
// You can also explore other ways to constrain the hue used, like below
|
||||
// leds[XY(i,j)] = CHSV(ihue + (noise[j][i]>>2),255,noise[i][j]);
|
||||
}
|
||||
}
|
||||
ihue+=1;
|
||||
|
||||
LEDS.show();
|
||||
// delay(10);
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define kMatrixWidth 16
|
||||
#define kMatrixHeight 16
|
||||
|
||||
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
|
||||
// Param for different pixel layouts
|
||||
#define kMatrixSerpentineLayout true
|
||||
|
||||
// led array
|
||||
CRGB leds[kMatrixWidth * kMatrixHeight];
|
||||
|
||||
// x,y, & time values
|
||||
uint32_t x,y,v_time,hue_time,hxy;
|
||||
|
||||
// Play with the values of the variables below and see what kinds of effects they
|
||||
// have! More octaves will make things slower.
|
||||
|
||||
// how many octaves to use for the brightness and hue functions
|
||||
uint8_t octaves=1;
|
||||
uint8_t hue_octaves=3;
|
||||
|
||||
// the 'distance' between points on the x and y axis
|
||||
int xscale=57771;
|
||||
int yscale=57771;
|
||||
|
||||
// the 'distance' between x/y points for the hue noise
|
||||
int hue_scale=1;
|
||||
|
||||
// how fast we move through time & hue noise
|
||||
int time_speed=1111;
|
||||
int hue_speed=31;
|
||||
|
||||
// adjust these values to move along the x or y axis between frames
|
||||
int x_speed=331;
|
||||
int y_speed=1111;
|
||||
|
||||
void loop() {
|
||||
// fill the led array 2/16-bit noise values
|
||||
fill_2dnoise16(LEDS.leds(), kMatrixWidth, kMatrixHeight, kMatrixSerpentineLayout,
|
||||
octaves,x,xscale,y,yscale,v_time,
|
||||
hue_octaves,hxy,hue_scale,hxy,hue_scale,hue_time, false);
|
||||
|
||||
LEDS.show();
|
||||
|
||||
// adjust the intra-frame time values
|
||||
x += x_speed;
|
||||
y += y_speed;
|
||||
v_time += time_speed;
|
||||
hue_time += hue_speed;
|
||||
// delay(50);
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
// initialize the x/y and time values
|
||||
random16_set_seed(8934);
|
||||
random16_add_entropy(analogRead(3));
|
||||
|
||||
Serial.begin(57600);
|
||||
Serial.println("resetting!");
|
||||
|
||||
delay(3000);
|
||||
LEDS.addLeds<WS2811,6,GRB>(leds,NUM_LEDS);
|
||||
LEDS.setBrightness(96);
|
||||
|
||||
hxy = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
|
||||
x = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
|
||||
y = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
|
||||
v_time = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
|
||||
hue_time = (uint32_t)((uint32_t)random16() << 16) + (uint32_t)random16();
|
||||
|
||||
}
|
273
libraries/FastLED/examples/NoisePlusPalette/NoisePlusPalette.ino
Normal file
273
libraries/FastLED/examples/NoisePlusPalette/NoisePlusPalette.ino
Normal file
@ -0,0 +1,273 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define LED_PIN 3
|
||||
#define BRIGHTNESS 96
|
||||
#define LED_TYPE WS2811
|
||||
#define COLOR_ORDER GRB
|
||||
|
||||
const uint8_t kMatrixWidth = 16;
|
||||
const uint8_t kMatrixHeight = 16;
|
||||
const bool kMatrixSerpentineLayout = true;
|
||||
|
||||
|
||||
// This example combines two features of FastLED to produce a remarkable range of
|
||||
// effects from a relatively small amount of code. This example combines FastLED's
|
||||
// color palette lookup functions with FastLED's Perlin/simplex noise generator, and
|
||||
// the combination is extremely powerful.
|
||||
//
|
||||
// You might want to look at the "ColorPalette" and "Noise" examples separately
|
||||
// if this example code seems daunting.
|
||||
//
|
||||
//
|
||||
// The basic setup here is that for each frame, we generate a new array of
|
||||
// 'noise' data, and then map it onto the LED matrix through a color palette.
|
||||
//
|
||||
// Periodically, the color palette is changed, and new noise-generation parameters
|
||||
// are chosen at the same time. In this example, specific noise-generation
|
||||
// values have been selected to match the given color palettes; some are faster,
|
||||
// or slower, or larger, or smaller than others, but there's no reason these
|
||||
// parameters can't be freely mixed-and-matched.
|
||||
//
|
||||
// In addition, this example includes some fast automatic 'data smoothing' at
|
||||
// lower noise speeds to help produce smoother animations in those cases.
|
||||
//
|
||||
// The FastLED built-in color palettes (Forest, Clouds, Lava, Ocean, Party) are
|
||||
// used, as well as some 'hand-defined' ones, and some proceedurally generated
|
||||
// palettes.
|
||||
|
||||
|
||||
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
|
||||
#define MAX_DIMENSION ((kMatrixWidth>kMatrixHeight) ? kMatrixWidth : kMatrixHeight)
|
||||
|
||||
// The leds
|
||||
CRGB leds[kMatrixWidth * kMatrixHeight];
|
||||
|
||||
// The 16 bit version of our coordinates
|
||||
static uint16_t x;
|
||||
static uint16_t y;
|
||||
static uint16_t z;
|
||||
|
||||
// We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll
|
||||
// use the z-axis for "time". speed determines how fast time moves forward. Try
|
||||
// 1 for a very slow moving effect, or 60 for something that ends up looking like
|
||||
// water.
|
||||
uint16_t speed = 20; // speed is set dynamically once we've started up
|
||||
|
||||
// Scale determines how far apart the pixels in our noise matrix are. Try
|
||||
// changing these values around to see how it affects the motion of the display. The
|
||||
// higher the value of scale, the more "zoomed out" the noise iwll be. A value
|
||||
// of 1 will be so zoomed in, you'll mostly see solid colors.
|
||||
uint16_t scale = 30; // scale is set dynamically once we've started up
|
||||
|
||||
// This is the array that we keep our computed noise values in
|
||||
uint8_t noise[MAX_DIMENSION][MAX_DIMENSION];
|
||||
|
||||
CRGBPalette16 currentPalette( PartyColors_p );
|
||||
uint8_t colorLoop = 1;
|
||||
|
||||
void setup() {
|
||||
delay(3000);
|
||||
LEDS.addLeds<LED_TYPE,LED_PIN,COLOR_ORDER>(leds,NUM_LEDS);
|
||||
LEDS.setBrightness(BRIGHTNESS);
|
||||
|
||||
// Initialize our coordinates to some random values
|
||||
x = random16();
|
||||
y = random16();
|
||||
z = random16();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Fill the x/y array of 8-bit noise values using the inoise8 function.
|
||||
void fillnoise8() {
|
||||
// If we're runing at a low "speed", some 8-bit artifacts become visible
|
||||
// from frame-to-frame. In order to reduce this, we can do some fast data-smoothing.
|
||||
// The amount of data smoothing we're doing depends on "speed".
|
||||
uint8_t dataSmoothing = 0;
|
||||
if( speed < 50) {
|
||||
dataSmoothing = 200 - (speed * 4);
|
||||
}
|
||||
|
||||
for(int i = 0; i < MAX_DIMENSION; i++) {
|
||||
int ioffset = scale * i;
|
||||
for(int j = 0; j < MAX_DIMENSION; j++) {
|
||||
int joffset = scale * j;
|
||||
|
||||
uint8_t data = inoise8(x + ioffset,y + joffset,z);
|
||||
|
||||
// The range of the inoise8 function is roughly 16-238.
|
||||
// These two operations expand those values out to roughly 0..255
|
||||
// You can comment them out if you want the raw noise data.
|
||||
data = qsub8(data,16);
|
||||
data = qadd8(data,scale8(data,39));
|
||||
|
||||
if( dataSmoothing ) {
|
||||
uint8_t olddata = noise[i][j];
|
||||
uint8_t newdata = scale8( olddata, dataSmoothing) + scale8( data, 256 - dataSmoothing);
|
||||
data = newdata;
|
||||
}
|
||||
|
||||
noise[i][j] = data;
|
||||
}
|
||||
}
|
||||
|
||||
z += speed;
|
||||
|
||||
// apply slow drift to X and Y, just for visual variation.
|
||||
x += speed / 8;
|
||||
y -= speed / 16;
|
||||
}
|
||||
|
||||
void mapNoiseToLEDsUsingPalette()
|
||||
{
|
||||
static uint8_t ihue=0;
|
||||
|
||||
for(int i = 0; i < kMatrixWidth; i++) {
|
||||
for(int j = 0; j < kMatrixHeight; j++) {
|
||||
// We use the value at the (i,j) coordinate in the noise
|
||||
// array for our brightness, and the flipped value from (j,i)
|
||||
// for our pixel's index into the color palette.
|
||||
|
||||
uint8_t index = noise[j][i];
|
||||
uint8_t bri = noise[i][j];
|
||||
|
||||
// if this palette is a 'loop', add a slowly-changing base value
|
||||
if( colorLoop) {
|
||||
index += ihue;
|
||||
}
|
||||
|
||||
// brighten up, as the color palette itself often contains the
|
||||
// light/dark dynamic range desired
|
||||
if( bri > 127 ) {
|
||||
bri = 255;
|
||||
} else {
|
||||
bri = dim8_raw( bri * 2);
|
||||
}
|
||||
|
||||
CRGB color = ColorFromPalette( currentPalette, index, bri);
|
||||
leds[XY(i,j)] = color;
|
||||
}
|
||||
}
|
||||
|
||||
ihue+=1;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Periodically choose a new palette, speed, and scale
|
||||
ChangePaletteAndSettingsPeriodically();
|
||||
|
||||
// generate noise data
|
||||
fillnoise8();
|
||||
|
||||
// convert the noise data to colors in the LED array
|
||||
// using the current palette
|
||||
mapNoiseToLEDsUsingPalette();
|
||||
|
||||
LEDS.show();
|
||||
// delay(10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// There are several different palettes of colors demonstrated here.
|
||||
//
|
||||
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
|
||||
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
|
||||
//
|
||||
// Additionally, you can manually define your own color palettes, or you can write
|
||||
// code that creates color palettes on the fly.
|
||||
|
||||
// 1 = 5 sec per palette
|
||||
// 2 = 10 sec per palette
|
||||
// etc
|
||||
#define HOLD_PALETTES_X_TIMES_AS_LONG 1
|
||||
|
||||
void ChangePaletteAndSettingsPeriodically()
|
||||
{
|
||||
uint8_t secondHand = ((millis() / 1000) / HOLD_PALETTES_X_TIMES_AS_LONG) % 60;
|
||||
static uint8_t lastSecond = 99;
|
||||
|
||||
if( lastSecond != secondHand) {
|
||||
lastSecond = secondHand;
|
||||
if( secondHand == 0) { currentPalette = RainbowColors_p; speed = 20; scale = 30; colorLoop = 1; }
|
||||
if( secondHand == 5) { SetupPurpleAndGreenPalette(); speed = 10; scale = 50; colorLoop = 1; }
|
||||
if( secondHand == 10) { SetupBlackAndWhiteStripedPalette(); speed = 20; scale = 30; colorLoop = 1; }
|
||||
if( secondHand == 15) { currentPalette = ForestColors_p; speed = 8; scale =120; colorLoop = 0; }
|
||||
if( secondHand == 20) { currentPalette = CloudColors_p; speed = 4; scale = 30; colorLoop = 0; }
|
||||
if( secondHand == 25) { currentPalette = LavaColors_p; speed = 8; scale = 50; colorLoop = 0; }
|
||||
if( secondHand == 30) { currentPalette = OceanColors_p; speed = 20; scale = 90; colorLoop = 0; }
|
||||
if( secondHand == 35) { currentPalette = PartyColors_p; speed = 20; scale = 30; colorLoop = 1; }
|
||||
if( secondHand == 40) { SetupRandomPalette(); speed = 20; scale = 20; colorLoop = 1; }
|
||||
if( secondHand == 45) { SetupRandomPalette(); speed = 50; scale = 50; colorLoop = 1; }
|
||||
if( secondHand == 50) { SetupRandomPalette(); speed = 90; scale = 90; colorLoop = 1; }
|
||||
if( secondHand == 55) { currentPalette = RainbowStripeColors_p; speed = 30; scale = 20; colorLoop = 1; }
|
||||
}
|
||||
}
|
||||
|
||||
// This function generates a random palette that's a gradient
|
||||
// between four different colors. The first is a dim hue, the second is
|
||||
// a bright hue, the third is a bright pastel, and the last is
|
||||
// another bright hue. This gives some visual bright/dark variation
|
||||
// which is more interesting than just a gradient of different hues.
|
||||
void SetupRandomPalette()
|
||||
{
|
||||
currentPalette = CRGBPalette16(
|
||||
CHSV( random8(), 255, 32),
|
||||
CHSV( random8(), 255, 255),
|
||||
CHSV( random8(), 128, 255),
|
||||
CHSV( random8(), 255, 255));
|
||||
}
|
||||
|
||||
// This function sets up a palette of black and white stripes,
|
||||
// using code. Since the palette is effectively an array of
|
||||
// sixteen CRGB colors, the various fill_* functions can be used
|
||||
// to set them up.
|
||||
void SetupBlackAndWhiteStripedPalette()
|
||||
{
|
||||
// 'black out' all 16 palette entries...
|
||||
fill_solid( currentPalette, 16, CRGB::Black);
|
||||
// and set every fourth one to white.
|
||||
currentPalette[0] = CRGB::White;
|
||||
currentPalette[4] = CRGB::White;
|
||||
currentPalette[8] = CRGB::White;
|
||||
currentPalette[12] = CRGB::White;
|
||||
|
||||
}
|
||||
|
||||
// This function sets up a palette of purple and green stripes.
|
||||
void SetupPurpleAndGreenPalette()
|
||||
{
|
||||
CRGB purple = CHSV( HUE_PURPLE, 255, 255);
|
||||
CRGB green = CHSV( HUE_GREEN, 255, 255);
|
||||
CRGB black = CRGB::Black;
|
||||
|
||||
currentPalette = CRGBPalette16(
|
||||
green, green, black, black,
|
||||
purple, purple, black, black,
|
||||
green, green, black, black,
|
||||
purple, purple, black, black );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Mark's xy coordinate mapping code. See the XYMatrix for more information on it.
|
||||
//
|
||||
uint16_t XY( uint8_t x, uint8_t y)
|
||||
{
|
||||
uint16_t i;
|
||||
if( kMatrixSerpentineLayout == false) {
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
if( kMatrixSerpentineLayout == true) {
|
||||
if( y & 0x01) {
|
||||
// Odd rows run backwards
|
||||
uint8_t reverseX = (kMatrixWidth - 1) - x;
|
||||
i = (y * kMatrixWidth) + reverseX;
|
||||
} else {
|
||||
// Even rows run forwards
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
105
libraries/FastLED/examples/Pintest/Pintest.ino
Normal file
105
libraries/FastLED/examples/Pintest/Pintest.ino
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
#include <FastSPI_LED.h>
|
||||
|
||||
const char *getPort(void *portPtr) {
|
||||
#ifdef PORTA
|
||||
if(portPtr == (void*)&PORTA) { return "PORTA"; }
|
||||
#endif
|
||||
#ifdef PORTB
|
||||
if(portPtr == (void*)&PORTB) { return "PORTB"; }
|
||||
#endif
|
||||
#ifdef PORTC
|
||||
if(portPtr == (void*)&PORTC) { return "PORTC"; }
|
||||
#endif
|
||||
#ifdef PORTD
|
||||
if(portPtr == (void*)&PORTD) { return "PORTD"; }
|
||||
#endif
|
||||
#ifdef PORTE
|
||||
if(portPtr == (void*)&PORTE) { return "PORTE"; }
|
||||
#endif
|
||||
#ifdef PORTF
|
||||
if(portPtr == (void*)&PORTF) { return "PORTF"; }
|
||||
#endif
|
||||
#ifdef PORTG
|
||||
if(portPtr == (void*)&PORTG) { return "PORTG"; }
|
||||
#endif
|
||||
#ifdef PORTH
|
||||
if(portPtr == (void*)&PORTH) { return "PORTH"; }
|
||||
#endif
|
||||
#ifdef PORTI
|
||||
if(portPtr == (void*)&PORTI) { return "PORTI"; }
|
||||
#endif
|
||||
#ifdef PORTJ
|
||||
if(portPtr == (void*)&PORTJ) { return "PORTJ"; }
|
||||
#endif
|
||||
#ifdef PORTK
|
||||
if(portPtr == (void*)&PORTK) { return "PORTK"; }
|
||||
#endif
|
||||
#ifdef PORTL
|
||||
if(portPtr == (void*)&PORTL) { return "PORTL"; }
|
||||
#endif
|
||||
#ifdef GPIO_A_PDOR
|
||||
if(portPtr == (void*)&GPIO_A_PDOR) { return "GPIO_A_PDOR"; }
|
||||
#endif
|
||||
#ifdef GPIO_B_PDOR
|
||||
if(portPtr == (void*)&GPIO_B_PDOR) { return "GPIO_B_PDOR"; }
|
||||
#endif
|
||||
#ifdef GPIO_C_PDOR
|
||||
if(portPtr == (void*)&GPIO_C_PDOR) { return "GPIO_C_PDOR"; }
|
||||
#endif
|
||||
#ifdef GPIO_D_PDOR
|
||||
if(portPtr == (void*)&GPIO_D_PDOR) { return "GPIO_D_PDOR"; }
|
||||
#endif
|
||||
#ifdef GPIO_E_PDOR
|
||||
if(portPtr == (void*)&GPIO_E_PDOR) { return "GPIO_E_PDOR"; }
|
||||
#endif
|
||||
#ifdef REG_PIO_A_ODSR
|
||||
if(portPtr == (void*)®_PIO_A_ODSR) { return "REG_PIO_A_ODSR"; }
|
||||
#endif
|
||||
#ifdef REG_PIO_B_ODSR
|
||||
if(portPtr == (void*)®_PIO_B_ODSR) { return "REG_PIO_B_ODSR"; }
|
||||
#endif
|
||||
#ifdef REG_PIO_C_ODSR
|
||||
if(portPtr == (void*)®_PIO_C_ODSR) { return "REG_PIO_C_ODSR"; }
|
||||
#endif
|
||||
#ifdef REG_PIO_D_ODSR
|
||||
if(portPtr == (void*)®_PIO_D_ODSR) { return "REG_PIO_D_ODSR"; }
|
||||
#endif
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
template<uint8_t PIN> void CheckPin()
|
||||
{
|
||||
CheckPin<PIN - 1>();
|
||||
|
||||
RwReg *systemThinksPortIs = portOutputRegister(digitalPinToPort(PIN));
|
||||
RwReg systemThinksMaskIs = digitalPinToBitMask(PIN);
|
||||
|
||||
Serial.print("Pin "); Serial.print(PIN); Serial.print(": Port ");
|
||||
|
||||
if(systemThinksPortIs == FastPin<PIN>::port()) {
|
||||
Serial.print("valid & mask ");
|
||||
} else {
|
||||
Serial.print("invalid, is "); Serial.print(getPort((void*)FastPin<PIN>::port())); Serial.print(" should be ");
|
||||
Serial.print(getPort((void*)systemThinksPortIs));
|
||||
Serial.print(" & mask ");
|
||||
}
|
||||
|
||||
if(systemThinksMaskIs == FastPin<PIN>::mask()) {
|
||||
Serial.println("valid.");
|
||||
} else {
|
||||
Serial.print("invalid, is "); Serial.print(FastPin<PIN>::mask()); Serial.print(" should be "); Serial.println(systemThinksMaskIs);
|
||||
}
|
||||
}
|
||||
|
||||
template<> void CheckPin<-1> () {}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(38400);
|
||||
Serial.println("resetting!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
CheckPin<MAX_PIN>();
|
||||
delay(10000);
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
// LED Audio Spectrum Analyzer Display
|
||||
//
|
||||
// Creates an impressive LED light show to music input
|
||||
// using Teensy 3.1 with the OctoWS2811 adaptor board
|
||||
// http://www.pjrc.com/store/teensy31.html
|
||||
// http://www.pjrc.com/store/octo28_adaptor.html
|
||||
//
|
||||
// Line Level Audio Input connects to analog pin A3
|
||||
// Recommended input circuit:
|
||||
// http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog
|
||||
//
|
||||
// This example code is in the public domain.
|
||||
|
||||
#define USE_OCTOWS2811
|
||||
#include <OctoWS2811.h>
|
||||
#include <FastLED.h>
|
||||
#include <Audio.h>
|
||||
#include <Wire.h>
|
||||
#include <SD.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// The display size and color to use
|
||||
const unsigned int matrix_width = 60;
|
||||
const unsigned int matrix_height = 32;
|
||||
const unsigned int myColor = 0x400020;
|
||||
|
||||
// These parameters adjust the vertical thresholds
|
||||
const float maxLevel = 0.5; // 1.0 = max, lower is more "sensitive"
|
||||
const float dynamicRange = 40.0; // total range to display, in decibels
|
||||
const float linearBlend = 0.3; // useful range is 0 to 0.7
|
||||
|
||||
CRGB leds[matrix_width * matrix_height];
|
||||
|
||||
// Audio library objects
|
||||
AudioInputAnalog adc1(A3); //xy=99,55
|
||||
AudioAnalyzeFFT1024 fft; //xy=265,75
|
||||
AudioConnection patchCord1(adc1, fft);
|
||||
|
||||
|
||||
// This array holds the volume level (0 to 1.0) for each
|
||||
// vertical pixel to turn on. Computed in setup() using
|
||||
// the 3 parameters above.
|
||||
float thresholdVertical[matrix_height];
|
||||
|
||||
// This array specifies how many of the FFT frequency bin
|
||||
// to use for each horizontal pixel. Because humans hear
|
||||
// in octaves and FFT bins are linear, the low frequencies
|
||||
// use a small number of bins, higher frequencies use more.
|
||||
int frequencyBinsHorizontal[matrix_width] = {
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
|
||||
3, 3, 3, 3, 4, 4, 4, 4, 4, 5,
|
||||
5, 5, 6, 6, 6, 7, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 12, 12, 13, 14, 15,
|
||||
15, 16, 17, 18, 19, 20, 22, 23, 24, 25
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Run setup once
|
||||
void setup() {
|
||||
// the audio library needs to be given memory to start working
|
||||
AudioMemory(12);
|
||||
|
||||
// compute the vertical thresholds before starting
|
||||
computeVerticalLevels();
|
||||
|
||||
// turn on the display
|
||||
FastLED.addLeds<OCTOWS2811>(leds,(matrix_width * matrix_height) / 8);
|
||||
}
|
||||
|
||||
// A simple xy() function to turn display matrix coordinates
|
||||
// into the index numbers OctoWS2811 requires. If your LEDs
|
||||
// are arranged differently, edit this code...
|
||||
unsigned int xy(unsigned int x, unsigned int y) {
|
||||
if ((y & 1) == 0) {
|
||||
// even numbered rows (0, 2, 4...) are left to right
|
||||
return y * matrix_width + x;
|
||||
} else {
|
||||
// odd numbered rows (1, 3, 5...) are right to left
|
||||
return y * matrix_width + matrix_width - 1 - x;
|
||||
}
|
||||
}
|
||||
|
||||
// Run repetitively
|
||||
void loop() {
|
||||
unsigned int x, y, freqBin;
|
||||
float level;
|
||||
|
||||
if (fft.available()) {
|
||||
// freqBin counts which FFT frequency data has been used,
|
||||
// starting at low frequency
|
||||
freqBin = 0;
|
||||
|
||||
for (x=0; x < matrix_width; x++) {
|
||||
// get the volume for each horizontal pixel position
|
||||
level = fft.read(freqBin, freqBin + frequencyBinsHorizontal[x] - 1);
|
||||
|
||||
// uncomment to see the spectrum in Arduino's Serial Monitor
|
||||
// Serial.print(level);
|
||||
// Serial.print(" ");
|
||||
|
||||
for (y=0; y < matrix_height; y++) {
|
||||
// for each vertical pixel, check if above the threshold
|
||||
// and turn the LED on or off
|
||||
if (level >= thresholdVertical[y]) {
|
||||
leds[xy(x,y)] = CRGB(myColor);
|
||||
} else {
|
||||
leds[xy(x,y)] = CRGB::Black;
|
||||
}
|
||||
}
|
||||
// increment the frequency bin count, so we display
|
||||
// low to higher frequency from left to right
|
||||
freqBin = freqBin + frequencyBinsHorizontal[x];
|
||||
}
|
||||
// after all pixels set, show them all at the same instant
|
||||
FastLED.show();
|
||||
// Serial.println();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Run once from setup, the compute the vertical levels
|
||||
void computeVerticalLevels() {
|
||||
unsigned int y;
|
||||
float n, logLevel, linearLevel;
|
||||
|
||||
for (y=0; y < matrix_height; y++) {
|
||||
n = (float)y / (float)(matrix_height - 1);
|
||||
logLevel = pow10f(n * -1.0 * (dynamicRange / 20.0));
|
||||
linearLevel = 1.0 - n;
|
||||
linearLevel = linearLevel * linearBlend;
|
||||
logLevel = logLevel * (1.0 - linearBlend);
|
||||
thresholdVertical[y] = (logLevel + linearLevel) * maxLevel;
|
||||
}
|
||||
}
|
72
libraries/FastLED/examples/RGBCalibrate/RGBCalibrate.ino
Normal file
72
libraries/FastLED/examples/RGBCalibrate/RGBCalibrate.ino
Normal file
@ -0,0 +1,72 @@
|
||||
#include "FastLED.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RGB Calibration code
|
||||
//
|
||||
// Use this sketch to determine what the RGB ordering for your chipset should be. Steps for setting up to use:
|
||||
|
||||
// * Uncomment the line in setup that corresponds to the LED chipset that you are using. (Note that they
|
||||
// all explicitly specify the RGB order as RGB)
|
||||
// * Define DATA_PIN to the pin that data is connected to.
|
||||
// * (Optional) if using software SPI for chipsets that are SPI based, define CLOCK_PIN to the clock pin
|
||||
// * Compile/upload/run the sketch
|
||||
|
||||
// You should see six leds on. If the RGB ordering is correct, you should see 1 red led, 2 green
|
||||
// leds, and 3 blue leds. If you see different colors, the count of each color tells you what the
|
||||
// position for that color in the rgb orering should be. So, for example, if you see 1 Blue, and 2
|
||||
// Red, and 3 Green leds then the rgb ordering should be BRG (Blue, Red, Green).
|
||||
|
||||
// You can then test this ordering by setting the RGB ordering in the addLeds line below to the new ordering
|
||||
// and it should come out correctly, 1 red, 2 green, and 3 blue.
|
||||
//
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
#define NUM_LEDS 6
|
||||
|
||||
// Data pin that led data will be written out over
|
||||
#define DATA_PIN 6
|
||||
// Clock pin only needed for SPI based chipsets when not using hardware SPI
|
||||
//#define CLOCK_PIN 8
|
||||
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
void setup() {
|
||||
// sanity check delay - allows reprogramming if accidently blowing power w/leds
|
||||
delay(2000);
|
||||
|
||||
// Uncomment one of the following lines for your leds arrangement.
|
||||
// FastLED.addLeds<TM1803, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<TM1804, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<TM1809, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
|
||||
// FastLED.setBrightness(CRGB(255,255,255));
|
||||
// FastLED.addLeds<GW6205, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<GW6205_400, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<UCS1903, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<UCS1903B, DATA_PIN, RGB>(leds, NUM_LEDS);
|
||||
|
||||
// FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<SM16716, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<LPD8806, 9, 10, RGB>(leds, NUM_LEDS);
|
||||
FastLED.addLeds<LPD6803, RGB>(leds, NUM_LEDS);
|
||||
|
||||
// FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<SM16716, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
// FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
leds[0] = CRGB(255,0,0);
|
||||
leds[1] = CRGB(0,255,0);
|
||||
leds[2] = CRGB(0,255,0);
|
||||
leds[3] = CRGB(0,0,255);
|
||||
leds[4] = CRGB(0,0,255);
|
||||
leds[5] = CRGB(0,0,255);
|
||||
leds[6] = CRGB(0,0,0);
|
||||
FastLED.show();
|
||||
delay(1000);
|
||||
}
|
22
libraries/FastLED/examples/RGBSetDemo/RGBSetDemo.ino
Normal file
22
libraries/FastLED/examples/RGBSetDemo/RGBSetDemo.ino
Normal file
@ -0,0 +1,22 @@
|
||||
#include <FastLED.h>
|
||||
#define NUM_LEDS 40
|
||||
|
||||
CRGBArray<NUM_LEDS> leds;
|
||||
|
||||
void setup() { FastLED.addLeds<NEOPIXEL,6>(leds, NUM_LEDS); }
|
||||
|
||||
void loop(){
|
||||
static uint8_t hue;
|
||||
for(int i = 0; i < NUM_LEDS/2; i++) {
|
||||
// fade everything out
|
||||
leds.fadeToBlackBy(40);
|
||||
|
||||
// let's set an led value
|
||||
leds[i] = CHSV(hue++,255,255);
|
||||
|
||||
// now, let's first 20 leds to the top 20 leds,
|
||||
leds(NUM_LEDS/2,NUM_LEDS-1) = leds(NUM_LEDS/2 - 1 ,0);
|
||||
FastLED.delay(33);
|
||||
}
|
||||
}
|
||||
|
121
libraries/FastLED/examples/SmartMatrix/SmartMatrix.ino
Normal file
121
libraries/FastLED/examples/SmartMatrix/SmartMatrix.ino
Normal file
@ -0,0 +1,121 @@
|
||||
#include <SmartMatrix.h>
|
||||
#include <FastLED.h>
|
||||
|
||||
#define kMatrixWidth 32
|
||||
#define kMatrixHeight 32
|
||||
const bool kMatrixSerpentineLayout = false;
|
||||
|
||||
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
|
||||
|
||||
CRGB leds[kMatrixWidth * kMatrixHeight];
|
||||
|
||||
|
||||
uint16_t XY( uint8_t x, uint8_t y)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if( kMatrixSerpentineLayout == false) {
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
|
||||
if( kMatrixSerpentineLayout == true) {
|
||||
if( y & 0x01) {
|
||||
// Odd rows run backwards
|
||||
uint8_t reverseX = (kMatrixWidth - 1) - x;
|
||||
i = (y * kMatrixWidth) + reverseX;
|
||||
} else {
|
||||
// Even rows run forwards
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// The 32bit version of our coordinates
|
||||
static uint16_t x;
|
||||
static uint16_t y;
|
||||
static uint16_t z;
|
||||
|
||||
// We're using the x/y dimensions to map to the x/y pixels on the matrix. We'll
|
||||
// use the z-axis for "time". speed determines how fast time moves forward. Try
|
||||
// 1 for a very slow moving effect, or 60 for something that ends up looking like
|
||||
// water.
|
||||
// uint16_t speed = 1; // almost looks like a painting, moves very slowly
|
||||
uint16_t speed = 20; // a nice starting speed, mixes well with a scale of 100
|
||||
// uint16_t speed = 33;
|
||||
// uint16_t speed = 100; // wicked fast!
|
||||
|
||||
// Scale determines how far apart the pixels in our noise matrix are. Try
|
||||
// changing these values around to see how it affects the motion of the display. The
|
||||
// higher the value of scale, the more "zoomed out" the noise iwll be. A value
|
||||
// of 1 will be so zoomed in, you'll mostly see solid colors.
|
||||
|
||||
// uint16_t scale = 1; // mostly just solid colors
|
||||
// uint16_t scale = 4011; // very zoomed out and shimmery
|
||||
uint16_t scale = 31;
|
||||
|
||||
// This is the array that we keep our computed noise values in
|
||||
uint8_t noise[kMatrixWidth][kMatrixHeight];
|
||||
|
||||
void setup() {
|
||||
// uncomment the following lines if you want to see FPS count information
|
||||
// Serial.begin(38400);
|
||||
// Serial.println("resetting!");
|
||||
delay(3000);
|
||||
LEDS.addLeds<SMART_MATRIX>(leds,NUM_LEDS);
|
||||
LEDS.setBrightness(96);
|
||||
|
||||
// Initialize our coordinates to some random values
|
||||
x = random16();
|
||||
y = random16();
|
||||
z = random16();
|
||||
|
||||
// Show off smart matrix scrolling text
|
||||
pSmartMatrix->setScrollMode(wrapForward);
|
||||
pSmartMatrix->setScrollColor({0xff, 0xff, 0xff});
|
||||
pSmartMatrix->setScrollSpeed(15);
|
||||
pSmartMatrix->setScrollFont(font6x10);
|
||||
pSmartMatrix->scrollText("Smart Matrix & FastLED", -1);
|
||||
pSmartMatrix->setScrollOffsetFromEdge(10);
|
||||
}
|
||||
|
||||
// Fill the x/y array of 8-bit noise values using the inoise8 function.
|
||||
void fillnoise8() {
|
||||
for(int i = 0; i < kMatrixWidth; i++) {
|
||||
int ioffset = scale * i;
|
||||
for(int j = 0; j < kMatrixHeight; j++) {
|
||||
int joffset = scale * j;
|
||||
noise[i][j] = inoise8(x + ioffset,y + joffset,z);
|
||||
}
|
||||
}
|
||||
z += speed;
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
static uint8_t circlex = 0;
|
||||
static uint8_t circley = 0;
|
||||
|
||||
static uint8_t ihue=0;
|
||||
fillnoise8();
|
||||
for(int i = 0; i < kMatrixWidth; i++) {
|
||||
for(int j = 0; j < kMatrixHeight; j++) {
|
||||
// We use the value at the (i,j) coordinate in the noise
|
||||
// array for our brightness, and the flipped value from (j,i)
|
||||
// for our pixel's hue.
|
||||
leds[XY(i,j)] = CHSV(noise[j][i],255,noise[i][j]);
|
||||
|
||||
// You can also explore other ways to constrain the hue used, like below
|
||||
// leds[XY(i,j)] = CHSV(ihue + (noise[j][i]>>2),255,noise[i][j]);
|
||||
}
|
||||
}
|
||||
ihue+=1;
|
||||
|
||||
// N.B. this requires SmartMatrix modified w/triple buffering support
|
||||
pSmartMatrix->fillCircle(circlex % 32,circley % 32,6,CRGB(CHSV(ihue+128,255,255)));
|
||||
circlex += random16(2);
|
||||
circley += random16(2);
|
||||
LEDS.show();
|
||||
// delay(10);
|
||||
}
|
196
libraries/FastLED/examples/XYMatrix/XYMatrix.ino
Normal file
196
libraries/FastLED/examples/XYMatrix/XYMatrix.ino
Normal file
@ -0,0 +1,196 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#define LED_PIN 3
|
||||
|
||||
#define COLOR_ORDER GRB
|
||||
#define CHIPSET WS2811
|
||||
|
||||
#define BRIGHTNESS 64
|
||||
|
||||
// Helper functions for an two-dimensional XY matrix of pixels.
|
||||
// Simple 2-D demo code is included as well.
|
||||
//
|
||||
// XY(x,y) takes x and y coordinates and returns an LED index number,
|
||||
// for use like this: leds[ XY(x,y) ] == CRGB::Red;
|
||||
// No error checking is performed on the ranges of x and y.
|
||||
//
|
||||
// XYsafe(x,y) takes x and y coordinates and returns an LED index number,
|
||||
// for use like this: leds[ XY(x,y) ] == CRGB::Red;
|
||||
// Error checking IS performed on the ranges of x and y, and an
|
||||
// index of "-1" is returned. Special instructions below
|
||||
// explain how to use this without having to do your own error
|
||||
// checking every time you use this function.
|
||||
// This is a slightly more advanced technique, and
|
||||
// it REQUIRES SPECIAL ADDITIONAL setup, described below.
|
||||
|
||||
|
||||
// Params for width and height
|
||||
const uint8_t kMatrixWidth = 16;
|
||||
const uint8_t kMatrixHeight = 16;
|
||||
|
||||
// Param for different pixel layouts
|
||||
const bool kMatrixSerpentineLayout = true;
|
||||
// Set 'kMatrixSerpentineLayout' to false if your pixels are
|
||||
// laid out all running the same way, like this:
|
||||
//
|
||||
// 0 > 1 > 2 > 3 > 4
|
||||
// |
|
||||
// .----<----<----<----'
|
||||
// |
|
||||
// 5 > 6 > 7 > 8 > 9
|
||||
// |
|
||||
// .----<----<----<----'
|
||||
// |
|
||||
// 10 > 11 > 12 > 13 > 14
|
||||
// |
|
||||
// .----<----<----<----'
|
||||
// |
|
||||
// 15 > 16 > 17 > 18 > 19
|
||||
//
|
||||
// Set 'kMatrixSerpentineLayout' to true if your pixels are
|
||||
// laid out back-and-forth, like this:
|
||||
//
|
||||
// 0 > 1 > 2 > 3 > 4
|
||||
// |
|
||||
// |
|
||||
// 9 < 8 < 7 < 6 < 5
|
||||
// |
|
||||
// |
|
||||
// 10 > 11 > 12 > 13 > 14
|
||||
// |
|
||||
// |
|
||||
// 19 < 18 < 17 < 16 < 15
|
||||
//
|
||||
// Bonus vocabulary word: anything that goes one way
|
||||
// in one row, and then backwards in the next row, and so on
|
||||
// is call "boustrophedon", meaning "as the ox plows."
|
||||
|
||||
|
||||
// This function will return the right 'led index number' for
|
||||
// a given set of X and Y coordinates on your matrix.
|
||||
// IT DOES NOT CHECK THE COORDINATE BOUNDARIES.
|
||||
// That's up to you. Don't pass it bogus values.
|
||||
//
|
||||
// Use the "XY" function like this:
|
||||
//
|
||||
// for( uint8_t x = 0; x < kMatrixWidth; x++) {
|
||||
// for( uint8_t y = 0; y < kMatrixHeight; y++) {
|
||||
//
|
||||
// // Here's the x, y to 'led index' in action:
|
||||
// leds[ XY( x, y) ] = CHSV( random8(), 255, 255);
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
uint16_t XY( uint8_t x, uint8_t y)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
if( kMatrixSerpentineLayout == false) {
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
|
||||
if( kMatrixSerpentineLayout == true) {
|
||||
if( y & 0x01) {
|
||||
// Odd rows run backwards
|
||||
uint8_t reverseX = (kMatrixWidth - 1) - x;
|
||||
i = (y * kMatrixWidth) + reverseX;
|
||||
} else {
|
||||
// Even rows run forwards
|
||||
i = (y * kMatrixWidth) + x;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
// Once you've gotten the basics working (AND NOT UNTIL THEN!)
|
||||
// here's a helpful technique that can be tricky to set up, but
|
||||
// then helps you avoid the needs for sprinkling array-bound-checking
|
||||
// throughout your code.
|
||||
//
|
||||
// It requires a careful attention to get it set up correctly, but
|
||||
// can potentially make your code smaller and faster.
|
||||
//
|
||||
// Suppose you have an 8 x 5 matrix of 40 LEDs. Normally, you'd
|
||||
// delcare your leds array like this:
|
||||
// CRGB leds[40];
|
||||
// But instead of that, declare an LED buffer with one extra pixel in
|
||||
// it, "leds_plus_safety_pixel". Then declare "leds" as a pointer to
|
||||
// that array, but starting with the 2nd element (id=1) of that array:
|
||||
// CRGB leds_with_safety_pixel[41];
|
||||
// CRGB* const leds( leds_plus_safety_pixel + 1);
|
||||
// Then you use the "leds" array as you normally would.
|
||||
// Now "leds[0..N]" are aliases for "leds_plus_safety_pixel[1..(N+1)]",
|
||||
// AND leds[-1] is now a legitimate and safe alias for leds_plus_safety_pixel[0].
|
||||
// leds_plus_safety_pixel[0] aka leds[-1] is now your "safety pixel".
|
||||
//
|
||||
// Now instead of using the XY function above, use the one below, "XYsafe".
|
||||
//
|
||||
// If the X and Y values are 'in bounds', this function will return an index
|
||||
// into the visible led array, same as "XY" does.
|
||||
// HOWEVER -- and this is the trick -- if the X or Y values
|
||||
// are out of bounds, this function will return an index of -1.
|
||||
// And since leds[-1] is actually just an alias for leds_plus_safety_pixel[0],
|
||||
// it's a totally safe and legal place to access. And since the 'safety pixel'
|
||||
// falls 'outside' the visible part of the LED array, anything you write
|
||||
// there is hidden from view automatically.
|
||||
// Thus, this line of code is totally safe, regardless of the actual size of
|
||||
// your matrix:
|
||||
// leds[ XYsafe( random8(), random8() ) ] = CHSV( random8(), 255, 255);
|
||||
//
|
||||
// The only catch here is that while this makes it safe to read from and
|
||||
// write to 'any pixel', there's really only ONE 'safety pixel'. No matter
|
||||
// what out-of-bounds coordinates you write to, you'll really be writing to
|
||||
// that one safety pixel. And if you try to READ from the safety pixel,
|
||||
// you'll read whatever was written there last, reglardless of what coordinates
|
||||
// were supplied.
|
||||
|
||||
#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
|
||||
CRGB leds_plus_safety_pixel[ NUM_LEDS + 1];
|
||||
CRGB* const leds( leds_plus_safety_pixel + 1);
|
||||
|
||||
uint16_t XYsafe( uint8_t x, uint8_t y)
|
||||
{
|
||||
if( x >= kMatrixWidth) return -1;
|
||||
if( y >= kMatrixHeight) return -1;
|
||||
return XY(x,y);
|
||||
}
|
||||
|
||||
|
||||
// Demo that USES "XY" follows code below
|
||||
|
||||
void loop()
|
||||
{
|
||||
uint32_t ms = millis();
|
||||
int32_t yHueDelta32 = ((int32_t)cos16( ms * (27/1) ) * (350 / kMatrixWidth));
|
||||
int32_t xHueDelta32 = ((int32_t)cos16( ms * (39/1) ) * (310 / kMatrixHeight));
|
||||
DrawOneFrame( ms / 65536, yHueDelta32 / 32768, xHueDelta32 / 32768);
|
||||
if( ms < 5000 ) {
|
||||
FastLED.setBrightness( scale8( BRIGHTNESS, (ms * 256) / 5000));
|
||||
} else {
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
}
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
void DrawOneFrame( byte startHue8, int8_t yHueDelta8, int8_t xHueDelta8)
|
||||
{
|
||||
byte lineStartHue = startHue8;
|
||||
for( byte y = 0; y < kMatrixHeight; y++) {
|
||||
lineStartHue += yHueDelta8;
|
||||
byte pixelHue = lineStartHue;
|
||||
for( byte x = 0; x < kMatrixWidth; x++) {
|
||||
pixelHue += xHueDelta8;
|
||||
leds[ XY(x, y)] = CHSV( pixelHue, 255, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalSMD5050);
|
||||
FastLED.setBrightness( BRIGHTNESS );
|
||||
}
|
40
libraries/FastLED/extras/AppleII.s65
Normal file
40
libraries/FastLED/extras/AppleII.s65
Normal file
@ -0,0 +1,40 @@
|
||||
KBD = $C000 ;Read keydown
|
||||
KBDSTRB = $C010 ;Reset keybd
|
||||
|
||||
SPKR = $C030 ;Toggle speaker
|
||||
|
||||
; TTL digital output pins on
|
||||
; 16-pin DIP game connector
|
||||
SETAN0 = $C058
|
||||
CLRAN0 = $C059
|
||||
SETAN1 = $C05A
|
||||
CLRAN1 = $C05B
|
||||
SETAN2 = $C05C
|
||||
CLRAN2 = $C05D
|
||||
SETAN3 = $C05E
|
||||
CLRAN3 = $C05F
|
||||
|
||||
PIN12ON = CLRAN3
|
||||
PIN12OFF= SETAN3
|
||||
PIN13ON = CLRAN2
|
||||
PIN13OFF= SETAN2
|
||||
PIN14ON = CLRAN1
|
||||
PIN14OFF= SETAN1
|
||||
PIN15ON = CLRAN0
|
||||
PIN15OFF= SETAN0
|
||||
|
||||
;Special for pin 5, except on //gs
|
||||
C040STROBE = $C040
|
||||
PIN5STROBE = C040STROBE
|
||||
|
||||
SolidApple = $C062 ; read SW1 or SA
|
||||
OpenApple = $C061 ; read SW0 or OA
|
||||
|
||||
VBL = $C019 ; vertical blanking
|
||||
|
||||
WAIT = $FCA8 ; wait a little while
|
||||
|
||||
CROUT = $FD8E ; print a CR
|
||||
PRBYTE = $FDDA ; print a hex byte
|
||||
|
||||
|
633
libraries/FastLED/extras/FastLED6502.s65
Normal file
633
libraries/FastLED/extras/FastLED6502.s65
Normal file
@ -0,0 +1,633 @@
|
||||
/////////////////////////////////
|
||||
//
|
||||
// FastLED6502
|
||||
// by Mark Kriegsman
|
||||
//
|
||||
// Device driver and animation
|
||||
// library for connecting addressable
|
||||
// LED strips to an Apple II.
|
||||
// The full "FastLED" library is
|
||||
// available for Arduino and related
|
||||
// microcontrollers.
|
||||
//
|
||||
/////////////////////////////////
|
||||
//
|
||||
// HOST COMPATIBILITY:
|
||||
// Apples with 16-pin DIP "game ports"
|
||||
// are fully supported; Apples with only
|
||||
// 9-pin "game ports" are NOT supported.
|
||||
//
|
||||
// Apple ][ fully supported
|
||||
// Apple ][+ fully supported
|
||||
// Apple //e fully supported
|
||||
//
|
||||
// Apple //c and //c+ NOT supported
|
||||
// as they lack the required 16-pin
|
||||
// DIP game port for digital I/O.
|
||||
//
|
||||
// Apple //gs:
|
||||
// motherboard game port IS supported
|
||||
// back panel connector NOT supported
|
||||
// See Notes section below.
|
||||
//
|
||||
// C64, PET, VIC-20, Atari400/800,
|
||||
// NES, SYM, KIM-1, and other 6502
|
||||
// systems are NOT supported at this
|
||||
// time, but porting should be
|
||||
// relatively easy for someone familiar
|
||||
// with each target platform.
|
||||
//
|
||||
//
|
||||
// LED STRIP COMPATIBILITY:
|
||||
// In general, "four-wire" (clocked)
|
||||
// LED strips can be supported, but
|
||||
// "three-wire" (clockless) LED strips
|
||||
// cannot be supported.
|
||||
//
|
||||
// APA102 tested & working
|
||||
// Adafruit DotStar tested & working
|
||||
// LPD8806 should work (untested)
|
||||
// WS2801 should work (untested)
|
||||
//
|
||||
// WS2811/WS2812/NeoPixel can NOT work
|
||||
// due to timing incompatibilities,
|
||||
// namely that the 1MHz Apple is far
|
||||
// too slow to drive them correctly.
|
||||
//
|
||||
//
|
||||
// USAGE - HARDWARE:
|
||||
// Connect an external power source to
|
||||
// +5 and GND on the LED strip.
|
||||
// Connect GND on the LED strip to GND
|
||||
// on the game port connector (pin 8)
|
||||
// Connect DATA IN on the LED strip to
|
||||
// pin 12, 13, or 14 on the game port.
|
||||
// Connect CLOCK IN on the LED strip to
|
||||
// pin 5 (preferred), 12, 13, or 14 on
|
||||
// the game port. Note: Apple //gs users
|
||||
// cannot use pin 5.
|
||||
//
|
||||
//
|
||||
// USAGE - SOFTWARE:
|
||||
// At build time provide definitions for
|
||||
// CHIPSET, DATA_PIN, CLOCK_PIN,
|
||||
// NUM_LEDS, & BRIGHTNESS.
|
||||
// Inside "Setup":
|
||||
// Store LED count into
|
||||
// FastLED_NumPixels,
|
||||
// Store brightness into
|
||||
// FastLED_Brightness
|
||||
// Inside "Loop":
|
||||
// Update the leds array, found in
|
||||
// ledsR, ledsG, and ledsB
|
||||
// Call FastLED_Show
|
||||
// Jump back to top of "Loop"
|
||||
//
|
||||
//
|
||||
// REFERENCE:
|
||||
// FastLED_Show:
|
||||
// display led array on LED strip
|
||||
// FastLED_FillBlack:
|
||||
// fill led array to black
|
||||
// FastLED_FillSolid_RGB_AXY:
|
||||
// fill led array with RGB color
|
||||
// FastLED_FillSolid_Hue_X:
|
||||
// fill led array with solid HSV Hue
|
||||
// FastLED_Random8:
|
||||
// return a pseudorandom number in A
|
||||
// FastLED_FillRainbow_XY:
|
||||
// fill led array with HSV rainbow
|
||||
// starting at hue X, incrementing by
|
||||
// huedelta Y each pixel.
|
||||
// FastLED_SetHue_XY:
|
||||
// set pixel Y to HSV hue X
|
||||
// FastLED_Beat8:
|
||||
// takes a speed increment in A, and
|
||||
// returns a triangle wave in A.
|
||||
//
|
||||
//
|
||||
// NOTES:
|
||||
// For speed and size, there IS some
|
||||
// self-modifying code in this
|
||||
// library, so it cannot be burned
|
||||
// into ROM without modification.
|
||||
// Brightness control only works on
|
||||
// APA102 at this point.
|
||||
// Pin 15 is currently used as a
|
||||
// 'frame start' signal for protocol
|
||||
// diagnostics - makes frames more
|
||||
// visible with an oscilloscope.
|
||||
// If Pin 5 is specified for the CLOCK
|
||||
// output pin, FastLED6502 will
|
||||
// automatically use the high speed
|
||||
// C040STROBE signal for clock. Note
|
||||
// that the Apple //gs lacks this
|
||||
// signal, even on the motherboard
|
||||
// game port.
|
||||
// The Apple joystick/mouse port on the
|
||||
// rear of the //c, //c+, and //gs
|
||||
// can NOT be used for LED connections
|
||||
// because it lacks the necessary
|
||||
// digital output pins.
|
||||
// This library can drive 100 LED pixels
|
||||
// at more than 30 frames per second.
|
||||
//
|
||||
//
|
||||
// VERSION HISTORY
|
||||
// 2015-02-07 - first version, by MEK
|
||||
// assembled with xa65
|
||||
// www.floodgap.com/retrotech/xa/
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
//
|
||||
// ENTRY POINT
|
||||
//
|
||||
|
||||
FastLED_Entry
|
||||
jsr FastLED_FillBlack
|
||||
jmp Setup
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
//
|
||||
// FASTLED6502 GLOBALS
|
||||
//
|
||||
|
||||
FastLED_NumPixels .byt NUM_LEDS
|
||||
FastLED_Brightness .byt BRIGHTNESS
|
||||
|
||||
FastLED_RandomState .byt 17
|
||||
FastLED_BeatState .byt 0
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
//
|
||||
// API FUNCTIONS
|
||||
//
|
||||
|
||||
FastLED_FillBlack
|
||||
lda FastLED_NumPixels
|
||||
pha
|
||||
lda #255
|
||||
sta FastLED_NumPixels
|
||||
lda #0
|
||||
tax
|
||||
tay
|
||||
jsr FastLED_FillSolid_RGB_AXY
|
||||
jsr FastLED_Show
|
||||
pla
|
||||
sta FastLED_NumPixels
|
||||
rts
|
||||
|
||||
|
||||
FastLED_FillRainbow_XY
|
||||
sty rbHueDelta
|
||||
ldy #0
|
||||
FR1
|
||||
lda FastLED_RainbowR,x
|
||||
sta ledsR,y
|
||||
lda FastLED_RainbowG,x
|
||||
sta ledsG,y
|
||||
lda FastLED_RainbowB,x
|
||||
sta ledsB,y
|
||||
|
||||
txa
|
||||
clc
|
||||
adc rbHueDelta
|
||||
tax
|
||||
|
||||
iny
|
||||
cpy FastLED_NumPixels
|
||||
bne FR1
|
||||
rts
|
||||
|
||||
rbHueDelta .byt 0
|
||||
|
||||
|
||||
FastLED_SetHue_XY
|
||||
lda FastLED_RainbowR,x
|
||||
sta ledsR,y
|
||||
lda FastLED_RainbowG,x
|
||||
sta ledsG,y
|
||||
lda FastLED_RainbowB,x
|
||||
sta ledsB,y
|
||||
rts
|
||||
|
||||
|
||||
FastLED_FillSolid_RGB_AXY
|
||||
sta ledsR
|
||||
stx ledsG
|
||||
sty ledsB
|
||||
ldy #0
|
||||
FillSolidRGBAXY1
|
||||
lda ledsR
|
||||
sta ledsR,y
|
||||
lda ledsG
|
||||
sta ledsG,y
|
||||
lda ledsB
|
||||
sta ledsB,y
|
||||
iny
|
||||
cpy FastLED_NumPixels
|
||||
bne FillSolidRGBAXY1
|
||||
rts
|
||||
|
||||
FastLED_FillSolid_Hue_X
|
||||
ldy #0
|
||||
FillSolidHX1
|
||||
lda FastLED_RainbowR,x
|
||||
sta ledsR,y
|
||||
lda FastLED_RainbowG,x
|
||||
sta ledsG,y
|
||||
lda FastLED_RainbowB,x
|
||||
sta ledsB,y
|
||||
iny
|
||||
cpy FastLED_NumPixels
|
||||
bne FillSolidHX1
|
||||
rts
|
||||
|
||||
|
||||
; NOTE: USES SELF-MODIFYING CODE
|
||||
FastLED_Random8
|
||||
inc Random8GetLo
|
||||
bne Random8Get
|
||||
inc Random8GetHi
|
||||
bne Random8Get
|
||||
lda #$F8
|
||||
sta Random8GetHi
|
||||
lda #03
|
||||
sta Random8GetLo
|
||||
Random8Get
|
||||
Random8GetLo = Random8Get + 1
|
||||
Random8GetHi = Random8Get + 2
|
||||
lda $F803
|
||||
adc FastLED_RandomState
|
||||
sta FastLED_RandomState
|
||||
rts
|
||||
|
||||
|
||||
FastLED_Beat8
|
||||
clc
|
||||
adc FastLED_BeatState
|
||||
sta FastLED_BeatState
|
||||
bit FastLED_BeatState
|
||||
bmi FastLED_Beat8Neg
|
||||
asl
|
||||
rts
|
||||
FastLED_Beat8Neg
|
||||
lda #$ff
|
||||
sec
|
||||
sbc FastLED_BeatState
|
||||
sbc FastLED_BeatState
|
||||
rts
|
||||
|
||||
|
||||
FastLED_Show
|
||||
jmp CHIPSET
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
//
|
||||
// HARDWARE INTERFACING
|
||||
//
|
||||
|
||||
PINOFF_BASE = PIN15OFF
|
||||
PINON_BASE = PIN15ON
|
||||
|
||||
#define PINON(P) PINON_BASE+((15-P)*2)
|
||||
#define PINOFF(P) PINOFF_BASE+((15-P)*2)
|
||||
|
||||
DATAOFF = PINOFF(DATA_PIN)
|
||||
DATAON = PINON(DATA_PIN)
|
||||
CLKOFF = PINOFF(CLOCK_PIN)
|
||||
CLKON = PINON(CLOCK_PIN)
|
||||
|
||||
// Special handling if CLOCK_PIN
|
||||
// is 5: the C040STROBE line.
|
||||
#if CLOCK_PIN = 5
|
||||
#define CLOCK_ON bit PIN5STROBE
|
||||
#define CLOCK_OFF
|
||||
#else
|
||||
#define CLOCK_ON bit CLKON
|
||||
#define CLOCK_OFF bit CLKOFF
|
||||
#endif
|
||||
|
||||
FRAMEON = PINON(15)
|
||||
FRAMEOFF = PINOFF(15)
|
||||
|
||||
/////////////////////////////////
|
||||
APA102
|
||||
bit FRAMEON
|
||||
jsr FastLED_Send00
|
||||
jsr FastLED_Send00
|
||||
jsr FastLED_Send00
|
||||
jsr FastLED_Send00
|
||||
|
||||
lda FastLED_Brightness
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
ora #$E0
|
||||
tax
|
||||
|
||||
ldy FastLED_NumPixels
|
||||
APA102PX
|
||||
txa
|
||||
jsr FastLED_SendA
|
||||
lda ledsB,y
|
||||
jsr FastLED_SendA
|
||||
lda ledsG,y
|
||||
jsr FastLED_SendA
|
||||
lda ledsR,y
|
||||
jsr FastLED_SendA
|
||||
dey
|
||||
bne APA102PX
|
||||
|
||||
lda FastLED_NumPixels
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tay
|
||||
iny
|
||||
APA102CL
|
||||
jsr FastLED_SendFF
|
||||
jsr FastLED_Send00
|
||||
jsr FastLED_Send00
|
||||
jsr FastLED_Send00
|
||||
dey
|
||||
bne APA102CL
|
||||
bit FRAMEOFF
|
||||
rts
|
||||
|
||||
/////////////////////////////////
|
||||
LPD8806
|
||||
bit FRAMEON
|
||||
ldy FastLED_NumPixels
|
||||
LPD8806PX
|
||||
lda ledsG,y
|
||||
lsr
|
||||
ora #$80
|
||||
jsr FastLED_SendA
|
||||
lda ledsR,y
|
||||
lsr
|
||||
ora #$80
|
||||
jsr FastLED_SendA
|
||||
lda ledsB,y
|
||||
lsr
|
||||
ora #$80
|
||||
jsr FastLED_SendA
|
||||
dey
|
||||
bne LPD8806PX
|
||||
|
||||
bit FRAMEOFF
|
||||
rts
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
WS2801
|
||||
bit FRAMEON
|
||||
ldy FastLED_NumPixels
|
||||
WS2801PX
|
||||
lda ledsG,y
|
||||
jsr FastLED_SendA
|
||||
lda ledsR,y
|
||||
jsr FastLED_SendA
|
||||
lda ledsB,y
|
||||
jsr FastLED_SendA
|
||||
dey
|
||||
bne WS2801PX
|
||||
|
||||
bit FRAMEOFF
|
||||
rts
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
FastLED_SendFF
|
||||
bit DATAON
|
||||
jmp FastLED_SendXX
|
||||
;
|
||||
FastLED_Send00
|
||||
bit DATAOFF
|
||||
;
|
||||
FastLED_SendXX
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
rts
|
||||
|
||||
FastLED_SendA
|
||||
cmp #0
|
||||
beq FastLED_Send00
|
||||
cmp #$FF
|
||||
beq FastLED_SendFF
|
||||
|
||||
asl
|
||||
bcc S0x0
|
||||
S0x1 bit DATAON
|
||||
bcs S0xK
|
||||
S0x0 bit DATAOFF
|
||||
S0xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
asl
|
||||
bcc S1x0
|
||||
S1x1 bit DATAON
|
||||
bcs S1xK
|
||||
S1x0 bit DATAOFF
|
||||
S1xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
asl
|
||||
bcc S2x0
|
||||
S2x1 bit DATAON
|
||||
bcs S2xK
|
||||
S2x0 bit DATAOFF
|
||||
S2xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
asl
|
||||
bcc S3x0
|
||||
S3x1 bit DATAON
|
||||
bcs S3xK
|
||||
S3x0 bit DATAOFF
|
||||
S3xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
asl
|
||||
bcc S4x0
|
||||
S4x1 bit DATAON
|
||||
bcs S4xK
|
||||
S4x0 bit DATAOFF
|
||||
S4xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
asl
|
||||
bcc S5x0
|
||||
S5x1 bit DATAON
|
||||
bcs S5xK
|
||||
S5x0 bit DATAOFF
|
||||
S5xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
asl
|
||||
bcc S6x0
|
||||
S6x1 bit DATAON
|
||||
bcs S6xK
|
||||
S6x0 bit DATAOFF
|
||||
S6xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
asl
|
||||
bcc S7x0
|
||||
S7x1 bit DATAON
|
||||
bcs S7xK
|
||||
S7x0 bit DATAOFF
|
||||
S7xK CLOCK_ON
|
||||
CLOCK_OFF
|
||||
|
||||
rts
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
//
|
||||
// Force page allignment for speed
|
||||
// for leds array and Rainbow table
|
||||
//
|
||||
.dsb 256-(* & $FF),0
|
||||
|
||||
|
||||
/////////////////////////////////
|
||||
//
|
||||
// LED ARRAY
|
||||
//
|
||||
|
||||
ledsR .dsb 256,0
|
||||
ledsG .dsb 256,0
|
||||
ledsB .dsb 256,0
|
||||
|
||||
/////////////////////////////////
|
||||
//
|
||||
// HSV RAINBOW DEFINITION
|
||||
//
|
||||
// Generated directly from FastLED.
|
||||
//
|
||||
|
||||
FastLED_RainbowR
|
||||
.byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED
|
||||
.byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8
|
||||
.byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2
|
||||
.byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD
|
||||
.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
|
||||
.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
|
||||
.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
|
||||
.byt $AB,$AB,$AB,$AB,$AB,$AB,$AB,$AB
|
||||
.byt $AB,$A6,$A1,$9C,$96,$91,$8C,$86
|
||||
.byt $81,$7C,$76,$71,$6C,$66,$61,$5C
|
||||
.byt $56,$51,$4C,$47,$41,$3C,$37,$31
|
||||
.byt $2C,$27,$21,$1C,$17,$11,$0C,$07
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$02,$05,$07,$0A,$0D,$0F,$12
|
||||
.byt $15,$17,$1A,$1D,$1F,$22,$25,$27
|
||||
.byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D
|
||||
.byt $3F,$42,$45,$47,$4A,$4D,$4F,$52
|
||||
.byt $55,$57,$5A,$5C,$5F,$62,$64,$67
|
||||
.byt $6A,$6C,$6F,$72,$74,$77,$7A,$7C
|
||||
.byt $7F,$82,$84,$87,$8A,$8C,$8F,$92
|
||||
.byt $94,$97,$9A,$9C,$9F,$A2,$A4,$A7
|
||||
.byt $AB,$AD,$B0,$B2,$B5,$B8,$BA,$BD
|
||||
.byt $C0,$C2,$C5,$C8,$CA,$CD,$D0,$D2
|
||||
.byt $D5,$D8,$DA,$DD,$E0,$E2,$E5,$E8
|
||||
.byt $EA,$ED,$F0,$F2,$F5,$F8,$FA,$FD
|
||||
FastLED_RainbowG
|
||||
.byt $00,$02,$05,$07,$0A,$0D,$0F,$12
|
||||
.byt $15,$17,$1A,$1D,$1F,$22,$25,$27
|
||||
.byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D
|
||||
.byt $3F,$42,$45,$47,$4A,$4D,$4F,$52
|
||||
.byt $55,$57,$5A,$5C,$5F,$62,$64,$67
|
||||
.byt $6A,$6C,$6F,$72,$74,$77,$7A,$7C
|
||||
.byt $7F,$82,$84,$87,$8A,$8C,$8F,$92
|
||||
.byt $94,$97,$9A,$9C,$9F,$A2,$A4,$A7
|
||||
.byt $AB,$AD,$B0,$B2,$B5,$B8,$BA,$BD
|
||||
.byt $C0,$C2,$C5,$C8,$CA,$CD,$D0,$D2
|
||||
.byt $D5,$D8,$DA,$DD,$E0,$E2,$E5,$E8
|
||||
.byt $EA,$ED,$F0,$F2,$F5,$F8,$FA,$FD
|
||||
.byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED
|
||||
.byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8
|
||||
.byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2
|
||||
.byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD
|
||||
.byt $AB,$A6,$A1,$9C,$96,$91,$8C,$86
|
||||
.byt $81,$7C,$76,$71,$6C,$66,$61,$5C
|
||||
.byt $56,$51,$4C,$47,$41,$3C,$37,$31
|
||||
.byt $2C,$27,$21,$1C,$17,$11,$0C,$07
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
FastLED_RainbowB
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.byt $00,$02,$05,$07,$0A,$0D,$0F,$12
|
||||
.byt $15,$17,$1A,$1D,$1F,$22,$25,$27
|
||||
.byt $2A,$2D,$2F,$32,$35,$37,$3A,$3D
|
||||
.byt $3F,$42,$45,$47,$4A,$4D,$4F,$52
|
||||
.byt $55,$5A,$5F,$64,$6A,$6F,$74,$7A
|
||||
.byt $7F,$84,$8A,$8F,$94,$9A,$9F,$A4
|
||||
.byt $AA,$AF,$B4,$B9,$BF,$C4,$C9,$CF
|
||||
.byt $D4,$D9,$DF,$E4,$E9,$EF,$F4,$F9
|
||||
.byt $FF,$FD,$FA,$F8,$F5,$F2,$F0,$ED
|
||||
.byt $EA,$E8,$E5,$E2,$E0,$DD,$DA,$D8
|
||||
.byt $D5,$D2,$D0,$CD,$CA,$C8,$C5,$C2
|
||||
.byt $C0,$BD,$BA,$B8,$B5,$B2,$B0,$AD
|
||||
.byt $AB,$A9,$A6,$A4,$A1,$9E,$9C,$99
|
||||
.byt $96,$94,$91,$8E,$8C,$89,$86,$84
|
||||
.byt $81,$7E,$7C,$79,$76,$74,$71,$6E
|
||||
.byt $6C,$69,$66,$64,$61,$5E,$5C,$59
|
||||
.byt $55,$53,$50,$4E,$4B,$48,$46,$43
|
||||
.byt $40,$3E,$3B,$38,$36,$33,$30,$2E
|
||||
.byt $2B,$28,$26,$23,$20,$1E,$1B,$18
|
||||
.byt $16,$13,$10,$0E,$0B,$08,$06,$03
|
BIN
libraries/FastLED/extras/RainbowDemo.bin.zip
Normal file
BIN
libraries/FastLED/extras/RainbowDemo.bin.zip
Normal file
Binary file not shown.
89
libraries/FastLED/extras/RainbowDemo.s65
Normal file
89
libraries/FastLED/extras/RainbowDemo.s65
Normal file
@ -0,0 +1,89 @@
|
||||
; "Rainbow with glitter" demo
|
||||
; for "FastLED6502"
|
||||
;
|
||||
; Runs on an Apple ][, ][+, //e, or //gs
|
||||
;
|
||||
; Supports APA102, Adafruit DotStar,
|
||||
; LPD8806, and WS2801 LED strips.
|
||||
;
|
||||
; LED strip connects to game port pins,
|
||||
; see FastLED6502.s65 for details.
|
||||
;
|
||||
; Mark Kriegsman, February 2015
|
||||
|
||||
#define NUM_LEDS 100
|
||||
#define BRIGHTNESS 64
|
||||
#define CHIPSET APA102
|
||||
#define DATA_PIN 14
|
||||
#define CLOCK_PIN 5
|
||||
|
||||
* = $6000
|
||||
|
||||
#include "FastLED6502.s65"
|
||||
#include "AppleII.s65"
|
||||
|
||||
gHue .byt 0
|
||||
gHueDelta .byt 17
|
||||
gHueSpeed .byt 7
|
||||
|
||||
|
||||
Setup
|
||||
lda #0
|
||||
sta gHue
|
||||
|
||||
Loop
|
||||
lda gHue
|
||||
clc
|
||||
adc gHueSpeed
|
||||
sta gHue
|
||||
ldx gHue
|
||||
ldy gHueDelta
|
||||
; Fill RGB array with HSV rainbow
|
||||
jsr FastLED_FillRainbow_XY
|
||||
; Use master brightness control
|
||||
lda #BRIGHTNESS
|
||||
sta FastLED_Brightness
|
||||
CheckOpenApple
|
||||
bit OpenApple
|
||||
bpl CheckSolidApple
|
||||
; Add glitter if requested
|
||||
jsr AddGlitter
|
||||
CheckSolidApple
|
||||
bit SolidApple
|
||||
bpl DoDisplay
|
||||
; Pulse brightness if requested
|
||||
jsr PulseBrightness
|
||||
DoDisplay
|
||||
; This is where the magic happens
|
||||
jsr FastLED_Show
|
||||
jmp Loop
|
||||
|
||||
|
||||
AddGlitter
|
||||
ldy #3
|
||||
MaybeAdd1Glitter
|
||||
jsr FastLED_Random8
|
||||
cmp FastLED_NumPixels
|
||||
bcs SkipThis1Glitter
|
||||
tax
|
||||
lda #$FF
|
||||
sta ledsR,x
|
||||
sta ledsG,x
|
||||
sta ledsB,x
|
||||
SkipThis1Glitter
|
||||
dey
|
||||
bne MaybeAdd1Glitter
|
||||
rts
|
||||
|
||||
|
||||
PulseBrightness
|
||||
lda #13
|
||||
jsr FastLED_Beat8
|
||||
clc
|
||||
adc #12
|
||||
bcc PulseBright1
|
||||
lda #$FF
|
||||
PulseBright1
|
||||
sta FastLED_Brightness
|
||||
rts
|
||||
|
69
libraries/FastLED/fastled_config.h
Normal file
69
libraries/FastLED/fastled_config.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef __INC_FASTLED_CONFIG_H
|
||||
#define __INC_FASTLED_CONFIG_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
///@file fastled_config.h
|
||||
/// contains definitions that can be used to configure FastLED at compile time
|
||||
|
||||
// Use this option only for debugging pin access and forcing software pin access. Note that
|
||||
// software pin access only works in Arduino based environments. Forces use of digitalWrite
|
||||
// methods for pin access vs. direct hardware port access
|
||||
// #define FASTLED_FORCE_SOFTWARE_PINS
|
||||
|
||||
// Use this option only for debugging bitbang'd spi access or to work around bugs in hardware
|
||||
// spi access. Forces use of bit-banged spi, even on pins that has hardware SPI available.
|
||||
// #define FASTLED_FORCE_SOFTWARE_SPI
|
||||
|
||||
// Use this to force FastLED to allow interrupts in the clockless chipsets (or to force it to
|
||||
// disallow), overriding the default on platforms that support this. Set the value to 1 to
|
||||
// allow interrupts or 0 to disallow them.
|
||||
// #define FASTLED_ALLOW_INTERRUPTS 1
|
||||
// #define FASTLED_ALLOW_INTERRUPTS 0
|
||||
|
||||
// Use this to allow some integer overflows/underflows in the inoise functions.
|
||||
// The original implementions allowed this, and had some discontinuties in the noise
|
||||
// output. It's technically an implementation bug, and was fixed, but you may wish
|
||||
// to preserve the old look and feel of the inoise functions in your existing animations.
|
||||
// The default is 0: NO overflow, and 'continuous' noise output, aka the fixed way.
|
||||
// #define FASTLED_NOISE_ALLOW_AVERAGE_TO_OVERFLOW 0
|
||||
// #define FASTLED_NOISE_ALLOW_AVERAGE_TO_OVERFLOW 1
|
||||
|
||||
// Use this toggle whether or not to use the 'fixed' FastLED scale8. The initial scale8
|
||||
// had a problem where scale8(255,255) would give you 254. This is now fixed, and that
|
||||
// fix is enabled by default. However, if for some reason you have code that is not
|
||||
// working right as a result of this (e.g. code that was expecting the old scale8 behavior)
|
||||
// you can disable it here.
|
||||
#define FASTLED_SCALE8_FIXED 1
|
||||
// #define FASTLED_SCALE8_FIXED 0
|
||||
|
||||
// Use this toggle whether to use 'fixed' FastLED pixel blending, including ColorFromPalette.
|
||||
// The prior pixel blend functions had integer-rounding math errors that led to
|
||||
// small errors being inadvertently added to the low bits of blended colors, including colors
|
||||
// retrieved from color palettes using LINEAR_BLEND. This is now fixed, and the
|
||||
// fix is enabled by default. However, if for some reason you wish to run with the old
|
||||
// blending, including the integer rounding and color errors, you can disable the bugfix here.
|
||||
#define FASTLED_BLEND_FIXED 1
|
||||
// #define FASTLED_BLEND_FIXED 0
|
||||
|
||||
// Use this toggle whether to use 'fixed' FastLED 8- and 16-bit noise functions.
|
||||
// The prior noise functions had some math errors that led to 'discontinuities' in the
|
||||
// output, which by definition should be smooth and continuous. The bug led to
|
||||
// noise function output that had 'edges' and glitches in it. This is now fixed, and the
|
||||
// fix is enabled by default. However, if for some reason you wish to run with the old
|
||||
// noise code, including the glitches, you can disable the bugfix here.
|
||||
#define FASTLED_NOISE_FIXED 1
|
||||
//#define FASTLED_NOISE_FIXED 0
|
||||
|
||||
// Use this to determine how many times FastLED will attempt to re-transmit a frame if interrupted
|
||||
// for too long by interrupts.
|
||||
#ifndef FASTLED_INTERRUPT_RETRY_COUNT
|
||||
#define FASTLED_INTERRUPT_RETRY_COUNT 2
|
||||
#endif
|
||||
|
||||
// Use this toggle to enable global brightness in contollers that support is (ADA102 and SK9822).
|
||||
// It changes how color scaling works and uses global brightness before scaling down color values.
|
||||
// This enable much more accurate color control on low brightness settings.
|
||||
//#define FASTLED_USE_GLOBAL_BRIGHTNESS 1
|
||||
|
||||
#endif
|
139
libraries/FastLED/fastled_delay.h
Normal file
139
libraries/FastLED/fastled_delay.h
Normal file
@ -0,0 +1,139 @@
|
||||
#ifndef __INC_FL_DELAY_H
|
||||
#define __INC_FL_DELAY_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
///@file fastled_delay.h
|
||||
///Utility functions and classes for managing delaycycles
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
/// 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
|
||||
/// this should make sure that chipsets that have
|
||||
template<int WAIT> class CMinWait {
|
||||
uint16_t mLastMicros;
|
||||
public:
|
||||
CMinWait() { mLastMicros = 0; }
|
||||
|
||||
void wait() {
|
||||
uint16_t diff;
|
||||
do {
|
||||
diff = (micros() & 0xFFFF) - mLastMicros;
|
||||
} while(diff < WAIT);
|
||||
}
|
||||
|
||||
void mark() { mLastMicros = micros() & 0xFFFF; }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Clock cycle counted delay loop
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Default is now just 'nop', with special case for AVR
|
||||
|
||||
// ESP32 core has it's own definition of NOP, so undef it first
|
||||
#ifdef ESP32
|
||||
#undef NOP
|
||||
#undef NOP2
|
||||
#endif
|
||||
|
||||
#if defined(__AVR__)
|
||||
# define FL_NOP __asm__ __volatile__ ("cp r0,r0\n");
|
||||
# define FL_NOP2 __asm__ __volatile__ ("rjmp .+0");
|
||||
#else
|
||||
# define FL_NOP __asm__ __volatile__ ("nop\n");
|
||||
# define FL_NOP2 __asm__ __volatile__ ("nop\n\t nop\n");
|
||||
#endif
|
||||
|
||||
// predeclaration to not upset the compiler
|
||||
template<int CYCLES> inline void delaycycles();
|
||||
template<int CYCLES> inline void delaycycles_min1() {
|
||||
delaycycles<1>();
|
||||
delaycycles<CYCLES-1>();
|
||||
}
|
||||
|
||||
|
||||
// TODO: ARM version of _delaycycles_
|
||||
|
||||
// usable definition
|
||||
#if defined(FASTLED_AVR)
|
||||
// worker template - this will nop for LOOP * 3 + PAD cycles total
|
||||
template<int LOOP, int PAD> inline void _delaycycles_AVR() {
|
||||
delaycycles<PAD>();
|
||||
// the loop below is 3 cycles * LOOP. the LDI is one cycle,
|
||||
// the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
|
||||
// 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
|
||||
__asm__ __volatile__ (
|
||||
" LDI R16, %0\n"
|
||||
"L_%=: DEC R16\n"
|
||||
" BRNE L_%=\n"
|
||||
: /* no outputs */
|
||||
: "M" (LOOP)
|
||||
: "r16"
|
||||
);
|
||||
}
|
||||
|
||||
template<int CYCLES> __attribute__((always_inline)) inline void delaycycles() {
|
||||
_delaycycles_AVR<CYCLES / 3, CYCLES % 3>();
|
||||
}
|
||||
#else
|
||||
// template<int LOOP, int PAD> inline void _delaycycles_ARM() {
|
||||
// delaycycles<PAD>();
|
||||
// // the loop below is 3 cycles * LOOP. the LDI is one cycle,
|
||||
// // the DEC is 1 cycle, the BRNE is 2 cycles if looping back and
|
||||
// // 1 if not (the LDI balances out the BRNE being 1 cycle on exit)
|
||||
// __asm__ __volatile__ (
|
||||
// " mov.w r9, %0\n"
|
||||
// "L_%=: subs.w r9, r9, #1\n"
|
||||
// " bne.n L_%=\n"
|
||||
// : /* no outputs */
|
||||
// : "M" (LOOP)
|
||||
// : "r9"
|
||||
// );
|
||||
// }
|
||||
|
||||
|
||||
template<int CYCLES> __attribute__((always_inline)) inline void delaycycles() {
|
||||
// _delaycycles_ARM<CYCLES / 3, CYCLES % 3>();
|
||||
FL_NOP; delaycycles<CYCLES-1>();
|
||||
}
|
||||
#endif
|
||||
|
||||
// pre-instantiations for values small enough to not need the loop, as well as sanity holders
|
||||
// for some negative values.
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-10>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-9>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-8>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-7>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-6>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-5>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-4>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-3>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-2>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<-1>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<0>() {}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<1>() {FL_NOP;}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<2>() {FL_NOP2;}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<3>() {FL_NOP;FL_NOP2;}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<4>() {FL_NOP2;FL_NOP2;}
|
||||
template<> __attribute__((always_inline)) inline void delaycycles<5>() {FL_NOP2;FL_NOP2;FL_NOP;}
|
||||
|
||||
// Some timing related macros/definitions
|
||||
|
||||
// Macro to convert from nano-seconds to clocks and clocks to nano-seconds
|
||||
// #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L)))
|
||||
#define F_CPU_MHZ (F_CPU / 1000000L)
|
||||
|
||||
// #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000
|
||||
#define NS(_NS) (((_NS * F_CPU_MHZ) + 999) / 1000)
|
||||
#define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L)
|
||||
|
||||
// Macro for making sure there's enough time available
|
||||
#define NO_TIME(A, B, C) (NS(A) < 3 || NS(B) < 3 || NS(C) < 6)
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
81
libraries/FastLED/fastled_progmem.h
Normal file
81
libraries/FastLED/fastled_progmem.h
Normal file
@ -0,0 +1,81 @@
|
||||
#ifndef __INC_FL_PROGMEM_H
|
||||
#define __INC_FL_PROGMEM_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
///@file fastled_progmem.h
|
||||
/// wrapper definitions to allow seamless use of PROGMEM in environmens that have it
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
// Compatibility layer for devices that do or don't
|
||||
// have "PROGMEM" and the associated pgm_ accessors.
|
||||
//
|
||||
// If a platform supports PROGMEM, it should define
|
||||
// "FASTLED_USE_PROGMEM" as 1, otherwise FastLED will
|
||||
// fall back to NOT using PROGMEM.
|
||||
//
|
||||
// Whether or not pgmspace.h is #included is separately
|
||||
// controllable by FASTLED_INCLUDE_PGMSPACE, if needed.
|
||||
|
||||
|
||||
// If FASTLED_USE_PROGMEM is 1, we'll map FL_PROGMEM
|
||||
// and the FL_PGM_* accessors to the Arduino equivalents.
|
||||
#if FASTLED_USE_PROGMEM == 1
|
||||
#ifndef FASTLED_INCLUDE_PGMSPACE
|
||||
#define FASTLED_INCLUDE_PGMSPACE 1
|
||||
#endif
|
||||
|
||||
#if FASTLED_INCLUDE_PGMSPACE == 1
|
||||
#include <avr/pgmspace.h>
|
||||
#endif
|
||||
|
||||
#define FL_PROGMEM PROGMEM
|
||||
|
||||
// Note: only the 'near' memory wrappers are provided.
|
||||
// If you're using 'far' memory, you already have
|
||||
// portability issues to work through, but you could
|
||||
// add more support here if needed.
|
||||
#define FL_PGM_READ_BYTE_NEAR(x) (pgm_read_byte_near(x))
|
||||
#define FL_PGM_READ_WORD_NEAR(x) (pgm_read_word_near(x))
|
||||
#define FL_PGM_READ_DWORD_NEAR(x) (pgm_read_dword_near(x))
|
||||
|
||||
// Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6))
|
||||
#ifdef FASTLED_AVR
|
||||
#ifdef PROGMEM
|
||||
#undef PROGMEM
|
||||
#define PROGMEM __attribute__((section(".progmem.data")))
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
// If FASTLED_USE_PROGMEM is 0 or undefined,
|
||||
// we'll use regular memory (RAM) access.
|
||||
|
||||
//empty PROGMEM simulation
|
||||
#define FL_PROGMEM
|
||||
#define FL_PGM_READ_BYTE_NEAR(x) (*((const uint8_t*)(x)))
|
||||
#define FL_PGM_READ_WORD_NEAR(x) (*((const uint16_t*)(x)))
|
||||
#define FL_PGM_READ_DWORD_NEAR(x) (*((const uint32_t*)(x)))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// On some platforms, most notably ARM M0, unaligned access
|
||||
// to 'PROGMEM' for multibyte values (eg read dword) is
|
||||
// not allowed and causes a crash. This macro can help
|
||||
// force 4-byte alignment as needed. The FastLED gradient
|
||||
// palette code uses 'read dword', and now uses this macro
|
||||
// to make sure that gradient palettes are 4-byte aligned.
|
||||
#if defined(FASTLED_ARM) || defined(ESP32)
|
||||
#define FL_ALIGN_PROGMEM __attribute__ ((aligned (4)))
|
||||
#else
|
||||
#define FL_ALIGN_PROGMEM
|
||||
#endif
|
||||
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
248
libraries/FastLED/fastpin.h
Normal file
248
libraries/FastLED/fastpin.h
Normal file
@ -0,0 +1,248 @@
|
||||
#ifndef __INC_FASTPIN_H
|
||||
#define __INC_FASTPIN_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
#include "led_sysdefs.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wignored-qualifiers"
|
||||
|
||||
///@file fastpin.h
|
||||
/// Class base definitions for defining fast pin access
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
#define NO_PIN 255
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Pin access class - needs to tune for various platforms (naive fallback solution?)
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class Selectable {
|
||||
public:
|
||||
virtual void select() = 0;
|
||||
virtual void release() = 0;
|
||||
virtual bool isSelected() = 0;
|
||||
};
|
||||
|
||||
#if !defined(FASTLED_NO_PINMAP)
|
||||
|
||||
class Pin : public Selectable {
|
||||
volatile RwReg *mPort;
|
||||
volatile RoReg *mInPort;
|
||||
RwReg mPinMask;
|
||||
uint8_t mPin;
|
||||
|
||||
void _init() {
|
||||
mPinMask = digitalPinToBitMask(mPin);
|
||||
mPort = (volatile RwReg*)portOutputRegister(digitalPinToPort(mPin));
|
||||
mInPort = (volatile RoReg*)portInputRegister(digitalPinToPort(mPin));
|
||||
}
|
||||
public:
|
||||
Pin(int pin) : mPin(pin) { _init(); }
|
||||
|
||||
typedef volatile RwReg * port_ptr_t;
|
||||
typedef RwReg port_t;
|
||||
|
||||
inline void setOutput() { pinMode(mPin, OUTPUT); }
|
||||
inline void setInput() { pinMode(mPin, INPUT); }
|
||||
|
||||
inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; }
|
||||
inline void lo() __attribute__ ((always_inline)) { *mPort &= ~mPinMask; }
|
||||
|
||||
inline void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
|
||||
inline void toggle() __attribute__ ((always_inline)) { *mInPort = mPinMask; }
|
||||
|
||||
inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; }
|
||||
inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; }
|
||||
inline void set(register port_t val) __attribute__ ((always_inline)) { *mPort = val; }
|
||||
|
||||
inline void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
|
||||
|
||||
port_t hival() __attribute__ ((always_inline)) { return *mPort | mPinMask; }
|
||||
port_t loval() __attribute__ ((always_inline)) { return *mPort & ~mPinMask; }
|
||||
port_ptr_t port() __attribute__ ((always_inline)) { return mPort; }
|
||||
port_t mask() __attribute__ ((always_inline)) { return mPinMask; }
|
||||
|
||||
virtual void select() { hi(); }
|
||||
virtual void release() { lo(); }
|
||||
virtual bool isSelected() { return (*mPort & mPinMask) == mPinMask; }
|
||||
};
|
||||
|
||||
class OutputPin : public Pin {
|
||||
public:
|
||||
OutputPin(int pin) : Pin(pin) { setOutput(); }
|
||||
};
|
||||
|
||||
class InputPin : public Pin {
|
||||
public:
|
||||
InputPin(int pin) : Pin(pin) { setInput(); }
|
||||
};
|
||||
|
||||
#else
|
||||
// This is the empty code version of the raw pin class, method bodies should be filled in to Do The Right Thing[tm] when making this
|
||||
// available on a new platform
|
||||
class Pin : public Selectable {
|
||||
volatile RwReg *mPort;
|
||||
volatile RoReg *mInPort;
|
||||
RwReg mPinMask;
|
||||
uint8_t mPin;
|
||||
|
||||
void _init() {
|
||||
// TODO: fill in init on a new platform
|
||||
mPinMask = 0;
|
||||
mPort = NULL;
|
||||
mInPort = NULL;
|
||||
}
|
||||
public:
|
||||
Pin(int pin) : mPin(pin) { _init(); }
|
||||
|
||||
void setPin(int pin) { mPin = pin; _init(); }
|
||||
|
||||
typedef volatile RwReg * port_ptr_t;
|
||||
typedef RwReg port_t;
|
||||
|
||||
inline void setOutput() { /* TODO: Set pin output */ }
|
||||
inline void setInput() { /* TODO: Set pin input */ }
|
||||
|
||||
inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; }
|
||||
inline void lo() __attribute__ ((always_inline)) { *mPort &= ~mPinMask; }
|
||||
|
||||
inline void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
|
||||
inline void toggle() __attribute__ ((always_inline)) { *mInPort = mPinMask; }
|
||||
|
||||
inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; }
|
||||
inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; }
|
||||
inline void set(register port_t val) __attribute__ ((always_inline)) { *mPort = val; }
|
||||
|
||||
inline void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
|
||||
|
||||
port_t hival() __attribute__ ((always_inline)) { return *mPort | mPinMask; }
|
||||
port_t loval() __attribute__ ((always_inline)) { return *mPort & ~mPinMask; }
|
||||
port_ptr_t port() __attribute__ ((always_inline)) { return mPort; }
|
||||
port_t mask() __attribute__ ((always_inline)) { return mPinMask; }
|
||||
|
||||
virtual void select() { hi(); }
|
||||
virtual void release() { lo(); }
|
||||
virtual bool isSelected() { return (*mPort & mPinMask) == mPinMask; }
|
||||
};
|
||||
|
||||
class OutputPin : public Pin {
|
||||
public:
|
||||
OutputPin(int pin) : Pin(pin) { setOutput(); }
|
||||
};
|
||||
|
||||
class InputPin : public Pin {
|
||||
public:
|
||||
InputPin(int pin) : Pin(pin) { setInput(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/// The simplest level of Pin class. This relies on runtime functions durinig initialization to get the port/pin mask for the pin. Most
|
||||
/// of the accesses involve references to these static globals that get set up. This won't be the fastest set of pin operations, but it
|
||||
/// will provide pin level access on pretty much all arduino environments. In addition, it includes some methods to help optimize access in
|
||||
/// various ways. Namely, the versions of hi, lo, and fastset that take the port register as a passed in register variable (saving a global
|
||||
/// dereference), since these functions are aggressively inlined, that can help collapse out a lot of extraneous memory loads/dereferences.
|
||||
///
|
||||
/// In addition, if, while writing a bunch of data to a pin, you know no other pins will be getting written to, you can get/cache a value of
|
||||
/// the pin's port register and use that to do a full set to the register. This results in one being able to simply do a store to the register,
|
||||
/// vs. the load, and/or, and store that would be done normally.
|
||||
///
|
||||
/// There are platform specific instantiations of this class that provide direct i/o register access to pins for much higher speed pin twiddling.
|
||||
///
|
||||
/// Note that these classes are all static functions. So the proper usage is Pin<13>::hi(); or such. Instantiating objects is not recommended,
|
||||
/// as passing Pin objects around will likely -not- have the effect you're expecting.
|
||||
#ifdef FASTLED_FORCE_SOFTWARE_PINS
|
||||
template<uint8_t PIN> class FastPin {
|
||||
static RwReg sPinMask;
|
||||
static volatile RwReg *sPort;
|
||||
static volatile RoReg *sInPort;
|
||||
static void _init() {
|
||||
#if !defined(FASTLED_NO_PINMAP)
|
||||
sPinMask = digitalPinToBitMask(PIN);
|
||||
sPort = portOutputRegister(digitalPinToPort(PIN));
|
||||
sInPort = portInputRegister(digitalPinToPort(PIN));
|
||||
#endif
|
||||
}
|
||||
public:
|
||||
typedef volatile RwReg * port_ptr_t;
|
||||
typedef RwReg port_t;
|
||||
|
||||
inline static void setOutput() { _init(); pinMode(PIN, OUTPUT); }
|
||||
inline static void setInput() { _init(); pinMode(PIN, INPUT); }
|
||||
|
||||
inline static void hi() __attribute__ ((always_inline)) { *sPort |= sPinMask; }
|
||||
inline static void lo() __attribute__ ((always_inline)) { *sPort &= ~sPinMask; }
|
||||
|
||||
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
|
||||
|
||||
inline static void toggle() __attribute__ ((always_inline)) { *sInPort = sPinMask; }
|
||||
|
||||
inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= sPinMask; }
|
||||
inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~sPinMask; }
|
||||
inline static void set(register port_t val) __attribute__ ((always_inline)) { *sPort = val; }
|
||||
|
||||
inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
|
||||
|
||||
static port_t hival() __attribute__ ((always_inline)) { return *sPort | sPinMask; }
|
||||
static port_t loval() __attribute__ ((always_inline)) { return *sPort & ~sPinMask; }
|
||||
static port_ptr_t port() __attribute__ ((always_inline)) { return sPort; }
|
||||
static port_t mask() __attribute__ ((always_inline)) { return sPinMask; }
|
||||
};
|
||||
|
||||
template<uint8_t PIN> RwReg FastPin<PIN>::sPinMask;
|
||||
template<uint8_t PIN> volatile RwReg *FastPin<PIN>::sPort;
|
||||
template<uint8_t PIN> volatile RoReg *FastPin<PIN>::sInPort;
|
||||
|
||||
#else
|
||||
|
||||
template<uint8_t PIN> class FastPin {
|
||||
constexpr static bool validpin() { return false; }
|
||||
|
||||
static_assert(validpin(), "Invalid pin specified");
|
||||
|
||||
static void _init() {
|
||||
}
|
||||
public:
|
||||
typedef volatile RwReg * port_ptr_t;
|
||||
typedef RwReg port_t;
|
||||
|
||||
inline static void setOutput() { }
|
||||
inline static void setInput() { }
|
||||
|
||||
inline static void hi() __attribute__ ((always_inline)) { }
|
||||
inline static void lo() __attribute__ ((always_inline)) { }
|
||||
|
||||
inline static void strobe() __attribute__ ((always_inline)) { }
|
||||
|
||||
inline static void toggle() __attribute__ ((always_inline)) { }
|
||||
|
||||
inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { }
|
||||
inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { }
|
||||
inline static void set(register port_t val) __attribute__ ((always_inline)) { }
|
||||
|
||||
inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { }
|
||||
|
||||
static port_t hival() __attribute__ ((always_inline)) { return 0; }
|
||||
static port_t loval() __attribute__ ((always_inline)) { return 0;}
|
||||
static port_ptr_t port() __attribute__ ((always_inline)) { return NULL; }
|
||||
static port_t mask() __attribute__ ((always_inline)) { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template<uint8_t PIN> class FastPinBB : public FastPin<PIN> {};
|
||||
|
||||
typedef volatile uint32_t & reg32_t;
|
||||
typedef volatile uint32_t * ptr_reg32_t;
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#endif // __INC_FASTPIN_H
|
134
libraries/FastLED/fastspi.h
Normal file
134
libraries/FastLED/fastspi.h
Normal file
@ -0,0 +1,134 @@
|
||||
#ifndef __INC_FASTSPI_H
|
||||
#define __INC_FASTSPI_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
#include "controller.h"
|
||||
#include "lib8tion.h"
|
||||
|
||||
#include "fastspi_bitbang.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
#if defined(FASTLED_TEENSY3) && (F_CPU > 48000000)
|
||||
#define DATA_RATE_MHZ(X) (((48000000L / 1000000L) / X))
|
||||
#define DATA_RATE_KHZ(X) (((48000000L / 1000L) / X))
|
||||
#else
|
||||
#define DATA_RATE_MHZ(X) ((F_CPU / 1000000L) / X)
|
||||
#define DATA_RATE_KHZ(X) ((F_CPU / 1000L) / X)
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// External SPI template definition with partial instantiation(s) to map to hardware SPI ports on platforms/builds where the pin
|
||||
// mappings are known at compile time.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(FASTLED_ALL_PINS_HARDWARE_SPI)
|
||||
template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
|
||||
class SPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {};
|
||||
#endif
|
||||
|
||||
template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
|
||||
class SoftwareSPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {};
|
||||
|
||||
#ifndef FASTLED_FORCE_SOFTWARE_SPI
|
||||
|
||||
#if defined(NRF51) && defined(FASTLED_ALL_PINS_HARDWARE_SPI)
|
||||
template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
|
||||
class SPIOutput : public NRF51SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {};
|
||||
#endif
|
||||
|
||||
#if defined(SPI_DATA) && defined(SPI_CLOCK)
|
||||
|
||||
#if defined(FASTLED_TEENSY3) && defined(ARM_HARDWARE_SPI)
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED, 0x4002C000> {};
|
||||
|
||||
#if defined(SPI2_DATA)
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED, 0x4002C000> {};
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI_DATA, SPI2_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI_DATA, SPI2_CLOCK, SPI_SPEED, 0x4002C000> {};
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED, 0x4002C000> {};
|
||||
#endif
|
||||
|
||||
#elif defined(FASTLED_TEENSYLC) && defined(ARM_HARDWARE_SPI)
|
||||
|
||||
#define DECLARE_SPI0(__DATA,__CLOCK) template<uint8_t SPI_SPEED>\
|
||||
class SPIOutput<__DATA, __CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<__DATA, __CLOCK, SPI_SPEED, 0x40076000> {};
|
||||
#define DECLARE_SPI1(__DATA,__CLOCK) template<uint8_t SPI_SPEED>\
|
||||
class SPIOutput<__DATA, __CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<__DATA, __CLOCK, SPI_SPEED, 0x40077000> {};
|
||||
|
||||
DECLARE_SPI0(7,13);
|
||||
DECLARE_SPI0(8,13);
|
||||
DECLARE_SPI0(11,13);
|
||||
DECLARE_SPI0(12,13);
|
||||
DECLARE_SPI0(7,14);
|
||||
DECLARE_SPI0(8,14);
|
||||
DECLARE_SPI0(11,14);
|
||||
DECLARE_SPI0(12,14);
|
||||
DECLARE_SPI1(0,20);
|
||||
DECLARE_SPI1(1,20);
|
||||
DECLARE_SPI1(21,20);
|
||||
|
||||
#elif defined(__SAM3X8E__)
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public SAMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {};
|
||||
|
||||
#elif defined(AVR_HARDWARE_SPI)
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public AVRHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {};
|
||||
|
||||
#if defined(SPI_UART0_DATA)
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> : public AVRUSART0SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> {};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(SPI_UART1_DATA)
|
||||
|
||||
template<uint8_t SPI_SPEED>
|
||||
class SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> : public AVRUSART1SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> {};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
# if !defined(FASTLED_INTERNAL) && !defined(FASTLED_ALL_PINS_HARDWARE_SPI)
|
||||
# ifdef FASTLED_HAS_PRAGMA_MESSAGE
|
||||
# pragma message "No hardware SPI pins defined. All SPI access will default to bitbanged output"
|
||||
# else
|
||||
# warning "No hardware SPI pins defined. All SPI access will default to bitbanged output"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// #if defined(USART_DATA) && defined(USART_CLOCK)
|
||||
// template<uint8_t SPI_SPEED>
|
||||
// class AVRSPIOutput<USART_DATA, USART_CLOCK, SPI_SPEED> : public AVRUSARTSPIOutput<USART_DATA, USART_CLOCK, SPI_SPEED> {};
|
||||
// #endif
|
||||
|
||||
#else
|
||||
# if !defined(FASTLED_INTERNAL) && !defined(FASTLED_ALL_PINS_HARDWARE_SPI)
|
||||
# ifdef FASTLED_HAS_PRAGMA_MESSAGE
|
||||
# pragma message "Forcing software SPI - no hardware SPI for you!"
|
||||
# else
|
||||
# warning "Forcing software SPI - no hardware SPI for you!"
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
374
libraries/FastLED/fastspi_bitbang.h
Normal file
374
libraries/FastLED/fastspi_bitbang.h
Normal file
@ -0,0 +1,374 @@
|
||||
#ifndef __INC_FASTSPI_BITBANG_H
|
||||
#define __INC_FASTSPI_BITBANG_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
#include "fastled_delay.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Software SPI (aka bit-banging) support - with aggressive optimizations for when the clock and data pin are on the same port
|
||||
//
|
||||
// TODO: Replace the select pin definition with a set of pins, to allow using mux hardware for routing in the future
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, uint8_t SPI_SPEED>
|
||||
class AVRSoftwareSPIOutput {
|
||||
// The data types for pointers to the pin port - typedef'd here from the Pin definition because on avr these
|
||||
// are pointers to 8 bit values, while on arm they are 32 bit
|
||||
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
|
||||
typedef typename FastPin<CLOCK_PIN>::port_ptr_t clock_ptr_t;
|
||||
|
||||
// The data type for what's at a pin's port - typedef'd here from the Pin definition because on avr the ports
|
||||
// are 8 bits wide while on arm they are 32.
|
||||
typedef typename FastPin<DATA_PIN>::port_t data_t;
|
||||
typedef typename FastPin<CLOCK_PIN>::port_t clock_t;
|
||||
Selectable *m_pSelect;
|
||||
|
||||
public:
|
||||
AVRSoftwareSPIOutput() { m_pSelect = NULL; }
|
||||
AVRSoftwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
|
||||
void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
|
||||
|
||||
void init() {
|
||||
// set the pins to output and make sure the select is released (which apparently means hi? This is a bit
|
||||
// confusing to me)
|
||||
FastPin<DATA_PIN>::setOutput();
|
||||
FastPin<CLOCK_PIN>::setOutput();
|
||||
release();
|
||||
}
|
||||
|
||||
// stop the SPI output. Pretty much a NOP with software, as there's no registers to kick
|
||||
static void stop() { }
|
||||
|
||||
// wait until the SPI subsystem is ready for more data to write. A NOP when bitbanging
|
||||
static void wait() __attribute__((always_inline)) { }
|
||||
static void waitFully() __attribute__((always_inline)) { wait(); }
|
||||
|
||||
static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { writeByte(b); }
|
||||
static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { writeByte(b); wait(); }
|
||||
|
||||
static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w&0xFF); }
|
||||
|
||||
// naive writeByte implelentation, simply calls writeBit on the 8 bits in the byte.
|
||||
static void writeByte(uint8_t b) {
|
||||
writeBit<7>(b);
|
||||
writeBit<6>(b);
|
||||
writeBit<5>(b);
|
||||
writeBit<4>(b);
|
||||
writeBit<3>(b);
|
||||
writeBit<2>(b);
|
||||
writeBit<1>(b);
|
||||
writeBit<0>(b);
|
||||
}
|
||||
|
||||
private:
|
||||
// writeByte implementation with data/clock registers passed in.
|
||||
static void writeByte(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin) {
|
||||
writeBit<7>(b, clockpin, datapin);
|
||||
writeBit<6>(b, clockpin, datapin);
|
||||
writeBit<5>(b, clockpin, datapin);
|
||||
writeBit<4>(b, clockpin, datapin);
|
||||
writeBit<3>(b, clockpin, datapin);
|
||||
writeBit<2>(b, clockpin, datapin);
|
||||
writeBit<1>(b, clockpin, datapin);
|
||||
writeBit<0>(b, clockpin, datapin);
|
||||
}
|
||||
|
||||
// writeByte implementation with the data register passed in and prebaked values for data hi w/clock hi and
|
||||
// low and data lo w/clock hi and lo. This is to be used when clock and data are on the same GPIO register,
|
||||
// can get close to getting a bit out the door in 2 clock cycles!
|
||||
static void writeByte(uint8_t b, data_ptr_t datapin,
|
||||
data_t hival, data_t loval,
|
||||
clock_t hiclock, clock_t loclock) {
|
||||
writeBit<7>(b, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<6>(b, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<5>(b, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<4>(b, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<3>(b, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<2>(b, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<1>(b, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<0>(b, datapin, hival, loval, hiclock, loclock);
|
||||
}
|
||||
|
||||
// writeByte implementation with not just registers passed in, but pre-baked values for said registers for
|
||||
// data hi/lo and clock hi/lo values. Note: weird things will happen if this method is called in cases where
|
||||
// the data and clock pins are on the same port! Don't do that!
|
||||
static void writeByte(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin,
|
||||
data_t hival, data_t loval,
|
||||
clock_t hiclock, clock_t loclock) {
|
||||
writeBit<7>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<6>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<5>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<4>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<3>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<2>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<1>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
writeBit<0>(b, clockpin, datapin, hival, loval, hiclock, loclock);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// We want to make sure that the clock pulse is held high for a nininum of 35ns.
|
||||
#define MIN_DELAY (NS(35) - 3)
|
||||
|
||||
#define CLOCK_HI_DELAY delaycycles<MIN_DELAY>(); delaycycles<(((SPI_SPEED-6) / 2) - MIN_DELAY)>();
|
||||
#define CLOCK_LO_DELAY delaycycles<(((SPI_SPEED-6) / 4))>();
|
||||
|
||||
// write the BIT'th bit out via spi, setting the data pin then strobing the clcok
|
||||
template <uint8_t BIT> __attribute__((always_inline, hot)) inline static void writeBit(uint8_t b) {
|
||||
//cli();
|
||||
if(b & (1 << BIT)) {
|
||||
FastPin<DATA_PIN>::hi();
|
||||
#ifdef ESP32
|
||||
// try to ensure we never have adjacent write opcodes to the same register
|
||||
FastPin<CLOCK_PIN>::lo();
|
||||
FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
|
||||
FastPin<CLOCK_PIN>::toggle(); CLOCK_LO_DELAY;
|
||||
#else
|
||||
FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
|
||||
FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY;
|
||||
#endif
|
||||
} else {
|
||||
FastPin<DATA_PIN>::lo();
|
||||
FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
|
||||
#ifdef ESP32
|
||||
// try to ensure we never have adjacent write opcodes to the same register
|
||||
FastPin<CLOCK_PIN>::toggle(); CLOCK_HI_DELAY;
|
||||
#else
|
||||
FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY;
|
||||
#endif
|
||||
}
|
||||
//sei();
|
||||
}
|
||||
|
||||
private:
|
||||
// write the BIT'th bit out via spi, setting the data pin then strobing the clock, using the passed in pin registers to accelerate access if needed
|
||||
template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin) {
|
||||
if(b & (1 << BIT)) {
|
||||
FastPin<DATA_PIN>::hi(datapin);
|
||||
FastPin<CLOCK_PIN>::hi(clockpin); CLOCK_HI_DELAY;
|
||||
FastPin<CLOCK_PIN>::lo(clockpin); CLOCK_LO_DELAY;
|
||||
} else {
|
||||
FastPin<DATA_PIN>::lo(datapin);
|
||||
FastPin<CLOCK_PIN>::hi(clockpin); CLOCK_HI_DELAY;
|
||||
FastPin<CLOCK_PIN>::lo(clockpin); CLOCK_LO_DELAY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// the version of write to use when clock and data are on separate pins with precomputed values for setting
|
||||
// the clock and data pins
|
||||
template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, clock_ptr_t clockpin, data_ptr_t datapin,
|
||||
data_t hival, data_t loval, clock_t hiclock, clock_t loclock) {
|
||||
// // only need to explicitly set clock hi if clock and data are on different ports
|
||||
if(b & (1 << BIT)) {
|
||||
FastPin<DATA_PIN>::fastset(datapin, hival);
|
||||
FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); CLOCK_HI_DELAY;
|
||||
FastPin<CLOCK_PIN>::fastset(clockpin, loclock); CLOCK_LO_DELAY;
|
||||
} else {
|
||||
// FL_NOP;
|
||||
FastPin<DATA_PIN>::fastset(datapin, loval);
|
||||
FastPin<CLOCK_PIN>::fastset(clockpin, hiclock); CLOCK_HI_DELAY;
|
||||
FastPin<CLOCK_PIN>::fastset(clockpin, loclock); CLOCK_LO_DELAY;
|
||||
}
|
||||
}
|
||||
|
||||
// the version of write to use when clock and data are on the same port with precomputed values for the various
|
||||
// combinations
|
||||
template <uint8_t BIT> __attribute__((always_inline)) inline static void writeBit(uint8_t b, data_ptr_t clockdatapin,
|
||||
data_t datahiclockhi, data_t dataloclockhi,
|
||||
data_t datahiclocklo, data_t dataloclocklo) {
|
||||
#if 0
|
||||
writeBit<BIT>(b);
|
||||
#else
|
||||
if(b & (1 << BIT)) {
|
||||
FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo);
|
||||
FastPin<DATA_PIN>::fastset(clockdatapin, datahiclockhi); CLOCK_HI_DELAY;
|
||||
FastPin<DATA_PIN>::fastset(clockdatapin, datahiclocklo); CLOCK_LO_DELAY;
|
||||
} else {
|
||||
// FL_NOP;
|
||||
FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo);
|
||||
FastPin<DATA_PIN>::fastset(clockdatapin, dataloclockhi); CLOCK_HI_DELAY;
|
||||
FastPin<DATA_PIN>::fastset(clockdatapin, dataloclocklo); CLOCK_LO_DELAY;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
public:
|
||||
|
||||
// select the SPI output (TODO: research whether this really means hi or lo. Alt TODO: move select responsibility out of the SPI classes
|
||||
// entirely, make it up to the caller to remember to lock/select the line?)
|
||||
void select() { if(m_pSelect != NULL) { m_pSelect->select(); } } // FastPin<SELECT_PIN>::hi(); }
|
||||
|
||||
// release the SPI line
|
||||
void release() { if(m_pSelect != NULL) { m_pSelect->release(); } } // FastPin<SELECT_PIN>::lo(); }
|
||||
|
||||
// Write out len bytes of the given value out over SPI. Useful for quickly flushing, say, a line of 0's down the line.
|
||||
void writeBytesValue(uint8_t value, int len) {
|
||||
select();
|
||||
writeBytesValueRaw(value, len);
|
||||
release();
|
||||
}
|
||||
|
||||
static void writeBytesValueRaw(uint8_t value, int len) {
|
||||
#ifdef FAST_SPI_INTERRUPTS_WRITE_PINS
|
||||
// TODO: Weird things may happen if software bitbanging SPI output and other pins on the output reigsters are being twiddled. Need
|
||||
// to allow specifying whether or not exclusive i/o access is allowed during this process, and if i/o access is not allowed fall
|
||||
// back to the degenerative code below
|
||||
while(len--) {
|
||||
writeByte(value);
|
||||
}
|
||||
#else
|
||||
register data_ptr_t datapin = FastPin<DATA_PIN>::port();
|
||||
|
||||
if(FastPin<DATA_PIN>::port() != FastPin<CLOCK_PIN>::port()) {
|
||||
// If data and clock are on different ports, then writing a bit will consist of writing the value foor
|
||||
// the bit (hi or low) to the data pin port, and then two writes to the clock port to strobe the clock line
|
||||
register clock_ptr_t clockpin = FastPin<CLOCK_PIN>::port();
|
||||
register data_t datahi = FastPin<DATA_PIN>::hival();
|
||||
register data_t datalo = FastPin<DATA_PIN>::loval();
|
||||
register clock_t clockhi = FastPin<CLOCK_PIN>::hival();
|
||||
register clock_t clocklo = FastPin<CLOCK_PIN>::loval();
|
||||
while(len--) {
|
||||
writeByte(value, clockpin, datapin, datahi, datalo, clockhi, clocklo);
|
||||
}
|
||||
|
||||
} else {
|
||||
// If data and clock are on the same port then we can combine setting the data and clock pins
|
||||
register data_t datahi_clockhi = FastPin<DATA_PIN>::hival() | FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datalo_clockhi = FastPin<DATA_PIN>::loval() | FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datahi_clocklo = FastPin<DATA_PIN>::hival() & ~FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datalo_clocklo = FastPin<DATA_PIN>::loval() & ~FastPin<CLOCK_PIN>::mask();
|
||||
|
||||
while(len--) {
|
||||
writeByte(value, datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// write a block of len uint8_ts out. Need to type this better so that explicit casts into the call aren't required.
|
||||
// note that this template version takes a class parameter for a per-byte modifier to the data.
|
||||
template <class D> void writeBytes(register uint8_t *data, int len) {
|
||||
select();
|
||||
#ifdef FAST_SPI_INTERRUPTS_WRITE_PINS
|
||||
uint8_t *end = data + len;
|
||||
while(data != end) {
|
||||
writeByte(D::adjust(*data++));
|
||||
}
|
||||
#else
|
||||
register clock_ptr_t clockpin = FastPin<CLOCK_PIN>::port();
|
||||
register data_ptr_t datapin = FastPin<DATA_PIN>::port();
|
||||
|
||||
if(FastPin<DATA_PIN>::port() != FastPin<CLOCK_PIN>::port()) {
|
||||
// If data and clock are on different ports, then writing a bit will consist of writing the value foor
|
||||
// the bit (hi or low) to the data pin port, and then two writes to the clock port to strobe the clock line
|
||||
register data_t datahi = FastPin<DATA_PIN>::hival();
|
||||
register data_t datalo = FastPin<DATA_PIN>::loval();
|
||||
register clock_t clockhi = FastPin<CLOCK_PIN>::hival();
|
||||
register clock_t clocklo = FastPin<CLOCK_PIN>::loval();
|
||||
uint8_t *end = data + len;
|
||||
|
||||
while(data != end) {
|
||||
writeByte(D::adjust(*data++), clockpin, datapin, datahi, datalo, clockhi, clocklo);
|
||||
}
|
||||
|
||||
} else {
|
||||
// FastPin<CLOCK_PIN>::hi();
|
||||
// If data and clock are on the same port then we can combine setting the data and clock pins
|
||||
register data_t datahi_clockhi = FastPin<DATA_PIN>::hival() | FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datalo_clockhi = FastPin<DATA_PIN>::loval() | FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datahi_clocklo = FastPin<DATA_PIN>::hival() & ~FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datalo_clocklo = FastPin<DATA_PIN>::loval() & ~FastPin<CLOCK_PIN>::mask();
|
||||
|
||||
uint8_t *end = data + len;
|
||||
|
||||
while(data != end) {
|
||||
writeByte(D::adjust(*data++), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
|
||||
}
|
||||
// FastPin<CLOCK_PIN>::lo();
|
||||
}
|
||||
#endif
|
||||
D::postBlock(len);
|
||||
release();
|
||||
}
|
||||
|
||||
// default version of writing a block of data out to the SPI port, with no data modifications being made
|
||||
void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
|
||||
|
||||
|
||||
// write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
|
||||
// parameters indicate how many uint8_ts to skip at the beginning of each grouping, as well as a class specifying a per
|
||||
// byte of data modification to be made. (See DATA_NOP above)
|
||||
template <uint8_t FLAGS, class D, EOrder RGB_ORDER> __attribute__((noinline)) void writePixels(PixelController<RGB_ORDER> pixels) {
|
||||
select();
|
||||
int len = pixels.mLen;
|
||||
|
||||
#ifdef FAST_SPI_INTERRUPTS_WRITE_PINS
|
||||
// If interrupts or other things may be generating output while we're working on things, then we need
|
||||
// to use this block
|
||||
while(pixels.has(1)) {
|
||||
if(FLAGS & FLAG_START_BIT) {
|
||||
writeBit<0>(1);
|
||||
}
|
||||
writeByte(D::adjust(pixels.loadAndScale0()));
|
||||
writeByte(D::adjust(pixels.loadAndScale1()));
|
||||
writeByte(D::adjust(pixels.loadAndScale2()));
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
}
|
||||
#else
|
||||
// If we can guaruntee that no one else will be writing data while we are running (namely, changing the values of the PORT/PDOR pins)
|
||||
// then we can use a bunch of optimizations in here
|
||||
register data_ptr_t datapin = FastPin<DATA_PIN>::port();
|
||||
|
||||
if(FastPin<DATA_PIN>::port() != FastPin<CLOCK_PIN>::port()) {
|
||||
register clock_ptr_t clockpin = FastPin<CLOCK_PIN>::port();
|
||||
// If data and clock are on different ports, then writing a bit will consist of writing the value foor
|
||||
// the bit (hi or low) to the data pin port, and then two writes to the clock port to strobe the clock line
|
||||
register data_t datahi = FastPin<DATA_PIN>::hival();
|
||||
register data_t datalo = FastPin<DATA_PIN>::loval();
|
||||
register clock_t clockhi = FastPin<CLOCK_PIN>::hival();
|
||||
register clock_t clocklo = FastPin<CLOCK_PIN>::loval();
|
||||
|
||||
while(pixels.has(1)) {
|
||||
if(FLAGS & FLAG_START_BIT) {
|
||||
writeBit<0>(1, clockpin, datapin, datahi, datalo, clockhi, clocklo);
|
||||
}
|
||||
writeByte(D::adjust(pixels.loadAndScale0()), clockpin, datapin, datahi, datalo, clockhi, clocklo);
|
||||
writeByte(D::adjust(pixels.loadAndScale1()), clockpin, datapin, datahi, datalo, clockhi, clocklo);
|
||||
writeByte(D::adjust(pixels.loadAndScale2()), clockpin, datapin, datahi, datalo, clockhi, clocklo);
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
}
|
||||
|
||||
} else {
|
||||
// If data and clock are on the same port then we can combine setting the data and clock pins
|
||||
register data_t datahi_clockhi = FastPin<DATA_PIN>::hival() | FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datalo_clockhi = FastPin<DATA_PIN>::loval() | FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datahi_clocklo = FastPin<DATA_PIN>::hival() & ~FastPin<CLOCK_PIN>::mask();
|
||||
register data_t datalo_clocklo = FastPin<DATA_PIN>::loval() & ~FastPin<CLOCK_PIN>::mask();
|
||||
|
||||
while(pixels.has(1)) {
|
||||
if(FLAGS & FLAG_START_BIT) {
|
||||
writeBit<0>(1, datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
|
||||
}
|
||||
writeByte(D::adjust(pixels.loadAndScale0()), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
|
||||
writeByte(D::adjust(pixels.loadAndScale1()), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
|
||||
writeByte(D::adjust(pixels.loadAndScale2()), datapin, datahi_clockhi, datalo_clockhi, datahi_clocklo, datalo_clocklo);
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
D::postBlock(len);
|
||||
release();
|
||||
}
|
||||
};
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
0
libraries/FastLED/fastspi_dma.h
Normal file
0
libraries/FastLED/fastspi_dma.h
Normal file
64
libraries/FastLED/fastspi_nop.h
Normal file
64
libraries/FastLED/fastspi_nop.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef __INC_FASTSPI_NOP_H
|
||||
#define __INC_FASTSPI_NOP_H
|
||||
|
||||
#if 0 // Guard against the arduino ide idiotically including every header file
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
/// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should
|
||||
/// be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the
|
||||
/// idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead)
|
||||
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
|
||||
class NOPSPIOutput {
|
||||
Selectable *m_pSelect;
|
||||
|
||||
public:
|
||||
NOPSPIOutput() { m_pSelect = NULL; }
|
||||
NOPSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
|
||||
|
||||
/// set the object representing the selectable
|
||||
void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
|
||||
|
||||
/// initialize the SPI subssytem
|
||||
void init() { /* TODO */ }
|
||||
|
||||
/// latch the CS select
|
||||
void select() { /* TODO */ }
|
||||
|
||||
/// release the CS select
|
||||
void release() { /* TODO */ }
|
||||
|
||||
/// wait until all queued up data has been written
|
||||
void waitFully();
|
||||
|
||||
/// not the most efficient mechanism in the world - but should be enough for sm16716 and friends
|
||||
template <uint8_t BIT> inline static void writeBit(uint8_t b) { /* TODO */ }
|
||||
|
||||
/// write a byte out via SPI (returns immediately on writing register)
|
||||
void writeByte(uint8_t b) { /* TODO */ }
|
||||
/// write a word out via SPI (returns immediately on writing register)
|
||||
void writeWord(uint16_t w) { /* TODO */ }
|
||||
|
||||
/// A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes)
|
||||
static void writeBytesValueRaw(uint8_t value, int len) { /* TODO */ }
|
||||
|
||||
/// A full cycle of writing a value for len bytes, including select, release, and waiting
|
||||
void writeBytesValue(uint8_t value, int len) { /* TODO */ }
|
||||
|
||||
/// A full cycle of writing a raw block of data out, including select, release, and waiting
|
||||
void writeBytes(uint8_t *data, int len) { /* TODO */ }
|
||||
|
||||
/// write a single bit out, which bit from the passed in byte is determined by template parameter
|
||||
template <uint8_t BIT> inline static void writeBit(uint8_t b) { /* TODO */ }
|
||||
|
||||
/// write out pixel data from the given PixelController object
|
||||
template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) { /* TODO */ }
|
||||
|
||||
};
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
#endif
|
95
libraries/FastLED/fastspi_ref.h
Normal file
95
libraries/FastLED/fastspi_ref.h
Normal file
@ -0,0 +1,95 @@
|
||||
#ifndef __INC_FASTSPI_ARM_SAM_H
|
||||
#define __INC_FASTSPI_ARM_SAM_H
|
||||
|
||||
#if 0 // guard against the arduino ide idiotically including every header file
|
||||
#include "FastLED.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
// A skeletal implementation of hardware SPI support. Fill in the necessary code for init, waiting, and writing. The rest of
|
||||
// the method implementations should provide a starting point, even if not hte most efficient to start with
|
||||
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
|
||||
class REFHardwareSPIOutput {
|
||||
Selectable *m_pSelect;
|
||||
public:
|
||||
SAMHardwareSPIOutput() { m_pSelect = NULL; }
|
||||
SAMHArdwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
|
||||
|
||||
// set the object representing the selectable
|
||||
void setSelect(Selectable *pSelect) { /* TODO */ }
|
||||
|
||||
// initialize the SPI subssytem
|
||||
void init() { /* TODO */ }
|
||||
|
||||
// latch the CS select
|
||||
void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } }
|
||||
|
||||
// release the CS select
|
||||
void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } }
|
||||
|
||||
// wait until all queued up data has been written
|
||||
static void waitFully() { /* TODO */ }
|
||||
|
||||
// write a byte out via SPI (returns immediately on writing register)
|
||||
static void writeByte(uint8_t b) { /* TODO */ }
|
||||
|
||||
// write a word out via SPI (returns immediately on writing register)
|
||||
static void writeWord(uint16_t w) { /* TODO */ }
|
||||
|
||||
// A raw set of writing byte values, assumes setup/init/waiting done elsewhere
|
||||
static void writeBytesValueRaw(uint8_t value, int len) {
|
||||
while(len--) { writeByte(value); }
|
||||
}
|
||||
|
||||
// A full cycle of writing a value for len bytes, including select, release, and waiting
|
||||
void writeBytesValue(uint8_t value, int len) {
|
||||
select(); writeBytesValueRaw(value, len); release();
|
||||
}
|
||||
|
||||
// A full cycle of writing a value for len bytes, including select, release, and waiting
|
||||
template <class D> void writeBytes(register uint8_t *data, int len) {
|
||||
uint8_t *end = data + len;
|
||||
select();
|
||||
// could be optimized to write 16bit words out instead of 8bit bytes
|
||||
while(data != end) {
|
||||
writeByte(D::adjust(*data++));
|
||||
}
|
||||
D::postBlock(len);
|
||||
waitFully();
|
||||
release();
|
||||
}
|
||||
|
||||
// A full cycle of writing a value for len bytes, including select, release, and waiting
|
||||
void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
|
||||
|
||||
// write a single bit out, which bit from the passed in byte is determined by template parameter
|
||||
template <uint8_t BIT> inline static void writeBit(uint8_t b) { /* TODO */ }
|
||||
|
||||
// write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template
|
||||
// parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping
|
||||
template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
|
||||
select();
|
||||
while(data != end) {
|
||||
if(FLAGS & FLAG_START_BIT) {
|
||||
writeBit<0>(1);
|
||||
}
|
||||
writeByte(D::adjust(pixels.loadAndScale0()));
|
||||
writeByte(D::adjust(pixels.loadAndScale1()));
|
||||
writeByte(D::adjust(pixels.loadAndScale2()));
|
||||
|
||||
pixels.advanceData();
|
||||
pixels.stepDithering();
|
||||
data += (3+skip);
|
||||
}
|
||||
D::postBlock(len);
|
||||
release();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
43
libraries/FastLED/fastspi_types.h
Normal file
43
libraries/FastLED/fastspi_types.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef __INC_FASTSPI_TYPES_H
|
||||
#define __INC_FASTSPI_TYPES_H
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
// Some helper macros for getting at mis-ordered byte values
|
||||
#define SPI_B0 (RGB_BYTE0(RGB_ORDER) + (MASK_SKIP_BITS & SKIP))
|
||||
#define SPI_B1 (RGB_BYTE1(RGB_ORDER) + (MASK_SKIP_BITS & SKIP))
|
||||
#define SPI_B2 (RGB_BYTE2(RGB_ORDER) + (MASK_SKIP_BITS & SKIP))
|
||||
#define SPI_ADVANCE (3 + (MASK_SKIP_BITS & SKIP))
|
||||
|
||||
/// Some of the SPI controllers will need to perform a transform on each byte before doing
|
||||
/// anyting with it. Creating a class of this form and passing it in as a template parameter to
|
||||
/// writeBytes/writeBytes3 below will ensure that the body of this method will get called on every
|
||||
/// byte worked on. Recommendation, make the adjust method aggressively inlined.
|
||||
///
|
||||
/// TODO: Convinience macro for building these
|
||||
class DATA_NOP {
|
||||
public:
|
||||
static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data) { return data; }
|
||||
static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data, register uint8_t scale) { return scale8(data, scale); }
|
||||
static __attribute__((always_inline)) inline void postBlock(int /* len */) { }
|
||||
};
|
||||
|
||||
#define FLAG_START_BIT 0x80
|
||||
#define MASK_SKIP_BITS 0x3F
|
||||
|
||||
// Clock speed dividers
|
||||
#define SPEED_DIV_2 2
|
||||
#define SPEED_DIV_4 4
|
||||
#define SPEED_DIV_8 8
|
||||
#define SPEED_DIV_16 16
|
||||
#define SPEED_DIV_32 32
|
||||
#define SPEED_DIV_64 64
|
||||
#define SPEED_DIV_128 128
|
||||
|
||||
#define MAX_DATA_RATE 0
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
714
libraries/FastLED/hsv2rgb.cpp
Normal file
714
libraries/FastLED/hsv2rgb.cpp
Normal file
@ -0,0 +1,714 @@
|
||||
#define FASTLED_INTERNAL
|
||||
#include <stdint.h>
|
||||
|
||||
#include "FastLED.h"
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
// Functions to convert HSV colors to RGB colors.
|
||||
//
|
||||
// The basically fall into two groups: spectra, and rainbows.
|
||||
// Spectra and rainbows are not the same thing. Wikipedia has a good
|
||||
// illustration here
|
||||
// http://upload.wikimedia.org/wikipedia/commons/f/f6/Prism_compare_rainbow_01.png
|
||||
// from this article
|
||||
// http://en.wikipedia.org/wiki/Rainbow#Number_of_colours_in_spectrum_or_rainbow
|
||||
// that shows a 'spectrum' and a 'rainbow' side by side. Among other
|
||||
// differences, you'll see that a 'rainbow' has much more yellow than
|
||||
// a plain spectrum. "Classic" LED color washes are spectrum based, and
|
||||
// usually show very little yellow.
|
||||
//
|
||||
// Wikipedia's page on HSV color space, with pseudocode for conversion
|
||||
// to RGB color space
|
||||
// http://en.wikipedia.org/wiki/HSL_and_HSV
|
||||
// Note that their conversion algorithm, which is (naturally) very popular
|
||||
// is in the "maximum brightness at any given hue" style, vs the "uniform
|
||||
// brightness for all hues" style.
|
||||
//
|
||||
// You can't have both; either purple is the same brightness as red, e.g
|
||||
// red = #FF0000 and purple = #800080 -> same "total light" output
|
||||
// OR purple is 'as bright as it can be', e.g.
|
||||
// red = #FF0000 and purple = #FF00FF -> purple is much brighter than red.
|
||||
// The colorspace conversions here try to keep the apparent brightness
|
||||
// constant even as the hue varies.
|
||||
//
|
||||
// Adafruit's "Wheel" function, discussed here
|
||||
// http://forums.adafruit.com/viewtopic.php?f=47&t=22483
|
||||
// is also of the "constant apparent brightness" variety.
|
||||
//
|
||||
// TODO: provide the 'maximum brightness no matter what' variation.
|
||||
//
|
||||
// See also some good, clear Arduino C code from Kasper Kamperman
|
||||
// http://www.kasperkamperman.com/blog/arduino/arduino-programming-hsb-to-rgb/
|
||||
// which in turn was was based on Windows C code from "nico80"
|
||||
// http://www.codeproject.com/Articles/9207/An-HSB-RGBA-colour-picker
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void hsv2rgb_raw_C (const struct CHSV & hsv, struct CRGB & rgb);
|
||||
void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb);
|
||||
|
||||
#if defined(__AVR__) && !defined( LIB8_ATTINY )
|
||||
void hsv2rgb_raw(const struct CHSV & hsv, struct CRGB & rgb)
|
||||
{
|
||||
hsv2rgb_raw_avr( hsv, rgb);
|
||||
}
|
||||
#else
|
||||
void hsv2rgb_raw(const struct CHSV & hsv, struct CRGB & rgb)
|
||||
{
|
||||
hsv2rgb_raw_C( hsv, rgb);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define APPLY_DIMMING(X) (X)
|
||||
#define HSV_SECTION_6 (0x20)
|
||||
#define HSV_SECTION_3 (0x40)
|
||||
|
||||
void hsv2rgb_raw_C (const struct CHSV & hsv, struct CRGB & rgb)
|
||||
{
|
||||
// Convert hue, saturation and brightness ( HSV/HSB ) to RGB
|
||||
// "Dimming" is used on saturation and brightness to make
|
||||
// the output more visually linear.
|
||||
|
||||
// Apply dimming curves
|
||||
uint8_t value = APPLY_DIMMING( hsv.val);
|
||||
uint8_t saturation = hsv.sat;
|
||||
|
||||
// The brightness floor is minimum number that all of
|
||||
// R, G, and B will be set to.
|
||||
uint8_t invsat = APPLY_DIMMING( 255 - saturation);
|
||||
uint8_t brightness_floor = (value * invsat) / 256;
|
||||
|
||||
// The color amplitude is the maximum amount of R, G, and B
|
||||
// that will be added on top of the brightness_floor to
|
||||
// create the specific hue desired.
|
||||
uint8_t color_amplitude = value - brightness_floor;
|
||||
|
||||
// Figure out which section of the hue wheel we're in,
|
||||
// and how far offset we are withing that section
|
||||
uint8_t section = hsv.hue / HSV_SECTION_3; // 0..2
|
||||
uint8_t offset = hsv.hue % HSV_SECTION_3; // 0..63
|
||||
|
||||
uint8_t rampup = offset; // 0..63
|
||||
uint8_t rampdown = (HSV_SECTION_3 - 1) - offset; // 63..0
|
||||
|
||||
// We now scale rampup and rampdown to a 0-255 range -- at least
|
||||
// in theory, but here's where architecture-specific decsions
|
||||
// come in to play:
|
||||
// To scale them up to 0-255, we'd want to multiply by 4.
|
||||
// But in the very next step, we multiply the ramps by other
|
||||
// values and then divide the resulting product by 256.
|
||||
// So which is faster?
|
||||
// ((ramp * 4) * othervalue) / 256
|
||||
// or
|
||||
// ((ramp ) * othervalue) / 64
|
||||
// It depends on your processor architecture.
|
||||
// On 8-bit AVR, the "/ 256" is just a one-cycle register move,
|
||||
// but the "/ 64" might be a multicycle shift process. So on AVR
|
||||
// it's faster do multiply the ramp values by four, and then
|
||||
// divide by 256.
|
||||
// On ARM, the "/ 256" and "/ 64" are one cycle each, so it's
|
||||
// faster to NOT multiply the ramp values by four, and just to
|
||||
// divide the resulting product by 64 (instead of 256).
|
||||
// Moral of the story: trust your profiler, not your insticts.
|
||||
|
||||
// Since there's an AVR assembly version elsewhere, we'll
|
||||
// assume what we're on an architecture where any number of
|
||||
// bit shifts has roughly the same cost, and we'll remove the
|
||||
// redundant math at the source level:
|
||||
|
||||
// // scale up to 255 range
|
||||
// //rampup *= 4; // 0..252
|
||||
// //rampdown *= 4; // 0..252
|
||||
|
||||
// compute color-amplitude-scaled-down versions of rampup and rampdown
|
||||
uint8_t rampup_amp_adj = (rampup * color_amplitude) / (256 / 4);
|
||||
uint8_t rampdown_amp_adj = (rampdown * color_amplitude) / (256 / 4);
|
||||
|
||||
// add brightness_floor offset to everything
|
||||
uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor;
|
||||
uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor;
|
||||
|
||||
|
||||
if( section ) {
|
||||
if( section == 1) {
|
||||
// section 1: 0x40..0x7F
|
||||
rgb.r = brightness_floor;
|
||||
rgb.g = rampdown_adj_with_floor;
|
||||
rgb.b = rampup_adj_with_floor;
|
||||
} else {
|
||||
// section 2; 0x80..0xBF
|
||||
rgb.r = rampup_adj_with_floor;
|
||||
rgb.g = brightness_floor;
|
||||
rgb.b = rampdown_adj_with_floor;
|
||||
}
|
||||
} else {
|
||||
// section 0: 0x00..0x3F
|
||||
rgb.r = rampdown_adj_with_floor;
|
||||
rgb.g = rampup_adj_with_floor;
|
||||
rgb.b = brightness_floor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(__AVR__) && !defined( LIB8_ATTINY )
|
||||
void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb)
|
||||
{
|
||||
uint8_t hue, saturation, value;
|
||||
|
||||
hue = hsv.hue;
|
||||
saturation = hsv.sat;
|
||||
value = hsv.val;
|
||||
|
||||
// Saturation more useful the other way around
|
||||
saturation = 255 - saturation;
|
||||
uint8_t invsat = APPLY_DIMMING( saturation );
|
||||
|
||||
// Apply dimming curves
|
||||
value = APPLY_DIMMING( value );
|
||||
|
||||
// The brightness floor is minimum number that all of
|
||||
// R, G, and B will be set to, which is value * invsat
|
||||
uint8_t brightness_floor;
|
||||
|
||||
asm volatile(
|
||||
"mul %[value], %[invsat] \n"
|
||||
"mov %[brightness_floor], r1 \n"
|
||||
: [brightness_floor] "=r" (brightness_floor)
|
||||
: [value] "r" (value),
|
||||
[invsat] "r" (invsat)
|
||||
: "r0", "r1"
|
||||
);
|
||||
|
||||
// The color amplitude is the maximum amount of R, G, and B
|
||||
// that will be added on top of the brightness_floor to
|
||||
// create the specific hue desired.
|
||||
uint8_t color_amplitude = value - brightness_floor;
|
||||
|
||||
// Figure how far we are offset into the section of the
|
||||
// color wheel that we're in
|
||||
uint8_t offset = hsv.hue & (HSV_SECTION_3 - 1); // 0..63
|
||||
uint8_t rampup = offset * 4; // 0..252
|
||||
|
||||
|
||||
// compute color-amplitude-scaled-down versions of rampup and rampdown
|
||||
uint8_t rampup_amp_adj;
|
||||
uint8_t rampdown_amp_adj;
|
||||
|
||||
asm volatile(
|
||||
"mul %[rampup], %[color_amplitude] \n"
|
||||
"mov %[rampup_amp_adj], r1 \n"
|
||||
"com %[rampup] \n"
|
||||
"mul %[rampup], %[color_amplitude] \n"
|
||||
"mov %[rampdown_amp_adj], r1 \n"
|
||||
: [rampup_amp_adj] "=&r" (rampup_amp_adj),
|
||||
[rampdown_amp_adj] "=&r" (rampdown_amp_adj),
|
||||
[rampup] "+r" (rampup)
|
||||
: [color_amplitude] "r" (color_amplitude)
|
||||
: "r0", "r1"
|
||||
);
|
||||
|
||||
|
||||
// add brightness_floor offset to everything
|
||||
uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor;
|
||||
uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor;
|
||||
|
||||
|
||||
// keep gcc from using "X" as the index register for storing
|
||||
// results back in the return structure. AVR's X register can't
|
||||
// do "std X+q, rnn", but the Y and Z registers can.
|
||||
// if the pointer to 'rgb' is in X, gcc will add all kinds of crazy
|
||||
// extra instructions. Simply killing X here seems to help it
|
||||
// try Y or Z first.
|
||||
asm volatile( "" : : : "r26", "r27" );
|
||||
|
||||
|
||||
if( hue & 0x80 ) {
|
||||
// section 2: 0x80..0xBF
|
||||
rgb.r = rampup_adj_with_floor;
|
||||
rgb.g = brightness_floor;
|
||||
rgb.b = rampdown_adj_with_floor;
|
||||
} else {
|
||||
if( hue & 0x40) {
|
||||
// section 1: 0x40..0x7F
|
||||
rgb.r = brightness_floor;
|
||||
rgb.g = rampdown_adj_with_floor;
|
||||
rgb.b = rampup_adj_with_floor;
|
||||
} else {
|
||||
// section 0: 0x00..0x3F
|
||||
rgb.r = rampdown_adj_with_floor;
|
||||
rgb.g = rampup_adj_with_floor;
|
||||
rgb.b = brightness_floor;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup_R1();
|
||||
}
|
||||
// End of AVR asm implementation
|
||||
|
||||
#endif
|
||||
|
||||
void hsv2rgb_spectrum( const CHSV& hsv, CRGB& rgb)
|
||||
{
|
||||
CHSV hsv2(hsv);
|
||||
hsv2.hue = scale8( hsv2.hue, 191);
|
||||
hsv2rgb_raw(hsv2, rgb);
|
||||
}
|
||||
|
||||
|
||||
// Sometimes the compiler will do clever things to reduce
|
||||
// code size that result in a net slowdown, if it thinks that
|
||||
// a variable is not used in a certain location.
|
||||
// This macro does its best to convince the compiler that
|
||||
// the variable is used in this location, to help control
|
||||
// code motion and de-duplication that would result in a slowdown.
|
||||
#define FORCE_REFERENCE(var) asm volatile( "" : : "r" (var) )
|
||||
|
||||
|
||||
#define K255 255
|
||||
#define K171 171
|
||||
#define K170 170
|
||||
#define K85 85
|
||||
|
||||
void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
|
||||
{
|
||||
// Yellow has a higher inherent brightness than
|
||||
// any other color; 'pure' yellow is perceived to
|
||||
// be 93% as bright as white. In order to make
|
||||
// yellow appear the correct relative brightness,
|
||||
// it has to be rendered brighter than all other
|
||||
// colors.
|
||||
// Level Y1 is a moderate boost, the default.
|
||||
// Level Y2 is a strong boost.
|
||||
const uint8_t Y1 = 1;
|
||||
const uint8_t Y2 = 0;
|
||||
|
||||
// G2: Whether to divide all greens by two.
|
||||
// Depends GREATLY on your particular LEDs
|
||||
const uint8_t G2 = 0;
|
||||
|
||||
// Gscale: what to scale green down by.
|
||||
// Depends GREATLY on your particular LEDs
|
||||
const uint8_t Gscale = 0;
|
||||
|
||||
|
||||
uint8_t hue = hsv.hue;
|
||||
uint8_t sat = hsv.sat;
|
||||
uint8_t val = hsv.val;
|
||||
|
||||
uint8_t offset = hue & 0x1F; // 0..31
|
||||
|
||||
// offset8 = offset * 8
|
||||
uint8_t offset8 = offset;
|
||||
{
|
||||
#if defined(__AVR__)
|
||||
// Left to its own devices, gcc turns "x <<= 3" into a loop
|
||||
// It's much faster and smaller to just do three single-bit shifts
|
||||
// So this business is to force that.
|
||||
offset8 <<= 1;
|
||||
asm volatile("");
|
||||
offset8 <<= 1;
|
||||
asm volatile("");
|
||||
offset8 <<= 1;
|
||||
#else
|
||||
// On ARM and other non-AVR platforms, we just shift 3.
|
||||
offset8 <<= 3;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t third = scale8( offset8, (256 / 3)); // max = 85
|
||||
|
||||
uint8_t r, g, b;
|
||||
|
||||
if( ! (hue & 0x80) ) {
|
||||
// 0XX
|
||||
if( ! (hue & 0x40) ) {
|
||||
// 00X
|
||||
//section 0-1
|
||||
if( ! (hue & 0x20) ) {
|
||||
// 000
|
||||
//case 0: // R -> O
|
||||
r = K255 - third;
|
||||
g = third;
|
||||
b = 0;
|
||||
FORCE_REFERENCE(b);
|
||||
} else {
|
||||
// 001
|
||||
//case 1: // O -> Y
|
||||
if( Y1 ) {
|
||||
r = K171;
|
||||
g = K85 + third ;
|
||||
b = 0;
|
||||
FORCE_REFERENCE(b);
|
||||
}
|
||||
if( Y2 ) {
|
||||
r = K170 + third;
|
||||
//uint8_t twothirds = (third << 1);
|
||||
uint8_t twothirds = scale8( offset8, ((256 * 2) / 3)); // max=170
|
||||
g = K85 + twothirds;
|
||||
b = 0;
|
||||
FORCE_REFERENCE(b);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//01X
|
||||
// section 2-3
|
||||
if( ! (hue & 0x20) ) {
|
||||
// 010
|
||||
//case 2: // Y -> G
|
||||
if( Y1 ) {
|
||||
//uint8_t twothirds = (third << 1);
|
||||
uint8_t twothirds = scale8( offset8, ((256 * 2) / 3)); // max=170
|
||||
r = K171 - twothirds;
|
||||
g = K170 + third;
|
||||
b = 0;
|
||||
FORCE_REFERENCE(b);
|
||||
}
|
||||
if( Y2 ) {
|
||||
r = K255 - offset8;
|
||||
g = K255;
|
||||
b = 0;
|
||||
FORCE_REFERENCE(b);
|
||||
}
|
||||
} else {
|
||||
// 011
|
||||
// case 3: // G -> A
|
||||
r = 0;
|
||||
FORCE_REFERENCE(r);
|
||||
g = K255 - third;
|
||||
b = third;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// section 4-7
|
||||
// 1XX
|
||||
if( ! (hue & 0x40) ) {
|
||||
// 10X
|
||||
if( ! ( hue & 0x20) ) {
|
||||
// 100
|
||||
//case 4: // A -> B
|
||||
r = 0;
|
||||
FORCE_REFERENCE(r);
|
||||
//uint8_t twothirds = (third << 1);
|
||||
uint8_t twothirds = scale8( offset8, ((256 * 2) / 3)); // max=170
|
||||
g = K171 - twothirds; //K170?
|
||||
b = K85 + twothirds;
|
||||
|
||||
} else {
|
||||
// 101
|
||||
//case 5: // B -> P
|
||||
r = third;
|
||||
g = 0;
|
||||
FORCE_REFERENCE(g);
|
||||
b = K255 - third;
|
||||
|
||||
}
|
||||
} else {
|
||||
if( ! (hue & 0x20) ) {
|
||||
// 110
|
||||
//case 6: // P -- K
|
||||
r = K85 + third;
|
||||
g = 0;
|
||||
FORCE_REFERENCE(g);
|
||||
b = K171 - third;
|
||||
|
||||
} else {
|
||||
// 111
|
||||
//case 7: // K -> R
|
||||
r = K170 + third;
|
||||
g = 0;
|
||||
FORCE_REFERENCE(g);
|
||||
b = K85 - third;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is one of the good places to scale the green down,
|
||||
// although the client can scale green down as well.
|
||||
if( G2 ) g = g >> 1;
|
||||
if( Gscale ) g = scale8_video_LEAVING_R1_DIRTY( g, Gscale);
|
||||
|
||||
// Scale down colors if we're desaturated at all
|
||||
// and add the brightness_floor to r, g, and b.
|
||||
if( sat != 255 ) {
|
||||
if( sat == 0) {
|
||||
r = 255; b = 255; g = 255;
|
||||
} else {
|
||||
//nscale8x3_video( r, g, b, sat);
|
||||
#if (FASTLED_SCALE8_FIXED==1)
|
||||
if( r ) r = scale8_LEAVING_R1_DIRTY( r, sat);
|
||||
if( g ) g = scale8_LEAVING_R1_DIRTY( g, sat);
|
||||
if( b ) b = scale8_LEAVING_R1_DIRTY( b, sat);
|
||||
#else
|
||||
if( r ) r = scale8_LEAVING_R1_DIRTY( r, sat) + 1;
|
||||
if( g ) g = scale8_LEAVING_R1_DIRTY( g, sat) + 1;
|
||||
if( b ) b = scale8_LEAVING_R1_DIRTY( b, sat) + 1;
|
||||
#endif
|
||||
cleanup_R1();
|
||||
|
||||
uint8_t desat = 255 - sat;
|
||||
desat = scale8( desat, desat);
|
||||
|
||||
uint8_t brightness_floor = desat;
|
||||
r += brightness_floor;
|
||||
g += brightness_floor;
|
||||
b += brightness_floor;
|
||||
}
|
||||
}
|
||||
|
||||
// Now scale everything down if we're at value < 255.
|
||||
if( val != 255 ) {
|
||||
|
||||
val = scale8_video_LEAVING_R1_DIRTY( val, val);
|
||||
if( val == 0 ) {
|
||||
r=0; g=0; b=0;
|
||||
} else {
|
||||
// nscale8x3_video( r, g, b, val);
|
||||
#if (FASTLED_SCALE8_FIXED==1)
|
||||
if( r ) r = scale8_LEAVING_R1_DIRTY( r, val);
|
||||
if( g ) g = scale8_LEAVING_R1_DIRTY( g, val);
|
||||
if( b ) b = scale8_LEAVING_R1_DIRTY( b, val);
|
||||
#else
|
||||
if( r ) r = scale8_LEAVING_R1_DIRTY( r, val) + 1;
|
||||
if( g ) g = scale8_LEAVING_R1_DIRTY( g, val) + 1;
|
||||
if( b ) b = scale8_LEAVING_R1_DIRTY( b, val) + 1;
|
||||
#endif
|
||||
cleanup_R1();
|
||||
}
|
||||
}
|
||||
|
||||
// Here we have the old AVR "missing std X+n" problem again
|
||||
// It turns out that fixing it winds up costing more than
|
||||
// not fixing it.
|
||||
// To paraphrase Dr Bronner, profile! profile! profile!
|
||||
//asm volatile( "" : : : "r26", "r27" );
|
||||
//asm volatile (" movw r30, r26 \n" : : : "r30", "r31");
|
||||
rgb.r = r;
|
||||
rgb.g = g;
|
||||
rgb.b = b;
|
||||
}
|
||||
|
||||
|
||||
void hsv2rgb_raw(const struct CHSV * phsv, struct CRGB * prgb, int numLeds) {
|
||||
for(int i = 0; i < numLeds; i++) {
|
||||
hsv2rgb_raw(phsv[i], prgb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void hsv2rgb_rainbow( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
|
||||
for(int i = 0; i < numLeds; i++) {
|
||||
hsv2rgb_rainbow(phsv[i], prgb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
|
||||
for(int i = 0; i < numLeds; i++) {
|
||||
hsv2rgb_spectrum(phsv[i], prgb[i]);
|
||||
}
|
||||