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

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Garcia <danielgarcia@gmail.com>2016-02-15 23:55:59 +0300
committerDaniel Garcia <danielgarcia@gmail.com>2016-02-15 23:55:59 +0300
commit7b83eb946723b40b5ae4b3b0dc5ac909603eb0aa (patch)
tree9d4171312c54b69c834d58f2502f769b4cec6bc6
parentbc008e867495ea36fa2d01eeb7f0851f5500e147 (diff)
parent91d79223c078de8e0c358dce0dfacd2a62e08e11 (diff)
Merge branch 'master' of https://github.com/FastLED/FastLED
-rw-r--r--FastLED.cpp10
-rw-r--r--FastLED.h4
-rw-r--r--README.md3
-rw-r--r--chipsets.h235
-rw-r--r--controller.h327
-rw-r--r--dmx.h82
-rw-r--r--docs/.Doxyfile.swpbin126976 -> 0 bytes
-rw-r--r--led_sysdefs.h6
-rw-r--r--lib8tion.h4
-rw-r--r--platforms.h6
-rw-r--r--platforms/arm/d21/clockless_arm_d21.h34
-rw-r--r--platforms/arm/d21/fastpin_arm_d21.h14
-rw-r--r--platforms/arm/k20/clockless_arm_k20.h36
-rw-r--r--platforms/arm/k20/clockless_block_arm_k20.h208
-rw-r--r--platforms/arm/k20/octows2811_controller.h38
-rw-r--r--platforms/arm/k20/smartmatrix_t3.h48
-rw-r--r--platforms/arm/kl26/clockless_arm_kl26.h34
-rw-r--r--platforms/arm/nrf51/clockless_arm_nrf51.h38
-rw-r--r--platforms/arm/sam/clockless_arm_sam.h32
-rw-r--r--platforms/arm/sam/clockless_block_arm_sam.h124
-rw-r--r--platforms/arm/stm32/clockless_arm_stm32.h28
-rw-r--r--platforms/avr/clockless_trinket.h36
-rw-r--r--platforms/esp/8266/clockless_esp8266.h116
-rw-r--r--platforms/esp/8266/fastled_esp8266.h5
-rw-r--r--platforms/esp/8266/fastpin_esp8266.h45
-rw-r--r--platforms/esp/8266/led_sysdefs_esp8266.h30
-rw-r--r--release_notes.md6
27 files changed, 502 insertions, 1047 deletions
diff --git a/FastLED.cpp b/FastLED.cpp
index 949372ea..f9f7ec4d 100644
--- a/FastLED.cpp
+++ b/FastLED.cpp
@@ -86,6 +86,11 @@ 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();
@@ -114,7 +119,7 @@ void CFastLED::clearData() {
void CFastLED::delay(unsigned long ms) {
unsigned long start = millis();
- do {
+ do {
#ifndef FASTLED_ACCURATE_CLOCK
// make sure to allow at least one ms to pass to ensure the clock moves
// forward
@@ -229,7 +234,10 @@ extern "C" int atexit(void (* /*func*/ )()) { return 0; }
#ifdef NEED_CXX_BITS
namespace __cxxabiv1
{
+ #ifndef ESP8266
extern "C" void __cxa_pure_virtual (void) {}
+ #endif
+
/* guard variables */
/* The ABI requires a 64-bit type. */
diff --git a/FastLED.h b/FastLED.h
index 496411a1..5cf6d3fa 100644
--- a/FastLED.h
+++ b/FastLED.h
@@ -388,8 +388,8 @@ public:
case WS2811_400_PORTD: return addLeds(new InlineBlockClocklessController<NUM_LANES, PORTD_FIRST_PIN, NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
#endif
#ifdef HAS_PORTDC
- case WS2811_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<16,NS(320), NS(320), NS(640), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
- case WS2811_400_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<16,NS(800), NS(800), NS(900), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset);
+ 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);
#endif
}
}
diff --git a/README.md b/README.md
index d0c68628..b500fd6e 100644
--- a/README.md
+++ b/README.md
@@ -71,7 +71,8 @@ Right now the library is supported on a variety of arduino compatable platforms.
* RFDuino
* SparkCore
* Arduino Zero
-* ESP8266 w/Arduino Core
+* ESP8266 using the arduino board definitions from http://arduino.esp8266.com/stable/package_esp8266com_index.json
+* 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
diff --git a/chipsets.h b/chipsets.h
index 51237b5c..79a03271 100644
--- a/chipsets.h
+++ b/chipsets.h
@@ -25,21 +25,19 @@ FASTLED_NAMESPACE_BEGIN
/// @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 CLEDController {
+class PixieController : public CPixelLEDController<RGB_ORDER> {
SoftwareSerial Serial;
CMinWait<2000> mWait;
public:
PixieController() : Serial(-1, DATA_PIN) {}
- virtual void clearLeds(int nLeds) { showColor(CRGB(0,0,0), nLeds, CRGB(0,0,0)); };
-
protected:
virtual void init() {
Serial.begin(115200);
mWait.mark();
}
- void show(PixelController<RGB_ORDER> & pixels) {
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
while(pixels.has(1)) {
uint8_t r = pixels.loadAndScale0();
@@ -54,22 +52,6 @@ protected:
mWait.mark();
}
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither());
- show(pixels);
- }
-
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither());
- show(pixels);
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds,, scale, getDither());
- show(pixels);
- }
-#endif
};
// template<SoftwareSerial & STREAM, EOrder RGB_ORDER = RGB>
@@ -96,7 +78,7 @@ protected:
/// @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 CLEDController {
+class LPD8806Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
class LPD8806_ADJUST {
@@ -110,51 +92,18 @@ class LPD8806Controller : public CLEDController {
};
SPI mSPI;
- int mClearedLeds;
-
- void checkClear(int nLeds) {
- if(nLeds > mClearedLeds) {
- clearLine(nLeds);
- mClearedLeds = nLeds;
- }
- }
-
- void clearLine(int nLeds) {
- int n = ((nLeds*3 + 63) >> 6);
- mSPI.writeBytesValue(0, n);
- }
public:
+
LPD8806Controller() {}
virtual void init() {
mSPI.init();
- mClearedLeds = 0;
- }
-
- virtual void clearLeds(int nLeds) {
- mSPI.select();
- mSPI.writeBytesValueRaw(0x80, nLeds * 3);
- mSPI.writeBytesValueRaw(0, ((nLeds*3+63)>>6));
- mSPI.waitFully();
- mSPI.release();
}
protected:
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
- }
-
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- // TODO rgb-ize scale
- mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(pixels);
}
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *data, int nLeds, uint8_t scale) {
- checkClear(nLeds);
- mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
- }
-#endif
};
@@ -170,7 +119,7 @@ protected:
/// @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 CLEDController {
+class WS2801Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI;
CMinWait<1000> mWaitDelay;
@@ -179,36 +128,16 @@ public:
virtual void init() {
mSPI.init();
- mWaitDelay.mark();
- }
-
- virtual void clearLeds(int nLeds) {
- mWaitDelay.wait();
- mSPI.writeBytesValue(0, nLeds*3);
- mWaitDelay.mark();
+ mWaitDelay.mark();
}
protected:
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- mWaitDelay.wait();
- mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
- mWaitDelay.mark();
- }
-
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWaitDelay.wait();
- mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
+ mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(pixels);
mWaitDelay.mark();
}
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- mWaitDelay.wait();
- mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
- mWaitDelay.mark();
- }
-#endif
};
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(25)>
@@ -225,8 +154,8 @@ class WS2803Controller : public WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER,
/// @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 = BGR, uint8_t SPI_SPEED = DATA_RATE_MHZ(24)>
-class APA102Controller : public CLEDController {
+template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(24)>
+class APA102Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI;
@@ -244,46 +173,13 @@ public:
mSPI.init();
}
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0,0,0), nLeds, CRGB(0,0,0));
- }
-
protected:
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither());
-
- mSPI.select();
-
- startBoundary();
- for(int i = 0; i < nLeds; i++) {
-#ifdef FASTLED_SPI_BYTE_ONLY
- mSPI.writeByte(0xFF);
- mSPI.writeByte(pixels.loadAndScale0());
- mSPI.writeByte(pixels.loadAndScale1());
- mSPI.writeByte(pixels.loadAndScale2());
-#else
- uint16_t b = 0xFF00 | (uint16_t)pixels.loadAndScale0();
- mSPI.writeWord(b);
- uint16_t w = pixels.loadAndScale1() << 8;
- w |= pixels.loadAndScale2();
- mSPI.writeWord(w);
-#endif
- pixels.stepDithering();
- }
- endBoundary(nLeds);
-
- mSPI.waitFully();
- mSPI.release();
- }
-
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither());
-
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
startBoundary();
- for(int i = 0; i < nLeds; i++) {
+ while(pixels.has(1)) {
#ifdef FASTLED_SPI_BYTE_ONLY
mSPI.writeByte(0xFF);
mSPI.writeByte(pixels.loadAndScale0());
@@ -299,31 +195,11 @@ protected:
pixels.stepDithering();
pixels.advanceData();
}
- endBoundary(nLeds);
+ endBoundary(pixels.size());
mSPI.waitFully();
mSPI.release();
}
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds,, scale, getDither());
-
- mSPI.select();
-
- startBoundary();
- for(int i = 0; i < nLeds; i++) {
- mSPI.writeByte(0xFF);
- uint8_t b = pixels.loadAndScale0(); mSPI.writeByte(b);
- b = pixels.loadAndScale1(); mSPI.writeByte(b);
- b = pixels.loadAndScale2(); mSPI.writeByte(b);
- pixels.advanceData();
- pixels.stepDithering();
- }
- endBoundary(nLeds);
- mSPI.waitFully();
- mSPI.release();
- }
-#endif
};
@@ -339,7 +215,7 @@ protected:
/// @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 CLEDController {
+class P9813Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI;
@@ -357,35 +233,13 @@ public:
mSPI.init();
}
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0,0,0), nLeds, CRGB(0,0,0));
- }
-
protected:
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither());
-
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
writeBoundary();
- while(nLeds--) {
- writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2());
- pixels.stepDithering();
- }
- writeBoundary();
-
- mSPI.waitFully();
- mSPI.release();
- }
-
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither());
-
- mSPI.select();
-
- writeBoundary();
- for(int i = 0; i < nLeds; i++) {
+ while(pixels.has(1)) {
writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2());
pixels.advanceData();
pixels.stepDithering();
@@ -396,24 +250,6 @@ protected:
mSPI.release();
}
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(data, nLeds,, scale, getDither());
-
- mSPI.select();
-
- writeBoundary();
- for(int i = 0; i < nLeds; i++) {
- writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2());
- pixels.advanceData();
- pixels.stepDithering();
- }
- writeBoundary();
- mSPI.waitFully();
-
- mSPI.release();
- }
-#endif
};
@@ -429,7 +265,7 @@ protected:
/// @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 CLEDController {
+class SM16716Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI;
@@ -450,45 +286,16 @@ public:
mSPI.init();
}
- virtual void clearLeds(int nLeds) {
- mSPI.select();
- while(nLeds--) {
- mSPI.template writeBit<0>(1);
- mSPI.writeByte(0);
- mSPI.writeByte(0);
- mSPI.writeByte(0);
- }
- mSPI.waitFully();
- mSPI.release();
- writeHeader();
- }
-
protected:
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- mSPI.template writePixels<FLAG_START_BIT, DATA_NOP, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
- writeHeader();
- }
-
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
+ 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>( PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
+ mSPI.template writePixels<FLAG_START_BIT, DATA_NOP, RGB_ORDER>( pixels );
writeHeader();
}
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *data, int nLeds, CRGB scale) {
- mSPI.writeBytesValue(0, 6);
- mSPI.template writeBit<0>(0);
- mSPI.template writeBit<0>(0);
-
- // 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
- mSPI.template writePixels<FLAG_START_BIT, DATA_NOP, RGB_ORDER>(PixelController<RGB_ORDER>(data, nLeds, scale, getDither()));
- }
-#endif
};
/// @}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/controller.h b/controller.h
index 3df29ee7..8c06c0ca 100644
--- a/controller.h
+++ b/controller.h
@@ -59,10 +59,6 @@ protected:
///@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;
-#ifdef SUPPORT_ARGB
- // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped
- virtual void show(const struct CARGB *data, int nLeds, CRGB scale) = 0;
-#endif
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) {
@@ -76,7 +72,7 @@ public:
virtual void init() = 0;
///clear out/zero out the given number of leds.
- virtual void clearLeds(int nLeds) = 0;
+ 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) {
@@ -103,13 +99,6 @@ public:
/// get the next controller in the chain after this one. will return NULL at the end of the chain
CLEDController *next() { return m_pNext; }
- #ifdef SUPPORT_ARGB
- // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped
- void show(const struct CARGB *data, int nLeds, uint8_t brightness) {
- show(data, nLeds, getAdjustment(brightness))
- }
-#endif
-
/// set the default array of leds to be used by this controller
CLEDController & setLeds(CRGB *data, int nLeds) {
m_Data = data;
@@ -181,214 +170,20 @@ public:
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>
-struct PixelController {
- const uint8_t *mData;
- int mLen;
- uint8_t d[3];
- uint8_t e[3];
- CRGB mScale;
- uint8_t mAdvance;
-
- ///copy constructor for the pixel controller object
- 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;
- mLen = other.mLen;
- }
-
-
- /// create a pixel controller for managing led data as it is being written out
- ///@{
- ///@param d the led data this controller is managing
- ///@param len the number of leds this controller is managing
- ///@param s the combined rgb scaling adjustment for the leds
- ///@param dither the dither mode for these pixels
- ///@param advance whether or not to walk through the array of data for each pixel, or just write out the first pixel len times
- ///@param skip whether or not there is extra data to skip when writing out led data, e.g. if passed in argb data
- PixelController(const uint8_t *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER, bool advance=true, uint8_t skip=0) : mData(d), mLen(len), mScale(s) {
- enable_dithering(dither);
- mData += skip;
- mAdvance = (advance) ? 3+skip : 0;
- }
-
- PixelController(const CRGB *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)d), mLen(len), mScale(s) {
- enable_dithering(dither);
- mAdvance = 3;
- }
-
- PixelController(const CRGB &d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)&d), mLen(len), mScale(s) {
- enable_dithering(dither);
- mAdvance = 0;
- }
-
-#ifdef SUPPORT_ARGB
- PixelController(const CARGB &d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)&d), mLen(len), mScale(s) {
- enable_dithering(dither);
- // skip the A in CARGB
- mData += 1;
- mAdvance = 0;
- }
-
- PixelController(const CARGB *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)d), mLen(len), mScale(s) {
- enable_dithering(dither);
- // skip the A in CARGB
- mData += 1;
- mAdvance = 4;
- }
-#endif
- ///@}
-
- /// initialize the binary dithering for this controller
- 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 byte R = 0;
- R++;
-
- // R is wrapped around at 2^ditherBits,
- // so if ditherBits is 2, R will cycle through (0,1,2,3)
- byte 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)
- byte 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++) {
- byte s = mScale.raw[i];
- e[i] = s ? (256/s) + 1 : 0;
- d[i] = scale8(Q, e[i]);
- if(e[i]) e[i]--;
- }
-#endif
- }
-
- /// Do we have n pixels left to process?
- __attribute__((always_inline)) inline bool has(int n) {
- return mLen >= 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;
- }
- }
-
- /// 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; mLen--;}
-
- /// 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 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 scale(PixelController & pc, uint8_t b) { return scale8(b, pc.mScale.raw[RO(SLOT)]); }
-
- // 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 advanceAndLoadAndScale(PixelController & pc) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc); }
-
- // Helper functions to get around gcc stupidities
- __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); }
-};
-
// 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<int LANES,int MASK, EOrder RGB_ORDER>
-struct MultiPixelController {
+template<EOrder RGB_ORDER, int LANES=1, uint32_t MASK=0xFFFFFFFF>
+struct PixelController {
const uint8_t *mData;
- int mLen;
+ int mLen,mLenRemaining;
uint8_t d[3];
uint8_t e[3];
CRGB mScale;
int8_t mAdvance;
int mOffsets[LANES];
- MultiPixelController(const MultiPixelController & other) {
+ PixelController(const PixelController & other) {
d[0] = other.d[0];
d[1] = other.d[1];
d[2] = other.d[2];
@@ -398,7 +193,7 @@ struct MultiPixelController {
mData = other.mData;
mScale = other.mScale;
mAdvance = other.mAdvance;
- mLen = other.mLen;
+ mLenRemaining = mLen = other.mLen;
for(int i = 0; i < LANES; i++) { mOffsets[i] = other.mOffsets[i]; }
}
@@ -411,43 +206,25 @@ struct MultiPixelController {
}
}
- MultiPixelController(const uint8_t *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER, bool advance=true, uint8_t skip=0) : mData(d), mLen(len), mScale(s) {
+ 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);
}
- MultiPixelController(const CRGB *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)d), mLen(len), mScale(s) {
+ 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);
}
- MultiPixelController(const CRGB &d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)&d), mLen(len), mScale(s) {
- enable_dithering(dither);
- mAdvance = 0;
- initOffsets(len);
- }
-
-#ifdef SUPPORT_ARGB
- MultiPixelController(const CARGB &d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)&d), mLen(len), mScale(s) {
+ 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);
- // skip the A in CARGB
- mData += 1;
mAdvance = 0;
initOffsets(len);
}
- MultiPixelController(const CARGB *d, int len, CRGB & s, EDitherMode dither = BINARY_DITHER) : mData((const uint8_t*)d), mLen(len), mScale(s) {
- enable_dithering(dither);
- // skip the A in CARGB
- mData += 1;
- mAdvance = 4;
- initOffsets(len);
- }
-#endif
-
void init_binary_dithering() {
#if !defined(NO_DITHERING) || (NO_DITHERING != 1)
@@ -526,7 +303,7 @@ struct MultiPixelController {
// Do we have n pixels left to process?
__attribute__((always_inline)) inline bool has(int n) {
- return mLen >= n;
+ return mLenRemaining >= n;
}
// toggle dithering enable
@@ -537,11 +314,13 @@ struct MultiPixelController {
}
}
+ __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; mLen--;}
+ __attribute__((always_inline)) inline void advanceData() { mData += mAdvance; mLenRemaining--;}
// step the dithering forward
__attribute__((always_inline)) inline void stepDithering() {
@@ -557,32 +336,68 @@ struct MultiPixelController {
d[RO(0)] = e[RO(0)] - d[RO(0)];
}
- template<int SLOT> __attribute__((always_inline)) inline static uint8_t loadByte(MultiPixelController & pc, int lane) { return pc.mData[pc.mOffsets[lane] + RO(SLOT)]; }
- template<int SLOT> __attribute__((always_inline)) inline static uint8_t dither(MultiPixelController & pc, uint8_t b) { return b ? qadd8(b, pc.d[RO(SLOT)]) : 0; }
- template<int SLOT> __attribute__((always_inline)) inline static uint8_t dither(MultiPixelController & pc, uint8_t b, uint8_t d) { return b ? qadd8(b,d) : 0; }
- template<int SLOT> __attribute__((always_inline)) inline static uint8_t scale(MultiPixelController & pc, uint8_t b) { return scale8(b, pc.mScale.raw[RO(SLOT)]); }
- template<int SLOT> __attribute__((always_inline)) inline static uint8_t scale(MultiPixelController & pc, uint8_t b, uint8_t scale) { return scale8(b, scale); }
+ 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(MultiPixelController & 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(MultiPixelController & 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(MultiPixelController & 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(MultiPixelController & pc, int lane) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc, lane); }
-
- template<int SLOT> __attribute__((always_inline)) inline static uint8_t getd(MultiPixelController & pc) { return pc.d[RO(SLOT)]; }
- template<int SLOT> __attribute__((always_inline)) inline static uint8_t getscale(MultiPixelController & pc) { return pc.mScale.raw[RO(SLOT)]; }
-
- // Helper functions to get around gcc stupidities
- __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 loadAndScale0(int lane, uint8_t d, uint8_t scale) { return loadAndScale<0>(*this, lane, d, scale); }
- __attribute__((always_inline)) inline uint8_t loadAndScale1(int lane, uint8_t d, uint8_t scale) { return loadAndScale<1>(*this, lane, d, scale); }
- __attribute__((always_inline)) inline uint8_t loadAndScale2(int lane, uint8_t d, uint8_t scale) { return loadAndScale<2>(*this, lane, d, scale); }
- __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); }
+ 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 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) { 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); }
};
+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
diff --git a/dmx.h b/dmx.h
index 0811ca85..245c7cfc 100644
--- a/dmx.h
+++ b/dmx.h
@@ -12,46 +12,22 @@
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 CLEDController {
+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); }
- // clear out/zero out the given number of leds.
- virtual void clearLeds(int nLeds) {
- int count = min(nLeds * 3, DMX_SIZE);
- for(int iChannel = 1; iChannel <= count; iChannel++) { DmxSimple.write(iChannel, 0); }
- }
-
protected:
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- int count = min(nLeds, DMX_SIZE / 3);
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
int iChannel = 1;
- for(int i = 0; i < count; i++) {
- DmxSimple.write(iChannel++, scale8(data[RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)]));
- DmxSimple.write(iChannel++, scale8(data[RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)]));
- DmxSimple.write(iChannel++, scale8(data[RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)]));
+ while(pixels.has(1)) {
+ DmxSimple.write(iChannel++, pixels.loadAndScale0());
+ DmxSimple.write(iChannel++, pixels.loadAndScale1());
+ DmxSimple.write(iChannel++, pixels.loadAndScale2());
+ pixels.advanceData();
+ pixels.stepDithering();
}
}
-
- // note that the uint8_ts will be in the order that you want them sent out to the device.
- // nLeds is the number of RGB leds being written to
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- int count = min(nLeds, DMX_SIZE / 3);
- int iChannel = 1;
- for(int i = 0; i < count; i++) {
- DmxSimple.write(iChannel++, scale8(data[i][RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)]));
- DmxSimple.write(iChannel++, scale8(data[i][RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)]));
- DmxSimple.write(iChannel++, scale8(data[i][RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)]));
- }
-
- }
-
-#ifdef SUPPORT_ARGB
- // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped
- virtual void show(const struct CARGB *data, int nLeds, uint8_t scale = 255) = 0;
-#endif
};
FASTLED_NAMESPACE_END
@@ -63,45 +39,21 @@ FASTLED_NAMESPACE_END
FASTLED_NAMESPACE_BEGIN
-template <EOrder RGB_ORDER = RGB> class DMXSerialController : public CLEDController {
+template <EOrder RGB_ORDER = RGB> class DMXSerialController : public CPixelLEDController<RGB_ORDER> {
public:
// initialize the LED controller
virtual void init() { DMXSerial.init(DMXController); }
- // clear out/zero out the given number of leds.
- virtual void clearLeds(int nLeds) {
- int count = min(nLeds * 3, DMXSERIAL_MAX);
- for(int iChannel = 0; iChannel < count; iChannel++) { DMXSerial.write(iChannel, 0); }
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- int count = min(nLeds, DMXSERIAL_MAX / 3);
- int iChannel = 0;
- for(int i = 0; i < count; i++) {
- DMXSerial.write(iChannel++, scale8(data[RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)]));
- DMXSerial.write(iChannel++, scale8(data[RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)]));
- DMXSerial.write(iChannel++, scale8(data[RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)]));
- }
- }
-
- // note that the uint8_ts will be in the order that you want them sent out to the device.
- // nLeds is the number of RGB leds being written to
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- int count = min(nLeds, DMXSERIAL_MAX / 3);
- int iChannel = 0;
- for(int i = 0; i < count; i++) {
- DMXSerial.write(iChannel++, scale8(data[i][RGB_BYTE0(RGB_ORDER)], scale.raw[RGB_BYTE0(RGB_ORDER)]));
- DMXSerial.write(iChannel++, scale8(data[i][RGB_BYTE1(RGB_ORDER)], scale.raw[RGB_BYTE1(RGB_ORDER)]));
- DMXSerial.write(iChannel++, scale8(data[i][RGB_BYTE2(RGB_ORDER)], scale.raw[RGB_BYTE2(RGB_ORDER)]));
+ 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();
}
-
}
-
-#ifdef SUPPORT_ARGB
- // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped
- virtual void show(const struct CARGB *data, int nLeds, uint8_t scale = 255) = 0;
-#endif
};
FASTLED_NAMESPACE_END
diff --git a/docs/.Doxyfile.swp b/docs/.Doxyfile.swp
deleted file mode 100644
index d223ba7d..00000000
--- a/docs/.Doxyfile.swp
+++ /dev/null
Binary files differ
diff --git a/led_sysdefs.h b/led_sysdefs.h
index c6cecd52..de3f307e 100644
--- a/led_sysdefs.h
+++ b/led_sysdefs.h
@@ -18,10 +18,10 @@
#include "platforms/arm/sam/led_sysdefs_arm_sam.h"
#elif defined(STM32F10X_MD)
#include "platforms/arm/stm32/led_sysdefs_arm_stm32.h"
-#elif defined(__SAMD21G18A__)
+#elif defined(__SAMD21G18A__) || defined(__SAMD21E17A__)
#include "platforms/arm/d21/led_sysdefs_arm_d21.h"
-#elif defined(__XTENSA__)
-#error "XTENSA-architecture microcontrollers are not supported."
+#elif defined(ESP8266)
+#include "platforms/esp/8266/led_sysdefs_esp8266.h"
#else
// AVR platforms
#include "platforms/avr/led_sysdefs_avr.h"
diff --git a/lib8tion.h b/lib8tion.h
index 9d66624a..0dbbbff4 100644
--- a/lib8tion.h
+++ b/lib8tion.h
@@ -837,9 +837,9 @@ typedef q<uint16_t, 12,4> q124;
// that provides similar functionality.
// You can also force use of the get_millisecond_timer function
// by #defining USE_GET_MILLISECOND_TIMER.
-#if (defined(ARDUINO) || defined(SPARK)) && !defined(USE_GET_MILLISECOND_TIMER)
+#if (defined(ARDUINO) || defined(SPARK) || defined(FASTLED_HAS_MILLIS)) && !defined(USE_GET_MILLISECOND_TIMER)
// Forward declaration of Arduino function 'millis'.
-uint32_t millis();
+//uint32_t millis();
#define GET_MILLIS millis
#else
uint32_t get_millisecond_timer();
diff --git a/platforms.h b/platforms.h
index c36b016c..287ebb8a 100644
--- a/platforms.h
+++ b/platforms.h
@@ -18,10 +18,10 @@
#include "platforms/arm/sam/fastled_arm_sam.h"
#elif defined(STM32F10X_MD)
#include "platforms/arm/stm32/fastled_arm_stm32.h"
-#elif defined(__SAMD21G18A__)
+#elif defined(__SAMD21G18A__) || defined(__SAMD21E17A__)
#include "platforms/arm/d21/fastled_arm_d21.h"
-#elif defined(__XTENSA__)
-#error "XTENSA-architecture microcontrollers are not supported"
+#elif defined(ESP8266)
+#include "platforms/esp/8266/fastled_esp8266.h"
#else
// AVR platforms
#include "platforms/avr/fastled_avr.h"
diff --git a/platforms/arm/d21/clockless_arm_d21.h b/platforms/arm/d21/clockless_arm_d21.h
index c6ca1792..94b596d7 100644
--- a/platforms/arm/d21/clockless_arm_d21.h
+++ b/platforms/arm/d21/clockless_arm_d21.h
@@ -6,7 +6,7 @@ FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class ClocklessController : public CLEDController {
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
@@ -22,43 +22,13 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- cli();
-
- showRGBInternal(pixels);
-
- sei();
- mWait.mark();
- }
-
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- cli();
-
- showRGBInternal(pixels);
-
- sei();
- mWait.mark();
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
showRGBInternal(pixels);
sei();
mWait.mark();
}
-#endif
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
diff --git a/platforms/arm/d21/fastpin_arm_d21.h b/platforms/arm/d21/fastpin_arm_d21.h
index 9e9fe191..72558c78 100644
--- a/platforms/arm/d21/fastpin_arm_d21.h
+++ b/platforms/arm/d21/fastpin_arm_d21.h
@@ -81,7 +81,19 @@ _DEFPIN_ARM(40,0, 6); _DEFPIN_ARM(41,0, 7); _DEFPIN_ARM(42,0, 3);
#define SPI_DATA 24
#define SPI_CLOCK 23
-#define HAS_HARDWARE_PIN_SUPPORT
+#define HAS_HARDWARE_PIN_SUPPORT 1
+
+#elif defined(ARDUINO_SAMD_WINO)
+
+#define MAX_PIN 22
+_DEFPIN_ARM( 0, 0, 23); _DEFPIN_ARM( 1, 0, 22); _DEFPIN_ARM( 2, 0, 16); _DEFPIN_ARM( 3, 0, 17);
+_DEFPIN_ARM( 4, 0, 18); _DEFPIN_ARM( 5, 0, 19); _DEFPIN_ARM( 6, 0, 24); _DEFPIN_ARM( 7, 0, 25);
+_DEFPIN_ARM( 8, 0, 27); _DEFPIN_ARM( 9, 0, 28); _DEFPIN_ARM( 10, 0, 30); _DEFPIN_ARM( 11, 0, 31);
+_DEFPIN_ARM( 12, 0, 15); _DEFPIN_ARM( 13, 0, 14); _DEFPIN_ARM( 14, 0, 2); _DEFPIN_ARM( 15, 0, 3);
+_DEFPIN_ARM( 16, 0, 4); _DEFPIN_ARM( 17, 0, 5); _DEFPIN_ARM( 18, 0, 6); _DEFPIN_ARM( 19, 0, 7);
+_DEFPIN_ARM( 20, 0, 8); _DEFPIN_ARM( 21, 0, 9); _DEFPIN_ARM( 22, 0, 10); _DEFPIN_ARM( 23, 0, 11);
+
+#define HAS_HARDWARE_PIN_SUPPORT 1
#endif
diff --git a/platforms/arm/k20/clockless_arm_k20.h b/platforms/arm/k20/clockless_arm_k20.h
index f17ba72d..c0fef13a 100644
--- a/platforms/arm/k20/clockless_arm_k20.h
+++ b/platforms/arm/k20/clockless_arm_k20.h
@@ -10,7 +10,7 @@ FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class ClocklessController : public CLEDController {
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<DATA_PIN>::port_t data_t;
@@ -26,37 +26,13 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
protected:
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
-
- mWait.wait();
- showRGBInternal(pixels);
- mWait.mark();
- }
-
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
-
- mWait.wait();
- showRGBInternal(pixels);
- mWait.mark();
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- showRGBInternal(pixels);
- mWait.mark();
- }
-#endif
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ mWait.wait();
+ showRGBInternal(pixels);
+ mWait.mark();
+ }
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
for(register uint32_t i = BITS-1; i > 0; i--) {
diff --git a/platforms/arm/k20/clockless_block_arm_k20.h b/platforms/arm/k20/clockless_block_arm_k20.h
index dda85ac3..f2b76468 100644
--- a/platforms/arm/k20/clockless_block_arm_k20.h
+++ b/platforms/arm/k20/clockless_block_arm_k20.h
@@ -13,14 +13,14 @@
#define PORT_MASK (((1<<LANES)-1) & ((FIRST_PIN==2) ? 0xFF : 0xFFF))
#define MIN(X,Y) (((X)<(Y)) ? (X):(Y))
-#define LANES ((FIRST_PIN==2) ? MIN(__LANES,8) : MIN(__LANES,12))
+#define USED_LANES ((FIRST_PIN==2) ? MIN(LANES,8) : MIN(LANES,12))
#include "kinetis.h"
FASTLED_NAMESPACE_BEGIN
-template <uint8_t __LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 40>
-class InlineBlockClocklessController : public CLEDController {
+template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 40>
+class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PORT_MASK> {
typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<FIRST_PIN>::port_t data_t;
@@ -28,11 +28,23 @@ class InlineBlockClocklessController : public CLEDController {
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
- virtual int size() { return m_nLeds * __LANES; }
+ virtual int size() { return CLEDController::size() * LANES; }
+
+ virtual void showPixels(PixelController<RGB_ORDER, LANES, PORT_MASK> & pixels) {
+ mWait.wait();
+ uint32_t clocks = showRGBInternal(pixels);
+ #if FASTLED_ALLOW_INTTERUPTS == 0
+ // Adjust the timer
+ long microsTaken = CLKS_TO_MICROS(clocks);
+ MS_COUNTER += (1 + (microsTaken / 1000));
+ #endif
+
+ mWait.mark();
+ }
virtual void init() {
if(FIRST_PIN == PORTC_FIRST_PIN) { // PORTC
- switch(LANES) {
+ switch(USED_LANES) {
case 12: FastPin<30>::setOutput();
case 11: FastPin<29>::setOutput();
case 10: FastPin<27>::setOutput();
@@ -47,7 +59,7 @@ public:
case 1: FastPin<15>::setOutput();
}
} else if(FIRST_PIN == PORTD_FIRST_PIN) { // PORTD
- switch(LANES) {
+ switch(USED_LANES) {
case 8: FastPin<5>::setOutput();
case 7: FastPin<21>::setOutput();
case 6: FastPin<20>::setOutput();
@@ -64,63 +76,15 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<LANES,PORT_MASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
- mWait.wait();
- uint32_t clocks = showRGBInternal(pixels,nLeds);
- #if FASTLED_ALLOW_INTTERUPTS == 0
- // Adjust the timer
- long microsTaken = CLKS_TO_MICROS(clocks);
- MS_COUNTER += (1 + (microsTaken / 1000));
- #endif
-
- mWait.mark();
- }
-
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<LANES,PORT_MASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
- mWait.wait();
- uint32_t clocks = showRGBInternal(pixels,nLeds);
- #if FASTLED_ALLOW_INTTERUPTS == 0
- // Adjust the timer
- long microsTaken = CLKS_TO_MICROS(clocks);
- MS_COUNTER += (1 + (microsTaken / 1000));
- #endif
-
- mWait.mark();
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<LANES,PORT_MASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
- mWait.wait();
- uint32_t clocks = showRGBInternal(pixels,nLeds);
-
- #if FASTLED_ALLOW_INTTERUPTS == 0
- // Adjust the timer
- long microsTaken = CLKS_TO_MICROS(clocks);
- MS_COUNTER += (1 + (microsTaken / 1000));
- #endif
-
- mWait.mark();
- }
-#endif
-
-
typedef union {
uint8_t bytes[12];
uint16_t shorts[6];
uint32_t raw[3];
} Lines;
- template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController<LANES, PORT_MASK, RGB_ORDER> &pixels) { // , register uint32_t & b2) {
+ template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, PixelController<RGB_ORDER, LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
register Lines b2;
- if(LANES>8) {
+ if(USED_LANES>8) {
transpose8<1,2>(b.bytes,b2.bytes);
transpose8<1,2>(b.bytes+8,b2.bytes+1);
} else {
@@ -129,13 +93,13 @@ public:
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; i < (LANES/2); i++) {
+ for(register uint32_t i = 0; i < (USED_LANES/2); i++) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
- if(LANES>8) {
+ if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK);
} else {
*FastPin<FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PORT_MASK);
@@ -145,20 +109,20 @@ public:
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
- b.bytes[i+(LANES/2)] = pixels.template loadAndScale<PX>(pixels,i+(LANES/2),d,scale);
+ b.bytes[i+(USED_LANES/2)] = pixels.template loadAndScale<PX>(pixels,i+(USED_LANES/2),d,scale);
}
// if folks use an odd numnber of lanes, get the last byte's value here
- if(LANES & 0x01) {
- b.bytes[LANES-1] = pixels.template loadAndScale<PX>(pixels,LANES-1,d,scale);
+ if(USED_LANES & 0x01) {
+ b.bytes[USED_LANES-1] = pixels.template loadAndScale<PX>(pixels,USED_LANES-1,d,scale);
}
- for(register uint32_t i = LANES/2; i < 8; i++) {
+ for(register uint32_t i = USED_LANES/2; i < 8; i++) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
- if(LANES>8) {
+ if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK);
} else {
// b2.bytes[0] = 0;
@@ -169,28 +133,13 @@ public:
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
}
-
-
- // while(ARM_DWT_CYCCNT < next_mark);
- // next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
- // *FastPin<FIRST_PIN>::sport() = PORT_MASK;
- //
- // while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6));
- // if(LANES>8) {
- // *FastPin<FIRST_PIN>::cport() = ((~b2.shorts[7]) & PORT_MASK);
- // } else {
- // *FastPin<FIRST_PIN>::cport() = PORT_MASK; // ((~b2.bytes[7-i]) & PORT_MASK);
- // }
- //
- // while((next_mark - ARM_DWT_CYCCNT) > (T3));
- // *FastPin<FIRST_PIN>::cport() = PORT_MASK;
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(MultiPixelController<LANES, PORT_MASK, RGB_ORDER> &allpixels, int nLeds) {
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
// Get access to the clock
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
@@ -201,14 +150,14 @@ public:
register Lines b0;
allpixels.preStepFirstByteDithering();
- for(int i = 0; i < LANES; i++) {
+ for(int i = 0; i < USED_LANES; i++) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
cli();
uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
- while(nLeds--) {
+ while(allpixels.has(1)) {
#if (FASTLED_ALLOW_INTERRUPTS == 1)
cli();
// if interrupts took longer than 45µs, punt on the current frame
@@ -236,13 +185,12 @@ public:
}
};
-#define DLANES (MIN(__LANES,16))
-#define PMASK ((1<<(DLANES))-1)
+#define PMASK ((1<<(LANES))-1)
#define PMASK_HI (PMASK>>8 & 0xFF)
#define PMASK_LO (PMASK & 0xFF)
-template <uint8_t __LANES, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class SixteenWayInlineBlockClocklessController : public CLEDController {
+template <uint8_t LANES, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
+class SixteenWayInlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PMASK> {
typedef typename FastPin<PORTC_FIRST_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<PORTC_FIRST_PIN>::port_t data_t;
@@ -251,59 +199,43 @@ class SixteenWayInlineBlockClocklessController : public CLEDController {
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
- // FastPin<30>::setOutput();
- // FastPin<29>::setOutput();
- // FastPin<27>::setOutput();
- // FastPin<28>::setOutput();
- switch(DLANES) {
- case 16: FastPin<12>::setOutput();
- case 15: FastPin<11>::setOutput();
- case 14: FastPin<13>::setOutput();
- case 13: FastPin<10>::setOutput();
- case 12: FastPin<9>::setOutput();
- case 11: FastPin<23>::setOutput();
- case 10: FastPin<22>::setOutput();
- case 9: FastPin<15>::setOutput();
-
- case 8: FastPin<5>::setOutput();
- case 7: FastPin<21>::setOutput();
- case 6: FastPin<20>::setOutput();
- case 5: FastPin<6>::setOutput();
- case 4: FastPin<8>::setOutput();
- case 3: FastPin<7>::setOutput();
- case 2: FastPin<14>::setOutput();
- case 1: FastPin<2>::setOutput();
- }
- }
-
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<DLANES,PMASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
- mWait.wait();
- showRGBInternal(pixels,nLeds);
- mWait.mark();
+ static_assert(LANES <= 16, "Maximum of 16 lanes for Teensy parallel controllers!");
+ // FastPin<30>::setOutput();
+ // FastPin<29>::setOutput();
+ // FastPin<27>::setOutput();
+ // FastPin<28>::setOutput();
+ switch(LANES) {
+ case 16: FastPin<12>::setOutput();
+ case 15: FastPin<11>::setOutput();
+ case 14: FastPin<13>::setOutput();
+ case 13: FastPin<10>::setOutput();
+ case 12: FastPin<9>::setOutput();
+ case 11: FastPin<23>::setOutput();
+ case 10: FastPin<22>::setOutput();
+ case 9: FastPin<15>::setOutput();
+
+ case 8: FastPin<5>::setOutput();
+ case 7: FastPin<21>::setOutput();
+ case 6: FastPin<20>::setOutput();
+ case 5: FastPin<6>::setOutput();
+ case 4: FastPin<8>::setOutput();
+ case 3: FastPin<7>::setOutput();
+ case 2: FastPin<14>::setOutput();
+ case 1: FastPin<2>::setOutput();
+ }
}
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<DLANES,PMASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
+ virtual void showPixels(PixelController<RGB_ORDER, LANES, PMASK> & pixels) {
mWait.wait();
- showRGBInternal(pixels,nLeds);
- mWait.mark();
- }
+ uint32_t clocks = showRGBInternal(pixels);
+ #if FASTLED_ALLOW_INTTERUPTS == 0
+ // Adjust the timer
+ long microsTaken = CLKS_TO_MICROS(clocks);
+ MS_COUNTER += (1 + (microsTaken / 1000));
+ #endif
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<DLANES,PMASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
- mWait.wait();
- showRGBInternal(pixels,nLeds);
mWait.mark();
}
-#endif
-
typedef union {
uint8_t bytes[16];
@@ -311,14 +243,14 @@ public:
uint32_t raw[4];
} Lines;
- template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController<DLANES, PMASK, RGB_ORDER> &pixels) { // , register uint32_t & b2) {
+ template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, PixelController<RGB_ORDER,LANES, PMASK> &pixels) { // , register uint32_t & b2) {
register Lines b2;
transpose8x1(b.bytes,b2.bytes);
transpose8x1(b.bytes+8,b2.bytes+8);
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
- for(register uint32_t i = 0; (i < DLANES) && (i < 8); i++) {
+ for(register uint32_t i = 0; (i < LANES) && (i < 8); i++) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<PORTD_FIRST_PIN>::sport() = PMASK_LO;
@@ -333,7 +265,7 @@ public:
*FastPin<PORTC_FIRST_PIN>::cport() = PMASK_HI;
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
- if(DLANES==16 || (DLANES>8 && ((i+8) < DLANES))) {
+ if(LANES==16 || (LANES>8 && ((i+8) < LANES))) {
b.bytes[i+8] = pixels.template loadAndScale<PX>(pixels,i+8,d,scale);
}
}
@@ -343,7 +275,7 @@ public:
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(MultiPixelController<DLANES, PMASK, RGB_ORDER> &allpixels, int nLeds) {
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER,LANES, PMASK> &allpixels) {
// Get access to the clock
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
@@ -354,14 +286,14 @@ public:
register Lines b0;
allpixels.preStepFirstByteDithering();
- for(int i = 0; i < DLANES; i++) {
+ for(int i = 0; i < LANES; i++) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
cli();
uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
- while(nLeds--) {
+ while(allpixels.has(1)) {
allpixels.stepDithering();
#if 0 && (FASTLED_ALLOW_INTERRUPTS == 1)
cli();
diff --git a/platforms/arm/k20/octows2811_controller.h b/platforms/arm/k20/octows2811_controller.h
index ed748919..ce959228 100644
--- a/platforms/arm/k20/octows2811_controller.h
+++ b/platforms/arm/k20/octows2811_controller.h
@@ -8,7 +8,7 @@
FASTLED_NAMESPACE_BEGIN
template<EOrder RGB_ORDER = GRB, boolean SLOW=false>
-class COctoWS2811Controller : public CLEDController {
+class COctoWS2811Controller : public CPixelLEDController<RGB_ORDER, 8, 0xFF> {
OctoWS2811 *pocto;
uint8_t *drawbuffer,*framebuffer;
@@ -34,45 +34,16 @@ public:
virtual void init() { /* do nothing yet */ }
- virtual void clearLeds(int nLeds) {
- _init(nLeds);
- showColor(CRGB(0,0,0),nLeds,CRGB(0,0,0));
- }
-
- virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) {
- _init(nLeds);
- // Get our pixel values
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither());
- uint8_t ball[3][8];
- memset(ball[0],pixels.loadAndScale0(),8);
- memset(ball[1],pixels.loadAndScale1(),8);
- memset(ball[2],pixels.loadAndScale2(),8);
-
- uint8_t bout[24];
- transpose8x1_MSB(ball[0],bout);
- transpose8x1_MSB(ball[1],bout+8);
- transpose8x1_MSB(ball[2],bout+16);
-
- uint8_t *pdata = drawbuffer;
- while(nLeds--) {
- memcpy(pdata,bout,24);
- pdata += 24;
- }
-
- pocto->show();
- }
-
typedef union {
uint8_t bytes[8];
uint32_t raw[2];
} Lines;
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- _init(nLeds);
- MultiPixelController<8,0xFF,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
+ virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> & pixels) {
+ _init(pixels.size());
uint8_t *pData = drawbuffer;
- while(nLeds--) {
+ while(pixels.has(1)) {
Lines b;
for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale0(i); }
@@ -87,6 +58,7 @@ public:
pocto->show();
}
+
};
FASTLED_NAMESPACE_END
diff --git a/platforms/arm/k20/smartmatrix_t3.h b/platforms/arm/k20/smartmatrix_t3.h
index 06b04f18..14c3734c 100644
--- a/platforms/arm/k20/smartmatrix_t3.h
+++ b/platforms/arm/k20/smartmatrix_t3.h
@@ -9,7 +9,7 @@ FASTLED_NAMESPACE_BEGIN
extern SmartMatrix *pSmartMatrix;
// note - dmx simple must be included before FastSPI for this code to be enabled
-class CSmartMatrixController : public CLEDController {
+class CSmartMatrixController : public CPixelLEDController<RGB_ORDER> {
SmartMatrix matrix;
public:
@@ -26,37 +26,13 @@ public:
pSmartMatrix = &matrix;
}
- // clear out/zero out the given number of leds.
- virtual void clearLeds(int nLeds) {
- const rgb24 black = {0,0,0};
- matrix.fillScreen(black);
- matrix.swapBuffers();
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & data, int nLeds,CRGB scale) {
- PixelController<RGB> pixels(data, nLeds, scale, getDither());
- rgb24 *md = matrix.backBuffer();
- while(nLeds--) {
- md->red = pixels.loadAndScale0();
- md->green = pixels.loadAndScale1();
- md->blue = pixels.loadAndScale2();
- md++;
- pixels.stepDithering();
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ if(SMART_MATRIX_CAN_TRIPLE_BUFFER) {
+ rgb24 *md = matrix.getRealBackBuffer();
+ } else {
+ rgb24 *md = matrix.backBuffer();
}
- matrix.swapBuffers();
- }
-
- // note that the uint8_ts will be in the order that you want them sent out to the device.
- // nLeds is the number of RGB leds being written to
- virtual void show(const struct CRGB *data, int nLeds, CRGB scale) {
- PixelController<RGB> pixels(data, nLeds, scale, getDither());
-#ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER
- rgb24 *md = matrix.getRealBackBuffer();
-#else
- rgb24 *md = matrix.backBuffer();
-#endif
- while(nLeds--) {
+ while(pixels.has(1)) {
md->red = pixels.loadAndScale0();
md->green = pixels.loadAndScale1();
md->blue = pixels.loadAndScale2();
@@ -65,15 +41,11 @@ public:
pixels.stepDithering();
}
matrix.swapBuffers();
-#ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER
- matrix.setBackBuffer((rgb24*)data);
-#endif
+ if(SMART_MATRIX_CAN_TRIPLE_BUFFER && pixels.advanceBy() > 0) {
+ matrix.setBackBuffer(pixels.mData);
+ }
}
-#ifdef SUPPORT_ARGB
- // as above, but every 4th uint8_t is assumed to be alpha channel data, and will be skipped
- virtual void show(const struct CARGB *data, int nLeds, CRGB scale) = 0;
-#endif
};
FASTLED_NAMESPACE_END
diff --git a/platforms/arm/kl26/clockless_arm_kl26.h b/platforms/arm/kl26/clockless_arm_kl26.h
index 8c441a8e..aba132f2 100644
--- a/platforms/arm/kl26/clockless_arm_kl26.h
+++ b/platforms/arm/kl26/clockless_arm_kl26.h
@@ -6,7 +6,7 @@ FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class ClocklessController : public CLEDController {
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
@@ -22,43 +22,13 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- cli();
-
- showRGBInternal(pixels);
-
- sei();
- mWait.mark();
- }
-
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- cli();
-
- showRGBInternal(pixels);
-
- sei();
- mWait.mark();
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
showRGBInternal(pixels);
sei();
mWait.mark();
}
-#endif
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
diff --git a/platforms/arm/nrf51/clockless_arm_nrf51.h b/platforms/arm/nrf51/clockless_arm_nrf51.h
index 98408ada..0fb56e3e 100644
--- a/platforms/arm/nrf51/clockless_arm_nrf51.h
+++ b/platforms/arm/nrf51/clockless_arm_nrf51.h
@@ -19,7 +19,7 @@
#include "platforms/arm/common/m0clockless.h"
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 75>
-class ClocklessController : public CLEDController {
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
@@ -35,51 +35,17 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
-
- // attempt to re-show a frame if we exit early because of interrupts.
if(!showRGBInternal(pixels)) {
sei(); delayMicroseconds(WAIT_TIME); cli();
showRGBInternal(pixels);
}
-
sei();
mWait.mark();
}
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- cli();
-
- if(!showRGBInternal(pixels)) {
- sei(); delayMicroseconds(WAIT_TIME); cli();
- showRGBInternal(pixels);
- }
-
- sei();
- mWait.mark();
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- cli();
- showRGBInternal(pixels);
- sei();
- mWait.mark();
- }
-#endif
-
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
static uint32_t showRGBInternal(PixelController<RGB_ORDER> & pixels) {
diff --git a/platforms/arm/sam/clockless_arm_sam.h b/platforms/arm/sam/clockless_arm_sam.h
index 4cbdf27f..08864b37 100644
--- a/platforms/arm/sam/clockless_arm_sam.h
+++ b/platforms/arm/sam/clockless_arm_sam.h
@@ -11,15 +11,11 @@ FASTLED_NAMESPACE_BEGIN
#define TADJUST 0
#define TOTAL ( (T1+TADJUST) + (T2+TADJUST) + (T3+TADJUST) )
-#define T1_MARK (TOTAL - (T1+TADJUST))
-#define T2_MARK (T1_MARK - (T2+TADJUST))
-#define SCALE(S,V) scale8_video(S,V)
-// #define SCALE(S,V) scale8(S,V)
#define FASTLED_HAS_CLOCKLESS 1
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class ClocklessController : public CLEDController {
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
@@ -35,38 +31,14 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
protected:
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- showRGBInternal(pixels);
- mWait.mark();
- }
-
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
showRGBInternal(pixels);
mWait.mark();
}
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- showRGBInternal(pixels);
- sei();
- mWait.mark();
- }
-#endif
-
-
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register uint8_t & b) {
// Make sure we don't slot into a wrapping spot, this will delay up to 12.5µs for WS2812
// bool bShift=0;
diff --git a/platforms/arm/sam/clockless_block_arm_sam.h b/platforms/arm/sam/clockless_block_arm_sam.h
index 745f61a6..2bfcf2b2 100644
--- a/platforms/arm/sam/clockless_block_arm_sam.h
+++ b/platforms/arm/sam/clockless_block_arm_sam.h
@@ -30,7 +30,7 @@ typedef union {
#define T1_MARK (TOTAL - (T1+TADJUST))
#define T2_MARK (T1_MARK - (T2+TADJUST))
template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class InlineBlockClocklessController : public CLEDController {
+class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, 0xFF> {
typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<FIRST_PIN>::port_t data_t;
@@ -38,8 +38,9 @@ class InlineBlockClocklessController : public CLEDController {
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
- virtual int size() { return m_nLeds * LANES; }
+ virtual int size() { return CLEDController::size() * LANES; }
virtual void init() {
+ static_assert(LANES <= 8, "Maximum of 8 lanes for Due parallel controllers!");
if(FIRST_PIN == PORTA_FIRST_PIN) {
switch(LANES) {
case 8: FastPin<31>::setOutput();
@@ -80,82 +81,23 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<LANES,PORT_MASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
- mWait.wait();
- showRGBInternal(pixels, nLeds);
- sei();
- mWait.mark();
- }
-
-// #define ADV_RGB
-#define ADV_RGB if(maskbit & PORT_MASK) { rgbdata += nLeds; } maskbit <<= 1;
-
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- MultiPixelController<LANES,PORT_MASK,RGB_ORDER> pixels(rgbdata,nLeds, scale, getDither() );
- mWait.wait();
- showRGBInternal(pixels, nLeds);
- mWait.mark();
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- mWait.wait();
- showRGBInternal(PixelController<RGB_ORDER>(rgbdata, nLeds, scale, getDither()));
- mWait.mark();
- }
-#endif
-
- template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, MultiPixelController<LANES, PORT_MASK, RGB_ORDER> &pixels) { // , register uint32_t & b2) {
- register Lines b2;
- transpose8x1(b.bytes,b2.bytes);
-
- register uint8_t d = pixels.template getd<PX>(pixels);
- register uint8_t scale = pixels.template getscale<PX>(pixels);
-
- for(uint32_t i = 0; (i < LANES) && (i<8); i++) {
- while(DUE_TIMER_VAL < next_mark);
- next_mark = (DUE_TIMER_VAL+TOTAL);
-
- *FastPin<FIRST_PIN>::sport() = PORT_MASK;
+ virtual void showPixels(PixelController<RGB_ORDER, LANES, 0xFF> & pixels) {
+ mWait.wait();
+ showRGBInternal(pixels);
+ sei();
+ mWait.mark();
+ }
- while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
- *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
-
- while((next_mark - (DUE_TIMER_VAL)) > T3);
- *FastPin<FIRST_PIN>::cport() = PORT_MASK;
-
- b3.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
- }
-
- for(uint32_t i = LANES; i < 8; i++) {
- while(DUE_TIMER_VAL > next_mark);
-
- next_mark = DUE_TIMER_VAL - (TOTAL-3);
- *FastPin<FIRST_PIN>::sport() = PORT_MASK;
-
- while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
- *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
-
- while((next_mark - DUE_TIMER_VAL) > T3);
- *FastPin<FIRST_PIN>::cport() = PORT_MASK;
- }
- }
-
- // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
- // gcc will use register Y for the this pointer.
- static uint32_t showRGBInternal(MultiPixelController<LANES, PORT_MASK, RGB_ORDER> &allpixels, int nLeds) {
+ static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
// Serial.println("Entering show");
- // Setup the pixel controller and load/scale the first byte
+
+ int nLeds = allpixels.mLen;
+
+ // Setup the pixel controller and load/scale the first byte
Lines b0,b1,b2;
allpixels.preStepFirstByteDithering();
- for(int i = 0; i < LANES; i++) {
+ for(uint8_t i = 0; i < LANES; i++) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
@@ -197,6 +139,42 @@ public:
return DUE_TIMER_VAL;
}
+ template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, PixelController<RGB_ORDER,LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
+ Lines b2;
+ transpose8x1(b.bytes,b2.bytes);
+
+ register uint8_t d = pixels.template getd<PX>(pixels);
+ register uint8_t scale = pixels.template getscale<PX>(pixels);
+
+ for(uint32_t i = 0; (i < LANES) && (i<8); i++) {
+ while(DUE_TIMER_VAL < next_mark);
+ next_mark = (DUE_TIMER_VAL+TOTAL);
+
+ *FastPin<FIRST_PIN>::sport() = PORT_MASK;
+
+ while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
+ *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
+
+ while((next_mark - (DUE_TIMER_VAL)) > T3);
+ *FastPin<FIRST_PIN>::cport() = PORT_MASK;
+
+ b3.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
+ }
+
+ for(uint32_t i = LANES; i < 8; i++) {
+ while(DUE_TIMER_VAL > next_mark);
+
+ next_mark = DUE_TIMER_VAL - (TOTAL-3);
+ *FastPin<FIRST_PIN>::sport() = PORT_MASK;
+
+ while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
+ *FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
+
+ while((next_mark - DUE_TIMER_VAL) > T3);
+ *FastPin<FIRST_PIN>::cport() = PORT_MASK;
+ }
+ }
+
};
diff --git a/platforms/arm/stm32/clockless_arm_stm32.h b/platforms/arm/stm32/clockless_arm_stm32.h
index d427abab..97786e29 100644
--- a/platforms/arm/stm32/clockless_arm_stm32.h
+++ b/platforms/arm/stm32/clockless_arm_stm32.h
@@ -8,7 +8,7 @@ FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
-class ClocklessController : public CLEDController {
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<DATA_PIN>::port_t data_t;
@@ -24,38 +24,14 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- showColor(CRGB(0, 0, 0), nLeds, 0);
- }
-
protected:
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
-
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
showRGBInternal(pixels);
mWait.mark();
}
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
-
- mWait.wait();
- showRGBInternal(pixels);
- mWait.mark();
- }
-
- #ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- PixelController<RGB_ORDER> pixels(rgbdata, nLeds, scale, getDither());
- mWait.wait();
- showRGBInternal(pixels);
- mWait.mark();
- }
- #endif
-
#define _CYCCNT (*(volatile uint32_t*)(0xE0001004UL))
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
diff --git a/platforms/avr/clockless_trinket.h b/platforms/avr/clockless_trinket.h
index 38c26984..2186906e 100644
--- a/platforms/avr/clockless_trinket.h
+++ b/platforms/avr/clockless_trinket.h
@@ -90,8 +90,8 @@ static uint8_t gTimeErrorAccum256ths;
#define FASTLED_HAS_CLOCKLESS 1
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 10>
-class ClocklessController : public CLEDController {
- static_assert(T1 >= 2 && T2 >= 2 && T3 >= 3, "Not enough cycles - use a higher clock speed");
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
+ static_assert(T1 >= 3 && T2 >= 2 && T3 >= 3, "Not enough cycles - use a higher clock speed");
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<DATA_PIN>::port_t data_t;
@@ -104,30 +104,9 @@ public:
virtual uint16_t getMaxRefreshRate() const { return 400; }
- virtual void clearLeds(int nLeds) {
- CRGB zeros(0,0,0);
- showAdjTime((uint8_t*)&zeros, nLeds, zeros, false, 0);
- }
-
protected:
- // set all the leds on the controller to a given color
- virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) {
- showAdjTime((uint8_t*)&rgbdata, nLeds, scale, false, 0);
- }
-
- virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) {
- showAdjTime((uint8_t*)rgbdata, nLeds, scale, true, 0);
- }
-
-#ifdef SUPPORT_ARGB
- virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) {
- showAdjTime((uint8_t*)rgbdata, nLeds, scale, true, 1);
- }
-#endif
-
- void showAdjTime(const uint8_t *data, int nLeds, CRGB & scale, bool advance, int skip) {
- PixelController<RGB_ORDER> pixels(data, nLeds, scale, getDither(), advance, skip);
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
@@ -136,12 +115,12 @@ protected:
// Adjust the timer
#if (!defined(NO_CORRECTION) || (NO_CORRECTION == 0)) && (FASTLED_ALLOW_INTERRUPTS == 0)
- uint32_t microsTaken = (uint32_t)nLeds * (uint32_t)CLKS_TO_MICROS(24 * (T1 + T2 + T3));
+ uint32_t microsTaken = (uint32_t)pixels.size() * (uint32_t)CLKS_TO_MICROS(24 * (T1 + T2 + T3));
// adust for approximate observed actal runtime (as of January 2015)
// roughly 9.6 cycles per pixel, which is 0.6us/pixel at 16MHz
// microsTaken += nLeds * 0.6 * CLKS_TO_MICROS(16);
- microsTaken += scale16by8(nLeds,(0.6 * 256) + 1) * CLKS_TO_MICROS(16);
+ microsTaken += scale16by8(pixels.size(),(0.6 * 256) + 1) * CLKS_TO_MICROS(16);
// if less than 1000us, there is NO timer impact,
// this is because the ONE interrupt that might come in while interrupts
@@ -502,11 +481,6 @@ protected:
#endif
}
-#ifdef SUPPORT_ARGB
- virtual void showARGB(struct CARGB *data, int nLeds) {
- // TODO: IMPLEMENTME
- }
-#endif
};
#endif
diff --git a/platforms/esp/8266/clockless_esp8266.h b/platforms/esp/8266/clockless_esp8266.h
new file mode 100644
index 00000000..99ac7d56
--- /dev/null
+++ b/platforms/esp/8266/clockless_esp8266.h
@@ -0,0 +1,116 @@
+#pragma once
+
+FASTLED_NAMESPACE_BEGIN
+
+// Info on reading cycle counter from https://github.com/kbeckmann/nodemcu-firmware/blob/ws2812-dual/app/modules/ws2812.c
+__attribute__ ((always_inline)) inline static uint32_t __clock_cycles() {
+ uint32_t cyc;
+ __asm__ __volatile__ ("rsr %0,ccount":"=a" (cyc));
+ return cyc;
+}
+
+#define FASTLED_HAS_CLOCKLESS 1
+
+template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5>
+class ClocklessController : public CPixelLEDController<RGB_ORDER> {
+ typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
+ typedef typename FastPin<DATA_PIN>::port_t data_t;
+
+ data_t mPinMask;
+ data_ptr_t mPort;
+ CMinWait<WAIT_TIME> mWait;
+public:
+ virtual void init() {
+ FastPin<DATA_PIN>::setOutput();
+ mPinMask = FastPin<DATA_PIN>::mask();
+ mPort = FastPin<DATA_PIN>::port();
+ }
+
+ virtual uint16_t getMaxRefreshRate() const { return 400; }
+
+protected:
+
+ virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
+ //mWait.wait();
+ showRGBInternal(pixels);
+ //mWait.mark();
+ }
+
+ template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
+ for(register uint32_t i = BITS; i > 0; i--) {
+ while(__clock_cycles() < next_mark);
+ next_mark = __clock_cycles() + (T1+T2+T3);
+ FastPin<DATA_PIN>::hi();
+ if(b&0x80) {
+ while((next_mark - __clock_cycles()) > (T3 - 3));
+ FastPin<DATA_PIN>::lo();
+ } else {
+ while((next_mark - __clock_cycles()) > (T2+T3 - 3));
+
+ FastPin<DATA_PIN>::lo();
+ }
+ b <<= 1;
+ }
+
+ // while(__clock_cycles() < next_mark);
+ // next_mark = __clock_cycles() + (T1+T2+T3);
+ // FastPin<DATA_PIN>::hi();
+ //
+ // if(b&0x80) {
+ // while((next_mark - __clock_cycles()) > (T3+(2*(F_CPU/24000000))));
+ // FastPin<DATA_PIN>::lo();
+ // } else {
+ // while((next_mark - __clock_cycles()) > (T2+T3+(2*(F_CPU/24000000))));
+ // FastPin<DATA_PIN>::lo();
+ // }
+ }
+
+ // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
+ // gcc will use register Y for the this pointer.
+ static uint32_t ICACHE_RAM_ATTR showRGBInternal(PixelController<RGB_ORDER> & pixels) {
+ register data_ptr_t port = FastPin<DATA_PIN>::port();
+ register data_t hi = *port | FastPin<DATA_PIN>::mask();;
+ register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
+ *port = lo;
+
+ // Setup the pixel controller and load/scale the first byte
+ pixels.preStepFirstByteDithering();
+ register uint8_t b = pixels.loadAndScale0();
+
+ os_intr_lock();
+ uint32_t start = __clock_cycles();
+ uint32_t next_mark = start + (T1+T2+T3);
+ while(pixels.has(1)) {
+ pixels.stepDithering();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ os_intr_lock();
+ // if interrupts took longer than 45µs, punt on the current frame
+ if(__clock_cycles() > next_mark) {
+ if((__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return __clock_cycles(); }
+ }
+
+ hi = *port | FastPin<DATA_PIN>::mask();
+ lo = *port & ~FastPin<DATA_PIN>::mask();
+ #endif
+ // Write first byte, read next byte
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.loadAndScale1();
+
+ // Write second byte, read 3rd byte
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.loadAndScale2();
+
+ // Write third byte, read 1st byte of next pixel
+ writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
+ b = pixels.advanceAndLoadAndScale0();
+ #if (FASTLED_ALLOW_INTERRUPTS == 1)
+ os_intr_unlock();
+ #endif
+ };
+
+ os_intr_unlock();
+ return __clock_cycles();
+ }
+};
+
+FASTLED_NAMESPACE_END
diff --git a/platforms/esp/8266/fastled_esp8266.h b/platforms/esp/8266/fastled_esp8266.h
new file mode 100644
index 00000000..9a9ee06b
--- /dev/null
+++ b/platforms/esp/8266/fastled_esp8266.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include "fastled_delay.h"
+#include "fastpin_esp8266.h"
+#include "clockless_esp8266.h"
diff --git a/platforms/esp/8266/fastpin_esp8266.h b/platforms/esp/8266/fastpin_esp8266.h
new file mode 100644
index 00000000..3d9bba1d
--- /dev/null
+++ b/platforms/esp/8266/fastpin_esp8266.h
@@ -0,0 +1,45 @@
+#pragma once
+
+FASTLED_NAMESPACE_BEGIN
+
+template<uint8_t PIN, uint32_t MASK> class _ESPPIN {
+
+public:
+ typedef volatile uint32_t * port_ptr_t;
+ typedef uint32_t port_t;
+
+ inline static void setOutput() { pinMode(PIN, OUTPUT); }
+ inline static void setInput() { pinMode(PIN, INPUT); }
+
+ inline static void hi() __attribute__ ((always_inline)) { if(PIN < 16) { GPOS = MASK; } else { GP16O |= MASK; } }
+ inline static void lo() __attribute__ ((always_inline)) { if(PIN < 16) { GPOC = MASK; } else { GP16O &= ~MASK; } }
+ inline static void set(register port_t val) __attribute__ ((always_inline)) { if(PIN < 16) { GPO = val; } else { GP16O = val; }}
+
+ inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
+
+ inline static void toggle() __attribute__ ((always_inline)) { if(PIN < 16) { GPO ^= MASK; } else { GP16O ^= MASK; } }
+
+ inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); }
+ inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); }
+ inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; }
+
+ inline static port_t hival() __attribute__ ((always_inline)) { if (PIN<16) { return GPO | MASK; } else { return GP16O | MASK; } }
+ inline static port_t loval() __attribute__ ((always_inline)) { if (PIN<16) { return GPO & ~MASK; } else { return GP16O & ~MASK; } }
+ inline static port_ptr_t port() __attribute__ ((always_inline)) { if(PIN<16) { return &GPO; } else { return &GP16O; } }
+ inline static port_t mask() __attribute__ ((always_inline)) { return MASK; }
+
+ inline static bool isset() __attribute__ ((always_inline)) { return (PIN < 16) ? (GPO & MASK) : (GP16O & MASK); }
+};
+
+#define _DEFPIN_ESP8266(PIN) template<> class FastPin<PIN> : public _ESPPIN<PIN, (1<<(PIN & 0xFF))> {};
+
+#define MAX_PIN 16
+_DEFPIN_ESP8266(0); _DEFPIN_ESP8266(1); _DEFPIN_ESP8266(2); _DEFPIN_ESP8266(3);
+_DEFPIN_ESP8266(4); _DEFPIN_ESP8266(5); _DEFPIN_ESP8266(6); _DEFPIN_ESP8266(7);
+_DEFPIN_ESP8266(8); _DEFPIN_ESP8266(9); _DEFPIN_ESP8266(10); _DEFPIN_ESP8266(11);
+_DEFPIN_ESP8266(12); _DEFPIN_ESP8266(13); _DEFPIN_ESP8266(14); _DEFPIN_ESP8266(15);
+_DEFPIN_ESP8266(16);
+
+#define HAS_HARDWARE_PIN_SUPPORT
+
+#define FASTLED_NAMESPACE_END
diff --git a/platforms/esp/8266/led_sysdefs_esp8266.h b/platforms/esp/8266/led_sysdefs_esp8266.h
new file mode 100644
index 00000000..382717af
--- /dev/null
+++ b/platforms/esp/8266/led_sysdefs_esp8266.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#ifndef ESP8266
+#define ESP8266
+#endif
+
+#define FASTLED_ESP8266
+
+// Use system millis timer
+#define FASTLED_HAS_MILLIS
+
+typedef volatile uint32_t RoReg;
+typedef volatile uint32_t RwReg;
+typedef uint32_t prog_uint32_t;
+typedef uint8_t boolean;
+
+// Default to NOT using PROGMEM here
+#ifndef FASTLED_USE_PROGMEM
+#define FASTLED_USE_PROGMEM 0
+#endif
+
+#ifndef FASTLED_ALLOW_INTERRUPTS
+#define FASTLED_ALLOW_INTERRUPTS 1
+#define INTERRUPT_THRESHOLD 1
+#endif
+
+#define NEED_CXX_BITS
+
+// #define cli() os_intr_lock();
+// #define sei() os_intr_lock();
diff --git a/release_notes.md b/release_notes.md
index e59d1de4..a322aa6c 100644
--- a/release_notes.md
+++ b/release_notes.md
@@ -2,6 +2,12 @@ FastLED3.1.2pre
===============
* Add SK6822 timings
+* Add ESP8266 support - note, only tested w/the arduino esp8266 build environment
+* Improvements to hsv2rgb, palette, and noise performance
+* Improvements to rgb2hsv accuracy
+* Fixed noise discontinuity
+* Add wino board support
+
FastLED3.1.1
============