diff options
author | Daniel Garcia <danielgarcia@gmail.com> | 2016-02-15 23:55:59 +0300 |
---|---|---|
committer | Daniel Garcia <danielgarcia@gmail.com> | 2016-02-15 23:55:59 +0300 |
commit | 7b83eb946723b40b5ae4b3b0dc5ac909603eb0aa (patch) | |
tree | 9d4171312c54b69c834d58f2502f769b4cec6bc6 | |
parent | bc008e867495ea36fa2d01eeb7f0851f5500e147 (diff) | |
parent | 91d79223c078de8e0c358dce0dfacd2a62e08e11 (diff) |
Merge branch 'master' of https://github.com/FastLED/FastLED
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. */ @@ -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 } } @@ -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 @@ -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 @@ -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 Binary files differdeleted file mode 100644 index d223ba7d..00000000 --- a/docs/.Doxyfile.swp +++ /dev/null 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" @@ -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 ============ |