From 7f37062fcb808ecfc7efc549343bc07508cc5876 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 19 Mar 2014 16:13:38 -0700 Subject: work in progress on parallel output --- clockless_arm_k20.h | 173 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 151 insertions(+), 22 deletions(-) diff --git a/clockless_arm_k20.h b/clockless_arm_k20.h index 59905d45..6d657064 100644 --- a/clockless_arm_k20.h +++ b/clockless_arm_k20.h @@ -14,7 +14,14 @@ class ClocklessController : public CLEDController { CMinWait mWait; public: virtual void init() { - FastPin::setOutput(); + FastPin<2>::setOutput(); + FastPin<14>::setOutput(); + FastPin<7>::setOutput(); + FastPin<8>::setOutput(); + FastPin<6>::setOutput(); + FastPin<20>::setOutput(); + FastPin<21>::setOutput(); + FastPin<25>::setOutput(); mPinMask = FastPin::mask(); mPort = FastPin::port(); } @@ -28,7 +35,14 @@ public: mWait.wait(); cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -41,7 +55,14 @@ public: mWait.wait(); cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -66,30 +87,141 @@ public: } #endif - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) { - for(register uint32_t i = BITS; i > 0; i--) { + typedef union { + uint32_t word; + struct { + uint32_t a0:1; + uint32_t a1:1; + uint32_t a2:1; + uint32_t a3:1; + uint32_t a4:1; + uint32_t a5:1; + uint32_t a6:1; + uint32_t a7:1; + uint32_t b0:1; + uint32_t b1:1; + uint32_t b2:1; + uint32_t b3:1; + uint32_t b4:1; + uint32_t b5:1; + uint32_t b6:1; + uint32_t b7:1; + uint32_t c0:1; + uint32_t c1:1; + uint32_t c2:1; + uint32_t c3:1; + uint32_t c4:1; + uint32_t c5:1; + uint32_t c6:1; + uint32_t c7:1; + uint32_t d0:1; + uint32_t d1:1; + uint32_t d2:1; + uint32_t d3:1; + uint32_t d4:1; + uint32_t d5:1; + uint32_t d6:1; + uint32_t d7:1; + }; + } xtype; + + +#define USE_LINES + typedef union { + uint8_t bytes[8]; + uint32_t raw[2]; + } Lines; + + __attribute__ ((always_inline)) inline static uint32_t bits(Lines & b) { + xtype fuckery; + fuckery.word = 0; + fuckery.a0 = (b.raw[0] >> 31); + fuckery.a1 = (b.raw[0] >> 23); + fuckery.a2 = (b.raw[0] >> 15); + fuckery.a3 = (b.raw[0] >> 7); + fuckery.a4 = (b.raw[1] >> 31); + fuckery.a5 = (b.raw[1] >> 23); + fuckery.a6 = (b.raw[1] >> 15); + fuckery.a7 = (b.raw[1] >> 7); + fuckery.b0 = (b.raw[0] >> 30); + fuckery.b1 = (b.raw[0] >> 22); + fuckery.b2 = (b.raw[0] >> 14); + fuckery.b3 = (b.raw[0] >> 6); + fuckery.b4 = (b.raw[1] >> 30); + fuckery.b5 = (b.raw[1] >> 22); + fuckery.b6 = (b.raw[1] >> 14); + fuckery.b7 = (b.raw[1] >> 6); + fuckery.c0 = (b.raw[0] >> 29); + fuckery.c1 = (b.raw[0] >> 21); + fuckery.c2 = (b.raw[0] >> 13); + fuckery.c3 = (b.raw[0] >> 5); + fuckery.c4 = (b.raw[1] >> 20); + fuckery.c5 = (b.raw[1] >> 21); + fuckery.c6 = (b.raw[1] >> 13); + fuckery.c7 = (b.raw[1] >> 5); + // fuckery.d0 = (b.raw[0] >> 28); + // fuckery.d1 = (b.raw[0] >> 19); + // fuckery.d2 = (b.raw[0] >> 12); + // fuckery.d3 = (b.raw[0] >> 4); + // fuckery.d4 = (b.raw[1] >> 28); + // fuckery.d5 = (b.raw[1] >> 19); + // fuckery.d6 = (b.raw[1] >> 12); + // fuckery.d7 = (b.raw[1] >> 4); + return fuckery.word; + } + + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[8]) { // , register uint32_t & b2) { + uint32_t flipper = bits(b); + for(register uint32_t i = 0; i < 8; i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - FastPin::fastset(port, hi); - uint32_t flip_mark = next_mark - ((b&0x80) ? (T3) : (T2+T3)); - b <<= 1; + *FastPin<2>::port() = 0xFF; + uint32_t flip_mark = next_mark - (T2+T3); + while(ARM_DWT_CYCCNT < flip_mark); - FastPin::fastset(port, lo); + uint32_t last_flip_mark = next_mark - (T3+2); + *FastPin<2>::port() = flipper; + b.raw[0] <<= 1; + b.raw[1] <<= 1; + flipper = bits(b); + + switch(PX) { + case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; + case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + } + while(ARM_DWT_CYCCNT < last_flip_mark); + *FastPin<2>::port() = 0; + switch(PX) { + case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; + case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + } + switch(PX) { + case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; + case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + } } } // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then // gcc will use register Y for the this pointer. - static void showRGBInternal(PixelController pixels) { - register data_ptr_t port = FastPin::port(); - register data_t hi = *port | FastPin::mask();; - register data_t lo = *port & ~FastPin::mask();; - *port = lo; + static void showRGBInternal(PixelController pixels, PixelController pixels2, PixelController pixels3, PixelController pixels4, + PixelController pixels5, PixelController pixels6, PixelController pixels7, PixelController pixels8) { // Setup the pixel controller and load/scale the first byte + PixelController *allpixels[8] = {&pixels,&pixels2,&pixels3,&pixels4,&pixels5,&pixels6,&pixels7,&pixels8}; pixels.preStepFirstByteDithering(); - register uint8_t b = pixels.loadAndScale0(); - + register Lines b0,b1,b2; + b0.raw[0] = b0.raw[1] = 0; + b1.raw[0] = b1.raw[1] = 0; + b2.raw[0] = b2.raw[1] = 0; + for(int i = 0; i < 8; i++) { + allpixels[i]->preStepFirstByteDithering(); + b0.bytes[i] = allpixels[i]->loadAndScale0(); + } + // Get access to the clock ARM_DEMCR |= ARM_DEMCR_TRCENA; ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; @@ -100,16 +232,13 @@ public: pixels.stepDithering(); // Write first byte, read next byte - writeBits<8+XTRA0>(next_mark, port, hi, lo, b); - b = pixels.loadAndScale1(); + writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); // Write second byte, read 3rd byte - writeBits<8+XTRA0>(next_mark, port, hi, lo, b); - b = pixels.loadAndScale2(); + writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); // Write third byte - writeBits<8+XTRA0>(next_mark, port, hi, lo, b); - b = pixels.advanceAndLoadAndScale0(); + writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); }; } }; -- cgit v1.2.3 From f5a0df8d0e69febc9d58db83ad9e13a8c677122c Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Tue, 1 Apr 2014 11:26:31 -0700 Subject: Adding block controllers for arm k20/sam clockless chips --- FastLED.h | 2 +- clockless.h | 4 +- clockless_arm_k20.h | 179 ++++------------------- clockless_block_arm_k20.h | 250 ++++++++++++++++++++++++++++++++ clockless_block_arm_sam.h | 357 ++++++++++++++++++++++++++++++++++++++++++++++ examples/Cylon/Cylon.ino | 43 ++++-- fastpin_arm_sam.h | 9 ++ lib8tion.h | 2 +- 8 files changed, 677 insertions(+), 169 deletions(-) create mode 100644 clockless_block_arm_k20.h create mode 100644 clockless_block_arm_sam.h diff --git a/FastLED.h b/FastLED.h index 6f335a1e..48cf7dd6 100644 --- a/FastLED.h +++ b/FastLED.h @@ -156,7 +156,7 @@ public: template static CLEDController &addLeds(const struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { switch(CHIPSET) { - case WS2811_PORTC: return addLeds(new BlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); + case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); } } #endif diff --git a/clockless.h b/clockless.h index b3fabbc5..5eb3d27c 100644 --- a/clockless.h +++ b/clockless.h @@ -23,6 +23,8 @@ #include "clockless_arm_k20.h" #include "clockless_arm_sam.h" #include "clockless2.h" -#include "block_clockless.h" +// #include "block_clockless.h" +#include "clockless_block_arm_sam.h" +#include "clockless_block_arm_k20.h" #endif diff --git a/clockless_arm_k20.h b/clockless_arm_k20.h index 6d657064..f58be7e5 100644 --- a/clockless_arm_k20.h +++ b/clockless_arm_k20.h @@ -4,8 +4,9 @@ // Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 // See clockless.h for detailed info on how the template parameters are used. #if defined(FASTLED_TEENSY3) -template -class ClocklessController : public CLEDController { +#define HAS_BLOCKLESS 1 +template +class InlineBlockClocklessController : public CLEDController { typedef typename FastPin::port_ptr_t data_ptr_t; typedef typename FastPin::port_t data_t; @@ -14,14 +15,7 @@ class ClocklessController : public CLEDController { CMinWait mWait; public: virtual void init() { - FastPin<2>::setOutput(); - FastPin<14>::setOutput(); - FastPin<7>::setOutput(); - FastPin<8>::setOutput(); - FastPin<6>::setOutput(); - FastPin<20>::setOutput(); - FastPin<21>::setOutput(); - FastPin<25>::setOutput(); + FastPin::setOutput(); mPinMask = FastPin::mask(); mPort = FastPin::port(); } @@ -35,14 +29,7 @@ public: mWait.wait(); cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -55,14 +42,7 @@ public: mWait.wait(); cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -87,141 +67,30 @@ public: } #endif - typedef union { - uint32_t word; - struct { - uint32_t a0:1; - uint32_t a1:1; - uint32_t a2:1; - uint32_t a3:1; - uint32_t a4:1; - uint32_t a5:1; - uint32_t a6:1; - uint32_t a7:1; - uint32_t b0:1; - uint32_t b1:1; - uint32_t b2:1; - uint32_t b3:1; - uint32_t b4:1; - uint32_t b5:1; - uint32_t b6:1; - uint32_t b7:1; - uint32_t c0:1; - uint32_t c1:1; - uint32_t c2:1; - uint32_t c3:1; - uint32_t c4:1; - uint32_t c5:1; - uint32_t c6:1; - uint32_t c7:1; - uint32_t d0:1; - uint32_t d1:1; - uint32_t d2:1; - uint32_t d3:1; - uint32_t d4:1; - uint32_t d5:1; - uint32_t d6:1; - uint32_t d7:1; - }; - } xtype; - - -#define USE_LINES - typedef union { - uint8_t bytes[8]; - uint32_t raw[2]; - } Lines; - - __attribute__ ((always_inline)) inline static uint32_t bits(Lines & b) { - xtype fuckery; - fuckery.word = 0; - fuckery.a0 = (b.raw[0] >> 31); - fuckery.a1 = (b.raw[0] >> 23); - fuckery.a2 = (b.raw[0] >> 15); - fuckery.a3 = (b.raw[0] >> 7); - fuckery.a4 = (b.raw[1] >> 31); - fuckery.a5 = (b.raw[1] >> 23); - fuckery.a6 = (b.raw[1] >> 15); - fuckery.a7 = (b.raw[1] >> 7); - fuckery.b0 = (b.raw[0] >> 30); - fuckery.b1 = (b.raw[0] >> 22); - fuckery.b2 = (b.raw[0] >> 14); - fuckery.b3 = (b.raw[0] >> 6); - fuckery.b4 = (b.raw[1] >> 30); - fuckery.b5 = (b.raw[1] >> 22); - fuckery.b6 = (b.raw[1] >> 14); - fuckery.b7 = (b.raw[1] >> 6); - fuckery.c0 = (b.raw[0] >> 29); - fuckery.c1 = (b.raw[0] >> 21); - fuckery.c2 = (b.raw[0] >> 13); - fuckery.c3 = (b.raw[0] >> 5); - fuckery.c4 = (b.raw[1] >> 20); - fuckery.c5 = (b.raw[1] >> 21); - fuckery.c6 = (b.raw[1] >> 13); - fuckery.c7 = (b.raw[1] >> 5); - // fuckery.d0 = (b.raw[0] >> 28); - // fuckery.d1 = (b.raw[0] >> 19); - // fuckery.d2 = (b.raw[0] >> 12); - // fuckery.d3 = (b.raw[0] >> 4); - // fuckery.d4 = (b.raw[1] >> 28); - // fuckery.d5 = (b.raw[1] >> 19); - // fuckery.d6 = (b.raw[1] >> 12); - // fuckery.d7 = (b.raw[1] >> 4); - return fuckery.word; - } - - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[8]) { // , register uint32_t & b2) { - uint32_t flipper = bits(b); - for(register uint32_t i = 0; i < 8; i++) { + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) { + for(register uint32_t i = BITS; i > 0; i--) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - *FastPin<2>::port() = 0xFF; - uint32_t flip_mark = next_mark - (T2+T3); - + FastPin::fastset(port, hi); + uint32_t flip_mark = next_mark - ((b&0x80) ? (T3) : (T2+T3)); + b <<= 1; while(ARM_DWT_CYCCNT < flip_mark); - uint32_t last_flip_mark = next_mark - (T3+2); - *FastPin<2>::port() = flipper; - b.raw[0] <<= 1; - b.raw[1] <<= 1; - flipper = bits(b); - - switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; - case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } - while(ARM_DWT_CYCCNT < last_flip_mark); - *FastPin<2>::port() = 0; - switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; - case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } - switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; - case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } + FastPin::fastset(port, lo); } } // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then // gcc will use register Y for the this pointer. - static void showRGBInternal(PixelController pixels, PixelController pixels2, PixelController pixels3, PixelController pixels4, - PixelController pixels5, PixelController pixels6, PixelController pixels7, PixelController pixels8) { + static void showRGBInternal(PixelController pixels) { + register data_ptr_t port = FastPin::port(); + register data_t hi = *port | FastPin::mask();; + register data_t lo = *port & ~FastPin::mask();; + *port = lo; // Setup the pixel controller and load/scale the first byte - PixelController *allpixels[8] = {&pixels,&pixels2,&pixels3,&pixels4,&pixels5,&pixels6,&pixels7,&pixels8}; pixels.preStepFirstByteDithering(); - register Lines b0,b1,b2; - b0.raw[0] = b0.raw[1] = 0; - b1.raw[0] = b1.raw[1] = 0; - b2.raw[0] = b2.raw[1] = 0; - for(int i = 0; i < 8; i++) { - allpixels[i]->preStepFirstByteDithering(); - b0.bytes[i] = allpixels[i]->loadAndScale0(); - } - + register uint8_t b = pixels.loadAndScale0(); + // Get access to the clock ARM_DEMCR |= ARM_DEMCR_TRCENA; ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; @@ -232,17 +101,19 @@ public: pixels.stepDithering(); // Write first byte, read next byte - writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); + writeBits<8+XTRA0>(next_mark, port, hi, lo, b); + b = pixels.loadAndScale1(); // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + writeBits<8+XTRA0>(next_mark, port, hi, lo, b); + b = pixels.loadAndScale2(); // Write third byte - writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + writeBits<8+XTRA0>(next_mark, port, hi, lo, b); + b = pixels.advanceAndLoadAndScale0(); }; } }; #endif #endif - diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h new file mode 100644 index 00000000..83b9b935 --- /dev/null +++ b/clockless_block_arm_k20.h @@ -0,0 +1,250 @@ +#ifndef __INC_CLOCKLESS_ARM_K20_H +#define __INC_CLOCKLESS_ARM_K20_H + +// Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 +// See clockless.h for detailed info on how the template parameters are used. +#if defined(FASTLED_TEENSY3) +#define HAS_BLOCKLESS 1 + +template +class InlineBlockClocklessController : public CLEDController { + typedef typename FastPin<2>::port_ptr_t data_ptr_t; + typedef typename FastPin<2>::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait mWait; +public: + virtual void init() { + FastPin<2>::setOutput(); + FastPin<14>::setOutput(); + FastPin<7>::setOutput(); + FastPin<8>::setOutput(); + FastPin<6>::setOutput(); + FastPin<20>::setOutput(); + FastPin<21>::setOutput(); + FastPin<25>::setOutput(); + mPinMask = FastPin::mask(); + mPort = FastPin::port(); + } + + 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) { + mWait.wait(); + cli(); + + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); + + // Adjust the timer + long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + MS_COUNTER += (microsTaken / 1000); + sei(); + mWait.mark(); + } + + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + mWait.wait(); + cli(); + + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); + + // Adjust the timer + long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + MS_COUNTER += (microsTaken / 1000); + sei(); + mWait.mark(); + } + +#ifdef SUPPORT_ARGB + virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { + mWait.wait(); + cli(); + + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); + + + // Adjust the timer + long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + MS_COUNTER += (microsTaken / 1000); + sei(); + mWait.mark(); + } +#endif + + typedef union { + uint32_t word; + struct { + uint32_t a0:1; + uint32_t a1:1; + uint32_t a2:1; + uint32_t a3:1; + uint32_t a4:1; + uint32_t a5:1; + uint32_t a6:1; + uint32_t a7:1; + uint32_t b0:1; + uint32_t b1:1; + uint32_t b2:1; + uint32_t b3:1; + uint32_t b4:1; + uint32_t b5:1; + uint32_t b6:1; + uint32_t b7:1; + uint32_t c0:1; + uint32_t c1:1; + uint32_t c2:1; + uint32_t c3:1; + uint32_t c4:1; + uint32_t c5:1; + uint32_t c6:1; + uint32_t c7:1; + uint32_t d0:1; + uint32_t d1:1; + uint32_t d2:1; + uint32_t d3:1; + uint32_t d4:1; + uint32_t d5:1; + uint32_t d6:1; + uint32_t d7:1; + }; + } xtype; + + +#define USE_LINES + typedef union { + uint8_t bytes[8]; + uint32_t raw[2]; + } Lines; + + __attribute__ ((always_inline)) inline static uint32_t bits(Lines & b) { + xtype fuckery; + fuckery.word = 0; + fuckery.a0 = (b.raw[0] >> 31); + fuckery.a1 = (b.raw[0] >> 23); + fuckery.a2 = (b.raw[0] >> 15); + fuckery.a3 = (b.raw[0] >> 7); + fuckery.a4 = (b.raw[1] >> 31); + fuckery.a5 = (b.raw[1] >> 23); + fuckery.a6 = (b.raw[1] >> 15); + fuckery.a7 = (b.raw[1] >> 7); + // fuckery.b0 = (b.raw[2] >> 30); + // fuckery.b1 = (b.raw[2] >> 22); + // fuckery.b2 = (b.raw[2] >> 14); + // fuckery.b3 = (b.raw[2] >> 6); + // fuckery.b4 = (b.raw[3] >> 30); + // fuckery.b5 = (b.raw[3] >> 22) + // fuckery.b6 = (b.raw[3] >> 14); + // fuckery.b7 = (b.raw[3] >> 6); + // fuckery.c0 = (b.raw[4] >> 29); + // fuckery.c1 = (b.raw[4] >> 21); + // fuckery.c2 = (b.raw[4] >> 13); + // fuckery.c3 = (b.raw[4] >> 5); + // fuckery.c4 = (b.raw[5] >> 20); + // fuckery.c5 = (b.raw[5] >> 21); + // fuckery.c6 = (b.raw[5] >> 13); + // fuckery.c7 = (b.raw[5] >> 5); + // fuckery.d0 = (b.raw[6] >> 28); + // fuckery.d1 = (b.raw[6] >> 19); + // fuckery.d2 = (b.raw[6] >> 12); + // fuckery.d3 = (b.raw[6] >> 4); + // fuckery.d4 = (b.raw[7] >> 28); + // fuckery.d5 = (b.raw[7] >> 19); + // fuckery.d6 = (b.raw[7] >> 12); + // fuckery.d7 = (b.raw[7] >> 4); + return fuckery.word; + } + + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[8]) { // , register uint32_t & b2) { + uint32_t flipper = bits(b); + for(register uint32_t i = 0; i < 8; i++) { + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + *FastPin<2>::port() = 0xFF; + uint32_t flip_mark = next_mark - (T2+T3); + + while(ARM_DWT_CYCCNT < flip_mark); + uint32_t last_flip_mark = next_mark - (T3+2); + *FastPin<2>::port() = flipper; + b.raw[0] <<= 1; + b.raw[1] <<= 1; + flipper = bits(b); + + // switch(PX) { + // case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; + // case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + // case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + // } + while(ARM_DWT_CYCCNT < last_flip_mark); + *FastPin<2>::port() = 0; + // switch(PX) { + // case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; + // case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + // case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + // } + switch(PX) { + case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; + case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + } + } + } + + // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then + // gcc will use register Y for the this pointer. + static void showRGBInternal(PixelController pixels, PixelController pixels2, PixelController pixels3, PixelController pixels4, + PixelController pixels5, PixelController pixels6, PixelController pixels7, PixelController pixels8) { + + // Setup the pixel controller and load/scale the first byte + PixelController *allpixels[8] = {&pixels,&pixels2,&pixels3,&pixels4,&pixels5,&pixels6,&pixels7,&pixels8}; + pixels.preStepFirstByteDithering(); + register Lines b0,b1,b2; + b0.raw[0] = b0.raw[1] = 0; + b1.raw[0] = b1.raw[1] = 0; + b2.raw[0] = b2.raw[1] = 0; + for(int i = 0; i < 8; i++) { + allpixels[i]->preStepFirstByteDithering(); + b0.bytes[i] = allpixels[i]->loadAndScale0(); + } + + // Get access to the clock + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + ARM_DWT_CYCCNT = 0; + uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + + while(pixels.has(1)) { + pixels.stepDithering(); + + // Write first byte, read next byte + writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); + + // Write second byte, read 3rd byte + writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + + // Write third byte + writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + }; + } +}; +#endif + +#endif + diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h new file mode 100644 index 00000000..1fc61b8a --- /dev/null +++ b/clockless_block_arm_sam.h @@ -0,0 +1,357 @@ + #ifndef __INC_BLOCK_CLOCKLESS_H +#define __INC_BLOCK_CLOCKLESS_H + +#include "controller.h" +#include "lib8tion.h" +#include "led_sysdefs.h" +#include "delay.h" + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point +// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the +// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define PORT_MASK 0x77EFF3FE +#define SKIPLIST ~PORT_MASK + +#if defined(__SAM3X8E__) +#define HAS_BLOCKLESS 1 +#define LANES 16 + +#define TADJUST 0 +#define TOTAL ( (T1+TADJUST) + (T2+TADJUST) + (T3+TADJUST) ) +#define T1_MARK (TOTAL - (T1+TADJUST)) +#define T2_MARK (T1_MARK - (T2+TADJUST)) +template +class InlineBlockClocklessController : public CLEDController { + typedef typename FastPin<33>::port_ptr_t data_ptr_t; + typedef typename FastPin<33>::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait mWait; +public: + virtual void init() { + //FastPinBB::setOutput(); + uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 72, 106, 0 }; + int i = 0; + while(pins[i]) { pinMode(pins[i++], OUTPUT); } + } + + 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 px1(rgbdata, nLeds, scale, getDither()); + PixelController px2(rgbdata, nLeds, scale, getDither()); + PixelController px3(rgbdata, nLeds, scale, getDither()); + PixelController px4(rgbdata, nLeds, scale, getDither()); + PixelController px5(rgbdata, nLeds, scale, getDither()); + PixelController px6(rgbdata, nLeds, scale, getDither()); + PixelController px7(rgbdata, nLeds, scale, getDither()); + PixelController px8(rgbdata, nLeds, scale, getDither()); +#if (LANES > 8) + PixelController px9(rgbdata, nLeds, scale, getDither()); + PixelController px10(rgbdata, nLeds, scale, getDither()); + PixelController px11(rgbdata, nLeds, scale, getDither()); + PixelController px12(rgbdata, nLeds, scale, getDither()); + PixelController px13(rgbdata, nLeds, scale, getDither()); + PixelController px14(rgbdata, nLeds, scale, getDither()); + PixelController px15(rgbdata, nLeds, scale, getDither()); + PixelController px16(rgbdata, nLeds, scale, getDither()); +#if (LANES > 16) + PixelController px17(rgbdata, nLeds, scale, getDither()); + PixelController px18(rgbdata, nLeds, scale, getDither()); + PixelController px19(rgbdata, nLeds, scale, getDither()); + PixelController px20(rgbdata, nLeds, scale, getDither()); + PixelController px21(rgbdata, nLeds, scale, getDither()); + PixelController px22(rgbdata, nLeds, scale, getDither()); + PixelController px23(rgbdata, nLeds, scale, getDither()); + PixelController px24(rgbdata, nLeds, scale, getDither()); +#endif +#endif + + PixelController *allpixels[LANES] = { + &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 +#if (LANES > 8) + ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 +#if (LANES > 16) + , &px17, &px18, &px19, &px20, &px21, &px22, &px23, &px24 +#endif +#endif + }; + + mWait.wait(); + cli(); + SysClockSaver savedClock(TOTAL); + + showRGBInternal(allpixels, nLeds); + + long microsTaken = nLeds * CLKS_TO_MICROS(24 * (TOTAL)); + long millisTaken = (microsTaken / 1000); + savedClock.restore(); + do { TimeTick_Increment(); } while(--millisTaken > 0); + sei(); + mWait.mark(); + } + +// #define ADV_RGB rgbdata += nLeds; +// #define ADV_RGB +#define ADV_RGB rgbdata += nLeds; + + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + PixelController px1(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px2(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px3(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px4(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px5(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px6(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px7(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px8(rgbdata, nLeds, scale, getDither()); ADV_RGB +#if LANES > 8 + PixelController px9(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px10(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px11(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px12(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px13(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px14(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px15(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px16(rgbdata, nLeds, scale, getDither()); ADV_RGB +#if LANES > 16 + PixelController px17(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px18(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px19(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px20(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px21(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px22(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px23(rgbdata, nLeds, scale, getDither()); ADV_RGB + PixelController px24(rgbdata, nLeds, scale, getDither()); ADV_RGB +#endif +#endif + + PixelController *allpixels[LANES] = { + &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 +#if LANES > 8 + ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 +#if LANES > 16 + , &px17, &px18, &px19, &px20, &px21, &px22, &px23, &px24 +#endif +#endif + }; + + mWait.wait(); + cli(); + SysClockSaver savedClock(TOTAL); + + showRGBInternal(allpixels,nLeds); + + + long microsTaken = nLeds * CLKS_TO_MICROS(24 * (TOTAL)); + long millisTaken = (microsTaken / 1000); + savedClock.restore(); + do { TimeTick_Increment(); } while(--millisTaken > 0); + sei(); + // Adjust the timer + // long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + // MS_COUNTER += (microsTaken / 1000); + // sei(); + mWait.mark(); + } + +#ifdef SUPPORT_ARGB + virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { + mWait.wait(); + cli(); + + showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); + + + // Adjust the timer + long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + MS_COUNTER += (microsTaken / 1000); + sei(); + mWait.mark(); + } +#endif + + typedef union { + uint32_t word; + struct { + uint32_t a0:1; + uint32_t a1:1; + uint32_t a2:1; + uint32_t a3:1; + uint32_t a4:1; + uint32_t a5:1; + uint32_t a6:1; + uint32_t a7:1; + uint32_t b0:1; + uint32_t b1:1; + uint32_t b2:1; + uint32_t b3:1; + uint32_t b4:1; + uint32_t b5:1; + uint32_t b6:1; + uint32_t b7:1; + uint32_t c0:1; + uint32_t c1:1; + uint32_t c2:1; + uint32_t c3:1; + uint32_t c4:1; + uint32_t c5:1; + uint32_t c6:1; + uint32_t c7:1; + uint32_t d0:1; + uint32_t d1:1; + uint32_t d2:1; + uint32_t d3:1; + uint32_t d4:1; + uint32_t d5:1; + uint32_t d6:1; + uint32_t d7:1; + }; + } xtype; + + + typedef union { + uint8_t bytes[LANES]; + uint64_t raw[LANES/4]; + } Lines; + +// #define IFSKIP(N,X) if(PORT_MASK & 1<> 31); + fuckery.a1 = (b.raw[0] >> 23); + fuckery.a2 = (b.raw[0] >> 15); + fuckery.a3 = (b.raw[0] >> 7); + b.raw[0] <<= 1; + fuckery.a4 = (b.raw[1] >> 31); + fuckery.a5 = (b.raw[1] >> 23); + fuckery.a6 = (b.raw[1] >> 15); + fuckery.a7 = (b.raw[1] >> 7); + b.raw[1] <<= 1; +#if (LANES > 8) + fuckery.b0 = (b.raw[2] >> 31); + fuckery.b1 = (b.raw[2] >> 23); + fuckery.b2 = (b.raw[2] >> 15); + fuckery.b3 = (b.raw[2] >> 7); + b.raw[2] <<= 1; + fuckery.b4 = (b.raw[3] >> 31); + fuckery.b5 = (b.raw[3] >> 23); + fuckery.b6 = (b.raw[3] >> 15); + fuckery.b7 = (b.raw[3] >> 7); + b.raw[3] <<= 1; +#if (LANES > 16) + fuckery.c0 = (b.raw[4] >> 31); + fuckery.c1 = (b.raw[4] >> 23); + fuckery.c2 = (b.raw[4] >> 15); + fuckery.c3 = (b.raw[4] >> 7); + fuckery.c4 = (b.raw[5] >> 31); + fuckery.c5 = (b.raw[5] >> 23); + fuckery.c6 = (b.raw[5] >> 15); + fuckery.c7 = (b.raw[5] >> 7); +#if (LANES > 24) + fuckery.d0 = (b.raw[6] >> 31); + fuckery.d1 = (b.raw[6] >> 23); + fuckery.d2 = (b.raw[6] >> 15); + fuckery.d3 = (b.raw[6] >> 7); + fuckery.d4 = (b.raw[7] >> 31); + fuckery.d5 = (b.raw[7] >> 23); + fuckery.d6 = (b.raw[7] >> 15); + fuckery.d7 = (b.raw[7] >> 7); +#endif +#endif +#endif + return fuckery.word; + } + +#define VAL *((uint32_t*)(SysTick_BASE + 8)) + + template __attribute__ ((always_inline)) inline static void writeBits(register volatile uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[LANES]) { // , register uint32_t & b2) { + uint32_t flipper = bits(b); + // Serial.print("flipper is "); Serial.println(flipper); + for(uint32_t i = 0; i < LANES; i++) { + while(VAL > next_mark); + + next_mark = VAL - (T1+T2+T3+6); + *FastPin<33>::port() = 0xFFFFFFFFL; + uint32_t flip_mark = next_mark + (T2+T3+3); + + while(VAL > flip_mark); + *FastPin<33>::port() = flipper; + flip_mark = next_mark + (T3); + flipper = bits(b); + +#if (LANES > 8) + switch(PX) { + case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; + case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + } + i++; +#endif + + while(VAL > flip_mark); + *FastPin<33>::port() = 0L; + switch(PX) { + case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; + case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; + case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; + } + } + + // for(register uint32_t i = 0; i < XTRA0; i++) { + // AT_BIT_START(*FastPin<33>::port() = 0xFFFF); + // AT_MARK(*FastPin<33>::port() = 0); + // AT_END(*FastPin<2>::port() = 0); + // } + } + + // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then + // gcc will use register Y for the this pointer. + static void showRGBInternal(PixelController *allpixels[LANES], int nLeds) { + // Serial.println("Entering show"); + // Setup the pixel controller and load/scale the first byte + Lines b0,b1,b2; + for(int i = 0; i < LANES/4; i++) { + b0.raw[i] = b1.raw[i] = b2.raw[i] = 0; + } + for(int i = 0; i < LANES; i++) { + allpixels[i]->preStepFirstByteDithering(); + b0.bytes[i] = allpixels[i]->loadAndScale0(); + } + + // Setup and start the clock + register volatile uint32_t *CTPTR asm("r6")= &SysTick->CTRL; FORCE_REFERENCE(CTPTR); + _LOAD = 0x00FFFFFF; + _VAL = 0; + _CTRL |= SysTick_CTRL_CLKSOURCE_Msk; + _CTRL |= SysTick_CTRL_ENABLE_Msk; + + VAL = 0; + uint32_t next_mark = (VAL - (TOTAL)); + while(nLeds--) { + // Write first byte, read next byte + writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); + + // Write second byte, read 3rd byte + writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + + // Write third byte + writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + } + } + + +}; + +#endif + +#endif \ No newline at end of file diff --git a/examples/Cylon/Cylon.ino b/examples/Cylon/Cylon.ino index dfb6ed78..ea102095 100644 --- a/examples/Cylon/Cylon.ino +++ b/examples/Cylon/Cylon.ino @@ -1,7 +1,7 @@ #include "FastLED.h" // How many leds in your strip? -#define NUM_LEDS 40 +#define NUM_LEDS 64 // For led chips like Neopixels, which have a data line, ground, and power, you just // need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock, @@ -10,34 +10,53 @@ #define CLOCK_PIN 13 // Define the array of leds -CRGB leds[NUM_LEDS]; +CRGB leds[(NUM_LEDS * 16)+1]; void setup() { - FastLED.addLeds(leds, NUM_LEDS); + Serial.begin(19200); + delay(3000); + Serial.println("resetting"); + delay(500); Serial.print("."); + delay(500); Serial.print("."); + delay(500); Serial.print("."); + delay(500); Serial.print("."); + delay(500); Serial.print("."); + delay(500); Serial.print("."); + delay(500); Serial.print("."); + delay(500); Serial.print("."); + LEDS.addLeds(leds, NUM_LEDS); // .setDither(DISABLE_DITHER); + // LEDS.addLeds(leds,NUM_LEDS); + Serial.println("Entering loopx"); } +void fadeall() { for(int i = 0; i < NUM_LEDS*16; i++) { leds[i].nscale8(250); } } + void loop() { + uint8_t hue = 0; + // Serial.print("x"); // First slide the led in one direction - for(int i = 0; i < NUM_LEDS; i++) { + for(int i = 0; i < NUM_LEDS*5; i++) { // Set the i'th led to red - leds[i] = CRGB::Red; + leds[i] = CHSV(hue++, 255, 255); // Show the leds - FastLED.show(); + FastLED.show(); // now that we've shown the leds, reset the i'th led to black - leds[i] = CRGB::Black; + // leds[i] = CRGB::Black; + fadeall(); // Wait a little bit before we loop around and do it again - delay(30); + delay(10); } // Now go in the other direction. - for(int i = NUM_LEDS-1; i >= 0; i--) { + for(int i = (NUM_LEDS*5)-1; i >= 0; i--) { // Set the i'th led to red - leds[i] = CRGB::Red; + leds[i] = CHSV(hue++, 255, 255); // Show the leds FastLED.show(); // now that we've shown the leds, reset the i'th led to black - leds[i] = CRGB::Black; + // leds[i] = CRGB::Black; + fadeall(); // Wait a little bit before we loop around and do it again - delay(30); + delay(10); } } diff --git a/fastpin_arm_sam.h b/fastpin_arm_sam.h index 164754c8..8a5c8730 100644 --- a/fastpin_arm_sam.h +++ b/fastpin_arm_sam.h @@ -28,6 +28,7 @@ public: inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } + inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } }; @@ -96,6 +97,14 @@ _DEFPIN_DUE(68, 1, A); _DEFPIN_DUE(69, 0, A); _DEFPIN_DUE(70, 17, A); _DEFPIN_DU _DEFPIN_DUE(72, 30, C); _DEFPIN_DUE(73, 21, A); _DEFPIN_DUE(74, 25, A); _DEFPIN_DUE(75, 26, A); _DEFPIN_DUE(76, 27, A); _DEFPIN_DUE(77, 28, A); _DEFPIN_DUE(78, 23, B); +// digix pins +_DEFPIN_DUE(90, 0, B); _DEFPIN_DUE(91, 1, B); _DEFPIN_DUE(92, 2, B); _DEFPIN_DUE(93, 3, B); +_DEFPIN_DUE(94, 4, B); _DEFPIN_DUE(95, 5, B); _DEFPIN_DUE(96, 6, B); _DEFPIN_DUE(97, 7, B); +_DEFPIN_DUE(98, 8, B); _DEFPIN_DUE(99, 9, B); _DEFPIN_DUE(100, 5, A); _DEFPIN_DUE(101, 22, B); +_DEFPIN_DUE(102, 23, B); _DEFPIN_DUE(103, 24, B); _DEFPIN_DUE(104, 27, C); _DEFPIN_DUE(105, 20, C); +_DEFPIN_DUE(106, 11, C); _DEFPIN_DUE(107, 10, C); _DEFPIN_DUE(108, 21, A); _DEFPIN_DUE(109, 30, C); +_DEFPIN_DUE(110, 29, B); _DEFPIN_DUE(111, 30, B); _DEFPIN_DUE(112, 31, B); _DEFPIN_DUE(113, 28, B); + #define SPI_DATA 75 #define SPI_CLOCK 76 #define ARM_HARDWARE_SPI diff --git a/lib8tion.h b/lib8tion.h index a2e70fe4..1e9dd614 100644 --- a/lib8tion.h +++ b/lib8tion.h @@ -303,7 +303,7 @@ typedef union { LIB8STATIC uint8_t qadd8( uint8_t i, uint8_t j) { #if QADD8_C == 1 - int t = i + j; + unsigned int t = i + j; if( t > 255) t = 255; return t; #elif QADD8_AVRASM == 1 -- cgit v1.2.3 From 3eb3483ed9e63e142b44fef79ca3d637c6fc590b Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 2 Apr 2014 04:11:33 -0700 Subject: Give up on the dream of 24-way parallel output on the due, at least until we can figure out how to overclock the fscker. --- FastLED.h | 2 +- clockless_block_arm_sam.h | 107 +++++++++++++++------------------------------- fastpin_arm_sam.h | 1 + 3 files changed, 37 insertions(+), 73 deletions(-) diff --git a/FastLED.h b/FastLED.h index 346785b8..ef56605c 100644 --- a/FastLED.h +++ b/FastLED.h @@ -156,7 +156,7 @@ public: template static CLEDController &addLeds(const struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { switch(CHIPSET) { - case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); + case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); } } #endif diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 1fc61b8a..a600da69 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -55,7 +55,6 @@ public: PixelController px6(rgbdata, nLeds, scale, getDither()); PixelController px7(rgbdata, nLeds, scale, getDither()); PixelController px8(rgbdata, nLeds, scale, getDither()); -#if (LANES > 8) PixelController px9(rgbdata, nLeds, scale, getDither()); PixelController px10(rgbdata, nLeds, scale, getDither()); PixelController px11(rgbdata, nLeds, scale, getDither()); @@ -64,26 +63,10 @@ public: PixelController px14(rgbdata, nLeds, scale, getDither()); PixelController px15(rgbdata, nLeds, scale, getDither()); PixelController px16(rgbdata, nLeds, scale, getDither()); -#if (LANES > 16) - PixelController px17(rgbdata, nLeds, scale, getDither()); - PixelController px18(rgbdata, nLeds, scale, getDither()); - PixelController px19(rgbdata, nLeds, scale, getDither()); - PixelController px20(rgbdata, nLeds, scale, getDither()); - PixelController px21(rgbdata, nLeds, scale, getDither()); - PixelController px22(rgbdata, nLeds, scale, getDither()); - PixelController px23(rgbdata, nLeds, scale, getDither()); - PixelController px24(rgbdata, nLeds, scale, getDither()); -#endif -#endif PixelController *allpixels[LANES] = { &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 -#if (LANES > 8) ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 -#if (LANES > 16) - , &px17, &px18, &px19, &px20, &px21, &px22, &px23, &px24 -#endif -#endif }; mWait.wait(); @@ -100,11 +83,11 @@ public: mWait.mark(); } -// #define ADV_RGB rgbdata += nLeds; // #define ADV_RGB -#define ADV_RGB rgbdata += nLeds; +#define ADV_RGB if(maskbit & PORT_MASK) { rgbdata += nLeds; } maskbit <<= 1; virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + uint32_t maskbit = 0x00001; PixelController px1(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px2(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px3(rgbdata, nLeds, scale, getDither()); ADV_RGB @@ -113,7 +96,6 @@ public: PixelController px6(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px7(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px8(rgbdata, nLeds, scale, getDither()); ADV_RGB -#if LANES > 8 PixelController px9(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px10(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px11(rgbdata, nLeds, scale, getDither()); ADV_RGB @@ -122,26 +104,10 @@ public: PixelController px14(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px15(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px16(rgbdata, nLeds, scale, getDither()); ADV_RGB -#if LANES > 16 - PixelController px17(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px18(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px19(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px20(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px21(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px22(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px23(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px24(rgbdata, nLeds, scale, getDither()); ADV_RGB -#endif -#endif PixelController *allpixels[LANES] = { &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 -#if LANES > 8 ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 -#if LANES > 16 - , &px17, &px18, &px19, &px20, &px21, &px22, &px23, &px24 -#endif -#endif }; mWait.wait(); @@ -220,7 +186,7 @@ public: typedef union { uint8_t bytes[LANES]; - uint64_t raw[LANES/4]; + uint32_t raw[LANES/4]; } Lines; // #define IFSKIP(N,X) if(PORT_MASK & 1<> 15); fuckery.a7 = (b.raw[1] >> 7); b.raw[1] <<= 1; -#if (LANES > 8) fuckery.b0 = (b.raw[2] >> 31); fuckery.b1 = (b.raw[2] >> 23); fuckery.b2 = (b.raw[2] >> 15); @@ -248,28 +213,29 @@ public: fuckery.b6 = (b.raw[3] >> 15); fuckery.b7 = (b.raw[3] >> 7); b.raw[3] <<= 1; -#if (LANES > 16) - fuckery.c0 = (b.raw[4] >> 31); - fuckery.c1 = (b.raw[4] >> 23); - fuckery.c2 = (b.raw[4] >> 15); - fuckery.c3 = (b.raw[4] >> 7); - fuckery.c4 = (b.raw[5] >> 31); - fuckery.c5 = (b.raw[5] >> 23); - fuckery.c6 = (b.raw[5] >> 15); - fuckery.c7 = (b.raw[5] >> 7); -#if (LANES > 24) - fuckery.d0 = (b.raw[6] >> 31); - fuckery.d1 = (b.raw[6] >> 23); - fuckery.d2 = (b.raw[6] >> 15); - fuckery.d3 = (b.raw[6] >> 7); - fuckery.d4 = (b.raw[7] >> 31); - fuckery.d5 = (b.raw[7] >> 23); - fuckery.d6 = (b.raw[7] >> 15); - fuckery.d7 = (b.raw[7] >> 7); -#endif -#endif -#endif - return fuckery.word; +// #if (LANES > 16) +// fuckery.c0 = (b.raw[4] >> 31); +// fuckery.c1 = (b.raw[4] >> 23); +// fuckery.c2 = (b.raw[4] >> 15); +// fuckery.c3 = (b.raw[4] >> 7); +// b.raw[4] <<= 1; +// fuckery.c4 = (b.raw[5] >> 31); +// fuckery.c5 = (b.raw[5] >> 23); +// fuckery.c6 = (b.raw[5] >> 15); +// fuckery.c7 = (b.raw[5] >> 7); +// b.raw[5] <<= 1; +// #if (LANES > 24) +// fuckery.d0 = (b.raw[6] >> 31); +// fuckery.d1 = (b.raw[6] >> 23); +// fuckery.d2 = (b.raw[6] >> 15); +// fuckery.d3 = (b.raw[6] >> 7); +// fuckery.d4 = (b.raw[7] >> 31); +// fuckery.d5 = (b.raw[7] >> 23); +// fuckery.d6 = (b.raw[7] >> 15); +// fuckery.d7 = (b.raw[7] >> 7); +// #endif +// #endif + return ~fuckery.word; } #define VAL *((uint32_t*)(SysTick_BASE + 8)) @@ -280,31 +246,28 @@ public: for(uint32_t i = 0; i < LANES; i++) { while(VAL > next_mark); - next_mark = VAL - (T1+T2+T3+6); - *FastPin<33>::port() = 0xFFFFFFFFL; - uint32_t flip_mark = next_mark + (T2+T3+3); + next_mark = VAL - (TOTAL); + *FastPin<33>::sport() = PORT_MASK; - while(VAL > flip_mark); - *FastPin<33>::port() = flipper; - flip_mark = next_mark + (T3); + while((VAL-next_mark) > (T2+T3+3)); + *FastPin<33>::cport() = (flipper & PORT_MASK); flipper = bits(b); -#if (LANES > 8) + + while((VAL - next_mark) > T3); + *FastPin<33>::cport() = PORT_MASK; + switch(PX) { case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; } i++; -#endif - - while(VAL > flip_mark); - *FastPin<33>::port() = 0L; switch(PX) { case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } + } } // for(register uint32_t i = 0; i < XTRA0; i++) { diff --git a/fastpin_arm_sam.h b/fastpin_arm_sam.h index 8a5c8730..0296bd50 100644 --- a/fastpin_arm_sam.h +++ b/fastpin_arm_sam.h @@ -28,6 +28,7 @@ public: inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } + inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } }; -- cgit v1.2.3 From 5d8d7e8644d03cc2a6059b42edd89c28315e3881 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 2 Apr 2014 18:37:53 -0700 Subject: Getting rid of noise --- clockless.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/clockless.h b/clockless.h index 5eb3d27c..896cf046 100644 --- a/clockless.h +++ b/clockless.h @@ -22,8 +22,6 @@ #include "clockless_trinket.h" #include "clockless_arm_k20.h" #include "clockless_arm_sam.h" -#include "clockless2.h" -// #include "block_clockless.h" #include "clockless_block_arm_sam.h" #include "clockless_block_arm_k20.h" -- cgit v1.2.3 From 7a71fa5ea17c0eaea8edb9f00dfbf2597718f3c6 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 4 Apr 2014 18:06:49 -0700 Subject: Fix k20 blockless --- FastLED.h | 4 ++-- clockless_arm_k20.h | 6 +++--- clockless_block_arm_k20.h | 26 +++++++++++++------------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/FastLED.h b/FastLED.h index ef56605c..a43c795f 100644 --- a/FastLED.h +++ b/FastLED.h @@ -152,14 +152,14 @@ public: } #endif -#ifdef HAS_BLOCKLESS +// #ifdef HAS_BLOCKLESS template static CLEDController &addLeds(const struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { switch(CHIPSET) { case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); } } -#endif +// #endif void setBrightness(uint8_t scale) { m_Scale = scale; } uint8_t getBrightness() { return m_Scale; } diff --git a/clockless_arm_k20.h b/clockless_arm_k20.h index c66db7ca..a54a61e7 100644 --- a/clockless_arm_k20.h +++ b/clockless_arm_k20.h @@ -4,9 +4,9 @@ // Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 // See clockless.h for detailed info on how the template parameters are used. #if defined(FASTLED_TEENSY3) -#define HAS_BLOCKLESS 1 -template -class InlineBlockClocklessController : public CLEDController { + +template +class ClocklessController : public CLEDController { typedef typename FastPin::port_ptr_t data_ptr_t; typedef typename FastPin::port_t data_t; diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 83b9b935..b953aa2d 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -1,9 +1,9 @@ -#ifndef __INC_CLOCKLESS_ARM_K20_H -#define __INC_CLOCKLESS_ARM_K20_H +#ifndef __INC_BLOCK_CLOCKLESS_ARM_K20_H +#define __INC_BLOCK_CLOCKLESS_ARM_K20_H // Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 // See clockless.h for detailed info on how the template parameters are used. -#if defined(FASTLED_TEENSY3) +#if 1 || defined(FASTLED_TEENSY3) #define HAS_BLOCKLESS 1 template @@ -24,8 +24,8 @@ public: FastPin<20>::setOutput(); FastPin<21>::setOutput(); FastPin<25>::setOutput(); - mPinMask = FastPin::mask(); - mPort = FastPin::port(); + mPinMask = FastPin<2>::mask(); + mPort = FastPin<2>::port(); } virtual void clearLeds(int nLeds) { @@ -58,13 +58,13 @@ public: cli(); showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); + PixelController(rgbdata/**/+(1*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/**/+(2*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/**/+(3*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/**/+(4*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/**/+(5*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/**/+(6*nLeds)/**/, nLeds, scale, getDither()), + PixelController(rgbdata/**/+(7*nLeds)/**/, nLeds, scale, getDither())); // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -200,7 +200,7 @@ public: // case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; // } switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; + case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; } -- cgit v1.2.3 From 167c579c92c6128968159e9b282f6c6e5e520df3 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 7 Apr 2014 20:41:00 -0700 Subject: Cleaning up k20 block timings --- clockless_block_arm_k20.h | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index b953aa2d..000c0275 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -3,7 +3,7 @@ // Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 // See clockless.h for detailed info on how the template parameters are used. -#if 1 || defined(FASTLED_TEENSY3) +#if defined(FASTLED_TEENSY3) #define HAS_BLOCKLESS 1 template @@ -187,20 +187,11 @@ public: b.raw[1] <<= 1; flipper = bits(b); - // switch(PX) { - // case 0: b2.bytes[i] = allpixels[i]->loadAndScale0(); break; - // case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - // case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - // } + while(ARM_DWT_CYCCNT < last_flip_mark); *FastPin<2>::port() = 0; - // switch(PX) { - // case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; - // case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - // case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - // } switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; + case 0: b2.bytes[i] = allpixels[i]->advanceAndLoadAndScale0(); break; case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; } -- cgit v1.2.3 From ea065f8760bbececa515de6f8fd0ea97a2b8f00b Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 10 Apr 2014 23:27:53 -0700 Subject: Make things work on the due again for multi-lane, fix timing reporting on due for both clockless and block --- clockless_arm_sam.h | 8 ++++---- clockless_block_arm_sam.h | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h index 3a7cb108..4781fc96 100644 --- a/clockless_arm_sam.h +++ b/clockless_arm_sam.h @@ -41,10 +41,10 @@ public: cli(); SysClockSaver savedClock(TOTAL); - showRGBInternal(pixels); + uint32_t clocks = showRGBInternal(pixels); // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (TOTAL)); + long microsTaken = nLeds * CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); savedClock.restore(); do { TimeTick_Increment(); } while(--millisTaken > 0); @@ -66,7 +66,7 @@ public: uint32_t clocks = showRGBInternal(pixels); // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(clocks); + long microsTaken = CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); savedClock.restore(); do { TimeTick_Increment(); } while(--millisTaken > 0); @@ -84,7 +84,7 @@ public: uint32_t clocks = showRGBInternal(pixels); // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(clocks); + long microsTaken = CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); savedClock.restore(); do { TimeTick_Increment(); } while(--millisTaken > 0); diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index a600da69..ab85b76c 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -36,7 +36,7 @@ class InlineBlockClocklessController : public CLEDController { public: virtual void init() { //FastPinBB::setOutput(); - uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 72, 106, 0 }; + uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 0}; // 72, 106, 0 }; int i = 0; while(pins[i]) { pinMode(pins[i++], OUTPUT); } } @@ -73,12 +73,12 @@ public: cli(); SysClockSaver savedClock(TOTAL); - showRGBInternal(allpixels, nLeds); + uint32_t clocks = showRGBInternal(allpixels, nLeds); - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (TOTAL)); + long microsTaken = CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); savedClock.restore(); - do { TimeTick_Increment(); } while(--millisTaken > 0); + while(millisTaken-- > 0) { TimeTick_Increment(); } sei(); mWait.mark(); } @@ -114,13 +114,13 @@ public: cli(); SysClockSaver savedClock(TOTAL); - showRGBInternal(allpixels,nLeds); + uint32_t clocks = showRGBInternal(allpixels,nLeds); - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (TOTAL)); + long microsTaken = CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); savedClock.restore(); - do { TimeTick_Increment(); } while(--millisTaken > 0); + while(millisTaken-- > 0) { TimeTick_Increment(); } sei(); // Adjust the timer // long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -279,7 +279,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 void showRGBInternal(PixelController *allpixels[LANES], int nLeds) { + static uint32_t showRGBInternal(PixelController *allpixels[LANES], int nLeds) { // Serial.println("Entering show"); // Setup the pixel controller and load/scale the first byte Lines b0,b1,b2; @@ -310,6 +310,8 @@ public: // Write third byte writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); } + + return 0x00FFFFFF - _VAL; } -- cgit v1.2.3 From fac270fc7dc74ca8f5c669e1b871b1b6676fc1e6 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 21 Apr 2014 21:17:53 -0700 Subject: Tweaking K20 block timing --- clockless_block_arm_k20.h | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 000c0275..1bfae31a 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -15,7 +15,7 @@ class InlineBlockClocklessController : public CLEDController { data_ptr_t mPort; CMinWait mWait; public: - virtual void init() { + virtual void init() { FastPin<2>::setOutput(); FastPin<14>::setOutput(); FastPin<7>::setOutput(); @@ -53,7 +53,7 @@ public: mWait.mark(); } - virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { mWait.wait(); cli(); @@ -65,7 +65,7 @@ public: PixelController(rgbdata/**/+(5*nLeds)/**/, nLeds, scale, getDither()), PixelController(rgbdata/**/+(6*nLeds)/**/, nLeds, scale, getDither()), PixelController(rgbdata/**/+(7*nLeds)/**/, nLeds, scale, getDither())); - + // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); MS_COUNTER += (microsTaken / 1000); @@ -74,12 +74,12 @@ public: } #ifdef SUPPORT_ARGB - virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { + virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { mWait.wait(); cli(); showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); - + // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -89,9 +89,9 @@ public: } #endif - typedef union { + typedef union { uint32_t word; - struct { + struct { uint32_t a0:1; uint32_t a1:1; uint32_t a2:1; @@ -128,8 +128,8 @@ public: } xtype; -#define USE_LINES - typedef union { +#define USE_LINES + typedef union { uint8_t bytes[8]; uint32_t raw[2]; } Lines; @@ -174,14 +174,14 @@ public: template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[8]) { // , register uint32_t & b2) { uint32_t flipper = bits(b); - for(register uint32_t i = 0; i < 8; i++) { + for(register uint32_t i = 0; i < 8; i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); *FastPin<2>::port() = 0xFF; - uint32_t flip_mark = next_mark - (T2+T3); - + uint32_t flip_mark = next_mark - (T2+T3+2); + while(ARM_DWT_CYCCNT < flip_mark); - uint32_t last_flip_mark = next_mark - (T3+2); + uint32_t last_flip_mark = next_mark - (T3); *FastPin<2>::port() = flipper; b.raw[0] <<= 1; b.raw[1] <<= 1; @@ -198,12 +198,12 @@ public: } } - // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then + // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then // gcc will use register Y for the this pointer. static void showRGBInternal(PixelController pixels, PixelController pixels2, PixelController pixels3, PixelController pixels4, - PixelController pixels5, PixelController pixels6, PixelController pixels7, PixelController pixels8) { + PixelController pixels5, PixelController pixels6, PixelController pixels7, PixelController pixels8) { - // Setup the pixel controller and load/scale the first byte + // Setup the pixel controller and load/scale the first byte PixelController *allpixels[8] = {&pixels,&pixels2,&pixels3,&pixels4,&pixels5,&pixels6,&pixels7,&pixels8}; pixels.preStepFirstByteDithering(); register Lines b0,b1,b2; @@ -215,27 +215,26 @@ public: b0.bytes[i] = allpixels[i]->loadAndScale0(); } - // Get access to the clock + // Get access to the clock ARM_DEMCR |= ARM_DEMCR_TRCENA; ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; ARM_DWT_CYCCNT = 0; uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - while(pixels.has(1)) { + while(pixels.has(1)) { pixels.stepDithering(); // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); // Write third byte - writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); }; } }; #endif #endif - -- cgit v1.2.3 From e48b5f8c228f0b30e7c296afba395eaf0f80933f Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 1 May 2014 11:58:14 -0700 Subject: checkpoint --- FastLED.cpp | 74 ++++++++++++++++++++++++++++++++++----------- clockless_block_arm_sam.h | 75 ++++++++++++++++++++++++---------------------- controller.h | 76 +++++++++++++++++++++++------------------------ 3 files changed, 135 insertions(+), 90 deletions(-) diff --git a/FastLED.cpp b/FastLED.cpp index 0c10a2a7..4a994c31 100644 --- a/FastLED.cpp +++ b/FastLED.cpp @@ -14,15 +14,15 @@ CLEDController *CLEDController::m_pTail = NULL; // uint32_t CRGB::Squant = ((uint32_t)((__TIME__[4]-'0') * 28))<<16 | ((__TIME__[6]-'0')*50)<<8 | ((__TIME__[7]-'0')*28); -CFastLED::CFastLED() { +CFastLED::CFastLED() { // clear out the array of led controllers // m_nControllers = 0; m_Scale = 255; } -CLEDController &CFastLED::addLeds(CLEDController *pLed, - const struct CRGB *data, - int nLedsOrOffset, int nLedsIfOffset) { +CLEDController &CFastLED::addLeds(CLEDController *pLed, + const struct CRGB *data, + int nLedsOrOffset, int nLedsIfOffset) { int nOffset = (nLedsIfOffset > 0) ? nLedsOrOffset : 0; int nLeds = (nLedsIfOffset > 0) ? nLedsIfOffset : nLedsOrOffset; @@ -31,24 +31,24 @@ CLEDController &CFastLED::addLeds(CLEDController *pLed, return *pLed; } -void CFastLED::show(uint8_t scale) { +void CFastLED::show(uint8_t scale) { CLEDController *pCur = CLEDController::head(); - while(pCur) { + while(pCur) { pCur->showLeds(scale); pCur = pCur->next(); } } -void CFastLED::showColor(const struct CRGB & color, uint8_t scale) { +void CFastLED::showColor(const struct CRGB & color, uint8_t scale) { CLEDController *pCur = CLEDController::head(); - while(pCur) { + while(pCur) { pCur->showColor(color, scale); pCur = pCur->next(); } } -void CFastLED::clear(boolean writeData) { - if(writeData) { +void CFastLED::clear(boolean writeData) { + if(writeData) { showColor(CRGB(0,0,0), 0); } clearData(); @@ -56,16 +56,16 @@ void CFastLED::clear(boolean writeData) { void CFastLED::clearData() { CLEDController *pCur = CLEDController::head(); - while(pCur) { + while(pCur) { pCur->clearLedData(); pCur = pCur->next(); } } -void CFastLED::delay(unsigned long ms) { +void CFastLED::delay(unsigned long ms) { unsigned long start = millis(); - while((millis()-start) < ms) { - show(); + while((millis()-start) < ms) { + show(); } @@ -73,7 +73,7 @@ void CFastLED::delay(unsigned long ms) { void CFastLED::setTemperature(const struct CRGB & temp) { CLEDController *pCur = CLEDController::head(); - while(pCur) { + while(pCur) { pCur->setTemperature(temp); pCur = pCur->next(); } @@ -81,7 +81,7 @@ void CFastLED::setTemperature(const struct CRGB & temp) { void CFastLED::setCorrection(const struct CRGB & correction) { CLEDController *pCur = CLEDController::head(); - while(pCur) { + while(pCur) { pCur->setCorrection(correction); pCur = pCur->next(); } @@ -89,9 +89,49 @@ void CFastLED::setCorrection(const struct CRGB & correction) { void CFastLED::setDither(uint8_t ditherMode) { CLEDController *pCur = CLEDController::head(); - while(pCur) { + while(pCur) { pCur->setDither(ditherMode); pCur = pCur->next(); } } + +template void transpose8(unsigned char A[8], unsigned char B[8]) { + uint32_t x, y, t; + + // Load the array and pack it into x and y. + y = *(unsigned int*)(A); + x = *(unsigned int*)(A+4); + + // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m]; + // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m]; + + t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); + t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); + + t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); + t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); + + t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); + y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); + x = t; + + B[7*n] = y; y >>= 8; + B[3*n] = x; x >>= 8; + + B[6*n] = y; y >>= 8; + B[2*n] = x; x >>= 8; + + B[5*n] = y; y >>= 8; + B[n] = x; x >>= 8; + + B[4*n] = y; + B[0] = x; + // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; + // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; +} + +void transposeLines(Lines & out, Lines & in) { + transpose8<1,2>(in.bytes, out.bytes); + transpose8<1,2>(in.bytes + 8, out.bytes + 1); +} diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index ab85b76c..047ae67f 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -9,7 +9,7 @@ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point -// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the +// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the // line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -21,6 +21,14 @@ #define HAS_BLOCKLESS 1 #define LANES 16 +typedef union { + uint8_t bytes[LANES]; + uint32_t raw[LANES/4]; + uint16_t shorts[LANES/2]; +} Lines; + +void transposeLines(Lines & out, Lines & in); + #define TADJUST 0 #define TOTAL ( (T1+TADJUST) + (T2+TADJUST) + (T3+TADJUST) ) #define T1_MARK (TOTAL - (T1+TADJUST)) @@ -34,7 +42,7 @@ class InlineBlockClocklessController : public CLEDController { data_ptr_t mPort; CMinWait mWait; public: - virtual void init() { + virtual void init() { //FastPinBB::setOutput(); uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 0}; // 72, 106, 0 }; int i = 0; @@ -64,9 +72,9 @@ public: PixelController px15(rgbdata, nLeds, scale, getDither()); PixelController px16(rgbdata, nLeds, scale, getDither()); - PixelController *allpixels[LANES] = { + PixelController *allpixels[LANES] = { &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 - ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 + ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 }; mWait.wait(); @@ -78,7 +86,7 @@ public: long microsTaken = CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); savedClock.restore(); - while(millisTaken-- > 0) { TimeTick_Increment(); } + while(millisTaken-- > 0) { TimeTick_Increment(); } sei(); mWait.mark(); } @@ -86,7 +94,7 @@ public: // #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) { + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { uint32_t maskbit = 0x00001; PixelController px1(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px2(rgbdata, nLeds, scale, getDither()); ADV_RGB @@ -105,9 +113,9 @@ public: PixelController px15(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px16(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController *allpixels[LANES] = { + PixelController *allpixels[LANES] = { &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 - ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 + ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 }; mWait.wait(); @@ -115,12 +123,12 @@ public: SysClockSaver savedClock(TOTAL); uint32_t clocks = showRGBInternal(allpixels,nLeds); - - + + long microsTaken = CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); savedClock.restore(); - while(millisTaken-- > 0) { TimeTick_Increment(); } + while(millisTaken-- > 0) { TimeTick_Increment(); } sei(); // Adjust the timer // long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -130,12 +138,12 @@ public: } #ifdef SUPPORT_ARGB - virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { + virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { mWait.wait(); cli(); showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); - + // Adjust the timer long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); @@ -145,9 +153,9 @@ public: } #endif - typedef union { + typedef union { uint32_t word; - struct { + struct { uint32_t a0:1; uint32_t a1:1; uint32_t a2:1; @@ -184,10 +192,6 @@ public: } xtype; - typedef union { - uint8_t bytes[LANES]; - uint32_t raw[LANES/4]; - } Lines; // #define IFSKIP(N,X) if(PORT_MASK & 1< __attribute__ ((always_inline)) inline static void writeBits(register volatile uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[LANES]) { // , register uint32_t & b2) { - uint32_t flipper = bits(b); + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[LANES]) { // , register uint32_t & b2) { + uint32_t flipper = bits(b); // Serial.print("flipper is "); Serial.println(flipper); - for(uint32_t i = 0; i < LANES; i++) { + for(uint32_t i = 0; i < LANES; i++) { while(VAL > next_mark); next_mark = VAL - (TOTAL); *FastPin<33>::sport() = PORT_MASK; while((VAL-next_mark) > (T2+T3+3)); - *FastPin<33>::cport() = (flipper & PORT_MASK); - flipper = bits(b); + *FastPin<33>::cport() = (flipper & PORT_MASK); + flipper = bits(b); while((VAL - next_mark) > T3); @@ -261,29 +265,30 @@ public: case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } + } i++; switch(PX) { case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } + } } + // transposeLines(b, b2); // for(register uint32_t i = 0; i < XTRA0; i++) { // AT_BIT_START(*FastPin<33>::port() = 0xFFFF); - // AT_MARK(*FastPin<33>::port() = 0); + // AT_MARK(*FastPin<33>::port() = 0); // AT_END(*FastPin<2>::port() = 0); - // } + // } } - // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then + // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then // gcc will use register Y for the this pointer. static uint32_t showRGBInternal(PixelController *allpixels[LANES], int nLeds) { // Serial.println("Entering show"); - // Setup the pixel controller and load/scale the first byte + // Setup the pixel controller and load/scale the first byte Lines b0,b1,b2; - for(int i = 0; i < LANES/4; i++) { + for(int i = 0; i < LANES/4; i++) { b0.raw[i] = b1.raw[i] = b2.raw[i] = 0; } for(int i = 0; i < LANES; i++) { @@ -300,15 +305,15 @@ public: VAL = 0; uint32_t next_mark = (VAL - (TOTAL)); - while(nLeds--) { + while(nLeds--) { // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); // Write third byte - writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); } return 0x00FFFFFF - _VAL; @@ -319,4 +324,4 @@ public: #endif -#endif \ No newline at end of file +#endif diff --git a/controller.h b/controller.h index 6a3660d6..55799665 100644 --- a/controller.h +++ b/controller.h @@ -8,8 +8,8 @@ #define RO(X) RGB_BYTE(RGB_ORDER, X) #define RGB_BYTE(RO,X) (((RO)>>(3*(2-(X)))) & 0x3) -#define RGB_BYTE0(RO) ((RO>>6) & 0x3) -#define RGB_BYTE1(RO) ((RO>>3) & 0x3) +#define RGB_BYTE0(RO) ((RO>>6) & 0x3) +#define RGB_BYTE1(RO) ((RO>>3) & 0x3) #define RGB_BYTE2(RO) ((RO) & 0x3) // operator byte *(struct CRGB[] arr) { return (byte*)arr; } @@ -19,17 +19,17 @@ typedef uint8_t EDitherMode; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// +// // LED Controller interface definition // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/// Base definition for an LED controller. Pretty much the methods that every LED controller object will make available. +/// Base definition for an LED controller. Pretty much the methods that every LED controller object will make available. /// Note that the showARGB method is not impelemented for all controllers yet. Note also the methods for eventual checking /// of background writing of data (I'm looking at you, teensy 3.0 DMA controller!). If you want to pass LED controllers around /// to methods, make them references to this type, keeps your code saner. However, most people won't be seeing/using these objects /// directly at all -class CLEDController { +class CLEDController { protected: friend class CFastLED; const CRGB *m_Data; @@ -44,7 +44,7 @@ protected: // set all the leds on the controller to a given color virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) = 0; - // note that the uint8_ts will be in the order that you want them sent out to the device. + // 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) = 0; @@ -77,11 +77,11 @@ public: } // show function using the "attached to this controller" led data - void showLeds(uint8_t brightness=255) { + void showLeds(uint8_t brightness=255) { show(m_Data, m_nLeds, getAdjustment(brightness)); } - void showColor(const struct CRGB & data, uint8_t brightness=255) { + void showColor(const struct CRGB & data, uint8_t brightness=255) { showColor(data, m_nLeds, getAdjustment(brightness)); } @@ -95,15 +95,15 @@ public: show(data, nLeds, getAdjustment(brightness)) } #endif - - CLEDController & setLeds(const CRGB *data, int nLeds) { + + CLEDController & setLeds(const CRGB *data, int nLeds) { m_Data = data; m_nLeds = nLeds; return *this; } void clearLedData() { - if(m_Data) { + if(m_Data) { memset8((void*)m_Data, 0, sizeof(struct CRGB) * m_nLeds); } } @@ -119,17 +119,17 @@ public: CLEDController & setTemperature(ColorTemperature temperature) { m_ColorTemperature = temperature; return *this; } CRGB getTemperature() { return m_ColorTemperature; } - CRGB getAdjustment(uint8_t scale) { + CRGB getAdjustment(uint8_t scale) { #if defined(NO_CORRECTION) && (NO_CORRECTION==1) return CRGB(scale,scale,scale); #else CRGB adj(0,0,0); - if(scale > 0) { - for(uint8_t i = 0; i < 3; i++) { + if(scale > 0) { + for(uint8_t i = 0; i < 3; i++) { uint8_t cc = m_ColorCorrection.raw[i]; uint8_t ct = m_ColorTemperature.raw[i]; - if(cc > 0 && ct > 0) { + if(cc > 0 && ct > 0) { uint32_t work = (((uint32_t)cc)+1) * (((uint32_t)ct)+1) * scale; work /= 0x10000L; adj.raw[i] = work & 0xFF; @@ -143,11 +143,11 @@ public: }; // 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 +// 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 struct PixelController { - const uint8_t *mData; + const uint8_t *mData; int mLen; uint8_t d[3]; uint8_t e[3]; @@ -186,7 +186,7 @@ struct PixelController { #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 + // skip the A in CARGB mData += 1; mAdvance = 0; } @@ -195,13 +195,13 @@ struct PixelController { enable_dithering(dither); // skip the A in CARGB mData += 1; - mAdvance = 4; + mAdvance = 4; } #endif void init_binary_dithering() { #if !defined(NO_DITHERING) || (NO_DITHERING != 1) - + #define VIRTUAL_BITS 8 // R is the digther signal 'counter'. static byte R = 0; @@ -216,7 +216,7 @@ struct PixelController { // 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; } @@ -228,7 +228,7 @@ struct PixelController { 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, @@ -236,13 +236,13 @@ struct PixelController { 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++) { + 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]); @@ -252,10 +252,10 @@ struct PixelController { } // Do we have n pixels left to process? - __attribute__((always_inline)) inline bool has(int n) { + __attribute__((always_inline)) inline bool has(int n) { return mLen >= n; } - + // toggle dithering enable void enable_dithering(EDitherMode dither) { switch(dither) { @@ -264,15 +264,15 @@ struct PixelController { } } - // get the amount to advance the pointer by + // 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 + // step the dithering forward __attribute__((always_inline)) inline void stepDithering() { - // IF UPDATING HERE, BE SURE TO UPDATE THE ASM VERSION IN + // 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]; @@ -280,7 +280,7 @@ struct PixelController { } // Some chipsets pre-cycle the first byte, which means we want to cycle byte 0's dithering separately - __attribute__((always_inline)) inline void preStepFirstByteDithering() { + __attribute__((always_inline)) inline void preStepFirstByteDithering() { d[RO(0)] = e[RO(0)] - d[RO(0)]; } @@ -293,11 +293,11 @@ struct PixelController { template __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(PixelController & pc) { pc.advanceData(); return pc.loadAndScale(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); } + __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); } }; -#endif \ No newline at end of file +#endif -- cgit v1.2.3 From fc9ddc366636e2dfa5ca4df56149094d5d8eb2a2 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 16 May 2014 12:21:26 -0700 Subject: build fixing, reference code commenting --- FastLED.cpp | 80 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/FastLED.cpp b/FastLED.cpp index 4a994c31..14e61f7b 100644 --- a/FastLED.cpp +++ b/FastLED.cpp @@ -95,43 +95,43 @@ void CFastLED::setDither(uint8_t ditherMode) { } } - -template void transpose8(unsigned char A[8], unsigned char B[8]) { - uint32_t x, y, t; - - // Load the array and pack it into x and y. - y = *(unsigned int*)(A); - x = *(unsigned int*)(A+4); - - // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m]; - // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m]; - - t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); - t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); - - t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); - t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); - - t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); - y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); - x = t; - - B[7*n] = y; y >>= 8; - B[3*n] = x; x >>= 8; - - B[6*n] = y; y >>= 8; - B[2*n] = x; x >>= 8; - - B[5*n] = y; y >>= 8; - B[n] = x; x >>= 8; - - B[4*n] = y; - B[0] = x; - // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; - // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; -} - -void transposeLines(Lines & out, Lines & in) { - transpose8<1,2>(in.bytes, out.bytes); - transpose8<1,2>(in.bytes + 8, out.bytes + 1); -} +// +// template void transpose8(unsigned char A[8], unsigned char B[8]) { +// uint32_t x, y, t; +// +// // Load the array and pack it into x and y. +// y = *(unsigned int*)(A); +// x = *(unsigned int*)(A+4); +// +// // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m]; +// // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m]; +// +// t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); +// t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); +// +// t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); +// t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); +// +// t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); +// y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); +// x = t; +// +// B[7*n] = y; y >>= 8; +// B[3*n] = x; x >>= 8; +// +// B[6*n] = y; y >>= 8; +// B[2*n] = x; x >>= 8; +// +// B[5*n] = y; y >>= 8; +// B[n] = x; x >>= 8; +// +// B[4*n] = y; +// B[0] = x; +// // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; +// // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; +// } +// +// void transposeLines(Lines & out, Lines & in) { +// transpose8<1,2>(in.bytes, out.bytes); +// transpose8<1,2>(in.bytes + 8, out.bytes + 1); +// } -- cgit v1.2.3 From aa57dff25ed5a33193e0a47c4b346af19c8c2eca Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 19 May 2014 20:00:15 -0700 Subject: Fixing up due/digix parallel/tm1809 output timing. --- FastLED.cpp | 33 +++++++++++++++++---------------- FastLED.h | 7 +++++++ chipsets.h | 2 +- clockless_arm_sam.h | 5 +++-- clockless_block_arm_sam.h | 23 ++++++++++++++++++----- 5 files changed, 46 insertions(+), 24 deletions(-) diff --git a/FastLED.cpp b/FastLED.cpp index 14e61f7b..716eabfd 100644 --- a/FastLED.cpp +++ b/FastLED.cpp @@ -95,7 +95,7 @@ void CFastLED::setDither(uint8_t ditherMode) { } } -// +// // template void transpose8(unsigned char A[8], unsigned char B[8]) { // uint32_t x, y, t; // @@ -106,26 +106,27 @@ void CFastLED::setDither(uint8_t ditherMode) { // // x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m]; // // y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m]; // -// t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); -// t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); -// -// t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); -// t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); -// -// t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); -// y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); -// x = t; + // // pre-transform x + // t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); + // t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); + // + // // pre-transform y + // t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); + // t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); + // + // // final transform + // t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); + // y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); + // x = t; // // B[7*n] = y; y >>= 8; -// B[3*n] = x; x >>= 8; -// // B[6*n] = y; y >>= 8; -// B[2*n] = x; x >>= 8; -// // B[5*n] = y; y >>= 8; -// B[n] = x; x >>= 8; -// // B[4*n] = y; +// +// B[3*n] = x; x >>= 8; +// B[2*n] = x; x >>= 8; +// B[n] = x; x >>= 8; // B[0] = x; // // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; // // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; diff --git a/FastLED.h b/FastLED.h index 30ff9071..a53d2cad 100644 --- a/FastLED.h +++ b/FastLED.h @@ -164,6 +164,13 @@ public: #endif // #ifdef HAS_BLOCKLESS + template + static CLEDController &addLeds(const struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { + switch(CHIPSET) { + case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); + } + } + template static CLEDController &addLeds(const struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { switch(CHIPSET) { diff --git a/chipsets.h b/chipsets.h index b93058c6..eca092fb 100644 --- a/chipsets.h +++ b/chipsets.h @@ -339,7 +339,7 @@ class UCS1903BController800Khz : public ClocklessController -class TM1809Controller800Khz : public ClocklessController {}; +class TM1809Controller800Khz : public ClocklessController {}; #if NO_TIME(350, 350, 550) #warning "Not enough clock cycles available for the TM1809" #endif diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h index d71e8162..35775b3c 100644 --- a/clockless_arm_sam.h +++ b/clockless_arm_sam.h @@ -163,11 +163,12 @@ public: if(b&0x80) { // we're a 1, wait until there's less than T3 clocks left while((VAL - next_mark) > (T3)); + *port=0; } else { // we're a 0, wait until there's less than (T2+T3+slop) clocks left in this bit - while((VAL-next_mark) > (T2+T3+4+TADJUST+TADJUST)); + while((VAL-next_mark) > (T2+T3+6+TADJUST+TADJUST)); + *port=0; } - *port=0; b <<= 1; } } diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 047ae67f..efdd545d 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -19,7 +19,7 @@ #if defined(__SAM3X8E__) #define HAS_BLOCKLESS 1 -#define LANES 16 +#define LANES 8 typedef union { uint8_t bytes[LANES]; @@ -63,6 +63,7 @@ public: PixelController px6(rgbdata, nLeds, scale, getDither()); PixelController px7(rgbdata, nLeds, scale, getDither()); PixelController px8(rgbdata, nLeds, scale, getDither()); +#if LANES > 8 PixelController px9(rgbdata, nLeds, scale, getDither()); PixelController px10(rgbdata, nLeds, scale, getDither()); PixelController px11(rgbdata, nLeds, scale, getDither()); @@ -71,10 +72,13 @@ public: PixelController px14(rgbdata, nLeds, scale, getDither()); PixelController px15(rgbdata, nLeds, scale, getDither()); PixelController px16(rgbdata, nLeds, scale, getDither()); +#endif PixelController *allpixels[LANES] = { &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 +#if LANES > 8 ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 +#endif }; mWait.wait(); @@ -104,6 +108,7 @@ public: PixelController px6(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px7(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px8(rgbdata, nLeds, scale, getDither()); ADV_RGB +#if LANES > 8 PixelController px9(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px10(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px11(rgbdata, nLeds, scale, getDither()); ADV_RGB @@ -112,10 +117,14 @@ public: PixelController px14(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px15(rgbdata, nLeds, scale, getDither()); ADV_RGB PixelController px16(rgbdata, nLeds, scale, getDither()); ADV_RGB +#endif PixelController *allpixels[LANES] = { - &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 - ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 + &px4, &px3, &px2, &px1, &px8, &px7, &px6, &px5 +#if LANES > 8 + ,&px12, &px11, &px10, &px9, &px16, &px15, &px14, &px13 +#endif + }; mWait.wait(); @@ -207,6 +216,7 @@ public: fuckery.a6 = (b.raw[1] >> 15); fuckery.a7 = (b.raw[1] >> 7); b.raw[1] <<= 1; +#if LANES > 8 fuckery.b0 = (b.raw[2] >> 31); fuckery.b1 = (b.raw[2] >> 23); fuckery.b2 = (b.raw[2] >> 15); @@ -217,6 +227,7 @@ public: fuckery.b6 = (b.raw[3] >> 15); fuckery.b7 = (b.raw[3] >> 7); b.raw[3] <<= 1; +#endif // #if (LANES > 16) // fuckery.c0 = (b.raw[4] >> 31); // fuckery.c1 = (b.raw[4] >> 23); @@ -253,9 +264,9 @@ public: next_mark = VAL - (TOTAL); *FastPin<33>::sport() = PORT_MASK; - while((VAL-next_mark) > (T2+T3+3)); + while((VAL-next_mark) > (T2+T3+6)); *FastPin<33>::cport() = (flipper & PORT_MASK); - flipper = bits(b); + flipper = bits(b); while((VAL - next_mark) > T3); @@ -266,12 +277,14 @@ public: case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; } + #if LANES > 8 i++; switch(PX) { case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; } + #endif } // transposeLines(b, b2); -- cgit v1.2.3 From 92c1c167814707f5d779ed7dc603d30b256cdd39 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 21 May 2014 00:59:47 -0700 Subject: Prelim DeepPixel support --- chipsets.h | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/chipsets.h b/chipsets.h index eca092fb..8f21dbab 100644 --- a/chipsets.h +++ b/chipsets.h @@ -4,6 +4,87 @@ #include "pixeltypes.h" #include "clockless.h" +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// DeepPixel controller class - takes data/clock/select pin values (N.B. should take an SPI definition?) +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class DeepPixelController : public CLEDController { + typedef SPIOutput SPI; + SPI mSPI; + + void writeStart() { mSPI.writeWord(0xFFFF); mSPI.writeWord(0xFFFF); } + void writeStop() { mSPI.writeWord(0x0000); mSPI.writeWord(0x0000); } + + inline void writeLed(uint8_t r, uint8_t g, uint8_t b) __attribute__((always_inline)) { + mSPI.writeByte(0xFF); mSPI.writeByte(r); mSPI.writeByte(g); mSPI.writeByte(b); + } + +public: + DeepPixelController() {} + + virtual void init() { + mSPI.init(); + } + + virtual void clearLeds(int nLeds) { + showColor(CRGB(0,0,0), nLeds, CRGB(0,0,0)); + } + + virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { + PixelController pixels(data, nLeds, scale, getDither()); + + mSPI.select(); + + writeStart(); + while(nLeds--) { + writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); + pixels.stepDithering(); + } + writeStop(); + + mSPI.waitFully(); + mSPI.release(); + } + + virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { + PixelController pixels(data, nLeds, scale, getDither()); + + mSPI.select(); + + writeStart(); + for(int i = 0; i < nLeds; i++) { + writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); + pixels.advanceData(); + pixels.stepDithering(); + } + writeStop(); + + mSPI.release(); + } + +#ifdef SUPPORT_ARGB + virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { + PixelController 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.release(); + } +#endif +}; + + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // LPD8806 controller class - takes data/clock/select pin values (N.B. should take an SPI definition?) -- cgit v1.2.3 From 9359e575c2e71c47982a539a91b2adebfb5dc828 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 21 May 2014 00:59:58 -0700 Subject: fixing a cast --- delay.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/delay.h b/delay.h index 0eeda245..05313127 100644 --- a/delay.h +++ b/delay.h @@ -103,7 +103,7 @@ template<> __attribute__((always_inline)) inline void delaycycles<5>() {NOP2;NOP // #define NS(_NS) (_NS / (1000 / (F_CPU / 1000000L))) #if 1 || (F_CPU < 96000000) #define NS(_NS) ( (_NS * (F_CPU / 1000000L))) / 1000 -#define CLKS_TO_MICROS(_CLKS) ((_CLKS)) / (F_CPU / 1000000L) +#define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 1000000L) #else #define NS(_NS) ( (_NS * (F_CPU / 2000000L))) / 1000 #define CLKS_TO_MICROS(_CLKS) ((long)(_CLKS)) / (F_CPU / 2000000L) -- cgit v1.2.3 From d82d7edc559098ec61f52f8975f70d5376e6467e Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 21 May 2014 01:00:25 -0700 Subject: Fixing clock for block k20 output --- clockless_block_arm_k20.h | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 1bfae31a..e1ec9d52 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -37,7 +37,7 @@ public: mWait.wait(); cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), + uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), @@ -47,7 +47,7 @@ public: PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + long microsTaken = CLKS_TO_MICROS(clocks); MS_COUNTER += (microsTaken / 1000); sei(); mWait.mark(); @@ -57,7 +57,7 @@ public: mWait.wait(); cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), + uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), PixelController(rgbdata/**/+(1*nLeds)/**/, nLeds, scale, getDither()), PixelController(rgbdata/**/+(2*nLeds)/**/, nLeds, scale, getDither()), PixelController(rgbdata/**/+(3*nLeds)/**/, nLeds, scale, getDither()), @@ -67,7 +67,7 @@ public: PixelController(rgbdata/**/+(7*nLeds)/**/, nLeds, scale, getDither())); // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + long microsTaken = CLKS_TO_MICROS(clocks); MS_COUNTER += (microsTaken / 1000); sei(); mWait.mark(); @@ -78,11 +78,11 @@ public: mWait.wait(); cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); + uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); + long microsTaken = CLKS_TO_MICROS(clocks); MS_COUNTER += (microsTaken / 1000); sei(); mWait.mark(); @@ -200,8 +200,12 @@ 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 void showRGBInternal(PixelController pixels, PixelController pixels2, PixelController pixels3, PixelController pixels4, + static uint32_t showRGBInternal(PixelController pixels, PixelController pixels2, PixelController pixels3, PixelController pixels4, PixelController pixels5, PixelController pixels6, PixelController pixels7, PixelController pixels8) { + // Get access to the clock + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + ARM_DWT_CYCCNT = 0; // Setup the pixel controller and load/scale the first byte PixelController *allpixels[8] = {&pixels,&pixels2,&pixels3,&pixels4,&pixels5,&pixels6,&pixels7,&pixels8}; @@ -215,10 +219,6 @@ public: b0.bytes[i] = allpixels[i]->loadAndScale0(); } - // Get access to the clock - ARM_DEMCR |= ARM_DEMCR_TRCENA; - ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; - ARM_DWT_CYCCNT = 0; uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); while(pixels.has(1)) { @@ -233,6 +233,8 @@ public: // Write third byte writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); }; + + return ARM_DWT_CYCCNT; } }; #endif -- cgit v1.2.3 From a4323c3d94faafbfa2bfc0d8ec26f40769132e0a Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 23 May 2014 12:59:16 -0700 Subject: checkpoint --- clockless_block_arm_sam.h | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index efdd545d..129c735a 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -211,11 +211,11 @@ public: fuckery.a2 = (b.raw[0] >> 15); fuckery.a3 = (b.raw[0] >> 7); b.raw[0] <<= 1; - fuckery.a4 = (b.raw[1] >> 31); - fuckery.a5 = (b.raw[1] >> 23); - fuckery.a6 = (b.raw[1] >> 15); - fuckery.a7 = (b.raw[1] >> 7); - b.raw[1] <<= 1; + // fuckery.a4 = (b.raw[1] >> 31); + // fuckery.a5 = (b.raw[1] >> 23); + // fuckery.a6 = (b.raw[1] >> 15); + // fuckery.a7 = (b.raw[1] >> 7); + // b.raw[1] <<= 1; #if LANES > 8 fuckery.b0 = (b.raw[2] >> 31); fuckery.b1 = (b.raw[2] >> 23); @@ -258,7 +258,7 @@ public: template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[LANES]) { // , register uint32_t & b2) { uint32_t flipper = bits(b); // Serial.print("flipper is "); Serial.println(flipper); - for(uint32_t i = 0; i < LANES; i++) { + for(uint32_t i = 0; i < LANES/2; i++) { while(VAL > next_mark); next_mark = VAL - (TOTAL); @@ -287,6 +287,21 @@ public: #endif } + for(uint32_t i = 0; i < LANES/2; i++) { + while(VAL > next_mark); + + next_mark = VAL - (TOTAL); + *FastPin<33>::sport() = PORT_MASK; + + while((VAL-next_mark) > (T2+T3+6)); + *FastPin<33>::cport() = (flipper & PORT_MASK); + flipper = bits(b); + + + while((VAL - next_mark) > T3); + *FastPin<33>::cport() = PORT_MASK; + } + // transposeLines(b, b2); // for(register uint32_t i = 0; i < XTRA0; i++) { // AT_BIT_START(*FastPin<33>::port() = 0xFFFF); -- cgit v1.2.3 From 5c3e03a4ea777a12bb2c181156a098926285d6d7 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sun, 15 Jun 2014 03:14:46 -0700 Subject: Adding parallel pixel controller --- controller.h | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 209 insertions(+), 1 deletion(-) diff --git a/controller.h b/controller.h index 1dbc5751..eaff967b 100644 --- a/controller.h +++ b/controller.h @@ -330,7 +330,215 @@ struct PixelController { __attribute__((always_inline)) inline uint8_t loadAndScale1() { return loadAndScale<1>(*this); } __attribute__((always_inline)) inline uint8_t loadAndScale2() { return loadAndScale<2>(*this); } __attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0() { return advanceAndLoadAndScale<0>(*this); } - __attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0() { stepDithering(); return advanceAndLoadAndScale<0>(*this); } + __attribute__((always_inline)) inline uint8_t 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 +struct MultiPixelController { + const uint8_t *mData; + int mLen; + uint8_t d[3]; + uint8_t e[3]; + CRGB mScale; + int8_t mAdvance; + int mOffsets[LANES]; + + MultiPixelController(const MultiPixelController & 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; + for(int i = 0; i < LANES; i++) { mOffsets = other.mOffsets[i]; } + + } + + void initOffsets(int len) { + int nOffset = 0; + for(int i = 0; i < LANES; i++) { + mOffsets[i] = nOffset; + if((1<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 __attribute__((always_inline)) inline static uint8_t loadByte(MultiPixelController & pc, int lane) { return pc.mData[pc.mOffsets[lane] + RO(SLOT)]; } + template __attribute__((always_inline)) inline static uint8_t dither(MultiPixelController & pc, uint8_t b) { return b ? qadd8(b, pc.d[RO(SLOT)]) : 0; } + template __attribute__((always_inline)) inline static uint8_t dither(MultiPixelController & pc, uint8_t b, uint8_t d) { return b ? qadd8(b,d) : 0; } + template __attribute__((always_inline)) inline static uint8_t scale(MultiPixelController & pc, uint8_t b) { return scale8(b, pc.mScale.raw[RO(SLOT)]); } + template __attribute__((always_inline)) inline static uint8_t scale(MultiPixelController & pc, uint8_t b, uint8_t scale) { return scale8(b, scale); } + + // composite shortcut functions for loading, dithering, and scaling + template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane) { return scale(pc, pc.dither(pc, pc.loadByte(pc, lane))); } + template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane, uint8_t d, uint8_t scale) { return scale(pc, pc.dither(pc, pc.loadByte(pc, lane), d), scale); } + template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane, uint8_t scale) { return scale(pc, pc.loadByte(pc, lane), scale); } + template __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(MultiPixelController & pc, int lane) { pc.advanceData(); return pc.loadAndScale(pc, lane); } + + template __attribute__((always_inline)) inline static uint8_t getd(MultiPixelController & pc) { return pc.d[RO(SLOT)]; } + template __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); } }; #endif -- cgit v1.2.3 From 634d458b7e95ce2adf8a59c75a192b6c0113d19c Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sun, 15 Jun 2014 03:16:02 -0700 Subject: tweaking block clockless --- clockless_block_arm_sam.h | 215 +++++++++++++++++++++------------------------- 1 file changed, 99 insertions(+), 116 deletions(-) diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 129c735a..40109f46 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -55,37 +55,12 @@ public: // set all the leds on the controller to a given color virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { - PixelController px1(rgbdata, nLeds, scale, getDither()); - PixelController px2(rgbdata, nLeds, scale, getDither()); - PixelController px3(rgbdata, nLeds, scale, getDither()); - PixelController px4(rgbdata, nLeds, scale, getDither()); - PixelController px5(rgbdata, nLeds, scale, getDither()); - PixelController px6(rgbdata, nLeds, scale, getDither()); - PixelController px7(rgbdata, nLeds, scale, getDither()); - PixelController px8(rgbdata, nLeds, scale, getDither()); -#if LANES > 8 - PixelController px9(rgbdata, nLeds, scale, getDither()); - PixelController px10(rgbdata, nLeds, scale, getDither()); - PixelController px11(rgbdata, nLeds, scale, getDither()); - PixelController px12(rgbdata, nLeds, scale, getDither()); - PixelController px13(rgbdata, nLeds, scale, getDither()); - PixelController px14(rgbdata, nLeds, scale, getDither()); - PixelController px15(rgbdata, nLeds, scale, getDither()); - PixelController px16(rgbdata, nLeds, scale, getDither()); -#endif - - PixelController *allpixels[LANES] = { - &px1, &px2, &px3, &px4, &px5, &px6, &px7, &px8 -#if LANES > 8 - ,&px9, &px10, &px11, &px12, &px13, &px14, &px15, &px16 -#endif - }; - + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); cli(); SysClockSaver savedClock(TOTAL); - uint32_t clocks = showRGBInternal(allpixels, nLeds); + uint32_t clocks = showRGBInternal(pixels, nLeds); long microsTaken = CLKS_TO_MICROS(clocks); long millisTaken = (microsTaken / 1000); @@ -99,39 +74,12 @@ public: #define ADV_RGB if(maskbit & PORT_MASK) { rgbdata += nLeds; } maskbit <<= 1; virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { - uint32_t maskbit = 0x00001; - PixelController px1(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px2(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px3(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px4(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px5(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px6(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px7(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px8(rgbdata, nLeds, scale, getDither()); ADV_RGB -#if LANES > 8 - PixelController px9(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px10(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px11(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px12(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px13(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px14(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px15(rgbdata, nLeds, scale, getDither()); ADV_RGB - PixelController px16(rgbdata, nLeds, scale, getDither()); ADV_RGB -#endif - - PixelController *allpixels[LANES] = { - &px4, &px3, &px2, &px1, &px8, &px7, &px6, &px5 -#if LANES > 8 - ,&px12, &px11, &px10, &px9, &px16, &px15, &px14, &px13 -#endif - - }; - + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); cli(); SysClockSaver savedClock(TOTAL); - uint32_t clocks = showRGBInternal(allpixels,nLeds); + uint32_t clocks = showRGBInternal(pixels, nLeds); long microsTaken = CLKS_TO_MICROS(clocks); @@ -211,11 +159,11 @@ public: fuckery.a2 = (b.raw[0] >> 15); fuckery.a3 = (b.raw[0] >> 7); b.raw[0] <<= 1; - // fuckery.a4 = (b.raw[1] >> 31); - // fuckery.a5 = (b.raw[1] >> 23); - // fuckery.a6 = (b.raw[1] >> 15); - // fuckery.a7 = (b.raw[1] >> 7); - // b.raw[1] <<= 1; + fuckery.a4 = (b.raw[1] >> 31); + fuckery.a5 = (b.raw[1] >> 23); + fuckery.a6 = (b.raw[1] >> 15); + fuckery.a7 = (b.raw[1] >> 7); + b.raw[1] <<= 1; #if LANES > 8 fuckery.b0 = (b.raw[2] >> 31); fuckery.b1 = (b.raw[2] >> 23); @@ -228,37 +176,42 @@ public: fuckery.b7 = (b.raw[3] >> 7); b.raw[3] <<= 1; #endif -// #if (LANES > 16) -// fuckery.c0 = (b.raw[4] >> 31); -// fuckery.c1 = (b.raw[4] >> 23); -// fuckery.c2 = (b.raw[4] >> 15); -// fuckery.c3 = (b.raw[4] >> 7); -// b.raw[4] <<= 1; -// fuckery.c4 = (b.raw[5] >> 31); -// fuckery.c5 = (b.raw[5] >> 23); -// fuckery.c6 = (b.raw[5] >> 15); -// fuckery.c7 = (b.raw[5] >> 7); -// b.raw[5] <<= 1; -// #if (LANES > 24) -// fuckery.d0 = (b.raw[6] >> 31); -// fuckery.d1 = (b.raw[6] >> 23); -// fuckery.d2 = (b.raw[6] >> 15); -// fuckery.d3 = (b.raw[6] >> 7); -// fuckery.d4 = (b.raw[7] >> 31); -// fuckery.d5 = (b.raw[7] >> 23); -// fuckery.d6 = (b.raw[7] >> 15); -// fuckery.d7 = (b.raw[7] >> 7); -// #endif -// #endif +#if (LANES > 16) + fuckery.c0 = (b.raw[4] >> 31); + fuckery.c1 = (b.raw[4] >> 23); + fuckery.c2 = (b.raw[4] >> 15); + fuckery.c3 = (b.raw[4] >> 7); + b.raw[4] <<= 1; + fuckery.c4 = (b.raw[5] >> 31); + fuckery.c5 = (b.raw[5] >> 23); + fuckery.c6 = (b.raw[5] >> 15); + fuckery.c7 = (b.raw[5] >> 7); + b.raw[5] <<= 1; +#if (LANES > 24) + fuckery.d0 = (b.raw[6] >> 31); + fuckery.d1 = (b.raw[6] >> 23); + fuckery.d2 = (b.raw[6] >> 15); + fuckery.d3 = (b.raw[6] >> 7); + b.raw[6] <<= 1; + fuckery.d4 = (b.raw[7] >> 31); + fuckery.d5 = (b.raw[7] >> 23); + fuckery.d6 = (b.raw[7] >> 15); + fuckery.d7 = (b.raw[7] >> 7); + b.raw[7] <<= 1; +#endif +#endif return ~fuckery.word; } #define VAL *((uint32_t*)(SysTick_BASE + 8)) - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[LANES]) { // , register uint32_t & b2) { + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, MultiPixelController &pixels) { // , register uint32_t & b2) { uint32_t flipper = bits(b); + register uint8_t d = pixels.template getd(pixels); + register uint8_t scale = pixels.template getscale(pixels); + // Serial.print("flipper is "); Serial.println(flipper); - for(uint32_t i = 0; i < LANES/2; i++) { + for(uint32_t i = 0; i < LANES/(LANES/8); i++) { while(VAL > next_mark); next_mark = VAL - (TOTAL); @@ -266,41 +219,68 @@ public: while((VAL-next_mark) > (T2+T3+6)); *FastPin<33>::cport() = (flipper & PORT_MASK); - flipper = bits(b); + flipper = bits(b); while((VAL - next_mark) > T3); *FastPin<33>::cport() = PORT_MASK; - switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; - case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } - #if LANES > 8 - i++; - switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->stepAdvanceAndLoadAndScale0(); break; - case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } - #endif - } - - for(uint32_t i = 0; i < LANES/2; i++) { - while(VAL > next_mark); - - next_mark = VAL - (TOTAL); - *FastPin<33>::sport() = PORT_MASK; - - while((VAL-next_mark) > (T2+T3+6)); - *FastPin<33>::cport() = (flipper & PORT_MASK); - flipper = bits(b); +b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +#if LANES > 8 +b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +#if LANES > 16 +b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +#if LANES > 24 +b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +#endif +#endif +#endif +// switch(PX) { +// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; +// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; +// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; +// } +// #if LANES > 8 +// i++; +// switch(PX) { +// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; +// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; +// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; +// } +// #endif +// #if LANES > 16 +// i++; +// switch(PX) { +// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; +// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; +// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; +// } +// #endif +// #if LANES > 24 +// i++; +// switch(PX) { +// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; +// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; +// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; +// } +// #endif + } - while((VAL - next_mark) > T3); - *FastPin<33>::cport() = PORT_MASK; - } + // for(uint32_t i = 0; i < LANES/2; i++) { + // while(VAL > next_mark); + // + // next_mark = VAL - (TOTAL); + // *FastPin<33>::sport() = PORT_MASK; + // + // while((VAL-next_mark) > (T2+T3+6)); + // *FastPin<33>::cport() = (flipper & PORT_MASK); + // flipper = bits(b); + // + // + // while((VAL - next_mark) > T3); + // *FastPin<33>::cport() = PORT_MASK; + // } // transposeLines(b, b2); // for(register uint32_t i = 0; i < XTRA0; i++) { @@ -312,7 +292,7 @@ public: // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then // gcc will use register Y for the this pointer. - static uint32_t showRGBInternal(PixelController *allpixels[LANES], int nLeds) { + static uint32_t showRGBInternal(MultiPixelController &allpixels, int nLeds) { // Serial.println("Entering show"); // Setup the pixel controller and load/scale the first byte Lines b0,b1,b2; @@ -320,8 +300,8 @@ public: b0.raw[i] = b1.raw[i] = b2.raw[i] = 0; } for(int i = 0; i < LANES; i++) { - allpixels[i]->preStepFirstByteDithering(); - b0.bytes[i] = allpixels[i]->loadAndScale0(); + allpixels.preStepFirstByteDithering(); + b0.bytes[i] = allpixels.loadAndScale0(i); } // Setup and start the clock @@ -334,12 +314,15 @@ public: VAL = 0; uint32_t next_mark = (VAL - (TOTAL)); while(nLeds--) { + allpixels.stepDithering(); + // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); // Write second byte, read 3rd byte writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + allpixels.advanceData(); // Write third byte writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); } -- cgit v1.2.3 From f131cd05c3350775becff6321c860f4438d05ed2 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sun, 15 Jun 2014 03:16:14 -0700 Subject: tweaking noise bits for locus --- noise.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/noise.cpp b/noise.cpp index 3b0dc599..5ab8e76b 100644 --- a/noise.cpp +++ b/noise.cpp @@ -506,12 +506,12 @@ void fill_raw_2dnoise8(uint8_t *pData, int width, int height, uint8_t octaves, q } void fill_raw_2dnoise8(uint8_t *pData, int width, int height, uint8_t octaves, uint16_t x, int scalex, uint16_t y, int scaley, uint16_t time) { - fill_raw_2dnoise8(pData, width, height, octaves, q44(2,0), 171, 1, x, scalex, y, scaley, time); + fill_raw_2dnoise8(pData, width, height, octaves, q44(2,0), 128, 1, x, scalex, y, scaley, time); } void fill_raw_2dnoise16(uint16_t *pData, int width, int height, uint8_t octaves, q88 freq88, fract16 amplitude, int skip, uint32_t x, int scalex, uint32_t y, int scaley, uint32_t time) { if(octaves > 1) { - fill_raw_2dnoise16(pData, width, height, octaves-1, freq88, amplitude, skip+1, x *freq88 , scalex *freq88, y * freq88, scaley * freq88, time); + fill_raw_2dnoise16(pData, width, height, octaves-1, freq88, amplitude, skip, x *freq88 , scalex *freq88, y * freq88, scaley * freq88, time); } else { // amplitude is always 255 on the lowest level amplitude=65535; @@ -667,10 +667,13 @@ void fill_2dnoise16(CRGB *leds, int width, int height, bool serpentine, int w1 = width-1; int h1 = height-1; + static int hz = 0; + uint8_t hue_off = hz>>8; + hz += 123; for(int i = 0; i < height; i++) { int wb = i*width; for(int j = 0; j < width; j++) { - CRGB led(CHSV(H[h1-i][h1-j],255,V[i][j])); + CRGB led(CHSV(hue_off + H[h1-i][h1-j],255,V[i][j])); int pos = j; if(serpentine && (i & 0x1)) { -- cgit v1.2.3 From 7359aaf0fade264d600f5babe5a29818486c14c3 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sun, 29 Jun 2014 11:52:33 -0700 Subject: full digix set of pins --- clockless_block_arm_sam.h | 8 +++++--- noise.cpp | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 40109f46..66fc7a8c 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -14,7 +14,8 @@ // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define PORT_MASK 0x77EFF3FE +// #define PORT_MASK 0x77EFF3FE // due +#define PORT_MASK 0x7FFFFFE #define SKIPLIST ~PORT_MASK #if defined(__SAM3X8E__) @@ -44,8 +45,9 @@ class InlineBlockClocklessController : public CLEDController { public: virtual void init() { //FastPinBB::setOutput(); - uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 0}; // 72, 106, 0 }; - int i = 0; + // uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 0}; // 72, 106, 0 }; // due + uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 107, 106, 51, 50, 49, 48, 47, 46,45, 44, 105, 9, 8, 7, 6, 5, 4, 104, 3, 10, 109, 0}; // 72, 106, 0 }; // digix + int i = 0; while(pins[i]) { pinMode(pins[i++], OUTPUT); } } diff --git a/noise.cpp b/noise.cpp index 5ab8e76b..d291a728 100644 --- a/noise.cpp +++ b/noise.cpp @@ -673,7 +673,7 @@ void fill_2dnoise16(CRGB *leds, int width, int height, bool serpentine, for(int i = 0; i < height; i++) { int wb = i*width; for(int j = 0; j < width; j++) { - CRGB led(CHSV(hue_off + H[h1-i][h1-j],255,V[i][j])); + CRGB led(CHSV(hue_off + H[h1-i][h1-j],210,V[i][j])); int pos = j; if(serpentine && (i & 0x1)) { -- cgit v1.2.3 From 5097274af4c772ba44e5b0233aa855230cd686bb Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 7 Jul 2014 11:19:42 -0700 Subject: checkpoint --- clockless_block_arm_sam.h | 28 ++++++++++++++++++---------- controller.h | 6 +++--- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 66fc7a8c..4aa242f3 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -202,6 +202,9 @@ public: b.raw[7] <<= 1; #endif #endif + fuckery.word |= (fuckery.word << 7); + fuckery.word |= (fuckery.word << 14); + return ~fuckery.word; } @@ -227,22 +230,27 @@ public: while((VAL - next_mark) > T3); *FastPin<33>::cport() = PORT_MASK; -b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +b2.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); #if LANES > 8 -b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); #if LANES > 16 -b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); #if LANES > 24 -b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; +i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); #endif #endif #endif -// switch(PX) { -// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; -// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; -// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; -// } + // switch(PX) { + // case 0: b2.bytes[i] = pixels.loadAndScale0(i); break; + // case 1: b2.bytes[i] = pixels.loadAndScale1(i); break; + // case 2: b2.bytes[i] = pixels.loadAndScale2(i); break; + // } + // switch(PX) { + // case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; + // case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; + // case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; + // } // #if LANES > 8 // i++; // switch(PX) { @@ -301,8 +309,8 @@ b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); i++; for(int i = 0; i < LANES/4; i++) { b0.raw[i] = b1.raw[i] = b2.raw[i] = 0; } + allpixels.preStepFirstByteDithering(); for(int i = 0; i < LANES; i++) { - allpixels.preStepFirstByteDithering(); b0.bytes[i] = allpixels.loadAndScale0(i); } diff --git a/controller.h b/controller.h index eaff967b..ace0d888 100644 --- a/controller.h +++ b/controller.h @@ -357,7 +357,7 @@ struct MultiPixelController { mScale = other.mScale; mAdvance = other.mAdvance; mLen = other.mLen; - for(int i = 0; i < LANES; i++) { mOffsets = other.mOffsets[i]; } + for(int i = 0; i < LANES; i++) { mOffsets[i] = other.mOffsets[i]; } } @@ -523,8 +523,8 @@ struct MultiPixelController { // composite shortcut functions for loading, dithering, and scaling template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane) { return scale(pc, pc.dither(pc, pc.loadByte(pc, lane))); } - template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane, uint8_t d, uint8_t scale) { return scale(pc, pc.dither(pc, pc.loadByte(pc, lane), d), scale); } - template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane, uint8_t scale) { return scale(pc, pc.loadByte(pc, lane), scale); } + template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane, uint8_t d, uint8_t scale) { return scale8(pc.dither(pc, pc.loadByte(pc, lane), d), scale); } + template __attribute__((always_inline)) inline static uint8_t loadAndScale(MultiPixelController & pc, int lane, uint8_t scale) { return scale8(pc.loadByte(pc, lane), scale); } template __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(MultiPixelController & pc, int lane) { pc.advanceData(); return pc.loadAndScale(pc, lane); } template __attribute__((always_inline)) inline static uint8_t getd(MultiPixelController & pc) { return pc.d[RO(SLOT)]; } -- cgit v1.2.3 From 10dc6ea0e74e6e83e040a01e7662355510f1dc65 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 15 Sep 2014 11:16:06 -0700 Subject: Fix k20 parallel output --- clockless_block_arm_k20.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index e1ec9d52..fdeca340 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -23,7 +23,7 @@ public: FastPin<6>::setOutput(); FastPin<20>::setOutput(); FastPin<21>::setOutput(); - FastPin<25>::setOutput(); + FastPin<5>::setOutput(); mPinMask = FastPin<2>::mask(); mPort = FastPin<2>::port(); } -- cgit v1.2.3 From 9a5dcd714e0652346a974d71d4e0b632b38a39cb Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 29 Sep 2014 17:26:53 -0700 Subject: Radio shack's supplier tweaked the TM1803 timing numbers again --- chipsets.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chipsets.h b/chipsets.h index 322305dd..dca647e6 100644 --- a/chipsets.h +++ b/chipsets.h @@ -470,7 +470,7 @@ template class TM1809Controller800Khz : public ClocklessController {}; template -class TM1803Controller400Khz : public ClocklessController {}; +class TM1803Controller400Khz : public ClocklessController {}; template class TM1829Controller800Khz : public ClocklessController {}; @@ -533,7 +533,7 @@ class WS2811Controller400Khz : public ClocklessController -class TM1803Controller400Khz : public ClocklessController {}; +class TM1803Controller400Khz : public ClocklessController {}; #if NO_TIME(750, 750, 750) #warning "Not enough clock cycles available for the TM1803" #endif -- cgit v1.2.3 From e9b0597130847a1101b11ce9be9a7eff343cd1be Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 24 Oct 2014 21:10:37 -0400 Subject: adding fast bitswap functions --- FastLED.h | 2 + bitswap.h | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 bitswap.h diff --git a/FastLED.h b/FastLED.h index 4547f24b..2c96d5e8 100644 --- a/FastLED.h +++ b/FastLED.h @@ -16,6 +16,7 @@ #include "controller.h" #include "fastpin.h" #include "fastspi.h" +#include "bitswap.h" #include "clockless.h" #include "lib8tion.h" #include "hsv2rgb.h" @@ -27,6 +28,7 @@ #include "noise.h" #include "power_mgt.h" + enum ESPIChipsets { LPD8806, WS2801, diff --git a/bitswap.h b/bitswap.h new file mode 100644 index 00000000..39eb4027 --- /dev/null +++ b/bitswap.h @@ -0,0 +1,219 @@ +#ifndef __INC_BITSWAP_H +#define __INC_BITSWAP_H + +// structure representing 8 bits of access +typedef union { + uint8_t raw; + struct { + uint32_t a0:1; + uint32_t a1:1; + uint32_t a2:1; + uint32_t a3:1; + uint32_t a4:1; + uint32_t a5:1; + uint32_t a6:1; + uint32_t a7:1; + }; +} just8bits; + +// structure representing 32 bits of access +typedef struct { + uint32_t a0:1; + uint32_t a1:1; + uint32_t a2:1; + uint32_t a3:1; + uint32_t a4:1; + uint32_t a5:1; + uint32_t a6:1; + uint32_t a7:1; + uint32_t b0:1; + uint32_t b1:1; + uint32_t b2:1; + uint32_t b3:1; + uint32_t b4:1; + uint32_t b5:1; + uint32_t b6:1; + uint32_t b7:1; + uint32_t c0:1; + uint32_t c1:1; + uint32_t c2:1; + uint32_t c3:1; + uint32_t c4:1; + uint32_t c5:1; + uint32_t c6:1; + uint32_t c7:1; + uint32_t d0:1; + uint32_t d1:1; + uint32_t d2:1; + uint32_t d3:1; + uint32_t d4:1; + uint32_t d5:1; + uint32_t d6:1; + uint32_t d7:1; +} sub4; + +// union containing a full 8 bytes to swap the bit orientation on +typedef union { + uint32_t word[2]; + uint8_t bytes[8]; + struct { + sub4 a; + sub4 b; + }; +} bitswap_type; + + +#define SWAPSA(X,N) out. X ## 0 = in.a.a ## N; \ + out. X ## 1 = in.a.b ## N; \ + out. X ## 2 = in.a.c ## N; \ + out. X ## 3 = in.a.d ## N; + +#define SWAPSB(X,N) out. X ## 0 = in.b.a ## N; \ + out. X ## 1 = in.b.b ## N; \ + out. X ## 2 = in.b.c ## N; \ + out. X ## 3 = in.b.d ## N; + +#define SWAPS(X,N) out. X ## 0 = in.a.a ## N; \ + out. X ## 1 = in.a.b ## N; \ + out. X ## 2 = in.a.c ## N; \ + out. X ## 3 = in.a.d ## N; \ + out. X ## 4 = in.b.a ## N; \ + out. X ## 5 = in.b.b ## N; \ + out. X ## 6 = in.b.c ## N; \ + out. X ## 7 = in.b.d ## N; + + +__attribute__((always_inline)) inline void swapbits8(bitswap_type in, bitswap_type & out) { + + // SWAPS(a.a,7); + // SWAPS(a.b,6); + // SWAPS(a.c,5); + // SWAPS(a.d,4); + // SWAPS(b.a,3); + // SWAPS(b.b,2); + // SWAPS(b.c,1); + // SWAPS(b.d,0); + + // SWAPSA(a.a,7); + // SWAPSA(a.b,6); + // SWAPSA(a.c,5); + // SWAPSA(a.d,4); + // + // SWAPSB(a.a,7); + // SWAPSB(a.b,6); + // SWAPSB(a.c,5); + // SWAPSB(a.d,4); + // + // SWAPSA(b.a,3); + // SWAPSA(b.b,2); + // SWAPSA(b.c,1); + // SWAPSA(b.d,0); + // // + // SWAPSB(b.a,3); + // SWAPSB(b.b,2); + // SWAPSB(b.c,1); + // SWAPSB(b.d,0); + + for(int i = 0; i < 8; i++) { + just8bits work; + work.a3 = in.word[0] >> 31; + work.a2 = in.word[0] >> 23; + work.a1 = in.word[0] >> 15; + work.a0 = in.word[0] >> 7; + in.word[0] <<= 1; + work.a7 = in.word[1] >> 31; + work.a6 = in.word[1] >> 23; + work.a5 = in.word[1] >> 15; + work.a4 = in.word[1] >> 7; + in.word[1] <<= 1; + out.bytes[i] = work.raw; + } +} + +__attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned char *B) { + for(int row = 0; row < 7; row++) { + uint8_t x = A[row]; + B[7] |= (x & 0x01) << row; x >>= 1; + B[6] |= (x & 0x01) << row; x >>= 1; + B[5] |= (x & 0x01) << row; x >>= 1; + B[4] |= (x & 0x01) << row; x >>= 1; + B[3] |= (x & 0x01) << row; x >>= 1; + B[2] |= (x & 0x01) << row; x >>= 1; + B[1] |= (x & 0x01) << row; x >>= 1; + B[0] |= (x & 0x01) << row; x >>= 1; + } +} + +__attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsigned char *B) { + uint32_t x, y, t; + + // Load the array and pack it into x and y. + y = *(unsigned int*)(A); + x = *(unsigned int*)(A+4); + + // pre-transform x + t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); + t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); + + // pre-transform y + t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); + t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); + + // final transform + t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); + y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); + x = t; + + //((uint64_t*)B) = x<<32 | y; + // + B[7] = y; y >>= 8; + B[6] = y; y >>= 8; + B[5] = y; y >>= 8; + B[4] = y; + + B[3] = x; x >>= 8; + B[2] = x; x >>= 8; + B[1] = x; x >>= 8; + B[0] = x; /* */ +} + +template +__attribute__((always_inline)) inline void transpose8(unsigned char *A, unsigned char *B) { + uint32_t x, y, t; + + // Load the array and pack it into x and y. + if(m == 1) { + y = *(unsigned int*)(A); + x = *(unsigned int*)(A+4); + } else { + x = (A[0]<<24) | (A[m]<<16) | (A[2*m]<<8) | A[3*m]; + y = (A[4*m]<<24) | (A[5*m]<<16) | (A[6*m]<<8) | A[7*m]; + } + + // pre-transform x + t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); + t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); + + // pre-transform y + t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); + t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); + + // final transform + t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); + y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); + x = t; + + B[7*n] = y; y >>= 8; + B[6*n] = y; y >>= 8; + B[5*n] = y; y >>= 8; + B[4*n] = y; + + B[3*n] = x; x >>= 8; + B[2*n] = x; x >>= 8; + B[n] = x; x >>= 8; + B[0] = x; + // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; + // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; +} + +#endif -- cgit v1.2.3 From b0a94d0732d187de08f3912897bdc5a1fe02c182 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 24 Oct 2014 22:10:15 -0400 Subject: Cleaning up the k20 blockless controller w/faster bit swapping --- clockless_block_arm_k20.h | 152 ++++++++++------------------------------------ 1 file changed, 33 insertions(+), 119 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index fdeca340..a144f91b 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -5,6 +5,11 @@ // See clockless.h for detailed info on how the template parameters are used. #if defined(FASTLED_TEENSY3) #define HAS_BLOCKLESS 1 +#define PORT_MASK 0x000000FF +#define SKIPLIST ~PORT_MASK +#define LANES 8 + +#include "kinetis.h" template class InlineBlockClocklessController : public CLEDController { @@ -34,17 +39,11 @@ public: // set all the leds on the controller to a given color virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); cli(); - uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+nLeds/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(2*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/*/+(3*nLeds)/**/, nLeds, scale, getDither())); + uint32_t clocks = showRGBInternal(pixels,nLeds); // Adjust the timer long microsTaken = CLKS_TO_MICROS(clocks); @@ -54,17 +53,11 @@ public: } virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); cli(); - uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither()), - PixelController(rgbdata/**/+(1*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/**/+(2*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/**/+(3*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/**/+(4*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/**/+(5*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/**/+(6*nLeds)/**/, nLeds, scale, getDither()), - PixelController(rgbdata/**/+(7*nLeds)/**/, nLeds, scale, getDither())); + uint32_t clocks = showRGBInternal(pixels,nLeds); // Adjust the timer long microsTaken = CLKS_TO_MICROS(clocks); @@ -89,44 +82,6 @@ public: } #endif - typedef union { - uint32_t word; - struct { - uint32_t a0:1; - uint32_t a1:1; - uint32_t a2:1; - uint32_t a3:1; - uint32_t a4:1; - uint32_t a5:1; - uint32_t a6:1; - uint32_t a7:1; - uint32_t b0:1; - uint32_t b1:1; - uint32_t b2:1; - uint32_t b3:1; - uint32_t b4:1; - uint32_t b5:1; - uint32_t b6:1; - uint32_t b7:1; - uint32_t c0:1; - uint32_t c1:1; - uint32_t c2:1; - uint32_t c3:1; - uint32_t c4:1; - uint32_t c5:1; - uint32_t c6:1; - uint32_t c7:1; - uint32_t d0:1; - uint32_t d1:1; - uint32_t d2:1; - uint32_t d3:1; - uint32_t d4:1; - uint32_t d5:1; - uint32_t d6:1; - uint32_t d7:1; - }; - } xtype; - #define USE_LINES typedef union { @@ -134,104 +89,63 @@ public: uint32_t raw[2]; } Lines; - __attribute__ ((always_inline)) inline static uint32_t bits(Lines & b) { - xtype fuckery; - fuckery.word = 0; - fuckery.a0 = (b.raw[0] >> 31); - fuckery.a1 = (b.raw[0] >> 23); - fuckery.a2 = (b.raw[0] >> 15); - fuckery.a3 = (b.raw[0] >> 7); - fuckery.a4 = (b.raw[1] >> 31); - fuckery.a5 = (b.raw[1] >> 23); - fuckery.a6 = (b.raw[1] >> 15); - fuckery.a7 = (b.raw[1] >> 7); - // fuckery.b0 = (b.raw[2] >> 30); - // fuckery.b1 = (b.raw[2] >> 22); - // fuckery.b2 = (b.raw[2] >> 14); - // fuckery.b3 = (b.raw[2] >> 6); - // fuckery.b4 = (b.raw[3] >> 30); - // fuckery.b5 = (b.raw[3] >> 22) - // fuckery.b6 = (b.raw[3] >> 14); - // fuckery.b7 = (b.raw[3] >> 6); - // fuckery.c0 = (b.raw[4] >> 29); - // fuckery.c1 = (b.raw[4] >> 21); - // fuckery.c2 = (b.raw[4] >> 13); - // fuckery.c3 = (b.raw[4] >> 5); - // fuckery.c4 = (b.raw[5] >> 20); - // fuckery.c5 = (b.raw[5] >> 21); - // fuckery.c6 = (b.raw[5] >> 13); - // fuckery.c7 = (b.raw[5] >> 5); - // fuckery.d0 = (b.raw[6] >> 28); - // fuckery.d1 = (b.raw[6] >> 19); - // fuckery.d2 = (b.raw[6] >> 12); - // fuckery.d3 = (b.raw[6] >> 4); - // fuckery.d4 = (b.raw[7] >> 28); - // fuckery.d5 = (b.raw[7] >> 19); - // fuckery.d6 = (b.raw[7] >> 12); - // fuckery.d7 = (b.raw[7] >> 4); - return fuckery.word; - } + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, MultiPixelController &pixels) { // , register uint32_t & b2) { + transpose8(b.raw,b2.raw); + register uint8_t d = pixels.template getd(pixels); + register uint8_t scale = pixels.template getscale(pixels); - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, PixelController *allpixels[8]) { // , register uint32_t & b2) { - uint32_t flipper = bits(b); for(register uint32_t i = 0; i < 8; i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); *FastPin<2>::port() = 0xFF; - uint32_t flip_mark = next_mark - (T2+T3+2); + // uint32_t flip_mark = next_mark - (T2+T3+2); - while(ARM_DWT_CYCCNT < flip_mark); - uint32_t last_flip_mark = next_mark - (T3); - *FastPin<2>::port() = flipper; - b.raw[0] <<= 1; - b.raw[1] <<= 1; - flipper = bits(b); + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); + // while(ARM_DWT_CYCCNT < flip_mark); + // uint32_t last_flip_mark = next_mark - (T3); + *FastPin<2>::port() = ~b2.raw[i]; - - while(ARM_DWT_CYCCNT < last_flip_mark); + while((next_mark - ARM_DWT_CYCCNT) > (T3)); + // while(ARM_DWT_CYCCNT < last_flip_mark); *FastPin<2>::port() = 0; - switch(PX) { - case 0: b2.bytes[i] = allpixels[i]->advanceAndLoadAndScale0(); break; - case 1: b2.bytes[i] = allpixels[i]->loadAndScale1(); break; - case 2: b2.bytes[i] = allpixels[i]->loadAndScale2(); break; - } + + b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); } } + + // 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 pixels, PixelController pixels2, PixelController pixels3, PixelController pixels4, - PixelController pixels5, PixelController pixels6, PixelController pixels7, PixelController pixels8) { + static uint32_t showRGBInternal(MultiPixelController &allpixels, int nLeds) { // Get access to the clock ARM_DEMCR |= ARM_DEMCR_TRCENA; ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; ARM_DWT_CYCCNT = 0; // Setup the pixel controller and load/scale the first byte - PixelController *allpixels[8] = {&pixels,&pixels2,&pixels3,&pixels4,&pixels5,&pixels6,&pixels7,&pixels8}; - pixels.preStepFirstByteDithering(); - register Lines b0,b1,b2; + allpixels.preStepFirstByteDithering(); + register Lines b0,b1; b0.raw[0] = b0.raw[1] = 0; b1.raw[0] = b1.raw[1] = 0; - b2.raw[0] = b2.raw[1] = 0; + allpixels->preStepFirstByteDithering(); for(int i = 0; i < 8; i++) { - allpixels[i]->preStepFirstByteDithering(); - b0.bytes[i] = allpixels[i]->loadAndScale0(); + b0.bytes[i] = allpixels->loadAndScale0(i); } uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - while(pixels.has(1)) { - pixels.stepDithering(); + while(nLeds--) { + allpixels.stepDithering(); // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + writeBits<8+XTRA0,2>(next_mark, b0, b1, allpixels); // Write third byte - writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + writeBits<8+XTRA0,0>(next_mark, b0, b1, allpixels); }; return ARM_DWT_CYCCNT; -- cgit v1.2.3 From 61d72db9d0855061735b85a361d5bf5463658c3b Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 24 Oct 2014 22:10:51 -0400 Subject: cleaning out dead code from the sam block controller --- clockless_block_arm_sam.h | 57 +---------------------------------------------- 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 4aa242f3..38ee69bb 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -14,11 +14,11 @@ // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if defined(__SAM3X8E__) // #define PORT_MASK 0x77EFF3FE // due #define PORT_MASK 0x7FFFFFE #define SKIPLIST ~PORT_MASK -#if defined(__SAM3X8E__) #define HAS_BLOCKLESS 1 #define LANES 8 @@ -241,63 +241,8 @@ i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); #endif #endif - // switch(PX) { - // case 0: b2.bytes[i] = pixels.loadAndScale0(i); break; - // case 1: b2.bytes[i] = pixels.loadAndScale1(i); break; - // case 2: b2.bytes[i] = pixels.loadAndScale2(i); break; - // } - // switch(PX) { - // case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; - // case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; - // case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; - // } -// #if LANES > 8 -// i++; -// switch(PX) { -// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; -// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; -// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; -// } -// #endif -// #if LANES > 16 -// i++; -// switch(PX) { -// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; -// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; -// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; -// } -// #endif -// #if LANES > 24 -// i++; -// switch(PX) { -// case 0: b2.bytes[i] = pixels.loadAndScale0(i,d,scale); break; -// case 1: b2.bytes[i] = pixels.loadAndScale1(i,d,scale); break; -// case 2: b2.bytes[i] = pixels.loadAndScale2(i,d,scale); break; -// } -// #endif } - // for(uint32_t i = 0; i < LANES/2; i++) { - // while(VAL > next_mark); - // - // next_mark = VAL - (TOTAL); - // *FastPin<33>::sport() = PORT_MASK; - // - // while((VAL-next_mark) > (T2+T3+6)); - // *FastPin<33>::cport() = (flipper & PORT_MASK); - // flipper = bits(b); - // - // - // while((VAL - next_mark) > T3); - // *FastPin<33>::cport() = PORT_MASK; - // } - - // transposeLines(b, b2); - // for(register uint32_t i = 0; i < XTRA0; i++) { - // AT_BIT_START(*FastPin<33>::port() = 0xFFFF); - // AT_MARK(*FastPin<33>::port() = 0); - // AT_END(*FastPin<2>::port() = 0); - // } } // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then -- cgit v1.2.3 From 2a11adcd88cffddc315f32aa40d2bf2e29909455 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 24 Oct 2014 22:11:05 -0400 Subject: switch style of swapping for comparison timings --- bitswap.h | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/bitswap.h b/bitswap.h index 39eb4027..e906c342 100644 --- a/bitswap.h +++ b/bitswap.h @@ -131,16 +131,27 @@ __attribute__((always_inline)) inline void swapbits8(bitswap_type in, bitswap_ty } __attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned char *B) { + for(int row = 0; row < 7; row++) { uint8_t x = A[row]; - B[7] |= (x & 0x01) << row; x >>= 1; - B[6] |= (x & 0x01) << row; x >>= 1; - B[5] |= (x & 0x01) << row; x >>= 1; - B[4] |= (x & 0x01) << row; x >>= 1; - B[3] |= (x & 0x01) << row; x >>= 1; - B[2] |= (x & 0x01) << row; x >>= 1; - B[1] |= (x & 0x01) << row; x >>= 1; - B[0] |= (x & 0x01) << row; x >>= 1; + + uint8_t bit = (1<>= 1) { + if(x & mask) { + *p++ |= bit; + } else { + *p++ &= ~bit; + } + } + // B[7] |= (x & 0x01) << row; x >>= 1; + // B[6] |= (x & 0x01) << row; x >>= 1; + // B[5] |= (x & 0x01) << row; x >>= 1; + // B[4] |= (x & 0x01) << row; x >>= 1; + // B[3] |= (x & 0x01) << row; x >>= 1; + // B[2] |= (x & 0x01) << row; x >>= 1; + // B[1] |= (x & 0x01) << row; x >>= 1; + // B[0] |= (x & 0x01) << row; x >>= 1; } } -- cgit v1.2.3 From 74466cb2163a42384a1127788635d495a53ece7f Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 11:56:54 -0700 Subject: Make transpose8x1 faster --- bitswap.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bitswap.h b/bitswap.h index e906c342..4205d7a3 100644 --- a/bitswap.h +++ b/bitswap.h @@ -175,8 +175,10 @@ __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsign y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); x = t; - //((uint64_t*)B) = x<<32 | y; - // +#if 1 + *((uint32_t*)B) = y; + *((uint32_t*)(B+4)) = x; +#else B[7] = y; y >>= 8; B[6] = y; y >>= 8; B[5] = y; y >>= 8; @@ -186,6 +188,7 @@ __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsign B[2] = x; x >>= 8; B[1] = x; x >>= 8; B[0] = x; /* */ +#endif } template -- cgit v1.2.3 From 4cff169ef1d1bcf52d3426011310d809b10871ec Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 16:13:05 -0700 Subject: Solid teensy 3/3.1 support for up to 8-way output on either PORT C or D --- FastLED.h | 23 ++++------- clockless_block_arm_k20.h | 102 ++++++++++++++++++++++++++++++---------------- fastpin_arm_k20.h | 18 ++++---- 3 files changed, 87 insertions(+), 56 deletions(-) diff --git a/FastLED.h b/FastLED.h index 0833a33d..c1364af9 100644 --- a/FastLED.h +++ b/FastLED.h @@ -79,7 +79,8 @@ template class DMXSERIAL : public DMXSerialController class SM16716 : public SM16716Controller {}; enum EBlockChipsets { - WS2811_PORTC + WS2811_PORTC, + WS2811_PORTD }; #if defined(LIB8_ATTINY) @@ -186,29 +187,23 @@ public: #endif #ifdef FASTSPI_USE_DMX_SIMPLE - template + template static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { switch(CHIPSET) { case DMX: { static DMXController controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); } } } - - template - static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { - switch(CHIPSET) { - case DMX: {static DMXController controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); } - } - } #endif #ifdef HAS_BLOCKLESS - template - static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { - switch(CHIPSET) { - case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); - } +template +static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { + switch(CHIPSET) { + case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); + case WS2811_PORTD: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); } +} #endif void setBrightness(uint8_t scale) { m_Scale = scale; } diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index a144f91b..aacef5de 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -5,13 +5,12 @@ // See clockless.h for detailed info on how the template parameters are used. #if defined(FASTLED_TEENSY3) #define HAS_BLOCKLESS 1 -#define PORT_MASK 0x000000FF -#define SKIPLIST ~PORT_MASK -#define LANES 8 + +#define PORT_MASK (((1< +template class InlineBlockClocklessController : public CLEDController { typedef typename FastPin<2>::port_ptr_t data_ptr_t; typedef typename FastPin<2>::port_t data_t; @@ -21,17 +20,38 @@ class InlineBlockClocklessController : public CLEDController { CMinWait mWait; public: virtual void init() { - FastPin<2>::setOutput(); - FastPin<14>::setOutput(); - FastPin<7>::setOutput(); - FastPin<8>::setOutput(); - FastPin<6>::setOutput(); - FastPin<20>::setOutput(); - FastPin<21>::setOutput(); - FastPin<5>::setOutput(); - mPinMask = FastPin<2>::mask(); - mPort = FastPin<2>::port(); - } + if(FIRST_PIN == 15) { + switch(LANES) { + // case 12: FastPin<30>::setOutput(); + // case 11: FastPin<29>::setOutput(); + // case 10: FastPin<27>::setOutput(); + // case 9: FastPin<28>::setOutput(); + case 8: FastPin<12>::setOutput(); + case 7: FastPin<11>::setOutput(); + case 6: FastPin<13>::setOutput(); + case 5: FastPin<10>::setOutput(); + case 4: FastPin<9>::setOutput(); + case 3: FastPin<23>::setOutput(); + case 2: FastPin<22>::setOutput(); + case 1: FastPin<15>::setOutput(); + } + mPinMask = FastPin<15>::mask(); + mPort = FastPin<15>::port(); + } else if(FIRST_PIN == 2) { + switch(LANES) { + 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(); + } + mPinMask = FastPin<2>::mask(); + mPort = FastPin<2>::port(); + } + } virtual void clearLeds(int nLeds) { showColor(CRGB(0, 0, 0), nLeds, 0); @@ -89,27 +109,41 @@ public: uint32_t raw[2]; } Lines; - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, MultiPixelController &pixels) { // , register uint32_t & b2) { - transpose8(b.raw,b2.raw); + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { + register Lines b2; + transpose8x1(b.bytes,b2.bytes); + register uint8_t d = pixels.template getd(pixels); register uint8_t scale = pixels.template getscale(pixels); - for(register uint32_t i = 0; 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); - *FastPin<2>::port() = 0xFF; - // uint32_t flip_mark = next_mark - (T2+T3+2); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; + *FastPin::sport() = PORT_MASK; while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); - // while(ARM_DWT_CYCCNT < flip_mark); - // uint32_t last_flip_mark = next_mark - (T3); - *FastPin<2>::port() = ~b2.raw[i]; + *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); while((next_mark - ARM_DWT_CYCCNT) > (T3)); - // while(ARM_DWT_CYCCNT < last_flip_mark); - *FastPin<2>::port() = 0; + *FastPin::cport() = PORT_MASK; b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); + if(LANES>8) { + b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); + } + } + + for(register uint32_t i = LANES; i < 8; i++) { + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; + *FastPin::sport() = PORT_MASK; + + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); + *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); + + while((next_mark - ARM_DWT_CYCCNT) > (T3)); + *FastPin::cport() = PORT_MASK; + } } @@ -126,11 +160,10 @@ public: // Setup the pixel controller and load/scale the first byte allpixels.preStepFirstByteDithering(); register Lines b0,b1; - b0.raw[0] = b0.raw[1] = 0; - b1.raw[0] = b1.raw[1] = 0; - allpixels->preStepFirstByteDithering(); - for(int i = 0; i < 8; i++) { - b0.bytes[i] = allpixels->loadAndScale0(i); + + allpixels.preStepFirstByteDithering(); + for(int i = 0; i < LANES; i++) { + b0.bytes[i] = allpixels.loadAndScale0(i); } uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); @@ -139,13 +172,14 @@ public: allpixels.stepDithering(); // Write first byte, read next byte - writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); + writeBits<8+XTRA0,1>(next_mark, b0, allpixels); // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b0, b1, allpixels); + writeBits<8+XTRA0,2>(next_mark, b0, allpixels); + allpixels.advanceData(); // Write third byte - writeBits<8+XTRA0,0>(next_mark, b0, b1, allpixels); + writeBits<8+XTRA0,0>(next_mark, b0, allpixels); }; return ARM_DWT_CYCCNT; diff --git a/fastpin_arm_k20.h b/fastpin_arm_k20.h index 71bddde3..2fb75fbd 100644 --- a/fastpin_arm_k20.h +++ b/fastpin_arm_k20.h @@ -5,7 +5,7 @@ /// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found /// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. /// The registers are data output, set output, clear output, toggle output, input, and direction -template class _ARMPIN { +template class _ARMPIN { public: typedef volatile uint32_t * port_ptr_t; typedef uint32_t port_t; @@ -18,7 +18,7 @@ public: inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - + inline static void toggle() __attribute__ ((always_inline)) { _PTOR::r() = _MASK; } inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } @@ -28,12 +28,14 @@ public: inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } + inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } + inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } }; -/// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC +/// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC /// does a poor job of optimizing around these accesses so they are not being used just yet. -template class _ARMPIN_BITBAND { +template class _ARMPIN_BITBAND { public: typedef volatile uint32_t * port_ptr_t; typedef uint32_t port_t; @@ -46,7 +48,7 @@ public: inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - + inline static void toggle() __attribute__ ((always_inline)) { *_PTOR::template rx<_BIT>() = 1; } inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } @@ -70,9 +72,9 @@ public: #define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin : public _ARMPIN {}; \ template<> class FastPinBB : public _ARMPIN_BITBAND {}; + _R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {}; -// Actual pin definitions +// Actual pin definitions #if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY) _IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); @@ -92,7 +94,7 @@ _DEFPIN_ARM(32, 18, B); _DEFPIN_ARM(33, 4, A); #define SPI_CLOCK 13 #define SPI1 (*(SPI_t *)0x4002D000) -#if defined(__MK20DX256__) +#if defined(__MK20DX256__) #define SPI2_DATA 7 #define SPI2_CLOCK 14 #endif -- cgit v1.2.3 From 99bd5de32ee5d503b11a6af14aa3f70bbe2f6947 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 16:48:18 -0700 Subject: Cleaning up blockless support for the due - normalizing definition of 8-way block outputs. --- FastLED.h | 33 +++++++- clockless_block_arm_k20.h | 20 ++--- clockless_block_arm_sam.h | 211 +++++++++++++++------------------------------- 3 files changed, 108 insertions(+), 156 deletions(-) diff --git a/FastLED.h b/FastLED.h index c1364af9..508beb22 100644 --- a/FastLED.h +++ b/FastLED.h @@ -79,8 +79,18 @@ template class DMXSERIAL : public DMXSerialController class SM16716 : public SM16716Controller {}; enum EBlockChipsets { +#ifdef PORTA_FIRST_PIN + WS2811_PORTA, +#endif +#ifdef PORTB_FIRST_PIN + WS2811_PORTB, +#endif +#ifdef PORTC_FIRST_PIN WS2811_PORTC, - WS2811_PORTD +#endif +#ifdef PORTD_FIRST_PIN + WS2811_PORTD, +#endif }; #if defined(LIB8_ATTINY) @@ -197,13 +207,28 @@ public: #endif #ifdef HAS_BLOCKLESS -template +template static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { switch(CHIPSET) { - case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); - case WS2811_PORTD: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); +#ifdef PORTA_FIRST_PIN + case WS2811_PORTA: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); +#endif +#ifdef PORTB_FIRST_PIN + case WS2811_PORTB: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); +#endif +#ifdef PORTC_FIRST_PIN + case WS2811_PORTC: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); +#endif +#ifdef PORTD_FIRST_PIN + case WS2811_PORTD: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); +#endif } } + +template +static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { + return addLeds(data,nLedsOrOffset,nLedsIfOffset); +} #endif void setBrightness(uint8_t scale) { m_Scale = scale; } diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index aacef5de..58137c58 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -6,14 +6,17 @@ #if defined(FASTLED_TEENSY3) #define HAS_BLOCKLESS 1 +#define PORTC_FIRST_PIN 15 +#define PORTD_FIRST_PIN 2 + #define PORT_MASK (((1< +template class InlineBlockClocklessController : public CLEDController { - typedef typename FastPin<2>::port_ptr_t data_ptr_t; - typedef typename FastPin<2>::port_t data_t; + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; data_t mPinMask; data_ptr_t mPort; @@ -35,8 +38,6 @@ public: case 2: FastPin<22>::setOutput(); case 1: FastPin<15>::setOutput(); } - mPinMask = FastPin<15>::mask(); - mPort = FastPin<15>::port(); } else if(FIRST_PIN == 2) { switch(LANES) { case 8: FastPin<5>::setOutput(); @@ -48,10 +49,10 @@ public: case 2: FastPin<14>::setOutput(); case 1: FastPin<2>::setOutput(); } - mPinMask = FastPin<2>::mask(); - mPort = FastPin<2>::port(); - } } + mPinMask = FastPin::mask(); + mPort = FastPin::port(); + } virtual void clearLeds(int nLeds) { showColor(CRGB(0, 0, 0), nLeds, 0); @@ -103,7 +104,6 @@ public: #endif -#define USE_LINES typedef union { uint8_t bytes[8]; uint32_t raw[2]; @@ -159,7 +159,7 @@ public: // Setup the pixel controller and load/scale the first byte allpixels.preStepFirstByteDithering(); - register Lines b0,b1; + register Lines b0; allpixels.preStepFirstByteDithering(); for(int i = 0; i < LANES; i++) { diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 38ee69bb..31b9e8b9 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -15,40 +15,69 @@ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(__SAM3X8E__) -// #define PORT_MASK 0x77EFF3FE // due -#define PORT_MASK 0x7FFFFFE -#define SKIPLIST ~PORT_MASK +#define PORT_MASK (((1< +template class InlineBlockClocklessController : public CLEDController { - typedef typename FastPin<33>::port_ptr_t data_ptr_t; - typedef typename FastPin<33>::port_t data_t; + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; data_t mPinMask; data_ptr_t mPort; CMinWait mWait; public: virtual void init() { - //FastPinBB::setOutput(); - // uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 0}; // 72, 106, 0 }; // due - uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 107, 106, 51, 50, 49, 48, 47, 46,45, 44, 105, 9, 8, 7, 6, 5, 4, 104, 3, 10, 109, 0}; // 72, 106, 0 }; // digix - int i = 0; - while(pins[i]) { pinMode(pins[i++], OUTPUT); } + if(FIRST_PIN == 69) { + switch(LANES) { + case 8: FastPin<31>::setOutput(); + case 7: FastPin<58>::setOutput(); + case 6: FastPin<100>::setOutput(); + case 5: FastPin<59>::setOutput(); + case 4: FastPin<60>::setOutput(); + case 3: FastPin<61>::setOutput(); + case 2: FastPin<68>::setOutput(); + case 1: FastPin<69>::setOutput(); + } + } else if(FIRST_PIN == 25) { + switch(LANES) { + case 8: FastPin<11>::setOutput(); + case 7: FastPin<29>::setOutput(); + case 6: FastPin<15>::setOutput(); + case 5: FastPin<14>::setOutput(); + case 4: FastPin<28>::setOutput(); + case 3: FastPin<27>::setOutput(); + case 2: FastPin<26>::setOutput(); + case 1: FastPin<25>::setOutput(); + } + } else if(FIRST_PIN == 90) { + switch(LANES) { + case 8: FastPin<97>::setOutput(); + case 7: FastPin<96>::setOutput(); + case 6: FastPin<95>::setOutput(); + case 5: FastPin<94>::setOutput(); + case 4: FastPin<93>::setOutput(); + case 3: FastPin<92>::setOutput(); + case 2: FastPin<91>::setOutput(); + case 1: FastPin<90>::setOutput(); + } + } + mPinMask = FastPin::mask(); + mPort = FastPin::port(); } virtual void clearLeds(int nLeds) { @@ -89,10 +118,6 @@ public: savedClock.restore(); while(millisTaken-- > 0) { TimeTick_Increment(); } sei(); - // Adjust the timer - // long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - // MS_COUNTER += (microsTaken / 1000); - // sei(); mWait.mark(); } @@ -112,137 +137,42 @@ public: } #endif - typedef union { - uint32_t word; - struct { - uint32_t a0:1; - uint32_t a1:1; - uint32_t a2:1; - uint32_t a3:1; - uint32_t a4:1; - uint32_t a5:1; - uint32_t a6:1; - uint32_t a7:1; - uint32_t b0:1; - uint32_t b1:1; - uint32_t b2:1; - uint32_t b3:1; - uint32_t b4:1; - uint32_t b5:1; - uint32_t b6:1; - uint32_t b7:1; - uint32_t c0:1; - uint32_t c1:1; - uint32_t c2:1; - uint32_t c3:1; - uint32_t c4:1; - uint32_t c5:1; - uint32_t c6:1; - uint32_t c7:1; - uint32_t d0:1; - uint32_t d1:1; - uint32_t d2:1; - uint32_t d3:1; - uint32_t d4:1; - uint32_t d5:1; - uint32_t d6:1; - uint32_t d7:1; - }; - } xtype; - - - -// #define IFSKIP(N,X) if(PORT_MASK & 1<> 31); - fuckery.a1 = (b.raw[0] >> 23); - fuckery.a2 = (b.raw[0] >> 15); - fuckery.a3 = (b.raw[0] >> 7); - b.raw[0] <<= 1; - fuckery.a4 = (b.raw[1] >> 31); - fuckery.a5 = (b.raw[1] >> 23); - fuckery.a6 = (b.raw[1] >> 15); - fuckery.a7 = (b.raw[1] >> 7); - b.raw[1] <<= 1; -#if LANES > 8 - fuckery.b0 = (b.raw[2] >> 31); - fuckery.b1 = (b.raw[2] >> 23); - fuckery.b2 = (b.raw[2] >> 15); - fuckery.b3 = (b.raw[2] >> 7); - b.raw[2] <<= 1; - fuckery.b4 = (b.raw[3] >> 31); - fuckery.b5 = (b.raw[3] >> 23); - fuckery.b6 = (b.raw[3] >> 15); - fuckery.b7 = (b.raw[3] >> 7); - b.raw[3] <<= 1; -#endif -#if (LANES > 16) - fuckery.c0 = (b.raw[4] >> 31); - fuckery.c1 = (b.raw[4] >> 23); - fuckery.c2 = (b.raw[4] >> 15); - fuckery.c3 = (b.raw[4] >> 7); - b.raw[4] <<= 1; - fuckery.c4 = (b.raw[5] >> 31); - fuckery.c5 = (b.raw[5] >> 23); - fuckery.c6 = (b.raw[5] >> 15); - fuckery.c7 = (b.raw[5] >> 7); - b.raw[5] <<= 1; -#if (LANES > 24) - fuckery.d0 = (b.raw[6] >> 31); - fuckery.d1 = (b.raw[6] >> 23); - fuckery.d2 = (b.raw[6] >> 15); - fuckery.d3 = (b.raw[6] >> 7); - b.raw[6] <<= 1; - fuckery.d4 = (b.raw[7] >> 31); - fuckery.d5 = (b.raw[7] >> 23); - fuckery.d6 = (b.raw[7] >> 15); - fuckery.d7 = (b.raw[7] >> 7); - b.raw[7] <<= 1; -#endif -#endif - fuckery.word |= (fuckery.word << 7); - fuckery.word |= (fuckery.word << 14); - - return ~fuckery.word; - } - #define VAL *((uint32_t*)(SysTick_BASE + 8)) - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b2, MultiPixelController &pixels) { // , register uint32_t & b2) { - uint32_t flipper = bits(b); + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { + register Lines b2; + transpose8x1(b.bytes,b2.bytes); + register uint8_t d = pixels.template getd(pixels); register uint8_t scale = pixels.template getscale(pixels); - // Serial.print("flipper is "); Serial.println(flipper); - for(uint32_t i = 0; i < LANES/(LANES/8); i++) { + for(uint32_t i = 0; (i < LANES) && (i<8); i++) { while(VAL > next_mark); next_mark = VAL - (TOTAL); *FastPin<33>::sport() = PORT_MASK; while((VAL-next_mark) > (T2+T3+6)); - *FastPin<33>::cport() = (flipper & PORT_MASK); - - flipper = bits(b); + *FastPin<33>::cport() = (~b2.bytes[7-i]) & PORT_MASK; while((VAL - next_mark) > T3); *FastPin<33>::cport() = PORT_MASK; -b2.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); -#if LANES > 8 -i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); -#if LANES > 16 -i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); -#if LANES > 24 -i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); -#endif -#endif -#endif - + b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); } + for(uint32_t i = LANES; i < 8; i++) { + while(VAL > next_mark); + + next_mark = VAL - (TOTAL); + *FastPin<33>::sport() = PORT_MASK; + + while((VAL-next_mark) > (T2+T3+6)); + *FastPin<33>::cport() = (~b2.bytes[7-i]) & PORT_MASK; + + while((VAL - next_mark) > T3); + *FastPin<33>::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 @@ -250,10 +180,7 @@ i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); static uint32_t showRGBInternal(MultiPixelController &allpixels, int nLeds) { // Serial.println("Entering show"); // Setup the pixel controller and load/scale the first byte - Lines b0,b1,b2; - for(int i = 0; i < LANES/4; i++) { - b0.raw[i] = b1.raw[i] = b2.raw[i] = 0; - } + Lines b0; allpixels.preStepFirstByteDithering(); for(int i = 0; i < LANES; i++) { b0.bytes[i] = allpixels.loadAndScale0(i); @@ -272,14 +199,14 @@ i++; b2.bytes[i] = pixels.template loadAndScale(pixels, i,d,scale); allpixels.stepDithering(); // Write first byte, read next byte - writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); + writeBits<8+XTRA0,1>(next_mark, b0, allpixels); // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + writeBits<8+XTRA0,2>(next_mark, b0, allpixels); allpixels.advanceData(); // Write third byte - writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + writeBits<8+XTRA0,0>(next_mark, b0, allpixels); } return 0x00FFFFFF - _VAL; -- cgit v1.2.3 From 1f643641e72bb44752a16c8d2c6c2e76025b3c6f Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 17:37:14 -0700 Subject: Tweak parallel output for the due --- FastLED.h | 2 +- clockless_block_arm_k20.h | 4 ++-- clockless_block_arm_sam.h | 35 ++++++++++++++++++----------------- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/FastLED.h b/FastLED.h index 508beb22..9bc51961 100644 --- a/FastLED.h +++ b/FastLED.h @@ -227,7 +227,7 @@ static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIf template static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) { - return addLeds(data,nLedsOrOffset,nLedsIfOffset); + return addLeds(data,nLedsOrOffset,nLedsIfOffset); } #endif diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 58137c58..3f94b11a 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -23,7 +23,7 @@ class InlineBlockClocklessController : public CLEDController { CMinWait mWait; public: virtual void init() { - if(FIRST_PIN == 15) { + if(FIRST_PIN == PORTC_FIRST_PIN) { // PORTC switch(LANES) { // case 12: FastPin<30>::setOutput(); // case 11: FastPin<29>::setOutput(); @@ -38,7 +38,7 @@ public: case 2: FastPin<22>::setOutput(); case 1: FastPin<15>::setOutput(); } - } else if(FIRST_PIN == 2) { + } else if(FIRST_PIN == PORTD_FIRST_PIN) { // PORTD switch(LANES) { case 8: FastPin<5>::setOutput(); case 7: FastPin<21>::setOutput(); diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 31b9e8b9..399bc34e 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -42,7 +42,7 @@ class InlineBlockClocklessController : public CLEDController { CMinWait mWait; public: virtual void init() { - if(FIRST_PIN == 69) { + if(FIRST_PIN == PORTA_FIRST_PIN) { switch(LANES) { case 8: FastPin<31>::setOutput(); case 7: FastPin<58>::setOutput(); @@ -53,7 +53,7 @@ public: case 2: FastPin<68>::setOutput(); case 1: FastPin<69>::setOutput(); } - } else if(FIRST_PIN == 25) { + } else if(FIRST_PIN == PORTD_FIRST_PIN) { switch(LANES) { case 8: FastPin<11>::setOutput(); case 7: FastPin<29>::setOutput(); @@ -64,7 +64,7 @@ public: case 2: FastPin<26>::setOutput(); case 1: FastPin<25>::setOutput(); } - } else if(FIRST_PIN == 90) { + } else if(FIRST_PIN == PORTB_FIRST_PIN) { switch(LANES) { case 8: FastPin<97>::setOutput(); case 7: FastPin<96>::setOutput(); @@ -139,7 +139,7 @@ public: #define VAL *((uint32_t*)(SysTick_BASE + 8)) - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, MultiPixelController &pixels) { // , register uint32_t & b2) { register Lines b2; transpose8x1(b.bytes,b2.bytes); @@ -149,29 +149,29 @@ public: for(uint32_t i = 0; (i < LANES) && (i<8); i++) { while(VAL > next_mark); - next_mark = VAL - (TOTAL); - *FastPin<33>::sport() = PORT_MASK; + next_mark = VAL - (TOTAL-12); + *FastPin::sport() = PORT_MASK; while((VAL-next_mark) > (T2+T3+6)); - *FastPin<33>::cport() = (~b2.bytes[7-i]) & PORT_MASK; + *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; while((VAL - next_mark) > T3); - *FastPin<33>::cport() = PORT_MASK; + *FastPin::cport() = PORT_MASK; - b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); + b3.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); } for(uint32_t i = LANES; i < 8; i++) { while(VAL > next_mark); - next_mark = VAL - (TOTAL); - *FastPin<33>::sport() = PORT_MASK; + next_mark = VAL - (TOTAL-3); + *FastPin::sport() = PORT_MASK; while((VAL-next_mark) > (T2+T3+6)); - *FastPin<33>::cport() = (~b2.bytes[7-i]) & PORT_MASK; + *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; while((VAL - next_mark) > T3); - *FastPin<33>::cport() = PORT_MASK; + *FastPin::cport() = PORT_MASK; } } @@ -180,7 +180,8 @@ public: static uint32_t showRGBInternal(MultiPixelController &allpixels, int nLeds) { // Serial.println("Entering show"); // Setup the pixel controller and load/scale the first byte - Lines b0; + Lines b0,b1,b2; + allpixels.preStepFirstByteDithering(); for(int i = 0; i < LANES; i++) { b0.bytes[i] = allpixels.loadAndScale0(i); @@ -199,14 +200,14 @@ public: allpixels.stepDithering(); // Write first byte, read next byte - writeBits<8+XTRA0,1>(next_mark, b0, allpixels); + writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b0, allpixels); + writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); allpixels.advanceData(); // Write third byte - writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); } return 0x00FFFFFF - _VAL; -- cgit v1.2.3 From 259eac2bb01a2313f1ef761cac9eb943f741fe33 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 17:39:40 -0700 Subject: Adding new demo for parallel output --- .../ParallelOutputDemo/ParallelOutputDemo.ino | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino diff --git a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino new file mode 100644 index 00000000..8705761f --- /dev/null +++ b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino @@ -0,0 +1,47 @@ +#include + +#define NUM_LEDS_PER_STRIP 64 +#define NUM_STRIPS 8 + +CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; + +// Pin layouts on the teensy 3: +// WS2811_PORTD: 2,14,7,8,6,20,21,5 +// WS2811_PORTC: 15,22,23,9,10,13,11,12 +// +// Pin layouts on the due +// WS2811_PORTA: 69,68,61,60,59,100,58,31 (note: pin 100 only available on the digix) +// WS2811_PORTB: 90,91,92,93,94,95,96,97 (note: only available on the digix) +// WS2811_PORTD: 25,26,27,28,14,15,29,11 +// + +void setup() { +// LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); +// LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); +// LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + + FastPin<0>::setOutput(); + LEDS.setBrightness(32); +} + +void loop() { + static uint8_t hue = 0; + for(int i = 0; i < NUM_STRIPS; i++) { + for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) { + leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255); + } + } + + // Set the first n leds on each strip to show which strip it is + for(int i = 0; i < NUM_STRIPS; i++) { + for(int j = 0; j <= i; j++) { + leds[(i*NUM_LEDS_PER_STRIP) + j] = CRGB::Red; + } + } + + hue++; + + LEDS.show(); + LEDS.delay(10); +} -- cgit v1.2.3 From fe4566821ad1a68cf8c4adefc6e8cacbadaa450a Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 18:29:08 -0700 Subject: Add OctoWS2811 wrapper support. --- FastLED.h | 20 ++++++++++- bitswap.h | 29 +++++++++++++--- octows2811_controller.h | 91 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 octows2811_controller.h diff --git a/FastLED.h b/FastLED.h index 9bc51961..685b49b9 100644 --- a/FastLED.h +++ b/FastLED.h @@ -38,7 +38,7 @@ #include "smartmatrix_t3.h" #include "noise.h" #include "power_mgt.h" - +#include "octows2811_controller.h" enum ESPIChipsets { LPD8806, @@ -50,6 +50,7 @@ enum ESPIChipsets { }; enum ESM { SMART_MATRIX }; +enum OWS2811 { OCTOWS2811 }; template class NEOPIXEL : public WS2811Controller800Khz {}; template class TM1829 : public TM1829Controller800Khz {}; @@ -186,6 +187,23 @@ public: return addLeds(&c, data, nLedsOrOffset, nLedsIfOffset); } +#ifdef USE_OCTOWS2811 +template +static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) +{ + switch(CHIPSET) { + case OCTOWS2811: { static COctoWS2811Controller controller; return addLeds(&controller, data, nLedsOrOffset, nLedsIfOffset); } + } +} + +template +static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) +{ + return addLeds(data,nLedsOrOffset,nLedsIfOffset); +} + +#endif + #ifdef SmartMatrix_h template static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) diff --git a/bitswap.h b/bitswap.h index 4205d7a3..c2869c6c 100644 --- a/bitswap.h +++ b/bitswap.h @@ -175,10 +175,30 @@ __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsign y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); x = t; -#if 1 - *((uint32_t*)B) = y; - *((uint32_t*)(B+4)) = x; -#else + *((uint32_t*)B) = y; + *((uint32_t*)(B+4)) = x; +} + +__attribute__((always_inline)) inline void transpose8x1_MSB(unsigned char *A, unsigned char *B) { + uint32_t x, y, t; + + // Load the array and pack it into x and y. + y = *(unsigned int*)(A); + x = *(unsigned int*)(A+4); + + // pre-transform x + t = (x ^ (x >> 7)) & 0x00AA00AA; x = x ^ t ^ (t << 7); + t = (x ^ (x >>14)) & 0x0000CCCC; x = x ^ t ^ (t <<14); + + // pre-transform y + t = (y ^ (y >> 7)) & 0x00AA00AA; y = y ^ t ^ (t << 7); + t = (y ^ (y >>14)) & 0x0000CCCC; y = y ^ t ^ (t <<14); + + // final transform + t = (x & 0xF0F0F0F0) | ((y >> 4) & 0x0F0F0F0F); + y = ((x << 4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F); + x = t; + B[7] = y; y >>= 8; B[6] = y; y >>= 8; B[5] = y; y >>= 8; @@ -188,7 +208,6 @@ __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsign B[2] = x; x >>= 8; B[1] = x; x >>= 8; B[0] = x; /* */ -#endif } template diff --git a/octows2811_controller.h b/octows2811_controller.h new file mode 100644 index 00000000..dd6c0b92 --- /dev/null +++ b/octows2811_controller.h @@ -0,0 +1,91 @@ +#ifndef __INC_OCTOWS2811_CONTROLLER_H +#define __INC_OCTOWS2811_CONTROLLER_H + +#ifdef USE_OCTOWS2811 + +// #include "OctoWS2811.h" + +template +class COctoWS2811Controller : public CLEDController { + OctoWS2811 *pocto; + uint8_t *drawbuffer,*framebuffer; + + void _init(int nLeds) { + if(pocto == NULL) { + drawbuffer = (uint8_t*)malloc(nLeds * 8 * 3); + framebuffer = (uint8_t*)malloc(nLeds * 8 * 3); + switch(RGB_ORDER) { + case RGB: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RGB); break; + case RBG: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RBG); break; + case GBR: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_GBR); break; + case GRB: + default: + pocto = new OctoWS2811(nLeds, framebuffer,drawbuffer, WS2811_GRB); break; + } + pocto->begin(); + } + } +public: + COctoWS2811Controller() { pocto = NULL; } + + + 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 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() ); + + uint8_t *pData = drawbuffer; + while(nLeds--) { + Lines b; + + for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale0(i); } + transpose8x1_MSB(b.bytes,pData); pData += 8; + for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale1(i); } + transpose8x1_MSB(b.bytes,pData); pData += 8; + for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale2(i); } + transpose8x1_MSB(b.bytes,pData); pData += 8; + pixels.stepDithering(); + pixels.advanceData(); + } + + pocto->show(); + } +}; + +#endif + +#endif -- cgit v1.2.3 From a23421e87a3c1246c9a680b60fec6a1f7f97a3b5 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 18:33:42 -0700 Subject: Add multi-output demos for the 8-way in library output and the octows2811 output wrapper. --- .../Multiple/OctoWS2811Demo/OctoWS2811Demo.ino | 37 ++++++++++++++++++++++ .../ParallelOutputDemo/ParallelOutputDemo.ino | 7 ++-- 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino diff --git a/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino b/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino new file mode 100644 index 00000000..6aad445d --- /dev/null +++ b/examples/Multiple/OctoWS2811Demo/OctoWS2811Demo.ino @@ -0,0 +1,37 @@ +#define USE_OCTOWS2811 +#include +#include + +#define NUM_LEDS_PER_STRIP 64 +#define NUM_STRIPS 8 + +CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; + +// Pin layouts on the teensy 3: +// OctoWS2811: 2,14,7,8,6,20,21,5 + +void setup() { + LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + LEDS.setBrightness(32); +} + +void loop() { + static uint8_t hue = 0; + for(int i = 0; i < NUM_STRIPS; i++) { + for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) { + leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255); + } + } + + // Set the first n leds on each strip to show which strip it is + for(int i = 0; i < NUM_STRIPS; i++) { + for(int j = 0; j <= i; j++) { + leds[(i*NUM_LEDS_PER_STRIP) + j] = CRGB::Red; + } + } + + hue++; + + LEDS.show(); + LEDS.delay(10); +} diff --git a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino index 8705761f..d575c9c6 100644 --- a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino +++ b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino @@ -16,12 +16,11 @@ CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; // void setup() { -// LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); -// LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); -// LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); - FastPin<0>::setOutput(); LEDS.setBrightness(32); } -- cgit v1.2.3 From 80e230af802215a6a5afcf37755edd6556ee3c5f Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 18:53:26 -0700 Subject: Adding source for transpose functions to bitswap.h --- bitswap.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bitswap.h b/bitswap.h index c2869c6c..0cbd95dc 100644 --- a/bitswap.h +++ b/bitswap.h @@ -155,6 +155,8 @@ __attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned c } } +// Simplified form of bits rotating function found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating +// data into LSB for a faster write (the code using this data can happily walk the array backwards) __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsigned char *B) { uint32_t x, y, t; @@ -179,6 +181,7 @@ __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsign *((uint32_t*)(B+4)) = x; } +// Simplified form of bits rotating function found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt __attribute__((always_inline)) inline void transpose8x1_MSB(unsigned char *A, unsigned char *B) { uint32_t x, y, t; @@ -210,6 +213,7 @@ __attribute__((always_inline)) inline void transpose8x1_MSB(unsigned char *A, un B[0] = x; /* */ } +// templated bit-rotating function based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt template __attribute__((always_inline)) inline void transpose8(unsigned char *A, unsigned char *B) { uint32_t x, y, t; -- cgit v1.2.3 From 2395bee77eee47af7984850ce5368f4b7a087da7 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 20:40:43 -0700 Subject: Add note about 12-way output for Teensy3 PORTC --- examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino index d575c9c6..d1f7fc4a 100644 --- a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino +++ b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino @@ -1,13 +1,14 @@ #include #define NUM_LEDS_PER_STRIP 64 +// Note: this can be 12 if you're using a teensy 3 and don't mind soldering the pads on the back #define NUM_STRIPS 8 CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; -// Pin layouts on the teensy 3: +// Pin layouts on the teensy 3/3.1: // WS2811_PORTD: 2,14,7,8,6,20,21,5 -// WS2811_PORTC: 15,22,23,9,10,13,11,12 +// WS2811_PORTC: 15,22,23,9,10,13,11,12,28,27,29,30 (these last 4 are pads on the bottom of the teensy) // // Pin layouts on the due // WS2811_PORTA: 69,68,61,60,59,100,58,31 (note: pin 100 only available on the digix) @@ -18,8 +19,8 @@ CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; void setup() { // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); - // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); - LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); + // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip); LEDS.setBrightness(32); } -- cgit v1.2.3 From 1fab66b74e275bcd407bd2eafecd453df1ba0bc5 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 20:40:58 -0700 Subject: Add 12-way output on port c for the teensy --- clockless_block_arm_k20.h | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 3f94b11a..4bbdb027 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -9,7 +9,7 @@ #define PORTC_FIRST_PIN 15 #define PORTD_FIRST_PIN 2 -#define PORT_MASK (((1<::setOutput(); - // case 11: FastPin<29>::setOutput(); - // case 10: FastPin<27>::setOutput(); - // case 9: FastPin<28>::setOutput(); + case 12: FastPin<30>::setOutput(); + case 11: FastPin<29>::setOutput(); + case 10: FastPin<27>::setOutput(); + case 9: FastPin<28>::setOutput(); case 8: FastPin<12>::setOutput(); case 7: FastPin<11>::setOutput(); case 6: FastPin<13>::setOutput(); @@ -105,14 +105,19 @@ public: typedef union { - uint8_t bytes[8]; - uint32_t raw[2]; + uint8_t bytes[16]; + uint16_t shorts[8]; + uint32_t raw[4]; } Lines; template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { register Lines b2; - transpose8x1(b.bytes,b2.bytes); - + if(LANES>8) { + transpose8<1,2>(b.bytes,b2.bytes); + transpose8<1,2>(b.bytes+8,b2.bytes+1); + } else { + transpose8x1(b.bytes,b2.bytes); + } register uint8_t d = pixels.template getd(pixels); register uint8_t scale = pixels.template getscale(pixels); @@ -122,13 +127,17 @@ public: *FastPin::sport() = PORT_MASK; while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); - *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); + if(LANES>8) { + *FastPin::cport() = ((~b2.shorts[i]) & PORT_MASK); + } else { + *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); + } while((next_mark - ARM_DWT_CYCCNT) > (T3)); *FastPin::cport() = PORT_MASK; b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); - if(LANES>8) { + if(LANES>8 && ((i+8) < LANES)) { b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); } } -- cgit v1.2.3 From 68d21f67189f3abed2a2c6d765f501869ec46b2b Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 22:12:02 -0700 Subject: Add 16-way parallel output for teensy 3/3.1. Update example to show off. Bump version number. --- FastLED.h | 11 +- clockless_block_arm_k20.h | 163 ++++++++++++++++++++- .../ParallelOutputDemo/ParallelOutputDemo.ino | 6 +- 3 files changed, 174 insertions(+), 6 deletions(-) diff --git a/FastLED.h b/FastLED.h index 685b49b9..b32abecc 100644 --- a/FastLED.h +++ b/FastLED.h @@ -7,8 +7,8 @@ #define xstr(s) str(s) #define str(s) #s -#define FASTLED_VERSION 3000000 -#warning FastLED version 3000000 (Not really a warning, just telling you here.) +#define FASTLED_VERSION 3001000 +#warning FastLED version 3001000 (Not really a warning, just telling you here.) #define __PROG_TYPES_COMPAT__ @@ -92,6 +92,9 @@ enum EBlockChipsets { #ifdef PORTD_FIRST_PIN WS2811_PORTD, #endif +#ifdef HAS_PORTDC + WS2811_PORTDC, +#endif }; #if defined(LIB8_ATTINY) @@ -239,8 +242,12 @@ static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIf #endif #ifdef PORTD_FIRST_PIN case WS2811_PORTD: return addLeds(new InlineBlockClocklessController(), data, nLedsOrOffset, nLedsIfOffset); +#endif +#ifdef HAS_PORTDC + case WS2811_PORTDC: return addLeds(new SixteenWayInlineBlockClocklessController<16,NS(250), NS(510), NS(490), RGB_ORDER>(), data, nLedsOrOffset, nLedsIfOffset); #endif } + } template diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 4bbdb027..d9ab69ff 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -8,9 +8,12 @@ #define PORTC_FIRST_PIN 15 #define PORTD_FIRST_PIN 2 +#define HAS_PORTDC 1 #define PORT_MASK (((1<>8 & 0xFF) +#define PMASK_LO (PMASK & 0xFF) #include "kinetis.h" template @@ -194,6 +197,164 @@ public: return ARM_DWT_CYCCNT; } }; + +template +class SixteenWayInlineBlockClocklessController : public CLEDController { + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait mWait; +public: + virtual void init() { + // 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 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 pixels(rgbdata,nLeds, scale, getDither() ); + mWait.wait(); + cli(); + + uint32_t clocks = showRGBInternal(pixels,nLeds); + + // Adjust the timer + long microsTaken = CLKS_TO_MICROS(clocks); + MS_COUNTER += (microsTaken / 1000); + sei(); + mWait.mark(); + } + + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); + mWait.wait(); + cli(); + + uint32_t clocks = showRGBInternal(pixels,nLeds); + + // Adjust the timer + long microsTaken = CLKS_TO_MICROS(clocks); + MS_COUNTER += (microsTaken / 1000); + sei(); + mWait.mark(); + } + +#ifdef SUPPORT_ARGB + virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { + mWait.wait(); + cli(); + + uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); + + + // Adjust the timer + long microsTaken = CLKS_TO_MICROS(clocks); + MS_COUNTER += (microsTaken / 1000); + sei(); + mWait.mark(); + } +#endif + + + typedef union { + uint8_t bytes[16]; + uint16_t shorts[8]; + uint32_t raw[4]; + } Lines; + + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &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(pixels); + register uint8_t scale = pixels.template getscale(pixels); + + 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::sport() = PMASK_LO; + *FastPin::sport() = PMASK_HI; + + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); + *FastPin::cport() = ((~b2.bytes[7-i]) & PMASK_LO); + *FastPin::cport() = ((~b2.bytes[15-i]) & PMASK_HI); + + while((next_mark - ARM_DWT_CYCCNT) > (T3)); + *FastPin::cport() = PMASK_LO; + *FastPin::cport() = PMASK_HI; + + b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); + if(LANES>8 && ((i+8) < LANES)) { + b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); + } + } + } + + + + // 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 &allpixels, int nLeds) { + // Get access to the clock + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + ARM_DWT_CYCCNT = 0; + + // Setup the pixel controller and load/scale the first byte + allpixels.preStepFirstByteDithering(); + register Lines b0; + + allpixels.preStepFirstByteDithering(); + for(int i = 0; i < LANES; i++) { + b0.bytes[i] = allpixels.loadAndScale0(i); + } + + uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + + while(nLeds--) { + allpixels.stepDithering(); + + // Write first byte, read next byte + writeBits<8+XTRA0,1>(next_mark, b0, allpixels); + + // Write second byte, read 3rd byte + writeBits<8+XTRA0,2>(next_mark, b0, allpixels); + allpixels.advanceData(); + + // Write third byte + writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + }; + + return ARM_DWT_CYCCNT; + } +}; #endif #endif diff --git a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino index d1f7fc4a..d646cdec 100644 --- a/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino +++ b/examples/Multiple/ParallelOutputDemo/ParallelOutputDemo.ino @@ -2,13 +2,14 @@ #define NUM_LEDS_PER_STRIP 64 // Note: this can be 12 if you're using a teensy 3 and don't mind soldering the pads on the back -#define NUM_STRIPS 8 +#define NUM_STRIPS 16 CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; // Pin layouts on the teensy 3/3.1: // WS2811_PORTD: 2,14,7,8,6,20,21,5 // WS2811_PORTC: 15,22,23,9,10,13,11,12,28,27,29,30 (these last 4 are pads on the bottom of the teensy) +// WS2811_PORTDC: 2,14,7,8,6,20,21,5,15,22,23,9,10,13,11,12 - 16 way parallel // // Pin layouts on the due // WS2811_PORTA: 69,68,61,60,59,100,58,31 (note: pin 100 only available on the digix) @@ -19,9 +20,8 @@ CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP]; void setup() { // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); - LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); // LEDS.addLeds(leds, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip); - + LEDS.addLeds(leds, NUM_LEDS_PER_STRIP); LEDS.setBrightness(32); } -- cgit v1.2.3 From 5274968e1392fb546fa751876e84efa7adfdb6d7 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 22:35:25 -0700 Subject: Improve the performance of single port parallel output. --- clockless_block_arm_k20.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index d9ab69ff..54a3fa69 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -124,7 +124,7 @@ public: register uint8_t d = pixels.template getd(pixels); register uint8_t scale = pixels.template getscale(pixels); - for(register uint32_t i = 0; (i < LANES) && (i < 8); i++) { + for(register uint32_t i = 0; i < 6; i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; *FastPin::sport() = PORT_MASK; @@ -140,18 +140,22 @@ public: *FastPin::cport() = PORT_MASK; b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); - if(LANES>8 && ((i+8) < LANES)) { - b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); + if((LANES>6) && ((i+6) < LANES)) { + b.bytes[i+6] = pixels.template loadAndScale(pixels,i,d,scale); } } - for(register uint32_t i = LANES; i < 8; i++) { + for(register uint32_t i = 6; i < 8; i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; *FastPin::sport() = PORT_MASK; while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); - *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); + if(LANES>8) { + *FastPin::cport() = ((~b2.shorts[i]) & PORT_MASK); + } else { + *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); + } while((next_mark - ARM_DWT_CYCCNT) > (T3)); *FastPin::cport() = PORT_MASK; -- cgit v1.2.3 From 88b865822b528d4a016c03283bb9c791c0794eb9 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 22:40:36 -0700 Subject: more tweaking of parallel performance --- clockless_block_arm_k20.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 54a3fa69..345379c1 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -315,7 +315,7 @@ public: *FastPin::cport() = PMASK_HI; b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); - if(LANES>8 && ((i+8) < LANES)) { + if(LANES==16 || (LANES>8 && ((i+8) < LANES))) { b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); } } -- cgit v1.2.3 From 54a7ae5d8370cc60583069dfa795f2e26610fd9e Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 22:48:40 -0700 Subject: Better handling of odd numbers of lanes --- clockless_block_arm_k20.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index 345379c1..b10b9836 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -124,7 +124,7 @@ public: register uint8_t d = pixels.template getd(pixels); register uint8_t scale = pixels.template getscale(pixels); - for(register uint32_t i = 0; i < 6; i++) { + for(register uint32_t i = 0; i < (LANES/2); i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; *FastPin::sport() = PORT_MASK; @@ -140,12 +140,15 @@ public: *FastPin::cport() = PORT_MASK; b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); - if((LANES>6) && ((i+6) < LANES)) { - b.bytes[i+6] = pixels.template loadAndScale(pixels,i,d,scale); - } + b.bytes[i+(LANES/2)] = pixels.template loadAndScale(pixels,i,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(pixels,LANES-1,d,scale); } - for(register uint32_t i = 6; i < 8; i++) { + for(register uint32_t i = LANES/2; i < 8; i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; *FastPin::sport() = PORT_MASK; -- cgit v1.2.3 From 74767cd6b47045ee713da3ae9f69f5a56fcb3d48 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 27 Oct 2014 23:02:00 -0700 Subject: Protect against people declaring more lanes than a port may support --- clockless_block_arm_k20.h | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index b10b9836..fc50caf1 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -11,12 +11,13 @@ #define HAS_PORTDC 1 #define PORT_MASK (((1<>8 & 0xFF) -#define PMASK_LO (PMASK & 0xFF) + +#define MIN(X,Y) (((X)<(Y)) ? (X):(Y)) +#define LANES ((FIRST_PIN==2) ? MIN(__LANES,8) : MIN(__LANES,12)) + #include "kinetis.h" -template +template class InlineBlockClocklessController : public CLEDController { typedef typename FastPin::port_ptr_t data_ptr_t; typedef typename FastPin::port_t data_t; @@ -205,7 +206,12 @@ public: } }; -template +#define DLANES (MIN(__LANES,16)) +#define PMASK ((1<<(DLANES))-1) +#define PMASK_HI (PMASK>>8 & 0xFF) +#define PMASK_LO (PMASK & 0xFF) + +template class SixteenWayInlineBlockClocklessController : public CLEDController { typedef typename FastPin::port_ptr_t data_ptr_t; typedef typename FastPin::port_t data_t; @@ -219,7 +225,7 @@ public: // FastPin<29>::setOutput(); // FastPin<27>::setOutput(); // FastPin<28>::setOutput(); - switch(LANES) { + switch(DLANES) { case 16: FastPin<12>::setOutput(); case 15: FastPin<11>::setOutput(); case 14: FastPin<13>::setOutput(); @@ -246,7 +252,7 @@ public: // set all the leds on the controller to a given color virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { - MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); cli(); @@ -260,7 +266,7 @@ public: } virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { - MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); cli(); @@ -296,14 +302,14 @@ public: uint32_t raw[4]; } Lines; - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &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(pixels); register uint8_t scale = pixels.template getscale(pixels); - for(register uint32_t i = 0; (i < LANES) && (i < 8); i++) { + for(register uint32_t i = 0; (i < DLANES) && (i < 8); i++) { while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; *FastPin::sport() = PMASK_LO; @@ -318,7 +324,7 @@ public: *FastPin::cport() = PMASK_HI; b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); - if(LANES==16 || (LANES>8 && ((i+8) < LANES))) { + if(DLANES==16 || (DLANES>8 && ((i+8) < DLANES))) { b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); } } @@ -328,7 +334,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 &allpixels, int nLeds) { + static uint32_t showRGBInternal(MultiPixelController &allpixels, int nLeds) { // Get access to the clock ARM_DEMCR |= ARM_DEMCR_TRCENA; ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; @@ -339,7 +345,7 @@ public: register Lines b0; allpixels.preStepFirstByteDithering(); - for(int i = 0; i < LANES; i++) { + for(int i = 0; i < DLANES; i++) { b0.bytes[i] = allpixels.loadAndScale0(i); } -- cgit v1.2.3 From f1502136f95db7c6c2c23837db86c05f23e8d6dd Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Tue, 28 Oct 2014 09:20:31 -0700 Subject: Adding a port of PJRC's spectrum analyzer to use FastLED's OctoWS2811 controller --- .../PJRCSpectrumAnalyzer/PJRCSpectrumAnalyzer.ino | 136 +++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 examples/Ports/PJRCSpectrumAnalyzer/PJRCSpectrumAnalyzer.ino diff --git a/examples/Ports/PJRCSpectrumAnalyzer/PJRCSpectrumAnalyzer.ino b/examples/Ports/PJRCSpectrumAnalyzer/PJRCSpectrumAnalyzer.ino new file mode 100644 index 00000000..24f2394e --- /dev/null +++ b/examples/Ports/PJRCSpectrumAnalyzer/PJRCSpectrumAnalyzer.ino @@ -0,0 +1,136 @@ +// LED Audio Spectrum Analyzer Display +// +// Creates an impressive LED light show to music input +// using Teensy 3.1 with the OctoWS2811 adaptor board +// http://www.pjrc.com/store/teensy31.html +// http://www.pjrc.com/store/octo28_adaptor.html +// +// Line Level Audio Input connects to analog pin A3 +// Recommended input circuit: +// http://www.pjrc.com/teensy/gui/?info=AudioInputAnalog +// +// This example code is in the public domain. + +#define USE_OCTOWS2811 +#include +#include +#include +#include +#include +#include + +// The display size and color to use +const unsigned int matrix_width = 60; +const unsigned int matrix_height = 32; +const unsigned int myColor = 0x400020; + +// These parameters adjust the vertical thresholds +const float maxLevel = 0.5; // 1.0 = max, lower is more "sensitive" +const float dynamicRange = 40.0; // total range to display, in decibels +const float linearBlend = 0.3; // useful range is 0 to 0.7 + +CRGB leds[matrix_width * matrix_height]; + +// Audio library objects +AudioInputAnalog adc1(A3); //xy=99,55 +AudioAnalyzeFFT1024 fft; //xy=265,75 +AudioConnection patchCord1(adc1, fft); + + +// This array holds the volume level (0 to 1.0) for each +// vertical pixel to turn on. Computed in setup() using +// the 3 parameters above. +float thresholdVertical[matrix_height]; + +// This array specifies how many of the FFT frequency bin +// to use for each horizontal pixel. Because humans hear +// in octaves and FFT bins are linear, the low frequencies +// use a small number of bins, higher frequencies use more. +int frequencyBinsHorizontal[matrix_width] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 12, 12, 13, 14, 15, + 15, 16, 17, 18, 19, 20, 22, 23, 24, 25 +}; + + + +// Run setup once +void setup() { + // the audio library needs to be given memory to start working + AudioMemory(12); + + // compute the vertical thresholds before starting + computeVerticalLevels(); + + // turn on the display + FastLED.addLeds(leds,(matrix_width * matrix_height) / 8); +} + +// A simple xy() function to turn display matrix coordinates +// into the index numbers OctoWS2811 requires. If your LEDs +// are arranged differently, edit this code... +unsigned int xy(unsigned int x, unsigned int y) { + if ((y & 1) == 0) { + // even numbered rows (0, 2, 4...) are left to right + return y * matrix_width + x; + } else { + // odd numbered rows (1, 3, 5...) are right to left + return y * matrix_width + matrix_width - 1 - x; + } +} + +// Run repetitively +void loop() { + unsigned int x, y, freqBin; + float level; + + if (fft.available()) { + // freqBin counts which FFT frequency data has been used, + // starting at low frequency + freqBin = 0; + + for (x=0; x < matrix_width; x++) { + // get the volume for each horizontal pixel position + level = fft.read(freqBin, freqBin + frequencyBinsHorizontal[x] - 1); + + // uncomment to see the spectrum in Arduino's Serial Monitor + // Serial.print(level); + // Serial.print(" "); + + for (y=0; y < matrix_height; y++) { + // for each vertical pixel, check if above the threshold + // and turn the LED on or off + if (level >= thresholdVertical[y]) { + leds[xy(x,y)] = CRGB(myColor); + } else { + leds[xy(x,y)] = CRGB::Black; + } + } + // increment the frequency bin count, so we display + // low to higher frequency from left to right + freqBin = freqBin + frequencyBinsHorizontal[x]; + } + // after all pixels set, show them all at the same instant + FastLED.show(); + // Serial.println(); + } +} + + +// Run once from setup, the compute the vertical levels +void computeVerticalLevels() { + unsigned int y; + float n, logLevel, linearLevel; + + for (y=0; y < matrix_height; y++) { + n = (float)y / (float)(matrix_height - 1); + logLevel = pow10f(n * -1.0 * (dynamicRange / 20.0)); + linearLevel = 1.0 - n; + linearLevel = linearLevel * linearBlend; + logLevel = logLevel * (1.0 - linearBlend); + thresholdVertical[y] = (logLevel + linearLevel) * maxLevel; + } +} -- cgit v1.2.3 From 046f94810155996118137992f13b64ba7703e4aa Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Tue, 28 Oct 2014 10:31:45 -0700 Subject: Make 3-wire led chip support on the teensy 3/3.1 interrupt friendly. --- clockless_arm_k20.h | 37 +++++++----------------- clockless_block_arm_k20.h | 73 ++++++++++++++--------------------------------- led_sysdefs.h | 1 + 3 files changed, 34 insertions(+), 77 deletions(-) diff --git a/clockless_arm_k20.h b/clockless_arm_k20.h index 3f3f73ee..88f508e1 100644 --- a/clockless_arm_k20.h +++ b/clockless_arm_k20.h @@ -5,7 +5,7 @@ // See clockless.h for detailed info on how the template parameters are used. #if defined(FASTLED_TEENSY3) -template +template class ClocklessController : public CLEDController { typedef typename FastPin::port_ptr_t data_ptr_t; typedef typename FastPin::port_t data_t; @@ -31,14 +31,7 @@ protected: PixelController pixels(rgbdata, nLeds, scale, getDither()); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(pixels); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (1 + (microsTaken / 1000)); - sei(); + showRGBInternal(pixels); mWait.mark(); } @@ -46,14 +39,7 @@ protected: PixelController pixels(rgbdata, nLeds, scale, getDither()); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(pixels); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (1 + (microsTaken / 1000)); - sei(); + showRGBInternal(pixels); mWait.mark(); } @@ -61,15 +47,7 @@ protected: virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { PixelController pixels(rgbdata, nLeds, scale, getDither()); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(pixels); - - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (1 + (microsTaken / 1000)); - sei(); + showRGBInternal(pixels); mWait.mark(); } #endif @@ -119,10 +97,16 @@ protected: pixels.preStepFirstByteDithering(); register uint8_t b = pixels.loadAndScale0(); + cli(); uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); while(pixels.has(1)) { pixels.stepDithering(); + cli(); + // if interrupts took longer than 45µs, punt on the current frame + if(ARM_DWT_CYCCNT > next_mark) { + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + } // Write first byte, read next byte writeBits<8+XTRA0>(next_mark, port, hi, lo, b); @@ -135,6 +119,7 @@ protected: // Write third byte, read 1st byte of next pixel writeBits<8+XTRA0>(next_mark, port, hi, lo, b); b = pixels.advanceAndLoadAndScale0(); + sei(); }; return ARM_DWT_CYCCNT; diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index fc50caf1..b38f69a3 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -66,43 +66,22 @@ public: virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(pixels,nLeds); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (microsTaken / 1000); - sei(); + showRGBInternal(pixels,nLeds); mWait.mark(); } virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(pixels,nLeds); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (microsTaken / 1000); - sei(); + showRGBInternal(pixels,nLeds); mWait.mark(); } #ifdef SUPPORT_ARGB virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); - - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (microsTaken / 1000); - sei(); + showRGBInternal(pixels,nLeds); mWait.mark(); } #endif @@ -186,9 +165,15 @@ public: b0.bytes[i] = allpixels.loadAndScale0(i); } + cli(); uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); while(nLeds--) { + cli(); + // if interrupts took longer than 45µs, punt on the current frame + if(ARM_DWT_CYCCNT > next_mark) { + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + } allpixels.stepDithering(); // Write first byte, read next byte @@ -200,6 +185,7 @@ public: // Write third byte writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + sei(); }; return ARM_DWT_CYCCNT; @@ -254,43 +240,22 @@ public: virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(pixels,nLeds); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (microsTaken / 1000); - sei(); + showRGBInternal(pixels,nLeds); mWait.mark(); } virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(pixels,nLeds); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (microsTaken / 1000); - sei(); + showRGBInternal(pixels,nLeds); mWait.mark(); } #ifdef SUPPORT_ARGB virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - - uint32_t clocks = showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); - - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - MS_COUNTER += (microsTaken / 1000); - sei(); + showRGBInternal(pixels,nLeds); mWait.mark(); } #endif @@ -349,11 +314,16 @@ public: b0.bytes[i] = allpixels.loadAndScale0(i); } + cli(); uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); while(nLeds--) { allpixels.stepDithering(); - + cli(); + // if interrupts took longer than 45µs, punt on the current frame + if(ARM_DWT_CYCCNT > next_mark) { + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + } // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, allpixels); @@ -363,6 +333,7 @@ public: // Write third byte writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + sei(); }; return ARM_DWT_CYCCNT; diff --git a/led_sysdefs.h b/led_sysdefs.h index c49410d0..96f86812 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -49,4 +49,5 @@ typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile u # define INLINE_SCALE(B, SCALE) B = scale8_video(B, SCALE) #endif +#define CLKS_PER_US (F_CPU/1000000) #endif -- cgit v1.2.3 From 94210b7858b2d909125ab3b8f1e041bf9202cbe4 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 29 Oct 2014 11:35:03 -0700 Subject: Update preview changes. Add max refresh rate setting w/default to 400Hz. --- FastLED.cpp | 21 +++++++++++++++++++++ FastLED.h | 6 ++++++ clockless_arm_sam.h | 2 +- clockless_block_arm_sam.h | 6 ++++++ led_sysdefs.h | 1 + preview_changes.txt | 29 +++++++---------------------- 6 files changed, 42 insertions(+), 23 deletions(-) diff --git a/FastLED.cpp b/FastLED.cpp index ae0eedb4..0f1e3262 100644 --- a/FastLED.cpp +++ b/FastLED.cpp @@ -13,6 +13,7 @@ CFastLED & FastLED = LEDS; CLEDController *CLEDController::m_pHead = NULL; CLEDController *CLEDController::m_pTail = NULL; +static uint32_t lastshow = 0; // uint32_t CRGB::Squant = ((uint32_t)((__TIME__[4]-'0') * 28))<<16 | ((__TIME__[6]-'0')*50)<<8 | ((__TIME__[7]-'0')*28); @@ -21,6 +22,7 @@ CFastLED::CFastLED() { // m_nControllers = 0; m_Scale = 255; m_nFPS = 0; + setMaxRefreshRate(400); } CLEDController &CFastLED::addLeds(CLEDController *pLed, @@ -35,6 +37,10 @@ CLEDController &CFastLED::addLeds(CLEDController *pLed, } void CFastLED::show(uint8_t scale) { + // guard against showing too rapidly + while(m_nMinMicros && ((micros()-lastshow) < m_nMinMicros)); + lastshow = micros(); + CLEDController *pCur = CLEDController::head(); while(pCur) { uint8_t d = pCur->getDither(); @@ -69,6 +75,9 @@ CLEDController & CFastLED::operator[](int x) { } void CFastLED::showColor(const struct CRGB & color, uint8_t scale) { + while(m_nMinMicros && ((micros()-lastshow) < m_nMinMicros)); + lastshow = micros(); + CLEDController *pCur = CLEDController::head(); while(pCur) { uint8_t d = pCur->getDither(); @@ -98,7 +107,11 @@ void CFastLED::clearData() { void CFastLED::delay(unsigned long ms) { unsigned long start = millis(); while((millis()-start) < ms) { +#ifndef FASTLED_ACCURATE_CLOCK + // make sure to allow at least one ms to pass to ensure the clock moves + // forward ::delay(1); +#endif show(); } } @@ -184,3 +197,11 @@ void CFastLED::countFPS(int nFrames) { lastframe = millis(); } } + +void CFastLED::setMaxRefreshRate(uint16_t refresh) { + if(refresh > 0) { + m_nMinMicros = 1000000 / refresh; + } else { + m_nMinMicros = 0; + } +} diff --git a/FastLED.h b/FastLED.h index b32abecc..78e5835b 100644 --- a/FastLED.h +++ b/FastLED.h @@ -107,6 +107,7 @@ class CFastLED { // int m_nControllers; uint8_t m_Scale; uint16_t m_nFPS; + uint32_t m_nMinMicros; public: CFastLED(); @@ -279,6 +280,11 @@ static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIf void setCorrection(const struct CRGB & correction); void setDither(uint8_t ditherMode = BINARY_DITHER); + // Set the maximum refresh rate. This is global for all leds. Attempts to + // call show faster than this rate will simply wait. Defaults to 400Hz. Set + // to 0 to have no maximum rate. + void setMaxRefreshRate(uint16_t refresh); + // for debugging, will keep track of time between calls to countFPS, and every // nFrames calls, it will update an internal counter for the current FPS. void countFPS(int nFrames=25); diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h index 74a0f602..95f833b8 100644 --- a/clockless_arm_sam.h +++ b/clockless_arm_sam.h @@ -15,7 +15,7 @@ #define SCALE(S,V) scale8_video(S,V) // #define SCALE(S,V) scale8(S,V) -template +template class ClocklessController : public CLEDController { typedef typename FastPinBB::port_ptr_t data_ptr_t; typedef typename FastPinBB::port_t data_t; diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 399bc34e..7b690849 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -195,9 +195,14 @@ public: _CTRL |= SysTick_CTRL_ENABLE_Msk; VAL = 0; + cli(); uint32_t next_mark = (VAL - (TOTAL)); while(nLeds--) { allpixels.stepDithering(); + cli(); + if(VAL < next_mask) { + if((next_mark - VAL) > ((WAIT_TIME*5)*CLKS_PER_US)) { sei(); return 0x00FFFFF - _VAL; } + } // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); @@ -208,6 +213,7 @@ public: allpixels.advanceData(); // Write third byte writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + sei(); } return 0x00FFFFFF - _VAL; diff --git a/led_sysdefs.h b/led_sysdefs.h index 96f86812..93a78071 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -4,6 +4,7 @@ #if defined(__MK20DX128__) || defined(__MK20DX256__) #define FASTLED_TEENSY3 #define FASTLED_ARM +#define FASTLED_ACCURATE_CLOCK #if (F_CPU == 96000000) #define CLK_DBL 1 #endif diff --git a/preview_changes.txt b/preview_changes.txt index 88a9f9bc..b6d1e8cb 100644 --- a/preview_changes.txt +++ b/preview_changes.txt @@ -1,22 +1,7 @@ -* ALL UNTESTED, USE AT YOUR OWN RISK! -* RGB based scaling, allow for color balancing -* (The moon) dithering support -* Teensy 3.1 support -* Second SPI support on teensy 3.1 -* Due support -* P9813 (aka Cool Neon Total Control Lighting support) -* Preliminary TM1829 support (broken, don't use!) -* Random code changes and cleanups -* More accurate timing adjustments for k20 and due clockless chips -* Added HUE_RED, HUE_ORANGE, etc. -* Added named color correction profiles (eg. TypicalSMD5050) -* Added XY Matrix example -* Added Fire2012 example, added HeatColor(...) to the library -* Added sin8, cos8, quadwave8, cubicwave8, triwave8, and ease8InOutQuad -* Added map8 -* Adjusted VIRTAL_BITS of dithering from a flickery 8 to a more solid 3 -* Added array versions of fade_video, fade_raw, and some variations -* Added fill_gradient -* Added inoise8/inoise16 and example program -* Added LEDS.countFPS() for debugging framerate counts. Bit rough at the moment, thought -* Added Palettes and associated functions and presets +FastLED 3.1 preview changes: +* 8-way parallel output on teensy 3, 3.1 (portc,portd), due/digix (porta, portb, portd) +* 12-way parallel output on teensy 3, 3.1 (portc) +* 16-way parallel output on teensy 3, 3.1 (portd & portd paired) +* refresh rate limiting +* interupt friendly code on teensy 3/3.1 + -- cgit v1.2.3 From d237a4b841ad0aadd3d15f2ed7684f646fe79f89 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 30 Oct 2014 12:19:44 -0700 Subject: Interrupt friendly behavior for AVR --- clockless_trinket.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/clockless_trinket.h b/clockless_trinket.h index 4f7b7db3..64d6d354 100644 --- a/clockless_trinket.h +++ b/clockless_trinket.h @@ -103,15 +103,6 @@ protected: showRGBInternal(pixels); - // Adjust the timer -#if !defined(NO_CORRECTION) || (NO_CORRECTION == 0) - uint32_t microsTaken = (uint32_t)nLeds * (uint32_t)CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - if(microsTaken > 1024) { - MS_COUNTER += (microsTaken >> 10); - } else { - MS_COUNTER++; - } -#endif sei(); mWait.mark(); } @@ -250,17 +241,21 @@ protected: uint8_t e2 = pixels.e[RO(2)]; uint8_t loopvar=0; - + uint8_t lasttime = TCNT0; { while(count--) { + lasttime = TCNT0; + sei(); // Loop beginning, does some stuff that's outside of the pixel write cycle, namely incrementing d0-2 and masking off // by the E values (see the definition ) // LOOP; ADJDITHER2(d0,e0); ADJDITHER2(d1,e1); ADJDITHER2(d2,e2); + cli(); + if((TCNT0-lasttime) > (F_CPU/2000000)) { sei(); return; } // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 // The values in the D1/D2/D3 indicate how many cycles the previous column takes // to allow things to line back up. -- cgit v1.2.3 From da847e5a1361cff5065468c9f50a0abcd42a0aa0 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 30 Oct 2014 12:21:24 -0700 Subject: update notes --- preview_changes.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/preview_changes.txt b/preview_changes.txt index b6d1e8cb..26933cde 100644 --- a/preview_changes.txt +++ b/preview_changes.txt @@ -3,5 +3,6 @@ FastLED 3.1 preview changes: * 12-way parallel output on teensy 3, 3.1 (portc) * 16-way parallel output on teensy 3, 3.1 (portd & portd paired) * refresh rate limiting -* interupt friendly code on teensy 3/3.1 +* interrupt friendly code on teensy 3/3.1 +* interrupt friendly code on AVR -- cgit v1.2.3 From 7adedb990ff9e1ee1a72f68247a579d984312075 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 30 Oct 2014 12:29:36 -0700 Subject: Make the interrupt gap-handling dynamic based on the define WAIT_TIME for the given chipset --- clockless_trinket.h | 4 +++- led_sysdefs.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/clockless_trinket.h b/clockless_trinket.h index 64d6d354..f0637a70 100644 --- a/clockless_trinket.h +++ b/clockless_trinket.h @@ -15,6 +15,8 @@ #define DITHER 1 #endif +#define US_PER_TICK (64 / (F_CPU/1000000)) + // Variations on the functions in delay.h - w/a loop var passed in to preserve registers across calls by the optimizer/compiler template inline void _dc(register uint8_t & loopvar); @@ -255,7 +257,7 @@ protected: ADJDITHER2(d2,e2); cli(); - if((TCNT0-lasttime) > (F_CPU/2000000)) { sei(); return; } + if((TCNT0-lasttime) > ((WAIT_TIME-10)/US_PER_TICK)) { sei(); return; } // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 // The values in the D1/D2/D3 indicate how many cycles the previous column takes // to allow things to line back up. diff --git a/led_sysdefs.h b/led_sysdefs.h index 93a78071..fa40a46a 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -12,6 +12,7 @@ #define FASTLED_ARM #else #define FASTLED_AVR +#define FASTLED_ACCURATE_CLOCK #endif #ifndef CLK_DBL -- cgit v1.2.3 From 4658c8bec68aacdbd09c4f7d2508de18a10edf9a Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 30 Oct 2014 12:52:37 -0700 Subject: Centralize setting the interrupt threshold adjustment --- clockless_arm_k20.h | 2 +- clockless_block_arm_k20.h | 2 +- clockless_trinket.h | 2 +- led_sysdefs.h | 11 +++++++++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/clockless_arm_k20.h b/clockless_arm_k20.h index 88f508e1..d96c9bb2 100644 --- a/clockless_arm_k20.h +++ b/clockless_arm_k20.h @@ -105,7 +105,7 @@ protected: cli(); // if interrupts took longer than 45µs, punt on the current frame if(ARM_DWT_CYCCNT > next_mark) { - if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } } // Write first byte, read next byte diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h index b38f69a3..63dc5030 100644 --- a/clockless_block_arm_k20.h +++ b/clockless_block_arm_k20.h @@ -322,7 +322,7 @@ public: cli(); // if interrupts took longer than 45µs, punt on the current frame if(ARM_DWT_CYCCNT > next_mark) { - if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } } // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, allpixels); diff --git a/clockless_trinket.h b/clockless_trinket.h index f0637a70..0d3451b7 100644 --- a/clockless_trinket.h +++ b/clockless_trinket.h @@ -257,7 +257,7 @@ protected: ADJDITHER2(d2,e2); cli(); - if((TCNT0-lasttime) > ((WAIT_TIME-10)/US_PER_TICK)) { sei(); return; } + if((TCNT0-lasttime) > ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)) { sei(); return; } // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 // The values in the D1/D2/D3 indicate how many cycles the previous column takes // to allow things to line back up. diff --git a/led_sysdefs.h b/led_sysdefs.h index fa40a46a..894055f1 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -5,6 +5,9 @@ #define FASTLED_TEENSY3 #define FASTLED_ARM #define FASTLED_ACCURATE_CLOCK +#ifndef INTERRUPT_THRESHOLD +#define INTERRUPT_THRESHOLD 5 +#endif #if (F_CPU == 96000000) #define CLK_DBL 1 #endif @@ -13,6 +16,9 @@ #else #define FASTLED_AVR #define FASTLED_ACCURATE_CLOCK +#ifndef INTERRUPT_THRESHOLD +#define INTERRUPT_THRESHOLD 10 +#endif #endif #ifndef CLK_DBL @@ -52,4 +58,9 @@ typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile u #endif #define CLKS_PER_US (F_CPU/1000000) + +#ifndef INTERRUPT_THRESHOLD +#define INTERRUPT_THRESHOLD 5 +#endif + #endif -- cgit v1.2.3 From 1d6a304bc8d89be07b4db8903cfbb49082e2926b Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 30 Oct 2014 13:28:54 -0700 Subject: Survive interrupts changing pins on AVR --- clockless_trinket.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/clockless_trinket.h b/clockless_trinket.h index 0d3451b7..844c045b 100644 --- a/clockless_trinket.h +++ b/clockless_trinket.h @@ -54,7 +54,7 @@ template<> __attribute__((always_inline)) inline void _dc<10>(register uint8_t & #define D1(ADJ) _dc(loopvar); #define D2(ADJ) _dc(loopvar); -#define D3(ADJ) _dc(loopvar); +#define D3(ADJ) (T3-(AVR_PIN_CYCLES(DATA_PIN)+ADJ)>0) ? _dc(loopvar) : _dc<0>(loopvar); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -257,6 +257,9 @@ protected: ADJDITHER2(d2,e2); cli(); + hi = *port | mask; + lo = *port & ~mask; + if((TCNT0-lasttime) > ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)) { sei(); return; } // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 // The values in the D1/D2/D3 indicate how many cycles the previous column takes @@ -304,13 +307,14 @@ protected: HI1 D1(1) QLO2(b2, 2) SCROR04(b0,5) D2(4) LO1 SCALE02(b0,6) D3(2) HI1 D1(1) QLO2(b2, 1) RORSC04(b0,7) D2(4) LO1 ROR1(b0) CLC1 D3(2) // HI1 D1(1) QLO2(b2, 0) DCOUNT2 BRLOOP1 D2(3) LO1 D3(2) JMPLOOP2 - HI1 D1(1) QLO2(b2, 0) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b2, 0) D2(0) LO1 switch(XTRA0) { - case 4: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); - case 3: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); - case 2: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); - case 1: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); + case 4: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; + case 3: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; + case 2: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; + case 1: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; } + D3(12); #else // no inline scaling - non-straight RGB ordering HI1 D1(1) QLO2(b0, 7) LD2(b1,O1) D2(2) LO1 D3(0) -- cgit v1.2.3 From 544b1313255cfa48c91f837992d21d2a9a156fc7 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Thu, 30 Oct 2014 16:53:58 -0400 Subject: Keep (TCNT0-lasttime) to 8-bits, as it'll never be more than that anyway. --- clockless_trinket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clockless_trinket.h b/clockless_trinket.h index 844c045b..5bc8e420 100644 --- a/clockless_trinket.h +++ b/clockless_trinket.h @@ -260,7 +260,7 @@ protected: hi = *port | mask; lo = *port & ~mask; - if((TCNT0-lasttime) > ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)) { sei(); return; } + if((uint8_t)(TCNT0-lasttime) > ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)) { sei(); return; } // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 // The values in the D1/D2/D3 indicate how many cycles the previous column takes // to allow things to line back up. -- cgit v1.2.3 From 926692ddd90612ef7a2af3bf95ca376ed92f9710 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 30 Oct 2014 13:54:05 -0700 Subject: Don't need bitswap functions on non-arm yet --- bitswap.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bitswap.h b/bitswap.h index 0cbd95dc..514e27f6 100644 --- a/bitswap.h +++ b/bitswap.h @@ -1,6 +1,7 @@ #ifndef __INC_BITSWAP_H #define __INC_BITSWAP_H +#ifdef FASTLED_ARM // structure representing 8 bits of access typedef union { uint8_t raw; @@ -252,5 +253,5 @@ __attribute__((always_inline)) inline void transpose8(unsigned char *A, unsigned // B[0]=x>>24; B[n]=x>>16; B[2*n]=x>>8; B[3*n]=x>>0; // B[4*n]=y>>24; B[5*n]=y>>16; B[6*n]=y>>8; B[7*n]=y>>0; } - +#endif #endif -- cgit v1.2.3 From 108ae29e73ab833a778a5e65b147e7176b3c45b9 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Thu, 30 Oct 2014 13:54:29 -0700 Subject: Get rid of some extra globals --- FastLED.cpp | 5 +---- FastLED.h | 11 +++++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/FastLED.cpp b/FastLED.cpp index 0f1e3262..ec95e075 100644 --- a/FastLED.cpp +++ b/FastLED.cpp @@ -6,10 +6,7 @@ volatile uint32_t fuckit; void *pSmartMatrix = NULL; -CFastLED LEDS; -CFastLED & FastSPI_LED = LEDS; -CFastLED & FastSPI_LED2 = LEDS; -CFastLED & FastLED = LEDS; +CFastLED FastLED; CLEDController *CLEDController::m_pHead = NULL; CLEDController *CLEDController::m_pTail = NULL; diff --git a/FastLED.h b/FastLED.h index 78e5835b..d94dc1ba 100644 --- a/FastLED.h +++ b/FastLED.h @@ -306,9 +306,12 @@ static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIf CRGB *leds() { return (*this)[0].leds(); } }; -extern CFastLED & FastSPI_LED; -extern CFastLED & FastSPI_LED2; -extern CFastLED & FastLED; -extern CFastLED LEDS; +#define FastSPI_LED FastLED +#define FastSPI_LED2 FastLED +#ifndef LEDS +#define LEDS FastLED +#endif + +extern CFastLED FastLED; #endif -- cgit v1.2.3 From 8c9b4e6e592ab97c053744f592a18218c568e265 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 31 Oct 2014 16:12:08 -0700 Subject: checkpoint --- clockless_arm_sam.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h index 95f833b8..68617af2 100644 --- a/clockless_arm_sam.h +++ b/clockless_arm_sam.h @@ -155,6 +155,9 @@ protected: #define VAL (volatile uint32_t)(*((uint32_t*)(SysTick_BASE + 8))) template __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 + // while(VAL < (TOTAL*10)); + for(register uint32_t i = BITS; i > 0; i--) { // wait to start the bit, then set the pin high while(VAL > next_mark); @@ -192,6 +195,7 @@ protected: pixels.preStepFirstByteDithering(); register uint8_t b = pixels.loadAndScale0(); + // while(VAL < (TOTAL*10)); uint32_t next_mark = (VAL - (TOTAL)); while(pixels.has(1)) { pixels.stepDithering(); -- cgit v1.2.3 From 380ea9c4e2494fecdea26b4e2738d1547f50d957 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 31 Oct 2014 16:31:42 -0700 Subject: example tweak --- examples/Cylon/Cylon.ino | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/examples/Cylon/Cylon.ino b/examples/Cylon/Cylon.ino index ea102095..56e2d1d5 100644 --- a/examples/Cylon/Cylon.ino +++ b/examples/Cylon/Cylon.ino @@ -6,36 +6,24 @@ // For led chips like Neopixels, which have a data line, ground, and power, you just // need to define DATA_PIN. For led chipsets that are SPI based (four wires - data, clock, // ground, and power), like the LPD8806, define both DATA_PIN and CLOCK_PIN -#define DATA_PIN 6 +#define DATA_PIN 7 #define CLOCK_PIN 13 // Define the array of leds -CRGB leds[(NUM_LEDS * 16)+1]; +CRGB leds[40]; void setup() { - Serial.begin(19200); - delay(3000); - Serial.println("resetting"); - delay(500); Serial.print("."); - delay(500); Serial.print("."); - delay(500); Serial.print("."); - delay(500); Serial.print("."); - delay(500); Serial.print("."); - delay(500); Serial.print("."); - delay(500); Serial.print("."); - delay(500); Serial.print("."); - LEDS.addLeds(leds, NUM_LEDS); // .setDither(DISABLE_DITHER); - // LEDS.addLeds(leds,NUM_LEDS); - Serial.println("Entering loopx"); + LEDS.addLeds(leds,NUM_LEDS); + LEDS.setBrightness(84); } -void fadeall() { for(int i = 0; i < NUM_LEDS*16; i++) { leds[i].nscale8(250); } } +void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } } void loop() { uint8_t hue = 0; // Serial.print("x"); // First slide the led in one direction - for(int i = 0; i < NUM_LEDS*5; i++) { + for(int i = 0; i < NUM_LEDS; i++) { // Set the i'th led to red leds[i] = CHSV(hue++, 255, 255); // Show the leds @@ -44,11 +32,11 @@ void loop() { // leds[i] = CRGB::Black; fadeall(); // Wait a little bit before we loop around and do it again - delay(10); + delay(100); } // Now go in the other direction. - for(int i = (NUM_LEDS*5)-1; i >= 0; i--) { + for(int i = (NUM_LEDS)-1; i >= 0; i--) { // Set the i'th led to red leds[i] = CHSV(hue++, 255, 255); // Show the leds @@ -57,6 +45,6 @@ void loop() { // leds[i] = CRGB::Black; fadeall(); // Wait a little bit before we loop around and do it again - delay(10); + delay(100); } } -- cgit v1.2.3 From f04ed32ab3ebc1a21b35a3d912c419d8b310eaed Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 31 Oct 2014 16:32:07 -0700 Subject: fix typo --- clockless_block_arm_sam.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 7b690849..f98afb16 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -200,7 +200,7 @@ public: while(nLeds--) { allpixels.stepDithering(); cli(); - if(VAL < next_mask) { + if(VAL < next_mark) { if((next_mark - VAL) > ((WAIT_TIME*5)*CLKS_PER_US)) { sei(); return 0x00FFFFF - _VAL; } } -- cgit v1.2.3 From 6092cad72f8c9439b42d513b5caf4230c6c83ac7 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 3 Nov 2014 17:20:37 -0800 Subject: Make the due interrupt friendly and get it off the SysTick timer. --- clockless_arm_sam.h | 130 ++++++++-------------------------------------- clockless_block_arm_sam.h | 62 ++++++---------------- examples/Cylon/Cylon.ino | 13 +++-- led_sysdefs.h | 20 +++++++ 4 files changed, 67 insertions(+), 158 deletions(-) diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h index 68617af2..0c38b611 100644 --- a/clockless_arm_sam.h +++ b/clockless_arm_sam.h @@ -40,39 +40,14 @@ protected: virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { PixelController pixels(rgbdata, nLeds, scale, getDither()); mWait.wait(); - cli(); - SysClockSaver savedClock(TOTAL); - - uint32_t clocks = showRGBInternal(pixels); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - long millisTaken = (microsTaken / 1000); - savedClock.restore(); - do { TimeTick_Increment(); } while(--millisTaken > 0); - sei(); + showRGBInternal(pixels); mWait.mark(); } virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { PixelController pixels(rgbdata, nLeds, scale, getDither()); mWait.wait(); - cli(); - SysClockSaver savedClock(TOTAL); - - // Serial.print("Scale is "); - // Serial.print(scale.raw[0]); Serial.print(" "); - // Serial.print(scale.raw[1]); Serial.print(" "); - // Serial.print(scale.raw[2]); Serial.println(" "); - // FastPinBB::hi(); delay(1); FastPinBB::lo(); - uint32_t clocks = showRGBInternal(pixels); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - long millisTaken = (microsTaken / 1000); - savedClock.restore(); - do { TimeTick_Increment(); } while(--millisTaken > 0); - sei(); + showRGBInternal(pixels); mWait.mark(); } @@ -80,97 +55,32 @@ protected: virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { PixelController pixels(rgbdata, nLeds, scale, getDither()); mWait.wait(); - cli(); - SysClockSaver savedClock(TOTAL); - - uint32_t clocks = showRGBInternal(pixels); - - // Adjust the timer - long microsTaken = CLKS_TO_MICROS(clocks); - long millisTaken = (microsTaken / 1000); - savedClock.restore(); - do { TimeTick_Increment(); } while(--millisTaken > 0); + showRGBInternal(pixels); sei(); mWait.mark(); } #endif -#if 0 -// Get the arm defs, register/macro defs from the k20 -#define ARM_DEMCR *(volatile uint32_t *)0xE000EDFC // Debug Exception and Monitor Control -#define ARM_DEMCR_TRCENA (1 << 24) // Enable debugging & monitoring blocks -#define ARM_DWT_CTRL *(volatile uint32_t *)0xE0001000 // DWT control register -#define ARM_DWT_CTRL_CYCCNTENA (1 << 0) // Enable cycle count -#define ARM_DWT_CYCCNT *(volatile uint32_t *)0xE0001004 // Cycle count register - - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register uint8_t & b) { - for(register uint32_t i = BITS; i > 0; i--) { - while(ARM_DWT_CYCCNT < next_mark); - next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - *port = 1; - uint32_t flip_mark = next_mark - ((b&0x80) ? (T3) : (T2+T3)); - b <<= 1; - while(ARM_DWT_CYCCNT < flip_mark); - *port = 0; - } - } - - // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then - // gcc will use register Y for the this pointer. - static void showRGBInternal(PixelController pixels) { - register data_ptr_t port = FastPinBB::port(); - *port = 0; - - // Setup the pixel controller and load/scale the first byte - pixels.preStepFirstByteDithering(); - register uint8_t b = pixels.loadAndScale0(); - - // Get access to the clock - ARM_DEMCR |= ARM_DEMCR_TRCENA; - ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; - ARM_DWT_CYCCNT = 0; - uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - - while(pixels.has(1)) { - pixels.stepDithering(); - - // Write first byte, read next byte - writeBits<8+XTRA0>(next_mark, port, b); - b = pixels.loadAndScale1(); - - // Write second byte, read 3rd byte - writeBits<8+XTRA0>(next_mark, port, b); - b = pixels.loadAndScale2(); - - // Write third byte - writeBits<8+XTRA0>(next_mark, port, b); - b = pixels.advanceAndLoadAndScale0(); - }; - } -#else -// I hate using defines for these, should find a better representation at some point -#define _CTRL CTPTR[0] -#define _LOAD CTPTR[1] -#define _VAL CTPTR[2] -#define VAL (volatile uint32_t)(*((uint32_t*)(SysTick_BASE + 8))) template __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 - // while(VAL < (TOTAL*10)); + // bool bShift=0; + // while(VAL < (TOTAL*10)) { bShift=true; } + // if(bShift) { next_mark = (VAL-TOTAL); }; for(register uint32_t i = BITS; i > 0; i--) { // wait to start the bit, then set the pin high - while(VAL > next_mark); - next_mark = (VAL-TOTAL); + while(DUE_TIMER_VAL < next_mark); + next_mark = (DUE_TIMER_VAL+TOTAL); *port = 1; // how long we want to wait next depends on whether or not our bit is set to 1 or 0 if(b&0x80) { // we're a 1, wait until there's less than T3 clocks left - while((VAL - next_mark) > (T3)); + while((next_mark - DUE_TIMER_VAL) > (T3)); } else { // we're a 0, wait until there's less than (T2+T3+slop) clocks left in this bit - while((VAL-next_mark) > (T2+T3+6+TADJUST+TADJUST)); + while((next_mark - DUE_TIMER_VAL) > (T2+T3+6+TADJUST+TADJUST)); } *port=0; b <<= 1; @@ -182,11 +92,9 @@ protected: // gcc will use register Y for the this pointer. static uint32_t showRGBInternal(PixelController & pixels) { // Setup and start the clock - register volatile uint32_t *CTPTR asm("r6")= &SysTick->CTRL; FORCE_REFERENCE(CTPTR); - _LOAD = 0x00FFFFFF; - _VAL = 0; - _CTRL |= SysTick_CTRL_CLKSOURCE_Msk; - _CTRL |= SysTick_CTRL_ENABLE_Msk; + TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1); + pmc_enable_periph_clk(DUE_TIMER_ID); + TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); register data_ptr_t port asm("r7") = FastPinBB::port(); FORCE_REFERENCE(port); *port = 0; @@ -195,11 +103,15 @@ protected: pixels.preStepFirstByteDithering(); register uint8_t b = pixels.loadAndScale0(); - // while(VAL < (TOTAL*10)); - uint32_t next_mark = (VAL - (TOTAL)); + uint32_t next_mark = (VAL + (TOTAL)); while(pixels.has(1)) { pixels.stepDithering(); + cli(); + if(DUE_TIMER_VAL > next_mark) { + if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; } + } + writeBits<8+XTRA0>(next_mark, port, b); b = pixels.loadAndScale1(); @@ -209,9 +121,11 @@ protected: writeBits<8+XTRA0>(next_mark, port,b); b = pixels.advanceAndLoadAndScale0(); + sei(); }; - return 0x00FFFFFF - _VAL; + TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); + return DUE_TIMER_VAL; } #endif }; diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index f98afb16..6f9fc797 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -88,15 +88,7 @@ public: virtual void showColor(const struct CRGB & rgbdata, int nLeds, CRGB scale) { MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - SysClockSaver savedClock(TOTAL); - - uint32_t clocks = showRGBInternal(pixels, nLeds); - - long microsTaken = CLKS_TO_MICROS(clocks); - long millisTaken = (microsTaken / 1000); - savedClock.restore(); - while(millisTaken-- > 0) { TimeTick_Increment(); } + showRGBInternal(pixels, nLeds); sei(); mWait.mark(); } @@ -107,38 +99,18 @@ public: virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); mWait.wait(); - cli(); - SysClockSaver savedClock(TOTAL); - - uint32_t clocks = showRGBInternal(pixels, nLeds); - - - long microsTaken = CLKS_TO_MICROS(clocks); - long millisTaken = (microsTaken / 1000); - savedClock.restore(); - while(millisTaken-- > 0) { TimeTick_Increment(); } - sei(); + showRGBInternal(pixels, nLeds); mWait.mark(); } #ifdef SUPPORT_ARGB virtual void show(const struct CARGB *rgbdata, int nLeds, CRGB scale) { mWait.wait(); - cli(); - showRGBInternal(PixelController(rgbdata, nLeds, scale, getDither())); - - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - sei(); mWait.mark(); } #endif -#define VAL *((uint32_t*)(SysTick_BASE + 8)) - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, MultiPixelController &pixels) { // , register uint32_t & b2) { register Lines b2; transpose8x1(b.bytes,b2.bytes); @@ -147,15 +119,15 @@ public: register uint8_t scale = pixels.template getscale(pixels); for(uint32_t i = 0; (i < LANES) && (i<8); i++) { - while(VAL > next_mark); + while(DUE_TIMER_VAL < next_mark); + next_mark = (DUE_TIMER_VAL+TOTAL); - next_mark = VAL - (TOTAL-12); *FastPin::sport() = PORT_MASK; - while((VAL-next_mark) > (T2+T3+6)); + while(next_mark - DUE_TIMER_VAL) > (T2+T3+6)); *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; - while((VAL - next_mark) > T3); + while((next_mark - DUE_TIMER_VAL) > T3); *FastPin::cport() = PORT_MASK; b3.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); @@ -167,10 +139,10 @@ public: next_mark = VAL - (TOTAL-3); *FastPin::sport() = PORT_MASK; - while((VAL-next_mark) > (T2+T3+6)); + while(next_mark - DUE_TIMER_VAL) > (T2+T3+6)); *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; - while((VAL - next_mark) > T3); + while((next_mark - DUE_TIMER_VAL) > T3); *FastPin::cport() = PORT_MASK; } } @@ -188,20 +160,20 @@ public: } // Setup and start the clock - register volatile uint32_t *CTPTR asm("r6")= &SysTick->CTRL; FORCE_REFERENCE(CTPTR); - _LOAD = 0x00FFFFFF; - _VAL = 0; - _CTRL |= SysTick_CTRL_CLKSOURCE_Msk; - _CTRL |= SysTick_CTRL_ENABLE_Msk; + TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1); + pmc_enable_periph_clk(DUE_TIMER_ID); + TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); VAL = 0; cli(); - uint32_t next_mark = (VAL - (TOTAL)); + uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); while(nLeds--) { allpixels.stepDithering(); cli(); - if(VAL < next_mark) { - if((next_mark - VAL) > ((WAIT_TIME*5)*CLKS_PER_US)) { sei(); return 0x00FFFFF - _VAL; } + if(DUE_TIMER_VAL > next_mark) { + if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { + sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; + } } // Write first byte, read next byte @@ -216,7 +188,7 @@ public: sei(); } - return 0x00FFFFFF - _VAL; + return DUE_TIMER_VAL; } diff --git a/examples/Cylon/Cylon.ino b/examples/Cylon/Cylon.ino index 56e2d1d5..76046b41 100644 --- a/examples/Cylon/Cylon.ino +++ b/examples/Cylon/Cylon.ino @@ -10,9 +10,11 @@ #define CLOCK_PIN 13 // Define the array of leds -CRGB leds[40]; +CRGB leds[NUM_LEDS]; void setup() { + Serial.begin(57600); + Serial.println("resetting"); LEDS.addLeds(leds,NUM_LEDS); LEDS.setBrightness(84); } @@ -20,8 +22,8 @@ void setup() { void fadeall() { for(int i = 0; i < NUM_LEDS; i++) { leds[i].nscale8(250); } } void loop() { - uint8_t hue = 0; - // Serial.print("x"); + static uint8_t hue = 0; + Serial.print("x"); // First slide the led in one direction for(int i = 0; i < NUM_LEDS; i++) { // Set the i'th led to red @@ -32,8 +34,9 @@ void loop() { // leds[i] = CRGB::Black; fadeall(); // Wait a little bit before we loop around and do it again - delay(100); + delay(10); } + Serial.print("x"); // Now go in the other direction. for(int i = (NUM_LEDS)-1; i >= 0; i--) { @@ -45,6 +48,6 @@ void loop() { // leds[i] = CRGB::Black; fadeall(); // Wait a little bit before we loop around and do it again - delay(100); + delay(10); } } diff --git a/led_sysdefs.h b/led_sysdefs.h index 894055f1..3ec49ad6 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -2,6 +2,7 @@ #define __INC_LED_SYSDEFS_H #if defined(__MK20DX128__) || defined(__MK20DX256__) + #define FASTLED_TEENSY3 #define FASTLED_ARM #define FASTLED_ACCURATE_CLOCK @@ -11,14 +12,33 @@ #if (F_CPU == 96000000) #define CLK_DBL 1 #endif + #elif defined(__SAM3X8E__) + #define FASTLED_ARM + +// Setup DUE timer defines/channels/etc... +#ifndef DUE_TIMER_CHANNEL +#define DUE_TIMER_GROUP 0 +#endif + +#ifndef DUE_TIMER_CHANNEL +#define DUE_TIMER_CHANNEL 0 +#endif + +#define DUE_TIMER ((DUE_TIMER_GROUP==0) ? TC0 : ((DUE_TIMER_GROUP==1) ? TC1 : TC2)) +#define DUE_TIMER_ID (ID_TC0 + (DUE_TIMER_GROUP*3) + DUE_TIMER_CHANNEL) +#define DUE_TIMER_VAL (DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_CV << 1) +#define DUE_TIMER_RUNNING ((DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_SR & TC_SR_CLKSTA) != 0) + #else + #define FASTLED_AVR #define FASTLED_ACCURATE_CLOCK #ifndef INTERRUPT_THRESHOLD #define INTERRUPT_THRESHOLD 10 #endif + #endif #ifndef CLK_DBL -- cgit v1.2.3 From e7e8962456fcabbfa39d64296bf93667991d2aed Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 3 Nov 2014 17:20:57 -0800 Subject: bumping preview changes doc --- preview_changes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/preview_changes.txt b/preview_changes.txt index 26933cde..84407524 100644 --- a/preview_changes.txt +++ b/preview_changes.txt @@ -5,4 +5,5 @@ FastLED 3.1 preview changes: * refresh rate limiting * interrupt friendly code on teensy 3/3.1 * interrupt friendly code on AVR +* interrupt friendly code on the due -- cgit v1.2.3 From 997ef116c1bb8a7c94f5bf4ac568ef1afa19c39d Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Tue, 4 Nov 2014 10:12:04 -0800 Subject: Fix #92 from bad cleanup of dead code --- clockless_arm_sam.h | 1 - 1 file changed, 1 deletion(-) diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h index 0c38b611..1e335b68 100644 --- a/clockless_arm_sam.h +++ b/clockless_arm_sam.h @@ -127,7 +127,6 @@ protected: TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; } -#endif }; #endif -- cgit v1.2.3 From 820ab41e5083ca685ebed447ce9ba3a0ed633de4 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Tue, 4 Nov 2014 10:38:45 -0800 Subject: Removing references to millisecond counter adjustments since they aren't needed anymore. --- block_clockless.h | 232 ---------------------------------------------------- clockless2.h | 241 ------------------------------------------------------ delay.h | 43 ---------- 3 files changed, 516 deletions(-) delete mode 100644 block_clockless.h delete mode 100644 clockless2.h diff --git a/block_clockless.h b/block_clockless.h deleted file mode 100644 index d561239c..00000000 --- a/block_clockless.h +++ /dev/null @@ -1,232 +0,0 @@ - #ifndef __INC_BLOCK_CLOCKLESS_H -#define __INC_BLOCK_CLOCKLESS_H - -#include "controller.h" -#include "lib8tion.h" -#include "led_sysdefs.h" -#include "delay.h" - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point -// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the -// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#define PORT_MASK 0x77EFF3FE -#define SKIPLIST ~PORT_MASK - -#if defined(__SAM3X8E__) -#define HAS_BLOCKLESS 1 -template -class BlockClocklessController : public CLEDController { - typedef typename FastPinBB<1>::port_ptr_t data_ptr_t; - typedef typename FastPinBB<1>::port_t data_t; - - CMinWait mWait; - uint32_t *m_pBuffer; - - void transformData(uint8_t *leddata, int num_leds, uint8_t scale = 255) { - if(m_pBuffer == NULL) { - m_pBuffer = (uint32_t*)malloc(4 * 8 * 3 * num_leds); - } - - uint32_t *outputdata = m_pBuffer; - for(register int i = 0; i < num_leds; i++) { - register byte rgboffset = RGB_BYTE0(RGB_ORDER); - for(int rgb = 0; rgb < 3; rgb++) { - register uint32_t mask = 0x01; // 0x01; - register uint32_t output[8] = {0,0,0,0,0,0,0,0}; - - // set the base address to skip through - uint8_t *database = leddata + (3*i) + rgboffset; - for(int j = 0; j < NUM_LANES; j++) { - register uint8_t byte = ~scale8(*database, scale); - if(byte & 0x80) { output[0] |= mask; } - if(byte & 0x40) { output[1] |= mask; } - if(byte & 0x20) { output[2] |= mask; } - if(byte & 0x10) { output[3] |= mask; } - if(byte & 0x08) { output[4] |= mask; } - if(byte & 0x04) { output[5] |= mask; } - if(byte & 0x02) { output[6] |= mask; } - if(byte & 0x01) { output[7] |= mask; } - - // SKIPLIST is a 32 bit constant that contains the bit positions that are off limits, courtesy of port stupidities - do { mask <<= 1; } while(SKIPLIST & mask); - - // move the data pointer forward a lane - database += (num_leds * 3); - - // cycle between rgb ordering according to RGB order set (may need per-lane rgb ordering? ugh ugh ugh, i hope not!) - rgboffset = (rgboffset == RGB_BYTE0(RGB_ORDER)) ? RGB_BYTE1(RGB_ORDER) : (rgboffset == RGB_BYTE1(RGB_ORDER) ? RGB_BYTE2(RGB_ORDER) : RGB_BYTE0(RGB_ORDER)); - - // copy data out - for(int j = 0; j < 8; j++) { *outputdata++ = output[j]; } - } - } - } - } - -public: - virtual void init() { - //FastPinBB::setOutput(); - uint8_t pins[] = { 33, 34, 35, 36, 37, 38, 39, 40, 41, 51, 50, 49, 48, 47, 46,45, 44, 9, 8, 7, 6, 5, 4, 3, 10, 72, 0 }; - int i = 0; - while(pins[i]) { pinMode(pins[i++], OUTPUT); } - m_pBuffer = NULL; - } - - 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 & data, int nLeds, uint8_t scale = 255) { - mWait.wait(); - cli(); - SysClockSaver savedClock(T1 + T2 + T3); - - // showRGBInternal<0, false>(nLeds, scale, (const byte*)&data); - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - savedClock.restore(); - sei(); - mWait.mark(); - } - - virtual void show(const struct CRGB *rgbdata, int nLeds, uint8_t scale = 255) { - transformData((uint8_t*)rgbdata, nLeds, scale); - mWait.wait(); - cli(); - SysClockSaver savedClock(T1 + T2 + T3); - - // FastPinBB::hi(); delay(1); FastPinBB::lo(); - showRGBInternal<0, true>(nLeds); - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - savedClock.restore(); - sei(); - mWait.mark(); - } - -#ifdef SUPPORT_ARGB - virtual void show(const struct CARGB *rgbdata, int nLeds, uint8_t scale = 255) { - transformData((uint8_t*)rgbdata, nLeds, scale); - - mWait.wait(); - cli(); - SysClockSaver savedClock(T1 + T2 + T3); - - showRGBInternal<1, true>(nLeds, scale, (const byte*)rgbdata); - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - savedClock.restore(); - sei(); - mWait.mark(); - } -#endif - -// I hate using defines for these, should find a better representation at some point -#define _CTRL CTPTR[0] -#define _LOAD CTPTR[1] -#define _VAL CTPTR[2] - - __attribute__((always_inline)) static inline void wait_loop_start(register volatile uint32_t *CTPTR) { - __asm__ __volatile__ ( - "L_%=: ldr.w r8, [%0]\n" - " tst.w r8, #65536\n" - " beq.n L_%=\n" - : /* no outputs */ - : "r" (CTPTR) - : "r8" - ); - } - - template __attribute__((always_inline)) static inline void wait_loop_mark(register volatile uint32_t *CTPTR) { - __asm__ __volatile__ ( - "L_%=: ldr.w r8, [%0, #8]\n" - " cmp.w r8, %1\n" - " bhi.n L_%=\n" - : /* no outputs */ - : "r" (CTPTR), "I" (MARK) - : "r8" - ); - } - - __attribute__((always_inline)) static inline void mark_port(register data_ptr_t port, register int val) { - __asm__ __volatile__ ( - " str.w %0, [%1]\n" - : /* no outputs */ - : "r" (val), "r" (port) - ); - } -#define AT_BIT_START(X) wait_loop_start(CTPTR); X; -#define AT_MARK(X) wait_loop_mark(CTPTR); { X; } -#define AT_END(X) wait_loop_mark(CTPTR); { X; } - -// #define AT_BIT_START(X) while(!(_CTRL & SysTick_CTRL_COUNTFLAG_Msk)); { X; } -// #define AT_MARK(X) while(_VAL > T1_MARK); { X; } -// #define AT_END(X) while(_VAL > T2_MARK); { X; } - -//#define AT_MARK(X) delayclocks_until(_VAL); X; -//#define AT_END(X) delayclocks_until(_VAL); X; - -#define TOTAL (T1 + T2 + T3) - -#define T1_MARK (TOTAL - T1) -#define T2_MARK (T1_MARK - T2) - template __attribute__((always_inline)) static inline void delayclocks_until(register byte b) { - __asm__ __volatile__ ( - " sub %0, %0, %1\n" - "L_%=: subs %0, %0, #2\n" - " bcs.n L_%=\n" - : /* no outputs */ - : "r" (b), "I" (MARK) - : /* no clobbers */ - ); - - } - -#define FORCE_REFERENCE(var) asm volatile( "" : : "r" (var) ) - - // 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. - template void showRGBInternal(register int nLeds) { - register uint32_t *data = m_pBuffer; - register uint32_t *end = data + 8*(nLeds*3); - - register volatile uint32_t *CTPTR asm("r6")= &SysTick->CTRL; FORCE_REFERENCE(CTPTR); - - // Setup and start the clock - _LOAD = TOTAL; - _VAL = 0; - _CTRL |= SysTick_CTRL_CLKSOURCE_Msk; - _CTRL |= SysTick_CTRL_ENABLE_Msk; - - // read to clear the loop flag - _CTRL; - - while(data < end) { - register uint32_t d = *data++; - // turn everything in the port on at the start - AT_BIT_START(REG_PIOC_SODR = PORT_MASK); - - // part way through early clear the ones that should be 0 bits - AT_MARK(REG_PIOC_CODR = d); - - // now all the way through zero everyone - AT_END(REG_PIOC_CODR= PORT_MASK); - }; - } -}; - -#endif - -#endif \ No newline at end of file diff --git a/clockless2.h b/clockless2.h deleted file mode 100644 index c48cde5d..00000000 --- a/clockless2.h +++ /dev/null @@ -1,241 +0,0 @@ -#ifndef __INC_CLOCKLESS2_H -#define __INC_CLOCKLESS2_H - -#include "controller.h" -#include "lib8tion.h" -#include "led_sysdefs.h" -#include "delay.h" - -#ifdef FASTLED_TEENSY3 -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point -// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the -// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Convinience macros to wrap around the toggling of hi vs. lo -#define SET2_LO FLIP ? FastPin::hi() : FastPin::lo() -#define SET2_HI FLIP ? FastPin::lo() : FastPin::hi() - -#define SET2_LO2 FLIP ? FastPin::hi() : FastPin::lo() -#define SET2_HI2 FLIP ? FastPin::lo() : FastPin::hi() - - -template -class ClocklessController2 : public CLEDController { - typedef typename FastPin::port_ptr_t data_ptr_t; - typedef typename FastPin::port_t data_t; - - CMinWait mWait; -public: - virtual void init() { - FastPin::setOutput(); - FastPin::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 & data, int nLeds, uint8_t scale = 255) { - mWait.wait(); - cli(); - - showRGBInternal<0, false>(nLeds, scale, (const byte*)&data, (const byte*)&data); - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - sei(); - mWait.mark(); - } - - virtual void show(const struct CRGB *rgbdata, int nLeds, uint8_t scale = 255) { - mWait.wait(); - cli(); - - showRGBInternal<0, true>(nLeds, scale, (const byte*)rgbdata, (const byte*)rgbdata); - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - sei(); - mWait.mark(); - } - - virtual void show(const struct CRGB *rgbdata, const struct CRGB *rgbdata2, int nLeds, uint8_t scale = 255) { - mWait.wait(); - cli(); - - showRGBInternal<0, true>(nLeds, scale, (const byte*)rgbdata, (const byte*)rgbdata2 ); - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - sei(); - mWait.mark(); - } - -#ifdef SUPPORT_ARGB - virtual void show(const struct CARGB *rgbdata, int nLeds, uint8_t scale = 255) { - mWait.wait(); - cli(); - - showRGBInternal<1, true>(nLeds, scale, (const byte*)rgbdata); - - // Adjust the timer - long microsTaken = nLeds * CLKS_TO_MICROS(24 * (T1 + T2 + T3)); - MS_COUNTER += (microsTaken / 1000); - 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. - template static void showRGBInternal(register int nLeds, register uint8_t scale, register const byte *rgbdata, register const byte *rgbdata2) { - register byte *data = (byte*)rgbdata; - register byte *data2 = (byte*)rgbdata2; - - nLeds *= (3 + SKIP); - register uint8_t *end = data + nLeds; - - register uint32_t b; - register uint32_t c; - if(ADVANCE) { - b = data[SKIP + RGB_BYTE0(RGB_ORDER)]; - c = data2[SKIP + RGB_BYTE0(RGB_ORDER)]; - } else { - b = rgbdata[SKIP + RGB_BYTE0(RGB_ORDER)]; - c = rgbdata2[SKIP + RGB_BYTE0(RGB_ORDER)]; - } - b = scale8(b, scale); - c = scale8(c, scale); - - while(data < end) { - // TODO: hand rig asm version of this method. The timings are based on adjusting/studying GCC compiler ouptut. This - // will bite me in the ass at some point, I know it. - for(register uint32_t i = 7; i > 0; i--) { - SET2_HI; delaycycles<3>(); SET2_HI2; - delaycycles(); // 6 cycles - 1/1 store, 1/1 test, 1/1 if, 1/1 port lookup - if(b & 0x80) { SET2_HI; } else { SET2_LO; } - if(c & 0x80) { SET2_HI2; } else { SET2_LO2; } - b <<= 1; c <<=1; - delaycycles(); // 3 cycles, 1/1 store, 1/1 store/skip, 1/1 shift , 1/1 port lookup - SET2_LO; SET2_LO2; - delaycycles(); // 4 cycles, 1/1 store, 1 sub, 1 branch backwards, 1/1 port lookup - } - // extra delay because branch is faster falling through - delaycycles<1>(); - - // 8th bit, interleave loading rest of data - SET2_HI; delaycycles<3>(); SET2_HI2; - delaycycles(); - if(b & 0x80) { SET2_HI; } else { SET2_LO; } - if(c & 0x80) { SET2_HI2; } else { SET2_LO2; } - delaycycles(); // 4 cycles, 2/2 store, 1/1 store/skip, 1/1 port lookup - SET2_LO; SET2_LO2; - - if(ADVANCE) { - b = data[SKIP + RGB_BYTE1(RGB_ORDER)]; - c = data2[SKIP + RGB_BYTE1(RGB_ORDER)]; - } else { - b = rgbdata[SKIP + RGB_BYTE1(RGB_ORDER)]; - c = rgbdata2[SKIP + RGB_BYTE1(RGB_ORDER)]; - } - b = scale8(b, scale); - c = scale8(c, scale); - - delaycycles(); // 1/1 store, 2/2 load, 1/1 mul, 1/1 shift, , 1/1 port lookup - - for(register uint32_t i = 7; i > 0; i--) { - SET2_HI; delaycycles<3>(); SET2_HI2; - delaycycles(); // 3 cycles - 1 store, 1 test, 1 if - if(b & 0x80) { SET2_HI; } else { SET2_LO; } - if(c & 0x80) { SET2_HI2; } else { SET2_LO2; } - b <<= 1; c <<= 1; - delaycycles(); // 6 cycles, 1/1 store, 1/1 store/skip, 1/1 shift , 1/1 port lookup - SET2_LO; SET2_LO2; - delaycycles(); // 4 cycles, 1/1 store, 1 sub, 1 branch backwards, 1/1 port lookup - } - // extra delay because branch is faster falling through - delaycycles<1>(); - - // 8th bit, interleave loading rest of data - SET2_HI; delaycycles<3>(); SET2_HI2; - delaycycles(); - if(b & 0x80) { SET2_HI; } else { SET2_LO; } - if(b & 0x80) { SET2_HI2; } else { SET2_LO2; } - delaycycles(); // 4 cycles, 2 store, store/skip, 1/1 port lookup - SET2_LO; SET2_LO2; - - if(ADVANCE) { - b = data[SKIP + RGB_BYTE2(RGB_ORDER)]; - c = data2[SKIP + RGB_BYTE2(RGB_ORDER)]; - } else { - b = rgbdata[SKIP + RGB_BYTE2(RGB_ORDER)]; - c = rgbdata2[SKIP + RGB_BYTE2(RGB_ORDER)]; - } - b = scale8(b, scale); - c = scale8(c, scale); - - data += 3 + SKIP; data2 += 3 + SKIP; - if((RGB_ORDER & 0070) == 0) { - delaycycles(); // 1/1 store, 2/2 load, 1/1 mul, 1/1 shift, 1/1 adds if BRG or GRB, 1/1 port lookup - } else { - delaycycles(); // 1/1 store, 2/2 load, 1/1 mul, 1/1 shift, , 1/1 port lookup - } - - for(register uint32_t i = 7; i > 0; i--) { - SET2_HI; delaycycles<3>(); SET2_HI2; - delaycycles(); // 3 cycles - 1 store, 1 test, 1 if - if(b & 0x80) { SET2_HI; } else { SET2_LO; } - if(c & 0x80) { SET2_HI2; } else { SET2_LO2; } - b <<= 1; c <<= 1; - delaycycles(); // 3 cycles, 1 store, 1 store/skip, 1 shift , 1/1 port lookup - SET2_LO; SET2_LO2; - delaycycles(); // 3 cycles, 1/1 store, 1 sub, 1 branch backwards, 1/1 port lookup - } - // extra delay because branch is faster falling through - delaycycles<1>(); - - // 8th bit, interleave loading rest of data - SET2_HI; delaycycles<3>(); SET2_HI2; - delaycycles(); - if(b & 0x80) { SET2_HI; } else { SET2_LO; } - if(c & 0x80) { SET2_HI2; } else { SET2_LO2; } - delaycycles(); // 4 cycles, 2/2 store, store/skip, 1/1 port lookup - SET2_LO; SET2_LO2; - - if(ADVANCE) { - b = data[SKIP + RGB_BYTE0(RGB_ORDER)]; - c = data2[SKIP + RGB_BYTE0(RGB_ORDER)]; - } else { - b = rgbdata[SKIP + RGB_BYTE0(RGB_ORDER)]; - c = rgbdata2[SKIP + RGB_BYTE0(RGB_ORDER)]; - } - b = scale8(b, scale); - c = scale8(c, scale); - delaycycles(); // 1/1 store, 2/2 load (with increment), 1/1 mul, 1/1 shift, 1 cmp, 1 branch backwards, 1 movim, 1/1 port lookup - }; - } - -#ifdef SUPPORT_ARGB - virtual void showARGB(struct CARGB *data, int nLeds) { - // TODO: IMPLEMENTME - } -#endif -}; - -#undef SET2_HI -#undef SET2_HI2 -#undef SET2_LO -#undef SET2_LO2 - -#endif - -#endif \ No newline at end of file diff --git a/delay.h b/delay.h index 05313127..4a54686a 100644 --- a/delay.h +++ b/delay.h @@ -113,47 +113,4 @@ template<> __attribute__((always_inline)) inline void delaycycles<5>() {NOP2;NOP #define NO_TIME(A, B, C) (NS(A) < 3 || NS(B) < 3 || NS(C) < 6) -#if defined(FASTLED_TEENSY3) - extern volatile uint32_t systick_millis_count; -# define MS_COUNTER systick_millis_count -#elif defined(__SAM3X8E__) - extern volatile uint32_t fuckit; -# define MS_COUNTER fuckit -#else -# if defined(CORE_TEENSY) - extern volatile unsigned long timer0_millis_count; -# define MS_COUNTER timer0_millis_count -# else - extern volatile unsigned long timer0_millis; -# define MS_COUNTER timer0_millis -# endif -#endif - -#ifdef __SAM3X8E__ -class SysClockSaver { - SysTick_Type m_Saved; -public: - SysClockSaver(int newTimeValue) { save(newTimeValue); } - void save(int newTimeValue) { - m_Saved.CTRL = SysTick->CTRL; - SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk); - m_Saved.LOAD = SysTick->LOAD; - m_Saved.VAL = SysTick->VAL; - - SysTick->VAL = 0; - SysTick->LOAD = newTimeValue; - SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk; - SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; - } - - void restore() { - SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk); - SysTick->LOAD = m_Saved.LOAD; - SysTick->VAL = m_Saved.VAL; - SysTick->CTRL = m_Saved.CTRL; - } -}; - -#endif - #endif -- cgit v1.2.3 From 6ca2090e95ca2a5c9d4bb79fc06c5e6c5a122f34 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Tue, 4 Nov 2014 11:09:13 -0800 Subject: Add extra C++ bits that some environments might need --- FastLED.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/FastLED.cpp b/FastLED.cpp index ec95e075..077efbe3 100644 --- a/FastLED.cpp +++ b/FastLED.cpp @@ -202,3 +202,34 @@ void CFastLED::setMaxRefreshRate(uint16_t refresh) { m_nMinMicros = 0; } } + + +#ifdef NEED_CXX_BITS +namespace __cxxabiv1 +{ + extern "C" void __cxa_pure_virtual (void) {} + /* guard variables */ + + /* The ABI requires a 64-bit type. */ + __extension__ typedef int __guard __attribute__((mode(__DI__))); + + extern "C" int __cxa_guard_acquire (__guard *); + extern "C" void __cxa_guard_release (__guard *); + extern "C" void __cxa_guard_abort (__guard *); + + extern "C" int __cxa_guard_acquire (__guard *g) + { + return !*(char *)(g); + } + + extern "C" void __cxa_guard_release (__guard *g) + { + *(char *)g = 1; + } + + extern "C" void __cxa_guard_abort (__guard *) + { + + } +} +#endif -- cgit v1.2.3 From 99fb98e06033c791f2a340ee6f00b81978338c23 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Tue, 4 Nov 2014 21:35:39 -0800 Subject: Shut up compiler warnings on arm --- noise.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/noise.cpp b/noise.cpp index 9f3e8777..d64e536d 100644 --- a/noise.cpp +++ b/noise.cpp @@ -47,7 +47,7 @@ FL_PROGMEM static uint8_t const p[] = { 151,160,137,91,90,15, #define FADE(x) scale16(x,x) #define LERP(a,b,u) lerp15by16(a,b,u) #endif -static int16_t __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y, int16_t z) { +static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y, int16_t z) { #if 0 switch(hash & 0xF) { case 0: return (( x) + ( y))>>1; @@ -78,7 +78,7 @@ static int16_t __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, i #endif } -static int16_t __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y) { +static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, int16_t y) { hash = hash & 7; int16_t u,v; if(hash < 4) { u = x; v = y; } else { u = y; v = x; } @@ -88,7 +88,7 @@ static int16_t __attribute__((always_inline)) grad16(uint8_t hash, int16_t x, in return (u+v)>>1; } -static int16_t __attribute__((always_inline)) grad16(uint8_t hash, int16_t x) { +static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_t x) { hash = hash & 15; int16_t u,v; if(hash > 8) { u=x;v=x; } @@ -100,7 +100,7 @@ static int16_t __attribute__((always_inline)) grad16(uint8_t hash, int16_t x) { return (u+v)>>1; } -static int8_t __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y, int8_t z) { +static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y, int8_t z) { #if 0 switch(hash & 0xF) { case 0: return (( x) + ( y))>>1; @@ -131,7 +131,7 @@ static int8_t __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8 #endif } -static int8_t __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y) { +static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y) { hash = hash & 7; int8_t u,v; if(hash < 4) { u = x; v = y; } else { u = y; v = x; } @@ -141,7 +141,7 @@ static int8_t __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_ return (u+v)>>1; } -static int8_t __attribute__((always_inline)) grad8(uint8_t hash, int8_t x) { +static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x) { hash = hash & 15; int8_t u,v; if(hash > 8) { u=x;v=x; } @@ -159,7 +159,7 @@ uint16_t logfade12(uint16_t val) { return scale16(val,val)>>4; } -static int16_t __attribute__((always_inline)) lerp15by12( int16_t a, int16_t b, fract16 frac) +static int16_t inline __attribute__((always_inline)) lerp15by12( int16_t a, int16_t b, fract16 frac) { //if(1) return (lerp(frac,a,b)); int16_t result; @@ -176,7 +176,7 @@ static int16_t __attribute__((always_inline)) lerp15by12( int16_t a, int16_t b, } #endif -static int8_t __attribute__((always_inline)) lerp7by8( int8_t a, int8_t b, fract8 frac) +static int8_t inline __attribute__((always_inline)) lerp7by8( int8_t a, int8_t b, fract8 frac) { // int8_t delta = b - a; // int16_t prod = (uint16_t)delta * (uint16_t)frac; -- cgit v1.2.3 From 1944051c42c6607b23e846d2993d07f052fffdbb Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Wed, 5 Nov 2014 23:56:47 -0500 Subject: Added avg8 and avg7 --- lib8tion.h | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lib8tion.h b/lib8tion.h index 9d262a3f..4edf7bf3 100644 --- a/lib8tion.h +++ b/lib8tion.h @@ -197,6 +197,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun #define ADD8_C 1 #define SUB8_C 1 #define EASE8_C 1 +#define AVG8_C 1 +#define AVG7_C 1 #elif defined(__AVR__) @@ -209,6 +211,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun #define ABS8_C 0 #define ADD8_C 0 #define SUB8_C 0 +#define AVG8_C 0 +#define AVG7_C 0 #define QADD8_AVRASM 1 #define QADD7_AVRASM 1 @@ -216,6 +220,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun #define ABS8_AVRASM 1 #define ADD8_AVRASM 1 #define SUB8_AVRASM 1 +#define AVG8_AVRASM 1 +#define AVG7_AVRASM 1 // Note: these require hardware MUL instruction // -- sorry, ATtiny! @@ -265,6 +271,8 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun #define ADD8_C 1 #define SUB8_C 1 #define EASE8_C 1 +#define AVG8_C 1 +#define AVG7_C 1 #endif @@ -463,6 +471,50 @@ LIB8STATIC uint8_t sub8( uint8_t i, uint8_t j) #endif } +// avg8: Calculate an integer average of two unsigned +// 8-bit integer values (uint8_t). +// Fractional results are rounded down, e.g. avg8(20,41) = 30 +LIB8STATIC uint8_t avg8( uint8_t i, uint8_t j) +{ +#if AVG8_C == 1 + return (i + j) >> 1; +#elif AVG8_AVRASM == 1 + asm volatile( + /* First, add j to i, 9th bit overflows into C flag */ + "add %0, %1 \n\t" + /* Divide by two, moving C flag into high 8th bit */ + "ror %0 \n\t" + : "+a" (i) + : "a" (j) ); + return i; +#else +#error "No implementation for avg8 available." +#endif +} + + +// avg7: Calculate an integer average of two signed 7-bit +// integers (int8_t) +// If the first argument is even, result is rounded down. +// If the first argument is odd, result is result up. +LIB8STATIC int8_t avg7( int8_t i, int8_t j) +{ +#if AVG7_C == 1 + return ((i + j) >> 1) + (i & 0x1); +#elif AVG7_AVRASM == 1 + asm volatile( + "asr %1 \n\t" + "asr %0 \n\t" + "adc %0, %1 \n\t" + : "+a" (i) + : "a" (j) ); + return i; +#else +#error "No implementation for avg7 available." +#endif +} + + // scale8: scale one byte by a second one, which is treated as // the numerator of a fraction whose denominator is 256 -- cgit v1.2.3 From 38e08de1dc039f2bd402787113672e7b537619c0 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Wed, 5 Nov 2014 23:58:22 -0500 Subject: Speedup for 8-bit noise (~5%) by using avg7(u,v) --- noise.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/noise.cpp b/noise.cpp index d64e536d..a54e9ce4 100644 --- a/noise.cpp +++ b/noise.cpp @@ -127,7 +127,7 @@ static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t if(hash&1) { u = -u; } if(hash&2) { v = -v; } - return (u+v)>>1; + return avg7(u,v); #endif } @@ -138,7 +138,7 @@ static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x if(hash&1) { u = -u; } if(hash&2) { v = -v; } - return (u+v)>>1; + return avg7(u,v); } static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x) { @@ -150,7 +150,7 @@ static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x if(hash&1) { u = -u; } if(hash&2) { v = -v; } - return (u+v)>>1; + return avg7(u,v); } -- cgit v1.2.3 From 0889b8058830fa82a7deb36a5f0f58f756468695 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Thu, 6 Nov 2014 08:55:38 -0500 Subject: Slight speedup and code size reduction by changing 16-bit-shift+AND to 8-bit shift (ASL) with no AND needed afterwards. The compiler should have done this itself but didn't; film at 0x0B. --- noise.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/noise.cpp b/noise.cpp index a54e9ce4..59205b3d 100644 --- a/noise.cpp +++ b/noise.cpp @@ -342,9 +342,9 @@ int8_t inoise8_raw(uint16_t x, uint16_t y, uint16_t z) uint8_t w = z; // Get a signed version of the above for the grad function - int8_t xx = (x>>1) & 0x7F; - int8_t yy = (y>>1) & 0x7F; - int8_t zz = (z>>1) & 0x7F; + int8_t xx = ((uint8_t)(x)>>1) & 0x7F; + int8_t yy = ((uint8_t)(y)>>1) & 0x7F; + int8_t zz = ((uint8_t)(z)>>1) & 0x7F; uint8_t N = 0x80; // u = FADE(u); v = FADE(v); w = FADE(w); @@ -386,8 +386,8 @@ int8_t inoise8_raw(uint16_t x, uint16_t y) uint8_t v = y; // Get a signed version of the above for the grad function - int8_t xx = (x>>1) & 0x7F; - int8_t yy = (y>>1) & 0x7F; + int8_t xx = ((uint8_t)(x)>>1) & 0x7F; + int8_t yy = ((uint8_t)(y)>>1) & 0x7F; uint8_t N = 0x80; // u = FADE(u); v = FADE(v); w = FADE(w); @@ -421,7 +421,7 @@ int8_t inoise8_raw(uint16_t x) uint8_t u = x; // Get a signed version of the above for the grad function - int8_t xx = (x>>1) & 0x7F; + int8_t xx = ((uint8_t)(x)>>1) & 0x7F; uint8_t N = 0x80; u = scale8(u,u); -- cgit v1.2.3 From 69a3fa68519b6b451fd63bc5064d16112bbb3b80 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Thu, 6 Nov 2014 15:20:45 -0500 Subject: Another 1-2% faster 8-bit noise on AVR using a small asm widget to replace badly-generated C code. --- noise.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 72 insertions(+), 10 deletions(-) diff --git a/noise.cpp b/noise.cpp index 59205b3d..4342a20c 100644 --- a/noise.cpp +++ b/noise.cpp @@ -100,6 +100,29 @@ static int16_t inline __attribute__((always_inline)) grad16(uint8_t hash, int16_ return (u+v)>>1; } +// selectBasedOnHashBit performs this: +// result = (hash & (1<>1; } #else + hash &= 0xF; - int8_t u = (hash&8)?y:x; - int8_t v = hash<4?y:hash==12||hash==14?x:z; + + int8_t u, v; + //u = (hash&8)?y:x; + u = selectBasedOnHashBit( hash, 3, y, x); + +#if 1 + v = hash<4?y:hash==12||hash==14?x:z; +#else + // Verbose version for analysis; generates idenitical code. + if( hash < 4) { // 00 01 02 03 + v = y; + } else { + if( hash==12 || hash==14) { // 0C 0E + v = x; + } else { + v = z; // 04 05 06 07 08 09 0A 0B 0D 0F + } + } +#endif + if(hash&1) { u = -u; } if(hash&2) { v = -v; } @@ -131,22 +173,42 @@ static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t #endif } -static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y) { - hash = hash & 7; +static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x, int8_t y) +{ + // since the tests below can be done bit-wise on the bottom + // three bits, there's no need to mask off the higher bits + // hash = hash & 7; + int8_t u,v; - if(hash < 4) { u = x; v = y; } else { u = y; v = x; } + if( hash & 4) { + u = y; v = x; + } else { + u = x; v = y; + } + if(hash&1) { u = -u; } if(hash&2) { v = -v; } return avg7(u,v); } -static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x) { - hash = hash & 15; +static int8_t inline __attribute__((always_inline)) grad8(uint8_t hash, int8_t x) +{ + // since the tests below can be done bit-wise on the bottom + // four bits, there's no need to mask off the higher bits + // hash = hash & 15; + int8_t u,v; - if(hash > 8) { u=x;v=x; } - else if(hash < 4) { u=x;v=1; } - else { u=1;v=x; } + if(hash & 8) { + u=x; v=x; + } else { + if(hash & 4) { + u=1; v=x; + } else { + u=x; v=1; + } + } + if(hash&1) { u = -u; } if(hash&2) { v = -v; } -- cgit v1.2.3 From 9fe19fc82fd52550d56e1ac652016a26e1caa419 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 7 Nov 2014 20:02:56 -0800 Subject: Fix due on 3.1 branch --- clockless_arm_sam.h | 2 +- clockless_block_arm_sam.h | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h index 1e335b68..6924cc9d 100644 --- a/clockless_arm_sam.h +++ b/clockless_arm_sam.h @@ -103,7 +103,7 @@ protected: pixels.preStepFirstByteDithering(); register uint8_t b = pixels.loadAndScale0(); - uint32_t next_mark = (VAL + (TOTAL)); + uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); while(pixels.has(1)) { pixels.stepDithering(); diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h index 6f9fc797..c75e3ce6 100644 --- a/clockless_block_arm_sam.h +++ b/clockless_block_arm_sam.h @@ -124,22 +124,22 @@ public: *FastPin::sport() = PORT_MASK; - while(next_mark - DUE_TIMER_VAL) > (T2+T3+6)); + while((next_mark - DUE_TIMER_VAL) > (T2+T3+6)); *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; - while((next_mark - DUE_TIMER_VAL) > T3); + while((next_mark - (DUE_TIMER_VAL)) > T3); *FastPin::cport() = PORT_MASK; b3.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); } for(uint32_t i = LANES; i < 8; i++) { - while(VAL > next_mark); + while(DUE_TIMER_VAL > next_mark); - next_mark = VAL - (TOTAL-3); + next_mark = DUE_TIMER_VAL - (TOTAL-3); *FastPin::sport() = PORT_MASK; - while(next_mark - DUE_TIMER_VAL) > (T2+T3+6)); + while((next_mark - DUE_TIMER_VAL) > (T2+T3+6)); *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; while((next_mark - DUE_TIMER_VAL) > T3); @@ -164,7 +164,6 @@ public: pmc_enable_periph_clk(DUE_TIMER_ID); TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); - VAL = 0; cli(); uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); while(nLeds--) { -- cgit v1.2.3 From 2f4fca43d4d6a6529856864206543b09dd99fd7b Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 7 Nov 2014 23:07:04 -0800 Subject: Shut down compiler warnings referenced in #96. Verified that the palettes still end up in program space. --- colorutils.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/colorutils.h b/colorutils.h index 55772c7f..9034c1ee 100644 --- a/colorutils.h +++ b/colorutils.h @@ -327,8 +327,8 @@ class CRGBPalette16; class CRGBPalette256; class CHSVPalette16; class CHSVPalette256; -typedef prog_uint32_t TProgmemRGBPalette16[16]; -typedef prog_uint32_t TProgmemHSVPalette16[16]; +typedef uint32_t TProgmemRGBPalette16[16]; +typedef uint32_t TProgmemHSVPalette16[16]; #define TProgmemPalette16 TProgmemRGBPalette16 // Convert a 16-entry palette to a 256-entry palette -- cgit v1.2.3 From c61689e3852c3b2a6cc96cdb4111f92fa200f546 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 12 Nov 2014 02:31:59 -0800 Subject: Adjust thresholds for a tighter timed world --- led_sysdefs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/led_sysdefs.h b/led_sysdefs.h index d4763d69..75cef775 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -7,7 +7,7 @@ #define FASTLED_ARM #define FASTLED_ACCURATE_CLOCK #ifndef INTERRUPT_THRESHOLD -#define INTERRUPT_THRESHOLD 5 +#define INTERRUPT_THRESHOLD 1 #endif #if (F_CPU == 96000000) #define CLK_DBL 1 @@ -36,7 +36,7 @@ #define FASTLED_AVR #define FASTLED_ACCURATE_CLOCK #ifndef INTERRUPT_THRESHOLD -#define INTERRUPT_THRESHOLD 10 +#define INTERRUPT_THRESHOLD 1 #endif #endif @@ -86,7 +86,7 @@ typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile u #define CLKS_PER_US (F_CPU/1000000) #ifndef INTERRUPT_THRESHOLD -#define INTERRUPT_THRESHOLD 5 +#define INTERRUPT_THRESHOLD 1 #endif #endif -- cgit v1.2.3 From 62fb31b91497f854b968cfe62af0bbc91bcfeaa0 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 12 Nov 2014 02:35:54 -0800 Subject: Tweak how the trinket clockless code tracks its timing --- clockless_trinket.h | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/clockless_trinket.h b/clockless_trinket.h index 3cee6954..592ea537 100644 --- a/clockless_trinket.h +++ b/clockless_trinket.h @@ -64,7 +64,7 @@ template<> __attribute__((always_inline)) inline void _dc<10>(register uint8_t & // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -template +template class ClocklessController : public CLEDController { typedef typename FastPin::port_ptr_t data_ptr_t; typedef typename FastPin::port_t data_t; @@ -243,24 +243,25 @@ protected: uint8_t e2 = pixels.e[RO(2)]; uint8_t loopvar=0; - uint8_t lasttime = TCNT0; + + TCCR0A |= 0x30; + OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); + TIFR0 = 0x04; { while(count--) { - lasttime = TCNT0; - sei(); // Loop beginning, does some stuff that's outside of the pixel write cycle, namely incrementing d0-2 and masking off // by the E values (see the definition ) // LOOP; ADJDITHER2(d0,e0); ADJDITHER2(d1,e1); ADJDITHER2(d2,e2); + cli(); - lasttime = (uint8_t)(TCNT0-lasttime); - if(lasttime > ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)) { + if(TIFR0 & 0x04) { sei(); - // Serial.print("Overflow:"); Serial.print(lasttime); Serial.print(">"); Serial.println( ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); + TCCR0A &= ~0x30; return; } hi = *port | mask; @@ -347,14 +348,15 @@ protected: HI1 D1(1) QLO2(b2, 1) D2(0) LO1 D3(0) HI1 D1(1) QLO2(b2, 0) D2(0) LO1 D3(0) #endif - // DONE - // D2(4) LO1 D3(0) + // set the counter mark + OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); + TIFR0 = 0x04; + sei(); } } - // save the d values - // d[0] = d0; - // d[1] = d1; - // d[2] = d2; + + // stop using the clock juggler + TCCR0A &= ~0x30; } #ifdef SUPPORT_ARGB -- cgit v1.2.3 From 3ae4b6304270d85cf18b5fa493aae02fd8c39f24 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 12 Nov 2014 02:36:40 -0800 Subject: Provide a FastLED specific version of wiring for the timing functions when on AVR to get more efficient TIMER0 interrupt handlers in place. --- FastLED.h | 9 ++ wiring.cpp | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 wiring.cpp diff --git a/FastLED.h b/FastLED.h index 07b26471..5c656aeb 100644 --- a/FastLED.h +++ b/FastLED.h @@ -308,6 +308,15 @@ static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIf CRGB *leds() { return (*this)[0].leds(); } }; +#ifdef FASTLED_AVR +extern "C" { + unsigned long millis(void); +unsigned long micros(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int us); +}; +#endif + #define FastSPI_LED FastLED #define FastSPI_LED2 FastLED #ifndef LEDS diff --git a/wiring.cpp b/wiring.cpp new file mode 100644 index 00000000..f0e64087 --- /dev/null +++ b/wiring.cpp @@ -0,0 +1,297 @@ +#include "FastLED.h" + +#ifdef FASTLED_AVR +extern "C" { +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +typedef union { unsigned long _long; uint8_t raw[4]; } tBytesForLong; +// tBytesForLong FastLED_timer0_overflow_count; +volatile unsigned long FastLED_timer0_overflow_count=0; +volatile unsigned long FastLED_timer0_millis = 0; + +LIB8STATIC void __attribute__((always_inline)) fastinc32 (volatile uint32_t & _long) { + uint8_t b = ++((tBytesForLong&)_long).raw[0]; + if(!b) { + b = ++((tBytesForLong&)_long).raw[1]; + if(!b) { + b = ++((tBytesForLong&)_long).raw[2]; + if(!b) { + ++((tBytesForLong&)_long).raw[3]; + } + } + } +} + +#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) +ISR(TIM0_OVF_vect) +#else +ISR(TIMER0_OVF_vect) +#endif +{ + fastinc32(FastLED_timer0_overflow_count); + // FastLED_timer0_overflow_count++; +} + +// there are 1024 microseconds per overflow counter tick. +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read FastLED_timer0_millis or we might get an + // inconsistent value (e.g. in the middle of a write to FastLED_timer0_millis) + cli(); + m = FastLED_timer0_overflow_count; //._long; + SREG = oldSREG; + + return (m*MICROSECONDS_PER_TIMER0_OVERFLOW)/1000; +} + +unsigned long micros() { + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = FastLED_timer0_overflow_count; // ._long; +#if defined(TCNT0) + t = TCNT0; +#elif defined(TCNT0L) + t = TCNT0L; +#else + #error TIMER 0 not defined +#endif + + +#ifdef TIFR0 + if ((TIFR0 & _BV(TOV0)) && (t < 255)) + m++; +#else + if ((TIFR & _BV(TOV0)) && (t < 255)) + m++; +#endif + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + +void delay(unsigned long ms) +{ + uint16_t start = (uint16_t)micros(); + + while (ms > 0) { + if (((uint16_t)micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); +#if F_CPU >= 20000000L + // for the 20 MHz clock on rare Arduino boards + + // for a one-microsecond delay, simply wait 2 cycle and return. The overhead + // of the function call yields a delay of exactly a one microsecond. + __asm__ __volatile__ ( + "nop" "\n\t" + "nop"); //just waiting 2 cycle + if (--us == 0) + return; + + // the following loop takes a 1/5 of a microsecond (4 cycles) + // per iteration, so execute it five times for each microsecond of + // delay requested. + us = (us<<2) + us; // x5 us + + // account for the time taken in the preceeding commands. + us -= 2; + +#elif F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; +#else + // for the 8 MHz internal clock on the ATmega168 + + // for a one- or two-microsecond delay, simply return. the overhead of + // the function calls takes more than two microseconds. can't just + // subtract two, since us is unsigned; we'd overflow. + if (--us == 0) + return; + if (--us == 0) + return; + + // the following loop takes half of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; + + // partially compensate for the time taken by the preceeding commands. + // we can't subtract any more than this or we'd overflow w/ small delays. + us--; +#endif + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); +} +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + sei(); + + // on the ATmega168, timer 0 is also used for fast hardware pwm + // (using phase-correct PWM would mean that timer 0 overflowed half as often + // resulting in different millis() behavior on the ATmega8 and ATmega168) +#if defined(TCCR0A) && defined(WGM01) + sbi(TCCR0A, WGM01); + sbi(TCCR0A, WGM00); +#endif + + // set timer 0 prescale factor to 64 +#if defined(__AVR_ATmega128__) + // CPU specific: different values for the ATmega128 + sbi(TCCR0, CS02); +#elif defined(TCCR0) && defined(CS01) && defined(CS00) + // this combination is for the standard atmega8 + sbi(TCCR0, CS01); + sbi(TCCR0, CS00); +#elif defined(TCCR0B) && defined(CS01) && defined(CS00) + // this combination is for the standard 168/328/1280/2560 + sbi(TCCR0B, CS01); + sbi(TCCR0B, CS00); +#elif defined(TCCR0A) && defined(CS01) && defined(CS00) + // this combination is for the __AVR_ATmega645__ series + sbi(TCCR0A, CS01); + sbi(TCCR0A, CS00); +#else + #error Timer 0 prescale factor 64 not set correctly +#endif + + // enable timer 0 overflow interrupt +#if defined(TIMSK) && defined(TOIE0) + sbi(TIMSK, TOIE0); +#elif defined(TIMSK0) && defined(TOIE0) + sbi(TIMSK0, TOIE0); +#else + #error Timer 0 overflow interrupt not set correctly +#endif + + // timers 1 and 2 are used for phase-correct hardware pwm + // this is better for motors as it ensures an even waveform + // note, however, that fast pwm mode can achieve a frequency of up + // 8 MHz (with a 16 MHz clock) at 50% duty cycle + +#if defined(TCCR1B) && defined(CS11) && defined(CS10) + TCCR1B = 0; + + // set timer 1 prescale factor to 64 + sbi(TCCR1B, CS11); +#if F_CPU >= 8000000L + sbi(TCCR1B, CS10); +#endif +#elif defined(TCCR1) && defined(CS11) && defined(CS10) + sbi(TCCR1, CS11); +#if F_CPU >= 8000000L + sbi(TCCR1, CS10); +#endif +#endif + // put timer 1 in 8-bit phase correct pwm mode +#if defined(TCCR1A) && defined(WGM10) + sbi(TCCR1A, WGM10); +#elif defined(TCCR1) + #warning this needs to be finished +#endif + + // set timer 2 prescale factor to 64 +#if defined(TCCR2) && defined(CS22) + sbi(TCCR2, CS22); +#elif defined(TCCR2B) && defined(CS22) + sbi(TCCR2B, CS22); +#else + #warning Timer 2 not finished (may not be present on this CPU) +#endif + + // configure timer 2 for phase correct pwm (8-bit) +#if defined(TCCR2) && defined(WGM20) + sbi(TCCR2, WGM20); +#elif defined(TCCR2A) && defined(WGM20) + sbi(TCCR2A, WGM20); +#else + #warning Timer 2 not finished (may not be present on this CPU) +#endif + +#if defined(TCCR3B) && defined(CS31) && defined(WGM30) + sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64 + sbi(TCCR3B, CS30); + sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode +#endif + +#if defined(TCCR4A) && defined(TCCR4B) && defined(TCCR4D) /* beginning of timer4 block for 32U4 and similar */ + sbi(TCCR4B, CS42); // set timer4 prescale factor to 64 + sbi(TCCR4B, CS41); + sbi(TCCR4B, CS40); + sbi(TCCR4D, WGM40); // put timer 4 in phase- and frequency-correct PWM mode + sbi(TCCR4A, PWM4A); // enable PWM mode for comparator OCR4A + sbi(TCCR4C, PWM4D); // enable PWM mode for comparator OCR4D +#else /* beginning of timer4 block for ATMEGA1280 and ATMEGA2560 */ +#if defined(TCCR4B) && defined(CS41) && defined(WGM40) + sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64 + sbi(TCCR4B, CS40); + sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode +#endif +#endif /* end timer4 block for ATMEGA1280/2560 and similar */ + +#if defined(TCCR5B) && defined(CS51) && defined(WGM50) + sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64 + sbi(TCCR5B, CS50); + sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode +#endif + +#if defined(ADCSRA) + // set a2d prescale factor to 128 + // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. + // XXX: this will not work properly for other clock speeds, and + // this code should use F_CPU to determine the prescale factor. + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + + // enable a2d conversions + sbi(ADCSRA, ADEN); +#endif + + // the bootloader connects pins 0 and 1 to the USART; disconnect them + // here so they can be used as normal digital i/o; they will be + // reconnected in Serial.begin() +#if defined(UCSRB) + UCSRB = 0; +#elif defined(UCSR0B) + UCSR0B = 0; +#endif +} +}; +#endif -- cgit v1.2.3 From 6674a8cb67d55ab48ed0047298fe7fd78fdcdca6 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 12 Nov 2014 09:57:35 -0800 Subject: Improve the math a bit --- wiring.cpp | 69 +------------------------------------------------------------- 1 file changed, 1 insertion(+), 68 deletions(-) diff --git a/wiring.cpp b/wiring.cpp index f0e64087..d9efc8f6 100644 --- a/wiring.cpp +++ b/wiring.cpp @@ -46,7 +46,7 @@ unsigned long millis() m = FastLED_timer0_overflow_count; //._long; SREG = oldSREG; - return (m*MICROSECONDS_PER_TIMER0_OVERFLOW)/1000; + return (m*(MICROSECONDS_PER_TIMER0_OVERFLOW/8))/(1000/8); } unsigned long micros() { @@ -89,73 +89,6 @@ void delay(unsigned long ms) } } -/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ -void delayMicroseconds(unsigned int us) -{ - // calling avrlib's delay_us() function with low values (e.g. 1 or - // 2 microseconds) gives delays longer than desired. - //delay_us(us); -#if F_CPU >= 20000000L - // for the 20 MHz clock on rare Arduino boards - - // for a one-microsecond delay, simply wait 2 cycle and return. The overhead - // of the function call yields a delay of exactly a one microsecond. - __asm__ __volatile__ ( - "nop" "\n\t" - "nop"); //just waiting 2 cycle - if (--us == 0) - return; - - // the following loop takes a 1/5 of a microsecond (4 cycles) - // per iteration, so execute it five times for each microsecond of - // delay requested. - us = (us<<2) + us; // x5 us - - // account for the time taken in the preceeding commands. - us -= 2; - -#elif F_CPU >= 16000000L - // for the 16 MHz clock on most Arduino boards - - // for a one-microsecond delay, simply return. the overhead - // of the function call yields a delay of approximately 1 1/8 us. - if (--us == 0) - return; - - // the following loop takes a quarter of a microsecond (4 cycles) - // per iteration, so execute it four times for each microsecond of - // delay requested. - us <<= 2; - - // account for the time taken in the preceeding commands. - us -= 2; -#else - // for the 8 MHz internal clock on the ATmega168 - - // for a one- or two-microsecond delay, simply return. the overhead of - // the function calls takes more than two microseconds. can't just - // subtract two, since us is unsigned; we'd overflow. - if (--us == 0) - return; - if (--us == 0) - return; - - // the following loop takes half of a microsecond (4 cycles) - // per iteration, so execute it twice for each microsecond of - // delay requested. - us <<= 1; - - // partially compensate for the time taken by the preceeding commands. - // we can't subtract any more than this or we'd overflow w/ small delays. - us--; -#endif - - // busy wait - __asm__ __volatile__ ( - "1: sbiw %0,1" "\n\t" // 2 cycles - "brne 1b" : "=w" (us) : "0" (us) // 2 cycles - ); -} #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) void init() { -- cgit v1.2.3 From 5b8c97da6f5629c5ee2b234744555e1eec4eeb8b Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 12 Nov 2014 17:38:58 -0800 Subject: Tightening up timing on avr a bit more --- led_sysdefs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/led_sysdefs.h b/led_sysdefs.h index 75cef775..e16ce2db 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -36,7 +36,7 @@ #define FASTLED_AVR #define FASTLED_ACCURATE_CLOCK #ifndef INTERRUPT_THRESHOLD -#define INTERRUPT_THRESHOLD 1 +#define INTERRUPT_THRESHOLD 2 #endif #endif -- cgit v1.2.3 From 2f21f1f9f0175a096e33d61cd9072fb0bbe66e94 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Wed, 12 Nov 2014 21:52:55 -0500 Subject: beat functions: added timebase adjustment and unilateral phase detractors. --- lib8tion.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lib8tion.h b/lib8tion.h index 4edf7bf3..acb008f5 100644 --- a/lib8tion.h +++ b/lib8tion.h @@ -1792,7 +1792,7 @@ uint32_t get_millisecond_timer(); #endif // beat16 generates a 16-bit 'sawtooth' wave at a given BPM -LIB8STATIC uint16_t beat16( accum88 beats_per_minute) +LIB8STATIC uint16_t beat16( accum88 beats_per_minute, uint32_t timebase = 0) { // Convert simple 8-bit BPM's to full Q8.8 accum88's if needed if( beats_per_minute < 256) beats_per_minute <<= 8; @@ -1807,21 +1807,22 @@ LIB8STATIC uint16_t beat16( accum88 beats_per_minute) // e.g. if you ask for "120 BPM", you'll get about "119.93". // If you need more precision than that, you can specify a // sixteen-bit BPM value in Q8.8 fixed-point (an 'accum88'). - return ((GET_MILLIS) * beats_per_minute * 280) >> 16; + return (((GET_MILLIS) - timebase) * beats_per_minute * 280) >> 16; } // beat8 generates an 8-bit 'sawtooth' wave at a given BPM -LIB8STATIC uint8_t beat8( accum88 beats_per_minute) +LIB8STATIC uint8_t beat8( accum88 beats_per_minute, uint32_t timebase = 0) { - return beat16( beats_per_minute) >> 8; + return beat16( beats_per_minute, timebase) >> 8; } // beatsin16 generates a 16-bit sine wave at a given BPM, // that oscillates within a given range. -LIB8STATIC uint16_t beatsin16( accum88 beats_per_minute, uint16_t lowest = 0, uint16_t highest = 65535) +LIB8STATIC uint16_t beatsin16( accum88 beats_per_minute, uint16_t lowest = 0, uint16_t highest = 65535, + uint32_t timebase = 0, uint16_t phase_offset = 0) { - uint16_t beat = beat16( beats_per_minute); - uint16_t beatsin = (sin16( beat) + 32768); + uint16_t beat = beat16( beats_per_minute, timebase); + uint16_t beatsin = (sin16( beat + phase_offset) + 32768); uint16_t rangewidth = highest - lowest; uint16_t scaledbeat = scale16( beatsin, rangewidth); uint16_t result = lowest + scaledbeat; @@ -1830,10 +1831,11 @@ LIB8STATIC uint16_t beatsin16( accum88 beats_per_minute, uint16_t lowest = 0, ui // beatsin8 generates an 8-bit sine wave at a given BPM, // that oscillates within a given range. -LIB8STATIC uint8_t beatsin8( accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255) +LIB8STATIC uint8_t beatsin8( accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255, + uint32_t timebase = 0, uint8_t phase_offset = 0) { - uint8_t beat = beat8( beats_per_minute); - uint8_t beatsin = sin8( beat); + uint8_t beat = beat8( beats_per_minute, timebase); + uint8_t beatsin = sin8( beat + phase_offset); uint8_t rangewidth = highest - lowest; uint8_t scaledbeat = scale8( beatsin, rangewidth); uint8_t result = lowest + scaledbeat; -- cgit v1.2.3 From 8dd7cc36c914df293ca30dd338354255067c877d Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Wed, 12 Nov 2014 21:57:23 -0500 Subject: Added blur1d, blur2d, and fadeUsingColor --- colorutils.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ colorutils.h | 34 +++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/colorutils.cpp b/colorutils.cpp index 995db69e..c0b615a7 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -207,6 +207,20 @@ void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale) } } +void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask) +{ + uint8_t fr, fg, fb; + fr = colormask.r; + fg = colormask.g; + fb = colormask.b; + + for( uint16_t i = 0; i < numLeds; i++) { + leds[i].r = scale8_LEAVING_R1_DIRTY( leds[i].r, fr); + leds[i].g = scale8_LEAVING_R1_DIRTY( leds[i].g, fg); + leds[i].b = scale8 ( leds[i].b, fb); + } +} + CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay ) { @@ -337,6 +351,79 @@ CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest, uint16_t count, fra +// Forward declaration of the function "XY" which must be provided by +// the application for use in two-dimensional filter functions. +uint16_t XY( uint8_t, uint8_t); + + +// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors. +// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors. +// +// 0 = no spread at all +// 64 = moderate spreading +// 172 = maximum smooth, even spreading +// +// 173..255 = wider spreading, but increasing flicker +// +// Total light is NOT entirely conserved, so many repeated +// calls to 'blur' will also result in the light fading, +// eventually all the way to black; this is by design so that +// it can be used to (slowly) clear the LEDs to black. +void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount) +{ + uint8_t keep = 255 - blur_amount; + uint8_t seep = blur_amount >> 1; + CRGB carryover = CRGB::Black; + for( uint16_t i = 0; i < numLeds; i++) { + CRGB cur = leds[i]; + CRGB part = cur; + part.nscale8( seep); + cur.nscale8( keep); + cur += carryover; + if( i) leds[i-1] += part; + leds[i] = cur; + carryover = part; + } +} + +void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount) +{ + blurRows(leds, width, height, blur_amount); + blurColumns(leds, width, height, blur_amount); +} + +// blurRows: perform a blur1d on every row of a rectangular matrix +void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount) +{ + for( uint8_t row = 0; row < height; row++) { + CRGB* rowbase = leds + (row * width); + blur1d( rowbase, width, blur_amount); + } +} + +// blurColumns: perform a blur1d on each column of a rectangular matrix +void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount) +{ + // blur columns + uint8_t keep = 255 - blur_amount; + uint8_t seep = blur_amount >> 1; + for( uint8_t col = 0; col < width; col++) { + CRGB carryover = CRGB::Black; + for( uint8_t i = 0; i < height; i++) { + CRGB cur = leds[XY(col,i)]; + CRGB part = cur; + part.nscale8( seep); + cur.nscale8( keep); + cur += carryover; + if( i) leds[XY(col,i-1)] += part; + leds[XY(col,i)] = cur; + carryover = part; + } + } +} + + + // CRGB HeatColor( uint8_t temperature) // // Approximates a 'black body radiation' spectrum for @@ -577,3 +664,4 @@ void SetupPartyColors(CRGBPalette16& pal) fill_gradient( pal, 8, CHSV( HUE_ORANGE,255,255), 15, CHSV(HUE_BLUE + 18,255,255), BACKWARD_HUES); } #endif + diff --git a/colorutils.h b/colorutils.h index 9034c1ee..76542acf 100644 --- a/colorutils.h +++ b/colorutils.h @@ -219,6 +219,19 @@ void fade_raw( CRGB* leds, uint16_t num_leds, uint8_t fadeBy); // way down to black even if 'scale' is not zero. void nscale8( CRGB* leds, uint16_t num_leds, uint8_t scale); +// fadeUsingColor - scale down the brightness of an array of pixels, +// as though it were seen through a transparent +// filter with the specified color. +// For example, if the colormask is +// CRGB( 200, 100, 50) +// then the pixels' red will be faded to 200/256ths, +// their green to 100/256ths, and their blue to 50/256ths. +// This particular example give a 'hot fade' look, +// with white fading to yellow, then red, then black. +// You can also use colormasks like CRGB::Blue to +// zero out the red and green elements, leaving blue +// (largely) the same. +void fadeUsingColor( CRGB* leds, uint16_t numLeds, const CRGB& colormask); // Pixel blending @@ -256,6 +269,27 @@ void nblend( CHSV* existing, CHSV* overlay, uint16_t count, fract8 amountOfOver TGradientDirectionCode directionCode = SHORTEST_HUES); +// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors. +// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors. +// +// 0 = no spread at all +// 64 = moderate spreading +// 172 = maximum smooth, even spreading +// +// 173..255 = wider spreading, but increasing flicker +// +// Total light is NOT entirely conserved, so many repeated +// calls to 'blur' will also result in the light fading, +// eventually all the way to black; this is by design so that +// it can be used to (slowly) clear the LEDs to black. +void blur1d( CRGB* leds, uint16_t numLeds, fract8 blur_amount); +void blur2d( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount); + +// blurRows: perform a blur1d on every row of a rectangular matrix +void blurRows( CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount); +// blurColumns: perform a blur1d on each column of a rectangular matrix +void blurColumns(CRGB* leds, uint8_t width, uint8_t height, fract8 blur_amount); + // CRGB HeatColor( uint8_t temperature) // -- cgit v1.2.3 From c7766f85f070f8dfab8727d105c78bb42db77f49 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 17 Nov 2014 23:53:57 -0800 Subject: Re-arranging code layout, pulling off platform specific headers into their own directories. --- FastLED.h | 29 ++- chipsets.h | 1 - clockless.h | 28 --- clockless_arm_k20.h | 130 ---------- clockless_arm_sam.h | 134 ---------- clockless_block_arm_k20.h | 344 ------------------------- clockless_block_arm_sam.h | 198 --------------- clockless_trinket.h | 371 --------------------------- colorutils.cpp | 115 +++++---- fastled_config.h | 12 + fastpin.h | 58 ++--- fastpin_arm_k20.h | 107 -------- fastpin_arm_sam.h | 117 --------- fastpin_avr.h | 199 --------------- fastspi.h | 44 +--- fastspi_arm_k20.h | 375 ---------------------------- fastspi_arm_sam.h | 160 ------------ fastspi_avr.h | 300 ---------------------- fastspi_types.h | 37 +++ hsv2rgb.cpp | 85 ++++--- led_sysdefs.h | 82 +----- lib8tion.h | 18 +- octows2811_controller.h | 91 ------- platforms.h | 15 ++ platforms/arm/k20/clockless_arm_k20.h | 130 ++++++++++ platforms/arm/k20/clockless_block_arm_k20.h | 344 +++++++++++++++++++++++++ platforms/arm/k20/fastled_arm_k20.h | 14 ++ platforms/arm/k20/fastpin_arm_k20.h | 118 +++++++++ platforms/arm/k20/fastspi_arm_k20.h | 375 ++++++++++++++++++++++++++++ platforms/arm/k20/led_sysdefs_arm_k20.h | 26 ++ platforms/arm/k20/octows2811_controller.h | 91 +++++++ platforms/arm/k20/smartmatrix_t3.h | 79 ++++++ platforms/arm/sam/clockless_arm_sam.h | 134 ++++++++++ platforms/arm/sam/clockless_block_arm_sam.h | 193 ++++++++++++++ platforms/arm/sam/fastled_arm_sam.h | 11 + platforms/arm/sam/fastpin_arm_sam.h | 132 ++++++++++ platforms/arm/sam/fastspi_arm_sam.h | 160 ++++++++++++ platforms/arm/sam/led_sysdefs_arm_sam.h | 30 +++ platforms/avr/clockless_trinket.h | 370 +++++++++++++++++++++++++++ platforms/avr/fastled_avr.h | 9 + platforms/avr/fastpin_avr.h | 208 +++++++++++++++ platforms/avr/fastspi_avr.h | 300 ++++++++++++++++++++++ platforms/avr/led_sysdefs_avr.h | 21 ++ preview_changes.txt | 2 +- smartmatrix_t3.h | 79 ------ wiring.cpp | 3 +- 46 files changed, 2970 insertions(+), 2909 deletions(-) delete mode 100644 clockless.h delete mode 100644 clockless_arm_k20.h delete mode 100644 clockless_arm_sam.h delete mode 100644 clockless_block_arm_k20.h delete mode 100644 clockless_block_arm_sam.h delete mode 100644 clockless_trinket.h create mode 100644 fastled_config.h delete mode 100644 fastpin_arm_k20.h delete mode 100644 fastpin_arm_sam.h delete mode 100644 fastpin_avr.h delete mode 100644 fastspi_arm_k20.h delete mode 100644 fastspi_arm_sam.h delete mode 100644 fastspi_avr.h create mode 100644 fastspi_types.h delete mode 100644 octows2811_controller.h create mode 100644 platforms.h create mode 100644 platforms/arm/k20/clockless_arm_k20.h create mode 100644 platforms/arm/k20/clockless_block_arm_k20.h create mode 100644 platforms/arm/k20/fastled_arm_k20.h create mode 100644 platforms/arm/k20/fastpin_arm_k20.h create mode 100644 platforms/arm/k20/fastspi_arm_k20.h create mode 100644 platforms/arm/k20/led_sysdefs_arm_k20.h create mode 100644 platforms/arm/k20/octows2811_controller.h create mode 100644 platforms/arm/k20/smartmatrix_t3.h create mode 100644 platforms/arm/sam/clockless_arm_sam.h create mode 100644 platforms/arm/sam/clockless_block_arm_sam.h create mode 100644 platforms/arm/sam/fastled_arm_sam.h create mode 100644 platforms/arm/sam/fastpin_arm_sam.h create mode 100644 platforms/arm/sam/fastspi_arm_sam.h create mode 100644 platforms/arm/sam/led_sysdefs_arm_sam.h create mode 100644 platforms/avr/clockless_trinket.h create mode 100644 platforms/avr/fastled_avr.h create mode 100644 platforms/avr/fastpin_avr.h create mode 100644 platforms/avr/fastspi_avr.h create mode 100644 platforms/avr/led_sysdefs_avr.h delete mode 100644 smartmatrix_t3.h diff --git a/FastLED.h b/FastLED.h index 5c656aeb..951d105f 100644 --- a/FastLED.h +++ b/FastLED.h @@ -26,21 +26,29 @@ #include #endif +#include + +#include "fastled_config.h" +#include "led_sysdefs.h" + +#include "bitswap.h" #include "controller.h" #include "fastpin.h" -#include "fastspi.h" -#include "bitswap.h" -#include "clockless.h" +#include "fastspi_types.h" +#include "./dmx.h" + +#include "platforms.h" + #include "lib8tion.h" #include "hsv2rgb.h" #include "colorutils.h" #include "colorpalettes.h" -#include "chipsets.h" -#include "./dmx.h" -#include "smartmatrix_t3.h" + #include "noise.h" #include "power_mgt.h" -#include "octows2811_controller.h" + +#include "fastspi.h" +#include "chipsets.h" enum ESPIChipsets { LPD8806, @@ -325,4 +333,11 @@ void delayMicroseconds(unsigned int us); extern CFastLED FastLED; +// Warnings for undefined things +#ifndef HAS_HARDWARE_PIN_SUPPORT +#warning "No pin/port mappings found, pin access will be slightly slower. See fastpin.h for info." +#define NO_HARDWARE_PIN_SUPPORT +#endif + + #endif diff --git a/chipsets.h b/chipsets.h index ef16a53d..95b148ee 100644 --- a/chipsets.h +++ b/chipsets.h @@ -2,7 +2,6 @@ #define __INC_CHIPSETS_H #include "pixeltypes.h" -#include "clockless.h" ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // diff --git a/clockless.h b/clockless.h deleted file mode 100644 index 896cf046..00000000 --- a/clockless.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __INC_CLOCKLESS_H -#define __INC_CLOCKLESS_H - -#include "controller.h" -#include "lib8tion.h" -#include "led_sysdefs.h" -#include "delay.h" - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point -// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the -// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// Convinience macros to wrap around the toggling of hi vs. lo -#define SET_LO FLIP ? FastPin::fastset(port, hi) : FastPin::fastset(port, lo); -#define SET_HI FLIP ? FastPin::fastset(port, lo) : FastPin::fastset(port, hi); - -// #include "clockless_avr.h" -#include "clockless_trinket.h" -#include "clockless_arm_k20.h" -#include "clockless_arm_sam.h" -#include "clockless_block_arm_sam.h" -#include "clockless_block_arm_k20.h" - -#endif diff --git a/clockless_arm_k20.h b/clockless_arm_k20.h deleted file mode 100644 index d96c9bb2..00000000 --- a/clockless_arm_k20.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef __INC_CLOCKLESS_ARM_K20_H -#define __INC_CLOCKLESS_ARM_K20_H - -// Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 -// See clockless.h for detailed info on how the template parameters are used. -#if defined(FASTLED_TEENSY3) - -template -class ClocklessController : public CLEDController { - typedef typename FastPin::port_ptr_t data_ptr_t; - typedef typename FastPin::port_t data_t; - - data_t mPinMask; - data_ptr_t mPort; - CMinWait mWait; -public: - virtual void init() { - FastPin::setOutput(); - mPinMask = FastPin::mask(); - mPort = FastPin::port(); - } - - 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 pixels(rgbdata, nLeds, scale, getDither()); - - mWait.wait(); - showRGBInternal(pixels); - mWait.mark(); - } - - virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { - PixelController 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 pixels(rgbdata, nLeds, scale, getDither()); - mWait.wait(); - showRGBInternal(pixels); - mWait.mark(); - } -#endif - - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) { - for(register uint32_t i = BITS-1; i > 0; i--) { - while(ARM_DWT_CYCCNT < next_mark); - next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - FastPin::fastset(port, hi); - if(b&0x80) { - while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); - FastPin::fastset(port, lo); - } else { - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); - FastPin::fastset(port, lo); - } - b <<= 1; - } - - while(ARM_DWT_CYCCNT < next_mark); - next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - FastPin::fastset(port, hi); - - if(b&0x80) { - while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); - FastPin::fastset(port, lo); - } else { - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); - FastPin::fastset(port, lo); - } - } - - // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then - // gcc will use register Y for the this pointer. - static uint32_t showRGBInternal(PixelController & pixels) { - // Get access to the clock - ARM_DEMCR |= ARM_DEMCR_TRCENA; - ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; - ARM_DWT_CYCCNT = 0; - - register data_ptr_t port = FastPin::port(); - register data_t hi = *port | FastPin::mask();; - register data_t lo = *port & ~FastPin::mask();; - *port = lo; - - // Setup the pixel controller and load/scale the first byte - pixels.preStepFirstByteDithering(); - register uint8_t b = pixels.loadAndScale0(); - - cli(); - uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - - while(pixels.has(1)) { - pixels.stepDithering(); - cli(); - // if interrupts took longer than 45µs, punt on the current frame - if(ARM_DWT_CYCCNT > next_mark) { - if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } - } - - // 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(); - sei(); - }; - - return ARM_DWT_CYCCNT; - } -}; -#endif - -#endif diff --git a/clockless_arm_sam.h b/clockless_arm_sam.h deleted file mode 100644 index 6924cc9d..00000000 --- a/clockless_arm_sam.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef __INC_CLOCKLESS_ARM_SAM_H -#define __INC_CLOCKLESS_ARM_SAM_H - -// Definition for a single channel clockless controller for the sam family of arm chips, like that used in the due and rfduino -// See clockless.h for detailed info on how the template parameters are used. - -#if defined(__SAM3X8E__) - - -#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) - -template -class ClocklessController : public CLEDController { - typedef typename FastPinBB::port_ptr_t data_ptr_t; - typedef typename FastPinBB::port_t data_t; - - data_t mPinMask; - data_ptr_t mPort; - CMinWait mWait; -public: - virtual void init() { - FastPinBB::setOutput(); - mPinMask = FastPinBB::mask(); - mPort = FastPinBB::port(); - } - - 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 pixels(rgbdata, nLeds, scale, getDither()); - mWait.wait(); - showRGBInternal(pixels); - mWait.mark(); - } - - virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { - PixelController 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 pixels(rgbdata, nLeds, scale, getDither()); - mWait.wait(); - showRGBInternal(pixels); - sei(); - mWait.mark(); - } -#endif - - - template __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; - // while(VAL < (TOTAL*10)) { bShift=true; } - // if(bShift) { next_mark = (VAL-TOTAL); }; - - for(register uint32_t i = BITS; i > 0; i--) { - // wait to start the bit, then set the pin high - while(DUE_TIMER_VAL < next_mark); - next_mark = (DUE_TIMER_VAL+TOTAL); - *port = 1; - - // how long we want to wait next depends on whether or not our bit is set to 1 or 0 - if(b&0x80) { - // we're a 1, wait until there's less than T3 clocks left - while((next_mark - DUE_TIMER_VAL) > (T3)); - } else { - // we're a 0, wait until there's less than (T2+T3+slop) clocks left in this bit - while((next_mark - DUE_TIMER_VAL) > (T2+T3+6+TADJUST+TADJUST)); - } - *port=0; - b <<= 1; - } - } - -#define FORCE_REFERENCE(var) asm volatile( "" : : "r" (var) ) - // 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 & pixels) { - // Setup and start the clock - TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1); - pmc_enable_periph_clk(DUE_TIMER_ID); - TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); - - register data_ptr_t port asm("r7") = FastPinBB::port(); FORCE_REFERENCE(port); - *port = 0; - - // Setup the pixel controller and load/scale the first byte - pixels.preStepFirstByteDithering(); - register uint8_t b = pixels.loadAndScale0(); - - uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); - while(pixels.has(1)) { - pixels.stepDithering(); - - cli(); - if(DUE_TIMER_VAL > next_mark) { - if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; } - } - - writeBits<8+XTRA0>(next_mark, port, b); - - b = pixels.loadAndScale1(); - writeBits<8+XTRA0>(next_mark, port,b); - - b = pixels.loadAndScale2(); - writeBits<8+XTRA0>(next_mark, port,b); - - b = pixels.advanceAndLoadAndScale0(); - sei(); - }; - - TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); - return DUE_TIMER_VAL; - } -}; - -#endif - -#endif diff --git a/clockless_block_arm_k20.h b/clockless_block_arm_k20.h deleted file mode 100644 index 63dc5030..00000000 --- a/clockless_block_arm_k20.h +++ /dev/null @@ -1,344 +0,0 @@ -#ifndef __INC_BLOCK_CLOCKLESS_ARM_K20_H -#define __INC_BLOCK_CLOCKLESS_ARM_K20_H - -// Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 -// See clockless.h for detailed info on how the template parameters are used. -#if defined(FASTLED_TEENSY3) -#define HAS_BLOCKLESS 1 - -#define PORTC_FIRST_PIN 15 -#define PORTD_FIRST_PIN 2 -#define HAS_PORTDC 1 - -#define PORT_MASK (((1< -class InlineBlockClocklessController : public CLEDController { - typedef typename FastPin::port_ptr_t data_ptr_t; - typedef typename FastPin::port_t data_t; - - data_t mPinMask; - data_ptr_t mPort; - CMinWait mWait; -public: - virtual void init() { - if(FIRST_PIN == PORTC_FIRST_PIN) { // PORTC - switch(LANES) { - case 12: FastPin<30>::setOutput(); - case 11: FastPin<29>::setOutput(); - case 10: FastPin<27>::setOutput(); - case 9: FastPin<28>::setOutput(); - case 8: FastPin<12>::setOutput(); - case 7: FastPin<11>::setOutput(); - case 6: FastPin<13>::setOutput(); - case 5: FastPin<10>::setOutput(); - case 4: FastPin<9>::setOutput(); - case 3: FastPin<23>::setOutput(); - case 2: FastPin<22>::setOutput(); - case 1: FastPin<15>::setOutput(); - } - } else if(FIRST_PIN == PORTD_FIRST_PIN) { // PORTD - switch(LANES) { - 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(); - } - } - mPinMask = FastPin::mask(); - mPort = FastPin::port(); - } - - 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 pixels(rgbdata,nLeds, scale, getDither() ); - mWait.wait(); - showRGBInternal(pixels,nLeds); - mWait.mark(); - } - - virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { - MultiPixelController 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) { - MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); - mWait.wait(); - showRGBInternal(pixels,nLeds); - mWait.mark(); - } -#endif - - - typedef union { - uint8_t bytes[16]; - uint16_t shorts[8]; - uint32_t raw[4]; - } Lines; - - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { - register Lines b2; - if(LANES>8) { - transpose8<1,2>(b.bytes,b2.bytes); - transpose8<1,2>(b.bytes+8,b2.bytes+1); - } else { - transpose8x1(b.bytes,b2.bytes); - } - register uint8_t d = pixels.template getd(pixels); - register uint8_t scale = pixels.template getscale(pixels); - - for(register uint32_t i = 0; i < (LANES/2); i++) { - while(ARM_DWT_CYCCNT < next_mark); - next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; - *FastPin::sport() = PORT_MASK; - - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); - if(LANES>8) { - *FastPin::cport() = ((~b2.shorts[i]) & PORT_MASK); - } else { - *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); - } - - while((next_mark - ARM_DWT_CYCCNT) > (T3)); - *FastPin::cport() = PORT_MASK; - - b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); - b.bytes[i+(LANES/2)] = pixels.template loadAndScale(pixels,i,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(pixels,LANES-1,d,scale); - } - - for(register uint32_t i = LANES/2; i < 8; i++) { - while(ARM_DWT_CYCCNT < next_mark); - next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; - *FastPin::sport() = PORT_MASK; - - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); - if(LANES>8) { - *FastPin::cport() = ((~b2.shorts[i]) & PORT_MASK); - } else { - *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); - } - - while((next_mark - ARM_DWT_CYCCNT) > (T3)); - *FastPin::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 &allpixels, int nLeds) { - // Get access to the clock - ARM_DEMCR |= ARM_DEMCR_TRCENA; - ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; - ARM_DWT_CYCCNT = 0; - - // Setup the pixel controller and load/scale the first byte - allpixels.preStepFirstByteDithering(); - register Lines b0; - - allpixels.preStepFirstByteDithering(); - 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--) { - cli(); - // if interrupts took longer than 45µs, punt on the current frame - if(ARM_DWT_CYCCNT > next_mark) { - if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } - } - allpixels.stepDithering(); - - // Write first byte, read next byte - writeBits<8+XTRA0,1>(next_mark, b0, allpixels); - - // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b0, allpixels); - allpixels.advanceData(); - - // Write third byte - writeBits<8+XTRA0,0>(next_mark, b0, allpixels); - sei(); - }; - - return ARM_DWT_CYCCNT; - } -}; - -#define DLANES (MIN(__LANES,16)) -#define PMASK ((1<<(DLANES))-1) -#define PMASK_HI (PMASK>>8 & 0xFF) -#define PMASK_LO (PMASK & 0xFF) - -template -class SixteenWayInlineBlockClocklessController : public CLEDController { - typedef typename FastPin::port_ptr_t data_ptr_t; - typedef typename FastPin::port_t data_t; - - data_t mPinMask; - data_ptr_t mPort; - CMinWait 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 pixels(rgbdata,nLeds, scale, getDither() ); - mWait.wait(); - showRGBInternal(pixels,nLeds); - mWait.mark(); - } - - virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { - MultiPixelController 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) { - MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); - mWait.wait(); - showRGBInternal(pixels,nLeds); - mWait.mark(); - } -#endif - - - typedef union { - uint8_t bytes[16]; - uint16_t shorts[8]; - uint32_t raw[4]; - } Lines; - - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &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(pixels); - register uint8_t scale = pixels.template getscale(pixels); - - for(register uint32_t i = 0; (i < DLANES) && (i < 8); i++) { - while(ARM_DWT_CYCCNT < next_mark); - next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; - *FastPin::sport() = PMASK_LO; - *FastPin::sport() = PMASK_HI; - - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); - *FastPin::cport() = ((~b2.bytes[7-i]) & PMASK_LO); - *FastPin::cport() = ((~b2.bytes[15-i]) & PMASK_HI); - - while((next_mark - ARM_DWT_CYCCNT) > (T3)); - *FastPin::cport() = PMASK_LO; - *FastPin::cport() = PMASK_HI; - - b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); - if(DLANES==16 || (DLANES>8 && ((i+8) < DLANES))) { - b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); - } - } - } - - - - // 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 &allpixels, int nLeds) { - // Get access to the clock - ARM_DEMCR |= ARM_DEMCR_TRCENA; - ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; - ARM_DWT_CYCCNT = 0; - - // Setup the pixel controller and load/scale the first byte - allpixels.preStepFirstByteDithering(); - register Lines b0; - - allpixels.preStepFirstByteDithering(); - for(int i = 0; i < DLANES; i++) { - b0.bytes[i] = allpixels.loadAndScale0(i); - } - - cli(); - uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); - - while(nLeds--) { - allpixels.stepDithering(); - cli(); - // if interrupts took longer than 45µs, punt on the current frame - if(ARM_DWT_CYCCNT > next_mark) { - if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } - } - // Write first byte, read next byte - writeBits<8+XTRA0,1>(next_mark, b0, allpixels); - - // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b0, allpixels); - allpixels.advanceData(); - - // Write third byte - writeBits<8+XTRA0,0>(next_mark, b0, allpixels); - sei(); - }; - - return ARM_DWT_CYCCNT; - } -}; -#endif - -#endif diff --git a/clockless_block_arm_sam.h b/clockless_block_arm_sam.h deleted file mode 100644 index c75e3ce6..00000000 --- a/clockless_block_arm_sam.h +++ /dev/null @@ -1,198 +0,0 @@ - #ifndef __INC_BLOCK_CLOCKLESS_H -#define __INC_BLOCK_CLOCKLESS_H - -#include "controller.h" -#include "lib8tion.h" -#include "led_sysdefs.h" -#include "delay.h" - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point -// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the -// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -#if defined(__SAM3X8E__) -#define PORT_MASK (((1< -class InlineBlockClocklessController : public CLEDController { - typedef typename FastPin::port_ptr_t data_ptr_t; - typedef typename FastPin::port_t data_t; - - data_t mPinMask; - data_ptr_t mPort; - CMinWait mWait; -public: - virtual void init() { - if(FIRST_PIN == PORTA_FIRST_PIN) { - switch(LANES) { - case 8: FastPin<31>::setOutput(); - case 7: FastPin<58>::setOutput(); - case 6: FastPin<100>::setOutput(); - case 5: FastPin<59>::setOutput(); - case 4: FastPin<60>::setOutput(); - case 3: FastPin<61>::setOutput(); - case 2: FastPin<68>::setOutput(); - case 1: FastPin<69>::setOutput(); - } - } else if(FIRST_PIN == PORTD_FIRST_PIN) { - switch(LANES) { - case 8: FastPin<11>::setOutput(); - case 7: FastPin<29>::setOutput(); - case 6: FastPin<15>::setOutput(); - case 5: FastPin<14>::setOutput(); - case 4: FastPin<28>::setOutput(); - case 3: FastPin<27>::setOutput(); - case 2: FastPin<26>::setOutput(); - case 1: FastPin<25>::setOutput(); - } - } else if(FIRST_PIN == PORTB_FIRST_PIN) { - switch(LANES) { - case 8: FastPin<97>::setOutput(); - case 7: FastPin<96>::setOutput(); - case 6: FastPin<95>::setOutput(); - case 5: FastPin<94>::setOutput(); - case 4: FastPin<93>::setOutput(); - case 3: FastPin<92>::setOutput(); - case 2: FastPin<91>::setOutput(); - case 1: FastPin<90>::setOutput(); - } - } - mPinMask = FastPin::mask(); - mPort = FastPin::port(); - } - - 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 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 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(rgbdata, nLeds, scale, getDither())); - mWait.mark(); - } -#endif - - template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, MultiPixelController &pixels) { // , register uint32_t & b2) { - register Lines b2; - transpose8x1(b.bytes,b2.bytes); - - register uint8_t d = pixels.template getd(pixels); - register uint8_t scale = pixels.template getscale(pixels); - - for(uint32_t i = 0; (i < LANES) && (i<8); i++) { - while(DUE_TIMER_VAL < next_mark); - next_mark = (DUE_TIMER_VAL+TOTAL); - - *FastPin::sport() = PORT_MASK; - - while((next_mark - DUE_TIMER_VAL) > (T2+T3+6)); - *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; - - while((next_mark - (DUE_TIMER_VAL)) > T3); - *FastPin::cport() = PORT_MASK; - - b3.bytes[i] = pixels.template loadAndScale(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::sport() = PORT_MASK; - - while((next_mark - DUE_TIMER_VAL) > (T2+T3+6)); - *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; - - while((next_mark - DUE_TIMER_VAL) > T3); - *FastPin::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 &allpixels, int nLeds) { - // Serial.println("Entering show"); - // Setup the pixel controller and load/scale the first byte - Lines b0,b1,b2; - - allpixels.preStepFirstByteDithering(); - for(int i = 0; i < LANES; i++) { - b0.bytes[i] = allpixels.loadAndScale0(i); - } - - // Setup and start the clock - TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1); - pmc_enable_periph_clk(DUE_TIMER_ID); - TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); - - cli(); - uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); - while(nLeds--) { - allpixels.stepDithering(); - cli(); - if(DUE_TIMER_VAL > next_mark) { - if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { - sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; - } - } - - // Write first byte, read next byte - writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); - - // Write second byte, read 3rd byte - writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); - - allpixels.advanceData(); - // Write third byte - writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); - sei(); - } - - return DUE_TIMER_VAL; - } - - -}; - -#endif - -#endif diff --git a/clockless_trinket.h b/clockless_trinket.h deleted file mode 100644 index 592ea537..00000000 --- a/clockless_trinket.h +++ /dev/null @@ -1,371 +0,0 @@ -#ifndef __INC_CLOCKLESS_TRINKET_H -#define __INC_CLOCKLESS_TRINKET_H - -#include "controller.h" -#include "lib8tion.h" -#include "delay.h" -#include // for cli/se definitions - -#if defined(FASTLED_AVR) - -// Scaling macro choice -#ifndef TRINKET_SCALE -#define TRINKET_SCALE 1 -// whether or not to use dithering -#define DITHER 1 -#endif - -#define US_PER_TICK (64 / (F_CPU/1000000)) - -// Variations on the functions in delay.h - w/a loop var passed in to preserve registers across calls by the optimizer/compiler -template inline void _dc(register uint8_t & loopvar); - -template inline void _dc_AVR(register uint8_t & loopvar) { - _dc(loopvar); - // The convolution in here is to ensure that the state of the carry flag coming into the delay loop is preserved - asm __volatile__ ( "BRCS L_PC%=\n\t" - " LDI %[loopvar], %[_LOOP]\n\tL_%=: DEC %[loopvar]\n\t BRNE L_%=\n\tBREQ L_DONE%=\n\t" - "L_PC%=: LDI %[loopvar], %[_LOOP]\n\tLL_%=: DEC %[loopvar]\n\t BRNE LL_%=\n\tBSET 0\n\t" - "L_DONE%=:\n\t" - : - [loopvar] "+a" (loopvar) : [_LOOP] "M" (_LOOP) : ); -} - -template __attribute__((always_inline)) inline void _dc(register uint8_t & loopvar) { - _dc_AVR(loopvar); -} -template<> __attribute__((always_inline)) inline void _dc<-6>(register uint8_t & loopvar) {} -template<> __attribute__((always_inline)) inline void _dc<-5>(register uint8_t & loopvar) {} -template<> __attribute__((always_inline)) inline void _dc<-4>(register uint8_t & loopvar) {} -template<> __attribute__((always_inline)) inline void _dc<-3>(register uint8_t & loopvar) {} -template<> __attribute__((always_inline)) inline void _dc<-2>(register uint8_t & loopvar) {} -template<> __attribute__((always_inline)) inline void _dc<-1>(register uint8_t & loopvar) {} -template<> __attribute__((always_inline)) inline void _dc<0>(register uint8_t & loopvar) {} -template<> __attribute__((always_inline)) inline void _dc<1>(register uint8_t & loopvar) {asm __volatile__("mov r0,r0":::);} -template<> __attribute__((always_inline)) inline void _dc<2>(register uint8_t & loopvar) {asm __volatile__("rjmp .+0":::);} -template<> __attribute__((always_inline)) inline void _dc<3>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<1>(loopvar); } -template<> __attribute__((always_inline)) inline void _dc<4>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<2>(loopvar); } -template<> __attribute__((always_inline)) inline void _dc<5>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<3>(loopvar); } -template<> __attribute__((always_inline)) inline void _dc<6>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<2>(loopvar); _dc<2>(loopvar);} -template<> __attribute__((always_inline)) inline void _dc<7>(register uint8_t & loopvar) { _dc<4>(loopvar); _dc<3>(loopvar); } -template<> __attribute__((always_inline)) inline void _dc<8>(register uint8_t & loopvar) { _dc<4>(loopvar); _dc<4>(loopvar); } -template<> __attribute__((always_inline)) inline void _dc<9>(register uint8_t & loopvar) { _dc<5>(loopvar); _dc<4>(loopvar); } -template<> __attribute__((always_inline)) inline void _dc<10>(register uint8_t & loopvar) { _dc<6>(loopvar); _dc<4>(loopvar); } - -#define D1(ADJ) _dc(loopvar); -#define D2(ADJ) _dc(loopvar); -#define D3(ADJ) (T3-(AVR_PIN_CYCLES(DATA_PIN)+ADJ)>0) ? _dc(loopvar) : _dc<0>(loopvar); - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point -// is where the line is raised hi. The second point is where the line is dropped low for a zero. The third point is where the -// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -template -class ClocklessController : public CLEDController { - typedef typename FastPin::port_ptr_t data_ptr_t; - typedef typename FastPin::port_t data_t; - - CMinWait mWait; -public: - virtual void init() { - FastPin::setOutput(); - } - - 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 pixels(data, nLeds, scale, getDither(), advance, skip); - - mWait.wait(); - cli(); - - showRGBInternal(pixels); - - sei(); - mWait.mark(); - } -#define USE_ASM_MACROS - -// The variables that our various asm statemetns use. The same block of variables needs to be declared for -// all the asm blocks because GCC is pretty stupid and it would clobber variables happily or optimize code away too aggressively -#define ASM_VARS : /* write variables */ \ - [count] "+x" (count), \ - [data] "+z" (data), \ - [b0] "+a" (b0), \ - [b1] "+a" (b1), \ - [b2] "+a" (b2), \ - [scale_base] "+a" (scale_base), \ - [loopvar] "+a" (loopvar), \ - [d0] "+r" (d0), \ - [d1] "+r" (d1), \ - [d2] "+r" (d2) \ - : /* use variables */ \ - [ADV] "r" (advanceBy), \ - [hi] "r" (hi), \ - [lo] "r" (lo), \ - [s0] "r" (s0), \ - [s1] "r" (s1), \ - [s2] "r" (s2), \ - [PORT] "M" (FastPin::port()-0x20), \ - [O0] "M" (RGB_BYTE0(RGB_ORDER)), \ - [O1] "M" (RGB_BYTE1(RGB_ORDER)), \ - [O2] "M" (RGB_BYTE2(RGB_ORDER)) \ - : /* clobber registers */ - - -// 1 cycle, write hi to the port -#define HI1 if((int)(FastPin::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[hi]" ASM_VARS ); } else { *FastPin::port()=hi; } -// 1 cycle, write lo to the port -#define LO1 if((int)(FastPin::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[lo]" ASM_VARS ); } else { *FastPin::port()=lo; } -// 2 cycles, sbrs on flipping the lne to lo if we're pushing out a 0 -#define QLO2(B, N) asm __volatile__("sbrs %[" #B "], " #N ASM_VARS ); LO1; -// load a byte from ram into the given var with the given offset -#define LD2(B,O) asm __volatile__("ldd %[" #B "], Z + %[" #O "]" ASM_VARS ); -// 4 cycles - load a byte from ram into the scaling scratch space with the given offset, clear the target var, clear carry -#define LDSCL4(B,O) asm __volatile__("ldd %[scale_base], Z + %[" #O "]\n\tclr %[" #B "]\n\tclc" ASM_VARS ); -// 2 cycles - perform one step of the scaling (if a given bit is set in scale, add scale-base to the scratch space) -#define SCALE02(B, N) asm __volatile__("sbrc %[s0], " #N "\n\tadd %[" #B "], %[scale_base]" ASM_VARS ); -#define SCALE12(B, N) asm __volatile__("sbrc %[s1], " #N "\n\tadd %[" #B "], %[scale_base]" ASM_VARS ); -#define SCALE22(B, N) asm __volatile__("sbrc %[s2], " #N "\n\tadd %[" #B "], %[scale_base]" ASM_VARS ); - -// apply dithering value before we do anything with scale_base -#define PRESCALE4(D) if(DITHER) { asm __volatile__("cpse %[scale_base], __zero_reg__\n\t add %[scale_base],%[" #D "]\n\tbrcc L_%=\n\tldi %[scale_base], 0xFF\n\tL_%=:\n\t" ASM_VARS); } \ - else { _dc<4>(loopvar); } - -// Do the add for the prescale -#define PRESCALEA2(D) if(DITHER) { asm __volatile__("cpse %[scale_base], __zero_reg__\n\t add %[scale_base],%[" #D "]\n\t" ASM_VARS); } \ - else { _dc<2>(loopvar); } -// Do the clamp for the prescale, clear carry when we're done - NOTE: Must ensure carry flag state is preserved! -#define PRESCALEB3(D) if(DITHER) { asm __volatile__("brcc L_%=\n\tldi %[scale_base], 0xFF\n\tL_%=:\n\tCLC" ASM_VARS); } \ - else { _dc<3>(loopvar); } - - -// 1 cycle - rotate right, pulling in from carry -#define ROR1(B) asm __volatile__("ror %[" #B "]" ASM_VARS ); -// 1 cycle, clear the carry bit -#define CLC1 asm __volatile__("clc" ASM_VARS ); -// 1 cycle, move one register to another -#define MOV1(B1, B2) asm __volatile__("mov %[" #B1 "], %[" #B2 "]" ASM_VARS ); -// 4 cycles, rotate, clear carry, scale next bit -#define RORSC04(B, N) ROR1(B) CLC1 SCALE02(B, N) -#define RORSC14(B, N) ROR1(B) CLC1 SCALE12(B, N) -#define RORSC24(B, N) ROR1(B) CLC1 SCALE22(B, N) -// 4 cycles, scale bit, rotate, clear carry -#define SCROR04(B, N) SCALE02(B,N) ROR1(B) CLC1 -#define SCROR14(B, N) SCALE12(B,N) ROR1(B) CLC1 -#define SCROR24(B, N) SCALE22(B,N) ROR1(B) CLC1 - -///////////////////////////////////////////////////////////////////////////////////// -// Loop life cycle - -// dither adjustment macro - should be kept in sync w/what's in stepDithering -#define ADJDITHER2(D, E) D = E - D; - -// #define xstr(a) str(a) -// #define str(a) #a -// #define ADJDITHER2(D,E) asm __volatile__("subi %[" #D "], " xstr(DUSE) "\n\tand %[" #D "], %[" #E "]\n\t" ASM_VARS); - -// define the beginning of the loop -#define LOOP asm __volatile__("1:" ASM_VARS ); -// define the end of the loop -#define DONE asm __volatile__("2:" ASM_VARS ); - -// 2 cycles - increment the data pointer -#define IDATA2 asm __volatile__("add %A[data], %[ADV]\n\tadc %B[data], __zero_reg__" ASM_VARS ); -// 2 cycles - decrement the counter -#define DCOUNT2 asm __volatile__("sbiw %[count], 1" ASM_VARS ); -// 2 cycles - jump to the beginning of the loop -#define JMPLOOP2 asm __volatile__("rjmp 1b" ASM_VARS ); -// 2 cycles - jump out of the loop -#define BRLOOP1 asm __volatile__("breq 2f" ASM_VARS ); - -#define DADVANCE 3 -#define DUSE (0xFF - (DADVANCE-1)) - - // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then - // gcc will use register Y for the this pointer. - static void __attribute__ ((always_inline)) showRGBInternal(PixelController & pixels) { - uint8_t *data = (uint8_t*)pixels.mData; - data_ptr_t port = FastPin::port(); - data_t mask = FastPin::mask(); - uint8_t scale_base = 0; - - // register uint8_t *end = data + nLeds; - data_t hi = *port | mask; - data_t lo = *port & ~mask; - *port = lo; - - uint8_t b0 = 0; - uint8_t b1 = 0; - uint8_t b2 = 0; - - // Setup the pixel controller and load/scale the first byte - pixels.preStepFirstByteDithering(); - b0 = pixels.loadAndScale0(); - - // pull the dithering/adjustment values out of the pixels object for direct asm access - - uint8_t advanceBy = pixels.advanceBy(); - uint16_t count = pixels.mLen; - - uint8_t s0 = pixels.mScale.raw[RO(0)]; - uint8_t s1 = pixels.mScale.raw[RO(1)]; - uint8_t s2 = pixels.mScale.raw[RO(2)]; - uint8_t d0 = pixels.d[RO(0)]; - uint8_t d1 = pixels.d[RO(1)]; - uint8_t d2 = pixels.d[RO(2)]; - uint8_t e0 = pixels.e[RO(0)]; - uint8_t e1 = pixels.e[RO(1)]; - uint8_t e2 = pixels.e[RO(2)]; - - uint8_t loopvar=0; - - TCCR0A |= 0x30; - OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); - TIFR0 = 0x04; - { - while(count--) - { - // Loop beginning, does some stuff that's outside of the pixel write cycle, namely incrementing d0-2 and masking off - // by the E values (see the definition ) - // LOOP; - ADJDITHER2(d0,e0); - ADJDITHER2(d1,e1); - ADJDITHER2(d2,e2); - - cli(); - - if(TIFR0 & 0x04) { - sei(); - TCCR0A &= ~0x30; - return; - } - hi = *port | mask; - lo = *port & ~mask; - - // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 - // The values in the D1/D2/D3 indicate how many cycles the previous column takes - // to allow things to line back up. - // - // While writing out byte 0, we're loading up byte 1, applying the dithering adjustment, - // then scaling it using 8 cycles of shift/add interleaved in between writing the bits - // out. When doing byte 1, we're doing the above for byte 2. When we're doing byte 2, - // we're cycling back around and doing the above for byte 0. -#if TRINKET_SCALE - // Inline scaling - RGB ordering - HI1 D1(1) QLO2(b0, 7) LDSCL4(b1,O1) D2(4) LO1 PRESCALEA2(d1) D3(2) - HI1 D1(1) QLO2(b0, 6) PRESCALEB3(d1) D2(3) LO1 SCALE12(b1,0) D3(2) - HI1 D1(1) QLO2(b0, 5) RORSC14(b1,1) D2(4) LO1 ROR1(b1) CLC1 D3(2) - HI1 D1(1) QLO2(b0, 4) SCROR14(b1,2) D2(4) LO1 SCALE12(b1,3) D3(2) - HI1 D1(1) QLO2(b0, 3) RORSC14(b1,4) D2(4) LO1 ROR1(b1) CLC1 D3(2) - HI1 D1(1) QLO2(b0, 2) SCROR14(b1,5) D2(4) LO1 SCALE12(b1,6) D3(2) - HI1 D1(1) QLO2(b0, 1) RORSC14(b1,7) D2(4) LO1 ROR1(b1) CLC1 D3(2) - HI1 D1(1) QLO2(b0, 0) D2(0) LO1 D3(0) - switch(XTRA0) { - case 4: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); - case 3: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); - case 2: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); - case 1: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); - } - HI1 D1(1) QLO2(b1, 7) LDSCL4(b2,O2) D2(4) LO1 PRESCALEA2(d2) D3(2) - HI1 D1(1) QLO2(b1, 6) PRESCALEB3(d2) D2(3) LO1 SCALE22(b2,0) D3(2) - HI1 D1(1) QLO2(b1, 5) RORSC24(b2,1) D2(4) LO1 ROR1(b2) CLC1 D3(2) - HI1 D1(1) QLO2(b1, 4) SCROR24(b2,2) D2(4) LO1 SCALE22(b2,3) D3(2) - HI1 D1(1) QLO2(b1, 3) RORSC24(b2,4) D2(4) LO1 ROR1(b2) CLC1 D3(2) - HI1 D1(1) QLO2(b1, 2) SCROR24(b2,5) D2(4) LO1 SCALE22(b2,6) D3(2) - HI1 D1(1) QLO2(b1, 1) RORSC24(b2,7) D2(4) LO1 ROR1(b2) CLC1 D3(2) - HI1 D1(1) QLO2(b1, 0) IDATA2 CLC1 D2(3) LO1 D3(0) - switch(XTRA0) { - case 4: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); - case 3: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); - case 2: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); - case 1: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); - } - HI1 D1(1) QLO2(b2, 7) LDSCL4(b0,O0) D2(4) LO1 PRESCALEA2(d0) D3(2) - HI1 D1(1) QLO2(b2, 6) PRESCALEB3(d0) D2(3) LO1 SCALE02(b0,0) D3(2) - HI1 D1(1) QLO2(b2, 5) RORSC04(b0,1) D2(4) LO1 ROR1(b0) CLC1 D3(2) - HI1 D1(1) QLO2(b2, 4) SCROR04(b0,2) D2(4) LO1 SCALE02(b0,3) D3(2) - HI1 D1(1) QLO2(b2, 3) RORSC04(b0,4) D2(4) LO1 ROR1(b0) CLC1 D3(2) - HI1 D1(1) QLO2(b2, 2) SCROR04(b0,5) D2(4) LO1 SCALE02(b0,6) D3(2) - HI1 D1(1) QLO2(b2, 1) RORSC04(b0,7) D2(4) LO1 ROR1(b0) CLC1 D3(2) - // HI1 D1(1) QLO2(b2, 0) DCOUNT2 BRLOOP1 D2(3) LO1 D3(2) JMPLOOP2 - HI1 D1(1) QLO2(b2, 0) D2(0) LO1 - switch(XTRA0) { - case 4: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; - case 3: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; - case 2: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; - case 1: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; - } - D3(12); -#else - // no inline scaling - non-straight RGB ordering - HI1 D1(1) QLO2(b0, 7) LD2(b1,O1) D2(2) LO1 D3(0) - HI1 D1(1) QLO2(b0, 6) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b0, 5) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b0, 4) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b0, 3) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b0, 2) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b0, 1) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b0, 0) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b1, 7) LD2(b2,O2) D2(2) LO1 D3(0) - HI1 D1(1) QLO2(b1, 6) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b1, 5) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b1, 4) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b1, 3) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b1, 2) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b1, 1) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b1, 0) IDATA2 D2(2) LO1 D3(0) - HI1 D1(1) QLO2(b2, 7) LD2(b0,O0) D2(2) LO1 D3(0) - HI1 D1(1) QLO2(b2, 6) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b2, 5) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b2, 4) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b2, 3) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b2, 2) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b2, 1) D2(0) LO1 D3(0) - HI1 D1(1) QLO2(b2, 0) D2(0) LO1 D3(0) -#endif - // set the counter mark - OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); - TIFR0 = 0x04; - sei(); - } - } - - // stop using the clock juggler - TCCR0A &= ~0x30; - } - -#ifdef SUPPORT_ARGB - virtual void showARGB(struct CARGB *data, int nLeds) { - // TODO: IMPLEMENTME - } -#endif -}; - -#endif - -#endif diff --git a/colorutils.cpp b/colorutils.cpp index 995db69e..9bb64b7e 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -2,8 +2,7 @@ #include -#include "hsv2rgb.h" -#include "colorutils.h" +#include "FastLED.h" @@ -73,22 +72,22 @@ void fill_gradient_RGB( CRGB* leds, endcolor = startcolor; endpos = startpos; } - + saccum87 rdistance87; saccum87 gdistance87; saccum87 bdistance87; - + rdistance87 = (endcolor.r - startcolor.r) << 7; gdistance87 = (endcolor.g - startcolor.g) << 7; bdistance87 = (endcolor.b - startcolor.b) << 7; - + uint16_t pixeldistance = endpos - startpos; int16_t divisor = pixeldistance ? pixeldistance : 1; saccum87 rdelta87 = rdistance87 / divisor; saccum87 gdelta87 = gdistance87 / divisor; saccum87 bdelta87 = bdistance87 / divisor; - + rdelta87 *= 2; gdelta87 *= 2; bdelta87 *= 2; @@ -213,23 +212,23 @@ CRGB& nblend( CRGB& existing, const CRGB& overlay, fract8 amountOfOverlay ) if( amountOfOverlay == 0) { return existing; } - + if( amountOfOverlay == 255) { existing = overlay; return existing; } - + fract8 amountOfKeep = 256 - amountOfOverlay; - + existing.red = scale8_LEAVING_R1_DIRTY( existing.red, amountOfKeep) + scale8_LEAVING_R1_DIRTY( overlay.red, amountOfOverlay); existing.green = scale8_LEAVING_R1_DIRTY( existing.green, amountOfKeep) + scale8_LEAVING_R1_DIRTY( overlay.green, amountOfOverlay); existing.blue = scale8_LEAVING_R1_DIRTY( existing.blue, amountOfKeep) + scale8_LEAVING_R1_DIRTY( overlay.blue, amountOfOverlay); - + cleanup_R1(); - + return existing; } @@ -266,30 +265,30 @@ CHSV& nblend( CHSV& existing, const CHSV& overlay, fract8 amountOfOverlay, TGrad if( amountOfOverlay == 0) { return existing; } - + if( amountOfOverlay == 255) { existing = overlay; return existing; } - + fract8 amountOfKeep = 256 - amountOfOverlay; - + uint8_t huedelta8 = overlay.hue - existing.hue; - + if( directionCode == SHORTEST_HUES ) { directionCode = FORWARD_HUES; if( huedelta8 > 127) { directionCode = BACKWARD_HUES; } } - + if( directionCode == LONGEST_HUES ) { directionCode = FORWARD_HUES; if( huedelta8 < 128) { directionCode = BACKWARD_HUES; } } - + if( directionCode == FORWARD_HUES) { existing.hue = existing.hue + scale8( huedelta8, amountOfOverlay); } @@ -298,14 +297,14 @@ CHSV& nblend( CHSV& existing, const CHSV& overlay, fract8 amountOfOverlay, TGrad huedelta8 = -huedelta8; existing.hue = existing.hue - scale8( huedelta8, amountOfOverlay); } - + existing.sat = scale8_LEAVING_R1_DIRTY( existing.sat, amountOfKeep) + scale8_LEAVING_R1_DIRTY( overlay.sat, amountOfOverlay); existing.val = scale8_LEAVING_R1_DIRTY( existing.val, amountOfKeep) + scale8_LEAVING_R1_DIRTY( overlay.val, amountOfOverlay); - + cleanup_R1(); - + return existing; } @@ -351,37 +350,37 @@ CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest, uint16_t count, fra CRGB HeatColor( uint8_t temperature) { CRGB heatcolor; - + // Scale 'heat' down from 0-255 to 0-191, // which can then be easily divided into three // equal 'thirds' of 64 units each. uint8_t t192 = scale8_video( temperature, 192); - + // calculate a value that ramps up from // zero to 255 in each 'third' of the scale. uint8_t heatramp = t192 & 0x3F; // 0..63 heatramp <<= 2; // scale up to 0..252 - + // now figure out which third of the spectrum we're in: if( t192 & 0x80) { // we're in the hottest third heatcolor.r = 255; // full red heatcolor.g = 255; // full green heatcolor.b = heatramp; // ramp up blue - + } else if( t192 & 0x40 ) { // we're in the middle third heatcolor.r = 255; // full red heatcolor.g = heatramp; // ramp up green heatcolor.b = 0; // no blue - + } else { // we're in the coolest third heatcolor.r = heatramp; // ramp up red heatcolor.g = 0; // no green heatcolor.b = 0; // no blue } - + return heatcolor; } @@ -391,33 +390,33 @@ CRGB ColorFromPalette( const CRGBPalette16& pal, uint8_t index, uint8_t brightne { uint8_t hi4 = index >> 4; uint8_t lo4 = index & 0x0F; - + // CRGB rgb1 = pal[ hi4]; const CRGB* entry = &(pal[0]) + hi4; uint8_t red1 = entry->red; uint8_t green1 = entry->green; uint8_t blue1 = entry->blue; - + uint8_t blend = lo4 && (blendType != NOBLEND); - + if( blend ) { - + if( hi4 == 15 ) { entry = &(pal[0]); } else { entry++; } - + uint8_t f2 = lo4 << 4; uint8_t f1 = 256 - f2; - + // rgb1.nscale8(f1); red1 = scale8_LEAVING_R1_DIRTY( red1, f1); green1 = scale8_LEAVING_R1_DIRTY( green1, f1); blue1 = scale8_LEAVING_R1_DIRTY( blue1, f1); - + // cleanup_R1(); - + // CRGB rgb2 = pal[ hi4]; // rgb2.nscale8(f2); uint8_t red2 = entry->red; @@ -426,21 +425,21 @@ CRGB ColorFromPalette( const CRGBPalette16& pal, uint8_t index, uint8_t brightne red2 = scale8_LEAVING_R1_DIRTY( red2, f2); green2 = scale8_LEAVING_R1_DIRTY( green2, f2); blue2 = scale8_LEAVING_R1_DIRTY( blue2, f2); - + cleanup_R1(); - + // These sums can't overflow, so no qadd8 needed. red1 += red2; green1 += green2; blue1 += blue2; } - + if( brightness != 255) { nscale8x3_video( red1, green1, blue1, brightness); } - - return CRGB( red1, green1, blue1); + + return CRGB( red1, green1, blue1); } @@ -451,11 +450,11 @@ CRGB ColorFromPalette( const CRGBPalette256& pal, uint8_t index, uint8_t brightn uint8_t red = entry->red; uint8_t green = entry->green; uint8_t blue = entry->blue; - + if( brightness != 255) { nscale8x3_video( red, green, blue, brightness); } - + return CRGB( red, green, blue); } @@ -464,27 +463,27 @@ CHSV ColorFromPalette( const struct CHSVPalette16& pal, uint8_t index, uint8_t b { uint8_t hi4 = index >> 4; uint8_t lo4 = index & 0x0F; - + // CRGB rgb1 = pal[ hi4]; const CHSV* entry = &(pal[0]) + hi4; uint8_t hue1 = entry->hue; uint8_t sat1 = entry->sat; uint8_t val1 = entry->val; - + uint8_t blend = lo4 && (blendType != NOBLEND); - + if( blend ) { - + if( hi4 == 15 ) { entry = &(pal[0]); } else { entry++; } - + uint8_t f2 = lo4 << 4; uint8_t f1 = 256 - f2; - + uint8_t hue2 = entry->hue; uint8_t sat2 = entry->sat; uint8_t val2 = entry->val; @@ -497,26 +496,26 @@ CHSV ColorFromPalette( const struct CHSVPalette16& pal, uint8_t index, uint8_t b // of the other color, so that you get the expected // brightness or saturation ramp, with hue staying // constant: - + // If we are starting from white (sat=0) // or black (val=0), adopt the target hue. if( sat1 == 0 || val1 == 0) { hue1 = hue2; } - + // If we are ending at white (sat=0) // or black (val=0), adopt the starting hue. if( sat2 == 0 || val2 == 0) { hue2 = hue1; } - - + + sat1 = scale8_LEAVING_R1_DIRTY( sat1, f1); val1 = scale8_LEAVING_R1_DIRTY( val1, f1); - + sat2 = scale8_LEAVING_R1_DIRTY( sat2, f2); val2 = scale8_LEAVING_R1_DIRTY( val2, f2); - + // cleanup_R1(); // These sums can't overflow, so no qadd8 needed. @@ -531,15 +530,15 @@ CHSV ColorFromPalette( const struct CHSVPalette16& pal, uint8_t index, uint8_t b // go forwards hue1 += scale8( deltaHue, f2); } - + cleanup_R1(); } - + if( brightness != 255) { val1 = scale8_video( val1, brightness); } - - return CHSV( hue1, sat1, val1); + + return CHSV( hue1, sat1, val1); } @@ -550,7 +549,7 @@ CHSV ColorFromPalette( const struct CHSVPalette256& pal, uint8_t index, uint8_t if( brightness != 255) { hsv.value = scale8_video( hsv.value, brightness); } - + return hsv; } diff --git a/fastled_config.h b/fastled_config.h new file mode 100644 index 00000000..3e5a8c4e --- /dev/null +++ b/fastled_config.h @@ -0,0 +1,12 @@ +#ifndef __INC_FASTLED_CONFIG_H +#define __INC_FASTLED_CONFIG_H + +// Use this option only for debugging pin access and forcing software pin access. Note that +// software pin access only works in Arduino based environments. Forces use of digitalWrite +// methods for pin access vs. direct hardware port access +// #define FORCE_SOFTWARE_PINS + +// Use this option only for debugging bitbang'd spi access or to work around bugs in hardware +// spi access. Forces use of bit-banged spi, even on pins that has hardware SPI available. +// #define FORCE_SOFTWARE_SPI +#endif diff --git a/fastpin.h b/fastpin.h index 56a9ea61..fc75d9a4 100644 --- a/fastpin.h +++ b/fastpin.h @@ -3,7 +3,7 @@ #include "led_sysdefs.h" -#define NO_PIN 255 +#define NO_PIN 255 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // @@ -18,13 +18,15 @@ public: virtual bool isSelected() = 0; }; -class Pin : public Selectable { +#if defined(ARDUINO) + +class Pin : public Selectable { volatile RwReg *mPort; volatile RoReg *mInPort; RwReg mPinMask; uint8_t mPin; - void _init() { + void _init() { mPinMask = digitalPinToBitMask(mPin); mPort = portOutputRegister(digitalPinToPort(mPin)); mInPort = portInputRegister(digitalPinToPort(mPin)); @@ -38,14 +40,14 @@ public: inline void setOutput() { pinMode(mPin, OUTPUT); } inline void setInput() { pinMode(mPin, INPUT); } - inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; } + inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; } inline void lo() __attribute__ ((always_inline)) { *mPort &= ~mPinMask; } inline void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } inline void toggle() __attribute__ ((always_inline)) { *mInPort = mPinMask; } - inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; } - inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; } + inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; } + inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; } inline void set(register port_t val) __attribute__ ((always_inline)) { *mPort = val; } inline void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } @@ -75,20 +77,20 @@ public: /// will provide pin level access on pretty much all arduino environments. In addition, it includes some methods to help optimize access in /// various ways. Namely, the versions of hi, lo, and fastset that take the port register as a passed in register variable (saving a global /// dereference), since these functions are aggressively inlined, that can help collapse out a lot of extraneous memory loads/dereferences. -/// +/// /// In addition, if, while writing a bunch of data to a pin, you know no other pins will be getting written to, you can get/cache a value of /// the pin's port register and use that to do a full set to the register. This results in one being able to simply do a store to the register, /// vs. the load, and/or, and store that would be done normally. /// /// There are platform specific instantiations of this class that provide direct i/o register access to pins for much higher speed pin twiddling. /// -/// Note that these classes are all static functions. So the proper usage is Pin<13>::hi(); or such. Instantiating objects is not recommended, +/// Note that these classes are all static functions. So the proper usage is Pin<13>::hi(); or such. Instantiating objects is not recommended, /// as passing Pin objects around will likely -not- have the effect you're expecting. -template class FastPin { +template class FastPin { static RwReg sPinMask; static volatile RwReg *sPort; static volatile RoReg *sInPort; - static void _init() { + static void _init() { sPinMask = digitalPinToBitMask(PIN); sPort = portOutputRegister(digitalPinToPort(PIN)); sInPort = portInputRegister(digitalPinToPort(PIN)); @@ -100,15 +102,15 @@ public: inline static void setOutput() { _init(); pinMode(PIN, OUTPUT); } inline static void setInput() { _init(); pinMode(PIN, INPUT); } - inline static void hi() __attribute__ ((always_inline)) { *sPort |= sPinMask; } + inline static void hi() __attribute__ ((always_inline)) { *sPort |= sPinMask; } inline static void lo() __attribute__ ((always_inline)) { *sPort &= ~sPinMask; } inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } inline static void toggle() __attribute__ ((always_inline)) { *sInPort = sPinMask; } - inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= sPinMask; } - inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~sPinMask; } + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= sPinMask; } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~sPinMask; } inline static void set(register port_t val) __attribute__ ((always_inline)) { *sPort = val; } inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } @@ -124,37 +126,11 @@ template volatile RwReg *FastPin::sPort; template volatile RoReg *FastPin::sInPort; template class FastPinBB : public FastPin {}; - +#endif // defined(ARDUINO) typedef volatile uint32_t & reg32_t; typedef volatile uint32_t * ptr_reg32_t; -/////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Pin definitions for AVR and ARM. If there are pin definitions supplied below for the platform being -// built on, then much higher speed access will be possible, namely with direct GPIO register accesses. -// -/////////////////////////////////////////////////////////////////////////////////////////////////////////// -#if defined(FORCE_SOFTWARE_PINS) - -#warning "Softwrae pin support forced pin access will be slightly slower. See fastpin.h for info." -#define NO_HARDWARE_PIN_SUPPORT -#undef HAS_HARDWARE_PIN_SUPPORT - -#else - -// We want hardware pin support, include the hardware pin header files -#include "fastpin_avr.h" -#include "fastpin_arm_k20.h" -#include "fastpin_arm_sam.h" - -#ifndef HAS_HARDWARE_PIN_SUPPORT -#warning "No pin/port mappings found, pin access will be slightly slower. See fastpin.h for info." -#define NO_HARDWARE_PIN_SUPPORT -#endif - -#endif - -#endif +#endif // __INC_FASTPIN_H diff --git a/fastpin_arm_k20.h b/fastpin_arm_k20.h deleted file mode 100644 index 2fb75fbd..00000000 --- a/fastpin_arm_k20.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef __FASTPIN_ARM_K20_H -#define __FASTPIN_ARM_K20_H - -/// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this -/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found -/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. -/// The registers are data output, set output, clear output, toggle output, input, and direction -template class _ARMPIN { -public: - typedef volatile uint32_t * port_ptr_t; - typedef uint32_t port_t; - - inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } - inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } - - inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } - inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } - inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } - - inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - - inline static void toggle() __attribute__ ((always_inline)) { _PTOR::r() = _MASK; } - - inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } - inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } - inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } - - inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } - inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } - inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } - inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } - inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } - inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } -}; - -/// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC -/// does a poor job of optimizing around these accesses so they are not being used just yet. -template class _ARMPIN_BITBAND { -public: - typedef volatile uint32_t * port_ptr_t; - typedef uint32_t port_t; - - inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } - inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } - - inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } - inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } - inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } - - inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - - inline static void toggle() __attribute__ ((always_inline)) { *_PTOR::template rx<_BIT>() = 1; } - - 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)) { *_PDOR::template rx<_BIT>() = val; } - - inline static port_t hival() __attribute__ ((always_inline)) { return 1; } - inline static port_t loval() __attribute__ ((always_inline)) { return 0; } - inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } - inline static port_t mask() __attribute__ ((always_inline)) { return 1; } -}; - -// Macros for k20 pin access/definition -#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) -#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) - -#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } \ - template static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } }; -#define _IO32(L) _RD32(GPIO ## L ## _PDOR); _RD32(GPIO ## L ## _PSOR); _RD32(GPIO ## L ## _PCOR); _RD32(GPIO ## L ## _PTOR); _RD32(GPIO ## L ## _PDIR); _RD32(GPIO ## L ## _PDDR); - -#define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin : public _ARMPIN {}; \ - template<> class FastPinBB : public _ARMPIN_BITBAND {}; - -// Actual pin definitions -#if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY) - -_IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); - -#define MAX_PIN 33 -_DEFPIN_ARM(0, 16, B); _DEFPIN_ARM(1, 17, B); _DEFPIN_ARM(2, 0, D); _DEFPIN_ARM(3, 12, A); -_DEFPIN_ARM(4, 13, A); _DEFPIN_ARM(5, 7, D); _DEFPIN_ARM(6, 4, D); _DEFPIN_ARM(7, 2, D); -_DEFPIN_ARM(8, 3, D); _DEFPIN_ARM(9, 3, C); _DEFPIN_ARM(10, 4, C); _DEFPIN_ARM(11, 6, C); -_DEFPIN_ARM(12, 7, C); _DEFPIN_ARM(13, 5, C); _DEFPIN_ARM(14, 1, D); _DEFPIN_ARM(15, 0, C); -_DEFPIN_ARM(16, 0, B); _DEFPIN_ARM(17, 1, B); _DEFPIN_ARM(18, 3, B); _DEFPIN_ARM(19, 2, B); -_DEFPIN_ARM(20, 5, D); _DEFPIN_ARM(21, 6, D); _DEFPIN_ARM(22, 1, C); _DEFPIN_ARM(23, 2, C); -_DEFPIN_ARM(24, 5, A); _DEFPIN_ARM(25, 19, B); _DEFPIN_ARM(26, 1, E); _DEFPIN_ARM(27, 9, C); -_DEFPIN_ARM(28, 8, C); _DEFPIN_ARM(29, 10, C); _DEFPIN_ARM(30, 11, C); _DEFPIN_ARM(31, 0, E); -_DEFPIN_ARM(32, 18, B); _DEFPIN_ARM(33, 4, A); - -#define SPI_DATA 11 -#define SPI_CLOCK 13 -#define SPI1 (*(SPI_t *)0x4002D000) - -#if defined(__MK20DX256__) -#define SPI2_DATA 7 -#define SPI2_CLOCK 14 -#endif - -#define FASTLED_TEENSY3 -#define ARM_HARDWARE_SPI -#define HAS_HARDWARE_PIN_SUPPORT -#endif - -#endif diff --git a/fastpin_arm_sam.h b/fastpin_arm_sam.h deleted file mode 100644 index 0296bd50..00000000 --- a/fastpin_arm_sam.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef __INC_FASTPIN_ARM_SAM_H -#define __INC_FASTPIN_ARM_SAM_H - -/// Template definition for arduino due style ARM pins, providing direct access to the various GPIO registers. Note that this -/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found -/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. -/// The registers are data register, set output register, clear output register, set data direction register -template class _DUEPIN { -public: - typedef volatile uint32_t * port_ptr_t; - typedef uint32_t port_t; - - inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } - inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } - - inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } - inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } - inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } - - inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - - inline static void toggle() __attribute__ ((always_inline)) { _PDOR::r() ^= _MASK; } - - inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } - inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } - inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } - - inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } - inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } - inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } - inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } - inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } - inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } -}; - - -/// Template definition for DUE style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC -/// does a poor job of optimizing around these accesses so they are not being used just yet. -template class _DUEPIN_BITBAND { -public: - typedef volatile uint32_t * port_ptr_t; - typedef uint32_t port_t; - - inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } - inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } - - inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } - inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } - inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } - - inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - - inline static void toggle() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() ^= 1; } - - inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } - inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } - inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } - - inline static port_t hival() __attribute__ ((always_inline)) { return 1; } - inline static port_t loval() __attribute__ ((always_inline)) { return 0; } - inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } - inline static port_t mask() __attribute__ ((always_inline)) { return 1; } -}; - -#define DUE_IO32(L) _RD32(REG_PIO ## L ## _ODSR); _RD32(REG_PIO ## L ## _SODR); _RD32(REG_PIO ## L ## _CODR); _RD32(REG_PIO ## L ## _OER); - -#define _DEFPIN_DUE(PIN, BIT, L) template<> class FastPin : public _DUEPIN {}; \ - template<> class FastPinBB : public _DUEPIN_BITBAND {}; - -#if defined(__SAM3X8E__) - -DUE_IO32(A); -DUE_IO32(B); -DUE_IO32(C); -DUE_IO32(D); - -#define MAX_PIN 78 -_DEFPIN_DUE(0, 8, A); _DEFPIN_DUE(1, 9, A); _DEFPIN_DUE(2, 25, B); _DEFPIN_DUE(3, 28, C); -_DEFPIN_DUE(4, 26, C); _DEFPIN_DUE(5, 25, C); _DEFPIN_DUE(6, 24, C); _DEFPIN_DUE(7, 23, C); -_DEFPIN_DUE(8, 22, C); _DEFPIN_DUE(9, 21, C); _DEFPIN_DUE(10, 29, C); _DEFPIN_DUE(11, 7, D); -_DEFPIN_DUE(12, 8, D); _DEFPIN_DUE(13, 27, B); _DEFPIN_DUE(14, 4, D); _DEFPIN_DUE(15, 5, D); -_DEFPIN_DUE(16, 13, A); _DEFPIN_DUE(17, 12, A); _DEFPIN_DUE(18, 11, A); _DEFPIN_DUE(19, 10, A); -_DEFPIN_DUE(20, 12, B); _DEFPIN_DUE(21, 13, B); _DEFPIN_DUE(22, 26, B); _DEFPIN_DUE(23, 14, A); -_DEFPIN_DUE(24, 15, A); _DEFPIN_DUE(25, 0, D); _DEFPIN_DUE(26, 1, D); _DEFPIN_DUE(27, 2, D); -_DEFPIN_DUE(28, 3, D); _DEFPIN_DUE(29, 6, D); _DEFPIN_DUE(30, 9, D); _DEFPIN_DUE(31, 7, A); -_DEFPIN_DUE(32, 10, D); _DEFPIN_DUE(33, 1, C); _DEFPIN_DUE(34, 2, C); _DEFPIN_DUE(35, 3, C); -_DEFPIN_DUE(36, 4, C); _DEFPIN_DUE(37, 5, C); _DEFPIN_DUE(38, 6, C); _DEFPIN_DUE(39, 7, C); -_DEFPIN_DUE(40, 8, C); _DEFPIN_DUE(41, 9, C); _DEFPIN_DUE(42, 19, A); _DEFPIN_DUE(43, 20, A); -_DEFPIN_DUE(44, 19, C); _DEFPIN_DUE(45, 18, C); _DEFPIN_DUE(46, 17, C); _DEFPIN_DUE(47, 16, C); -_DEFPIN_DUE(48, 15, C); _DEFPIN_DUE(49, 14, C); _DEFPIN_DUE(50, 13, C); _DEFPIN_DUE(51, 12, C); -_DEFPIN_DUE(52, 21, B); _DEFPIN_DUE(53, 14, B); _DEFPIN_DUE(54, 16, A); _DEFPIN_DUE(55, 24, A); -_DEFPIN_DUE(56, 23, A); _DEFPIN_DUE(57, 22, A); _DEFPIN_DUE(58, 6, A); _DEFPIN_DUE(59, 4, A); -_DEFPIN_DUE(60, 3, A); _DEFPIN_DUE(61, 2, A); _DEFPIN_DUE(62, 17, B); _DEFPIN_DUE(63, 18, B); -_DEFPIN_DUE(64, 19, B); _DEFPIN_DUE(65, 20, B); _DEFPIN_DUE(66, 15, B); _DEFPIN_DUE(67, 16, B); -_DEFPIN_DUE(68, 1, A); _DEFPIN_DUE(69, 0, A); _DEFPIN_DUE(70, 17, A); _DEFPIN_DUE(71, 18, A); -_DEFPIN_DUE(72, 30, C); _DEFPIN_DUE(73, 21, A); _DEFPIN_DUE(74, 25, A); _DEFPIN_DUE(75, 26, A); -_DEFPIN_DUE(76, 27, A); _DEFPIN_DUE(77, 28, A); _DEFPIN_DUE(78, 23, B); - -// digix pins -_DEFPIN_DUE(90, 0, B); _DEFPIN_DUE(91, 1, B); _DEFPIN_DUE(92, 2, B); _DEFPIN_DUE(93, 3, B); -_DEFPIN_DUE(94, 4, B); _DEFPIN_DUE(95, 5, B); _DEFPIN_DUE(96, 6, B); _DEFPIN_DUE(97, 7, B); -_DEFPIN_DUE(98, 8, B); _DEFPIN_DUE(99, 9, B); _DEFPIN_DUE(100, 5, A); _DEFPIN_DUE(101, 22, B); -_DEFPIN_DUE(102, 23, B); _DEFPIN_DUE(103, 24, B); _DEFPIN_DUE(104, 27, C); _DEFPIN_DUE(105, 20, C); -_DEFPIN_DUE(106, 11, C); _DEFPIN_DUE(107, 10, C); _DEFPIN_DUE(108, 21, A); _DEFPIN_DUE(109, 30, C); -_DEFPIN_DUE(110, 29, B); _DEFPIN_DUE(111, 30, B); _DEFPIN_DUE(112, 31, B); _DEFPIN_DUE(113, 28, B); - -#define SPI_DATA 75 -#define SPI_CLOCK 76 -#define ARM_HARDWARE_SPI -#define HAS_HARDWARE_PIN_SUPPORT - -#endif - - -#endif diff --git a/fastpin_avr.h b/fastpin_avr.h deleted file mode 100644 index 103498c2..00000000 --- a/fastpin_avr.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef __INC_FASTPIN_AVR_H -#define __INC_FASTPIN_AVR_H - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -#define AVR_PIN_CYCLES(_PIN) (((_PIN >= 62 ) || (_PIN>=42 && _PIN<=49) || (_PIN>=14 && _PIN <=17) || (_PIN>=6 && _PIN <=9)) ? 2 : 1) -#else -#define AVR_PIN_CYCLES(_PIN) ((_PIN >= 24) ? 2 : 1) -#endif - - -/// Class definition for a Pin where we know the port registers at compile time for said pin. This allows us to make -/// a lot of optimizations, as the inlined hi/lo methods will devolve to a single io register write/bitset. -template class _AVRPIN { -public: - typedef volatile uint8_t * port_ptr_t; - typedef uint8_t port_t; - - inline static void setOutput() { _DDR::r() |= _MASK; } - inline static void setInput() { _DDR::r() &= ~_MASK; } - - inline static void hi() __attribute__ ((always_inline)) { _PORT::r() |= _MASK; } - inline static void lo() __attribute__ ((always_inline)) { _PORT::r() &= ~_MASK; } - inline static void set(register uint8_t val) __attribute__ ((always_inline)) { _PORT::r() = val; } - - inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - - inline static void toggle() __attribute__ ((always_inline)) { _PIN::r() = _MASK; } - - inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } - inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } - inline static void fastset(register port_ptr_t port, register uint8_t val) __attribute__ ((always_inline)) { set(val); } - - inline static port_t hival() __attribute__ ((always_inline)) { return _PORT::r() | _MASK; } - inline static port_t loval() __attribute__ ((always_inline)) { return _PORT::r() & ~_MASK; } - inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PORT::r(); } - inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } -}; - - - -/// AVR definitions for pins. Getting around the fact that I can't pass GPIO register addresses in as template arguments by instead creating -/// a custom type for each GPIO register with a single, static, aggressively inlined function that returns that specific GPIO register. A similar -/// trick is used a bit further below for the ARM GPIO registers (of which there are far more than on AVR!) -typedef volatile uint8_t & reg8_t; -#define _R(T) struct __gen_struct_ ## T -#define _RD8(T) struct __gen_struct_ ## T { static inline reg8_t r() { return T; }}; -#define _IO(L) _RD8(DDR ## L); _RD8(PORT ## L); _RD8(PIN ## L); -#define _DEFPIN_AVR(_PIN, MASK, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, MASK, _R(PORT ## L), _R(DDR ## L), _R(PIN ## L)> {}; - -#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) -_IO(B); - -_DEFPIN_AVR(0, 0x01, B); _DEFPIN_AVR(1, 0x02, B); _DEFPIN_AVR(2, 0x04, B); _DEFPIN_AVR(3, 0x08, B); -_DEFPIN_AVR(4, 0x10, B); _DEFPIN_AVR(5, 0x20, B); - -#define HAS_HARDWARE_PIN_SUPPORT 1 - -#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) -_IO(A); _IO(B); - -_DEFPIN_AVR(0, 0x01, A); _DEFPIN_AVR(1, 0x02, A); _DEFPIN_AVR(2, 0x04, A); _DEFPIN_AVR(3, 0x08, A); -_DEFPIN_AVR(4, 0x10, A); _DEFPIN_AVR(5, 0x20, A); _DEFPIN_AVR(6, 0x40, A); _DEFPIN_AVR(7, 0x80, A); -_DEFPIN_AVR(8, 0x04, B); _DEFPIN_AVR(9, 0x02, B); _DEFPIN_AVR(10, 0x01, B); - -#define HAS_HARDWARE_PIN_SUPPORT 1 - -#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) -// Accelerated port definitions for arduino avrs -_IO(D); _IO(B); _IO(C); - -#define MAX_PIN 19 -_DEFPIN_AVR( 0, 0x01, D); _DEFPIN_AVR( 1, 0x02, D); _DEFPIN_AVR( 2, 0x04, D); _DEFPIN_AVR( 3, 0x08, D); -_DEFPIN_AVR( 4, 0x10, D); _DEFPIN_AVR( 5, 0x20, D); _DEFPIN_AVR( 6, 0x40, D); _DEFPIN_AVR( 7, 0x80, D); -_DEFPIN_AVR( 8, 0x01, B); _DEFPIN_AVR( 9, 0x02, B); _DEFPIN_AVR(10, 0x04, B); _DEFPIN_AVR(11, 0x08, B); -_DEFPIN_AVR(12, 0x10, B); _DEFPIN_AVR(13, 0x20, B); _DEFPIN_AVR(14, 0x01, C); _DEFPIN_AVR(15, 0x02, C); -_DEFPIN_AVR(16, 0x04, C); _DEFPIN_AVR(17, 0x08, C); _DEFPIN_AVR(18, 0x10, C); _DEFPIN_AVR(19, 0x20, C); - -#define SPI_DATA 11 -#define SPI_CLOCK 13 -#define SPI_SELECT 10 -#define AVR_HARDWARE_SPI 1 -#define HAS_HARDWARE_PIN_SUPPORT 1 - -#elif defined(__AVR_ATmega1284P__) - -_IO(A); _IO(B); _IO(C); _IO(D); - -_DEFPIN_AVR(0, 1<<0, D); _DEFPIN_AVR(1, 1<<1, D); _DEFPIN_AVR(2, 1<<2, B); _DEFPIN_AVR(3, 1<<3, B); -_DEFPIN_AVR(4, 1<<0, B); _DEFPIN_AVR(5, 1<<1, B); _DEFPIN_AVR(6, 1<<2, D); _DEFPIN_AVR(7, 1<<3, D); -_DEFPIN_AVR(8, 1<<5, D); _DEFPIN_AVR(9, 1<<6, D); _DEFPIN_AVR(10, 1<<4, B); _DEFPIN_AVR(11, 1<<5, B); -_DEFPIN_AVR(12, 1<<6, B); _DEFPIN_AVR(13, 1<<7, B); _DEFPIN_AVR(14, 1<<7, A); _DEFPIN_AVR(15, 1<<6, A); -_DEFPIN_AVR(16, 1<<5, A); _DEFPIN_AVR(17, 1<<4, A); _DEFPIN_AVR(18, 1<<3, A); _DEFPIN_AVR(19, 1<<2, A); -_DEFPIN_AVR(20, 1<<1, A); _DEFPIN_AVR(21, 1<<0, A); _DEFPIN_AVR(22, 1<<0, C); _DEFPIN_AVR(23, 1<<1, C); -_DEFPIN_AVR(24, 1<<2, C); _DEFPIN_AVR(25, 1<<3, C); _DEFPIN_AVR(26, 1<<4, C); _DEFPIN_AVR(27, 1<<5, C); -_DEFPIN_AVR(28, 1<<6, C); _DEFPIN_AVR(29, 1<<7, C); _DEFPIN_AVR(30, 1<<4, D); _DEFPIN_AVR(31, 1<<7, D); - -#define SPI_DATA 11 -#define SPI_CLOCK 13 -#define SPI_SELECT 10 -#define AVR_HARDWARE_SPI 1 -#define HAS_HARDWARE_PIN_SUPPORT 1 - -#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -// megas - -_IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); _IO(G); _IO(H); _IO(J); _IO(K); _IO(L); - -#define MAX_PIN 69 -_DEFPIN_AVR(0, 1, E); _DEFPIN_AVR(1, 2, E); _DEFPIN_AVR(2, 16, E); _DEFPIN_AVR(3, 32, E); -_DEFPIN_AVR(4, 32, G); _DEFPIN_AVR(5, 8, E); _DEFPIN_AVR(6, 8, H); _DEFPIN_AVR(7, 16, H); -_DEFPIN_AVR(8, 32, H); _DEFPIN_AVR(9, 64, H); _DEFPIN_AVR(10, 16, B); _DEFPIN_AVR(11, 32, B); -_DEFPIN_AVR(12, 64, B); _DEFPIN_AVR(13, 128, B); _DEFPIN_AVR(14, 2, J); _DEFPIN_AVR(15, 1, J); -_DEFPIN_AVR(16, 2, H); _DEFPIN_AVR(17, 1, H); _DEFPIN_AVR(18, 8, D); _DEFPIN_AVR(19, 4, D); -_DEFPIN_AVR(20, 2, D); _DEFPIN_AVR(21, 1, D); _DEFPIN_AVR(22, 1, A); _DEFPIN_AVR(23, 2, A); -_DEFPIN_AVR(24, 4, A); _DEFPIN_AVR(25, 8, A); _DEFPIN_AVR(26, 16, A); _DEFPIN_AVR(27, 32, A); -_DEFPIN_AVR(28, 64, A); _DEFPIN_AVR(29, 128, A); _DEFPIN_AVR(30, 128, C); _DEFPIN_AVR(31, 64, C); -_DEFPIN_AVR(32, 32, C); _DEFPIN_AVR(33, 16, C); _DEFPIN_AVR(34, 8, C); _DEFPIN_AVR(35, 4, C); -_DEFPIN_AVR(36, 2, C); _DEFPIN_AVR(37, 1, C); _DEFPIN_AVR(38, 128, D); _DEFPIN_AVR(39, 4, G); -_DEFPIN_AVR(40, 2, G); _DEFPIN_AVR(41, 1, G); _DEFPIN_AVR(42, 128, L); _DEFPIN_AVR(43, 64, L); -_DEFPIN_AVR(44, 32, L); _DEFPIN_AVR(45, 16, L); _DEFPIN_AVR(46, 8, L); _DEFPIN_AVR(47, 4, L); -_DEFPIN_AVR(48, 2, L); _DEFPIN_AVR(49, 1, L); _DEFPIN_AVR(50, 8, B); _DEFPIN_AVR(51, 4, B); -_DEFPIN_AVR(52, 2, B); _DEFPIN_AVR(53, 1, B); _DEFPIN_AVR(54, 1, F); _DEFPIN_AVR(55, 2, F); -_DEFPIN_AVR(56, 4, F); _DEFPIN_AVR(57, 8, F); _DEFPIN_AVR(58, 16, F); _DEFPIN_AVR(59, 32, F); -_DEFPIN_AVR(60, 64, F); _DEFPIN_AVR(61, 128, F); _DEFPIN_AVR(62, 1, K); _DEFPIN_AVR(63, 2, K); -_DEFPIN_AVR(64, 4, K); _DEFPIN_AVR(65, 8, K); _DEFPIN_AVR(66, 16, K); _DEFPIN_AVR(67, 32, K); -_DEFPIN_AVR(68, 64, K); _DEFPIN_AVR(69, 128, K); - -#define SPI_DATA 51 -#define SPI_CLOCK 52 -#define SPI_SELECT 53 -#define AVR_HARDWARE_SPI 1 -#define HAS_HARDWARE_PIN_SUPPORT 1 - -// Leonardo, teensy, blinkm -#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) - -// teensy defs -_IO(B); _IO(C); _IO(D); _IO(E); _IO(F); - -#define MAX_PIN 23 -_DEFPIN_AVR(0, 1, B); _DEFPIN_AVR(1, 2, B); _DEFPIN_AVR(2, 4, B); _DEFPIN_AVR(3, 8, B); -_DEFPIN_AVR(4, 128, B); _DEFPIN_AVR(5, 1, D); _DEFPIN_AVR(6, 2, D); _DEFPIN_AVR(7, 4, D); -_DEFPIN_AVR(8, 8, D); _DEFPIN_AVR(9, 64, C); _DEFPIN_AVR(10, 128, C); _DEFPIN_AVR(11, 64, D); -_DEFPIN_AVR(12, 128, D); _DEFPIN_AVR(13, 16, B); _DEFPIN_AVR(14, 32, B); _DEFPIN_AVR(15, 64, B); -_DEFPIN_AVR(16, 128, F); _DEFPIN_AVR(17, 64, F); _DEFPIN_AVR(18, 32, F); _DEFPIN_AVR(19, 16, F); -_DEFPIN_AVR(20, 2, F); _DEFPIN_AVR(21, 1, F); _DEFPIN_AVR(22, 16, D); _DEFPIN_AVR(23, 32, D); - -#define SPI_DATA 2 -#define SPI_CLOCK 1 -#define SPI_SELECT 0 -#define AVR_HARDWARE_SPI 1 -#define HAS_HARDWARE_PIN_SUPPORT 1 - -#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) -// teensy++ 2 defs - -_IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); - -#define MAX_PIN 45 -_DEFPIN_AVR(0, 1, D); _DEFPIN_AVR(1, 2, D); _DEFPIN_AVR(2, 4, D); _DEFPIN_AVR(3, 8, D); -_DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 32, D); _DEFPIN_AVR(6, 64, D); _DEFPIN_AVR(7, 128, D); -_DEFPIN_AVR(8, 1, E); _DEFPIN_AVR(9, 2, E); _DEFPIN_AVR(10, 1, C); _DEFPIN_AVR(11, 2, C); -_DEFPIN_AVR(12, 4, C); _DEFPIN_AVR(13, 8, C); _DEFPIN_AVR(14, 16, C); _DEFPIN_AVR(15, 32, C); -_DEFPIN_AVR(16, 64, C); _DEFPIN_AVR(17, 128, C); _DEFPIN_AVR(18, 64, E); _DEFPIN_AVR(19, 128, E); -_DEFPIN_AVR(20, 1, B); _DEFPIN_AVR(21, 2, B); _DEFPIN_AVR(22, 4, B); _DEFPIN_AVR(23, 8, B); -_DEFPIN_AVR(24, 16, B); _DEFPIN_AVR(25, 32, B); _DEFPIN_AVR(26, 64, B); _DEFPIN_AVR(27, 128, B); -_DEFPIN_AVR(28, 1, A); _DEFPIN_AVR(29, 2, A); _DEFPIN_AVR(30, 4, A); _DEFPIN_AVR(31, 8, A); -_DEFPIN_AVR(32, 16, A); _DEFPIN_AVR(33, 32, A); _DEFPIN_AVR(34, 64, A); _DEFPIN_AVR(35, 128, A); -_DEFPIN_AVR(36, 16, E); _DEFPIN_AVR(37, 32, E); _DEFPIN_AVR(38, 1, F); _DEFPIN_AVR(39, 2, F); -_DEFPIN_AVR(40, 4, F); _DEFPIN_AVR(41, 8, F); _DEFPIN_AVR(42, 16, F); _DEFPIN_AVR(43, 32, F); -_DEFPIN_AVR(44, 64, F); _DEFPIN_AVR(45, 128, F); - -#define SPI_DATA 22 -#define SPI_CLOCK 21 -#define SPI_SELECT 20 -#define AVR_HARDWARE_SPI 1 -#define HAS_HARDWARE_PIN_SUPPORT 1 - -#elif defined(__AVR_ATmega32U4__) - -// leonard defs -_IO(B); _IO(C); _IO(D); _IO(E); _IO(F); - -#define MAX_PIN 23 -_DEFPIN_AVR(0, 4, D); _DEFPIN_AVR(1, 8, D); _DEFPIN_AVR(2, 2, D); _DEFPIN_AVR(3, 1, D); -_DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 64, C); _DEFPIN_AVR(6, 128, D); _DEFPIN_AVR(7, 64, E); -_DEFPIN_AVR(8, 16, B); _DEFPIN_AVR(9, 32, B); _DEFPIN_AVR(10, 64, B); _DEFPIN_AVR(11, 128, B); -_DEFPIN_AVR(12, 64, D); _DEFPIN_AVR(13, 128, C); _DEFPIN_AVR(14, 8, B); _DEFPIN_AVR(15, 2, B); -_DEFPIN_AVR(16, 4, B); _DEFPIN_AVR(17, 1, B); _DEFPIN_AVR(18, 128, F); _DEFPIN_AVR(19, 64, F); -_DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_AVR(23, 0, F); - -#define SPI_DATA 16 -#define SPI_CLOCK 15 -#define AVR_HARDWARE_SPI 1 -#define HAS_HARDWARE_PIN_SUPPORT 1 - -#endif - -#endif diff --git a/fastspi.h b/fastspi.h index f80956f4..4c247157 100644 --- a/fastspi.h +++ b/fastspi.h @@ -3,40 +3,9 @@ #include "controller.h" #include "lib8tion.h" -#include "delay.h" - -// Some helper macros for getting at mis-ordered byte values -#define SPI_B0 (RGB_BYTE0(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) -#define SPI_B1 (RGB_BYTE1(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) -#define SPI_B2 (RGB_BYTE2(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) -#define SPI_ADVANCE (3 + (MASK_SKIP_BITS & SKIP)) - -/// Some of the SPI controllers will need to perform a transform on each byte before doing -/// anyting with it. Creating a class of this form and passing it in as a template parameter to -/// writeBytes/writeBytes3 below will ensure that the body of this method will get called on every -/// byte worked on. Recommendation, make the adjust method aggressively inlined. -/// -/// TODO: Convinience macro for building these -class DATA_NOP { -public: - static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data) { return data; } - static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data, register uint8_t scale) { return scale8(data, scale); } - static __attribute__((always_inline)) inline void postBlock(int len) {} -}; - -#define FLAG_START_BIT 0x80 -#define MASK_SKIP_BITS 0x3F - -// Clock speed dividers -#define SPEED_DIV_2 2 -#define SPEED_DIV_4 4 -#define SPEED_DIV_8 8 -#define SPEED_DIV_16 16 -#define SPEED_DIV_32 32 -#define SPEED_DIV_64 64 -#define SPEED_DIV_128 128 - -#define MAX_DATA_RATE 0 + +#include "fastspi_bitbang.h" + #if (CLK_DBL == 1) #define DATA_RATE_MHZ(X) (((F_CPU / 1000000L) / X)/2) #define DATA_RATE_KHZ(X) (((F_CPU / 1000L) / X)/2) @@ -45,13 +14,6 @@ public: #define DATA_RATE_KHZ(X) ((F_CPU / 1000L) / X) #endif -// Include the various specific SPI implementations -#include "fastspi_bitbang.h" -#include "fastspi_arm_k20.h" -#include "fastspi_arm_sam.h" -#include "fastspi_avr.h" -#include "fastspi_dma.h" - ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // External SPI template definition with partial instantiation(s) to map to hardware SPI ports on platforms/builds where the pin diff --git a/fastspi_arm_k20.h b/fastspi_arm_k20.h deleted file mode 100644 index ad9598ae..00000000 --- a/fastspi_arm_k20.h +++ /dev/null @@ -1,375 +0,0 @@ -#ifndef __INC_FASTSPI_ARM_H -#define __INC_FASTSPI_ARM_H - - -#if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY) - -// Version 1.20 renamed SPI_t to KINETISK_SPI_t -#if TEENSYDUINO >= 120 -#define SPI_t KINETISK_SPI_t -#endif - -#ifndef SPI_PUSHR_CONT -#define SPI_PUSHR_CONT SPIX.PUSHR_CONT -#define SPI_PUSHR_CTAS(X) SPIX.PUSHR_CTAS(X) -#define SPI_PUSHR_EOQ SPIX.PUSHR_EOQ -#define SPI_PUSHR_CTCNT SPIX.PUSHR_CTCNT -#define SPI_PUSHR_PCS(X) SPIX.PUSHR_PCS(X) -#endif - -// Template function that, on compilation, expands to a constant representing the highest bit set in a byte. Right now, -// if no bits are set (value is 0), it returns 0, which is also the value returned if the lowest bit is the only bit -// set (the zero-th bit). Unclear if I will want this to change at some point. -template class BitWork { - public: - static int highestBit() __attribute__((always_inline)) { return (VAL & 1 << BIT) ? BIT : BitWork::highestBit(); } -}; -template class BitWork { - public: - static int highestBit() __attribute__((always_inline)) { return 0; } -}; - -#define MAX(A, B) (( (A) > (B) ) ? (A) : (B)) - -#define USE_CONT 0 - -// Templated function to translate a clock divider value into the prescalar, scalar, and clock doubling setting for the world. -template void getScalars(uint32_t & preScalar, uint32_t & scalar, uint32_t & dbl) { - switch(VAL) { - // Handle the dbl clock cases - case 0: case 1: - case 2: preScalar = 0; scalar = 0; dbl = 1; break; - case 3: preScalar = 1; scalar = 0; dbl = 1; break; - case 5: preScalar = 2; scalar = 0; dbl = 1; break; - case 7: preScalar = 3; scalar = 0; dbl = 1; break; - - // Handle the scalar value 6 cases (since it's not a power of two, it won't get caught - // below) - case 9: preScalar = 1; scalar = 2; dbl = 1; break; - case 18: case 19: preScalar = 1; scalar = 2; dbl = 0; break; - - case 15: preScalar = 2; scalar = 2; dbl = 1; break; - case 30: case 31: preScalar = 2; scalar = 2; dbl = 0; break; - - case 21: case 22: case 23: preScalar = 3; scalar = 2; dbl = 1; break; - case 42: case 43: case 44: case 45: case 46: case 47: preScalar = 3; scalar = 2; dbl = 0; break; - default: { - int p2 = BitWork::highestBit(); - int p3 = BitWork::highestBit(); - int p5 = BitWork::highestBit(); - int p7 = BitWork::highestBit(); - - int w2 = 2 * (1 << p2); - int w3 = (VAL/3) > 0 ? 3 * (1 << p3) : 0; - int w5 = (VAL/5) > 0 ? 5 * (1 << p5) : 0; - int w7 = (VAL/7) > 0 ? 7 * (1 << p7) : 0; - - int maxval = MAX(MAX(w2, w3), MAX(w5, w7)); - - if(w2 == maxval) { preScalar = 0; scalar = p2; } - else if(w3 == maxval) { preScalar = 1; scalar = p3; } - else if(w5 == maxval) { preScalar = 2; scalar = p5; } - else if(w7 == maxval) { preScalar = 3; scalar = p7; } - - dbl = 0; - if(scalar == 0) { dbl = 1; } - else if(scalar < 3) { scalar--; } - } - } - return; -} - -#define SPIX (*(SPI_t*)pSPIX) - -template -class ARMHardwareSPIOutput { - Selectable *m_pSelect; - - // Borrowed from the teensy3 SPSR emulation code - static inline void enable_pins(void) __attribute__((always_inline)) { - //serial_print("enable_pins\n"); - if(_DATA_PIN == 11) { - CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); - CORE_PIN12_CONFIG = PORT_PCR_MUX(2); - CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); - } else if(_DATA_PIN == 7) { - CORE_PIN7_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); - CORE_PIN8_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); - CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); - } - } - - // Borrowed from the teensy3 SPSR emulation code - static inline void disable_pins(void) __attribute__((always_inline)) { - //serial_print("disable_pins\n"); - if(_DATA_PIN == 11) { - CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); - CORE_PIN12_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); - CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); - } else if(_DATA_PIN == 7) { - CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); - CORE_PIN8_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); - CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); - } -} -public: - ARMHardwareSPIOutput() { m_pSelect = NULL; } - ARMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } - void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } - - static inline void update_ctar0(uint32_t ctar) __attribute__((always_inline)) { - if (SPIX.CTAR0 == ctar) return; - uint32_t mcr = SPIX.MCR; - if (mcr & SPI_MCR_MDIS) { - SPIX.CTAR0 = ctar; - } else { - SPIX.MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT; - SPIX.CTAR0 = ctar; - - SPIX.MCR = mcr; - } - } - - static inline void update_ctar1(uint32_t ctar) __attribute__((always_inline)) { - if (SPIX.CTAR1 == ctar) return; - uint32_t mcr = SPIX.MCR; - if (mcr & SPI_MCR_MDIS) { - SPIX.CTAR1 = ctar; - } else { - SPIX.MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT; - SPIX.CTAR1 = ctar; - SPIX.MCR = mcr; - - } - } - - void setSPIRate() { - // Configure CTAR0, defaulting to 8 bits and CTAR1, defaulting to 16 bits - uint32_t _PBR = 0; - uint32_t _BR = 0; - uint32_t _CSSCK = 0; - uint32_t _DBR = 0; - - // if(_SPI_CLOCK_DIVIDER >= 256) { _PBR = 0; _BR = _CSSCK = 7; _DBR = 0; } // osc/256 - // else if(_SPI_CLOCK_DIVIDER >= 128) { _PBR = 0; _BR = _CSSCK = 6; _DBR = 0; } // osc/128 - // else if(_SPI_CLOCK_DIVIDER >= 64) { _PBR = 0; _BR = _CSSCK = 5; _DBR = 0; } // osc/64 - // else if(_SPI_CLOCK_DIVIDER >= 32) { _PBR = 0; _BR = _CSSCK = 4; _DBR = 0; } // osc/32 - // else if(_SPI_CLOCK_DIVIDER >= 16) { _PBR = 0; _BR = _CSSCK = 3; _DBR = 0; } // osc/16 - // else if(_SPI_CLOCK_DIVIDER >= 8) { _PBR = 0; _BR = _CSSCK = 1; _DBR = 0; } // osc/8 - // else if(_SPI_CLOCK_DIVIDER >= 7) { _PBR = 3; _BR = _CSSCK = 0; _DBR = 1; } // osc/7 - // else if(_SPI_CLOCK_DIVIDER >= 5) { _PBR = 2; _BR = _CSSCK = 0; _DBR = 1; } // osc/5 - // else if(_SPI_CLOCK_DIVIDER >= 4) { _PBR = 0; _BR = _CSSCK = 0; _DBR = 0; } // osc/4 - // else if(_SPI_CLOCK_DIVIDER >= 3) { _PBR = 1; _BR = _CSSCK = 0; _DBR = 1; } // osc/3 - // else { _PBR = 0; _BR = _CSSCK = 0; _DBR = 1; } // osc/2 - - getScalars<_SPI_CLOCK_DIVIDER>(_PBR, _BR, _DBR); - _CSSCK = _BR; - - uint32_t ctar0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(_PBR) | SPI_CTAR_BR(_BR) | SPI_CTAR_CSSCK(_CSSCK); - uint32_t ctar1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(_PBR) | SPI_CTAR_BR(_BR) | SPI_CTAR_CSSCK(_CSSCK); - -#if USE_CONT == 1 - ctar0 |= SPI_CTAR_CPHA | SPI_CTAR_CPOL; - ctar1 |= SPI_CTAR_CPHA | SPI_CTAR_CPOL; -#endif - - if(_DBR) { - ctar0 |= SPI_CTAR_DBR; - ctar1 |= SPI_CTAR_DBR; - } - - update_ctar0(ctar0); - update_ctar1(ctar1); - - } - - void init() { - // set the pins to output - FastPin<_DATA_PIN>::setOutput(); - FastPin<_CLOCK_PIN>::setOutput(); - release(); - - // Enable SPI0 clock - uint32_t sim6 = SIM_SCGC6; - if((SPI_t*)pSPIX == &SPI0) { - if (!(sim6 & SIM_SCGC6_SPI0)) { - //serial_print("init1\n"); - SIM_SCGC6 = sim6 | SIM_SCGC6_SPI0; - SPIX.CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1); - } - } else if((SPI_t*)pSPIX == &SPI1) { - if (!(sim6 & SIM_SCGC6_SPI1)) { - //serial_print("init1\n"); - SIM_SCGC6 = sim6 | SIM_SCGC6_SPI1; - SPIX.CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1); - } - } - setSPIRate(); - - // Configure SPI as the master and enable - SPIX.MCR |= SPI_MCR_MSTR; // | SPI_MCR_CONT_SCKE); - SPIX.MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT); - - enable_pins(); - } - - static void waitFully() __attribute__((always_inline)) { - while( (SPIX.SR & 0xF000) > 0); - while (!(SPIX.SR & SPI_SR_TCF)); - SPIX.SR |= (SPI_SR_TCF | SPI_SR_EOQF); - } - - static bool needwait() __attribute__((always_inline)) { return (SPIX.SR & 0x4000); } - static void wait() __attribute__((always_inline)) { while( (SPIX.SR & 0x4000) ); } - static void wait1() __attribute__((always_inline)) { while( (SPIX.SR & 0xF000) >= 0x2000); } - - enum ECont { CONT, NOCONT }; - enum EWait { PRE, POST, NONE }; - enum ELast { NOTLAST, LAST }; - -#if USE_CONT == 1 - #define CM CONT -#else - #define CM NOCONT -#endif - #define WM PRE - - template class Write { - public: - static void writeWord(uint16_t w) __attribute__((always_inline)) { - if(WAIT_STATE == PRE) { wait(); } - SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) | - ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) | - SPI_PUSHR_CTAS(1) | (w & 0xFFFF); - if(WAIT_STATE == POST) { wait(); } - } - - static void writeByte(uint8_t b) __attribute__((always_inline)) { - if(WAIT_STATE == PRE) { wait(); } - SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) | - ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) | - SPI_PUSHR_CTAS(0) | (b & 0xFF); - if(WAIT_STATE == POST) { wait(); } - } - }; - - static void writeWord(uint16_t w) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } - static void writeWordNoWait(uint16_t w) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } - - static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); } - static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); wait(); } - static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); } - - static void writeWordCont(uint16_t w) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } - static void writeWordContNoWait(uint16_t w) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } - - static void writeByteCont(uint8_t b) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); } - static void writeByteContPostWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); wait(); } - static void writeByteContNoWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); } - - // not the most efficient mechanism in the world - but should be enough for sm16716 and friends - template inline static void writeBit(uint8_t b) { - uint32_t ctar1_save = SPIX.CTAR1; - - // Clear out the FMSZ bits, reset them for 1 bit transferd for the start bit - uint32_t ctar1 = (ctar1_save & (~SPI_CTAR_FMSZ(15))) | SPI_CTAR_FMSZ(0); - update_ctar1(ctar1); - - writeWord( (b & (1 << BIT)) != 0); - - update_ctar1(ctar1_save); - } - - void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } - void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } - - static void writeBytesValueRaw(uint8_t value, int len) { - while(len--) { Write::writeByte(value); } - } - - void writeBytesValue(uint8_t value, int len) { - setSPIRate(); - select(); - while(len--) { - writeByte(value); - } - waitFully(); - release(); - } - - // Write a block of n uint8_ts out - template void writeBytes(register uint8_t *data, int len) { - setSPIRate(); - uint8_t *end = data + len; - select(); - // could be optimized to write 16bit words out instead of 8bit bytes - while(data != end) { - writeByte(D::adjust(*data++)); - } - D::postBlock(len); - waitFully(); - release(); - } - - void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } - - // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template - // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping - template void writePixels(PixelController pixels) { - // setSPIRate(); - select(); - int len = pixels.mLen; - - // Setup the pixel controller - if((FLAGS & FLAG_START_BIT) == 0) { - //If no start bit stupiditiy, write out as many 16-bit blocks as we can - while(pixels.has(2)) { - // Load and write out the first two bytes - if(WM == NONE) { wait1(); } - Write::writeWord(D::adjust(pixels.loadAndScale0()) << 8 | D::adjust(pixels.loadAndScale1())); - - // Load and write out the next two bytes (step dithering, advance data in between since we - // cross pixels here) - Write::writeWord(D::adjust(pixels.loadAndScale2()) << 8 | D::adjust(pixels.stepAdvanceAndLoadAndScale0())); - - // Load and write out the next two bytes - Write::writeWord(D::adjust(pixels.loadAndScale1()) << 8 | D::adjust(pixels.loadAndScale2())); - pixels.stepDithering(); - pixels.advanceData(); - } - - if(pixels.has(1)) { - if(WM == NONE) { wait1(); } - // write out the rest as alternating 16/8-bit blocks (likely to be just one) - Write::writeWord(D::adjust(pixels.loadAndScale0()) << 8 | D::adjust(pixels.loadAndScale1())); - Write::writeByte(D::adjust(pixels.loadAndScale2())); - } - - D::postBlock(len); - waitFully(); - } else if(FLAGS & FLAG_START_BIT) { - uint32_t ctar1_save = SPIX.CTAR1; - - // Clear out the FMSZ bits, reset them for 9 bits transferd for the start bit - uint32_t ctar1 = (ctar1_save & (~SPI_CTAR_FMSZ(15))) | SPI_CTAR_FMSZ(8); - update_ctar1(ctar1); - - while(pixels.has(1)) { - writeWord( 0x100 | D::adjust(pixels.loadAndScale0())); - writeByte(D::adjust(pixels.loadAndScale1())); - writeByte(D::adjust(pixels.loadAndScale2())); - pixels.advanceData(); - pixels.stepDithering(); - } - D::postBlock(len); - waitFully(); - - // restore ctar1 - update_ctar1(ctar1_save); - } - release(); - } -}; -#endif - -#endif diff --git a/fastspi_arm_sam.h b/fastspi_arm_sam.h deleted file mode 100644 index d756c221..00000000 --- a/fastspi_arm_sam.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef __INC_FASTSPI_ARM_SAM_H -#define __INC_FASTSPI_ARM_SAM_H - -#if defined(__SAM3X8E__) -#define m_SPI ((Spi*)SPI0) - -template -class SAMHardwareSPIOutput { - Selectable *m_pSelect; - - static inline void waitForEmpty() { while ((m_SPI->SPI_SR & SPI_SR_TDRE) == 0); } - - void enableConfig() { m_SPI->SPI_WPMR &= ~SPI_WPMR_WPEN; } - void disableConfig() { m_SPI->SPI_WPMR |= SPI_WPMR_WPEN; } - - void enableSPI() { m_SPI->SPI_CR = SPI_CR_SPIEN; } - void disableSPI() { m_SPI->SPI_CR = SPI_CR_SPIDIS; } - void resetSPI() { m_SPI->SPI_CR = SPI_CR_SWRST; } - - static inline void readyTransferBits(register uint32_t bits) { - bits -= 8; - // don't change the number of transfer bits while data is still being transferred from TDR to the shift register - waitForEmpty(); - m_SPI->SPI_CSR[0] = SPI_CSR_NCPHA | SPI_CSR_CSAAT | (bits << SPI_CSR_BITS_Pos) | SPI_CSR_DLYBCT(1) | SPI_CSR_SCBR(_SPI_CLOCK_DIVIDER); - } - - template static inline void writeBits(uint16_t w) { - waitForEmpty(); - m_SPI->SPI_TDR = (uint32_t)w | SPI_PCS(0); - } - -public: - SAMHardwareSPIOutput() { m_pSelect = NULL; } - SAMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } - - // set the object representing the selectable - void setSelect(Selectable *pSelect) { /* TODO */ } - - // initialize the SPI subssytem - void init() { - // m_SPI = SPI0; - - // set the output pins master out, master in, clock. Note doing this here because I still don't - // know how I want to expose this type of functionality in FastPin. - PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_DATA_PIN>::mask(), PIO_DEFAULT); - PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_DATA_PIN-1>::mask(), PIO_DEFAULT); - PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_CLOCK_PIN>::mask(), PIO_DEFAULT); - - release(); - - // Configure the SPI clock, divider between 1-255 - // SCBR = _SPI_CLOCK_DIVIDER - pmc_enable_periph_clk(ID_SPI0); - disableSPI(); - - // reset twice (what the sam code does, not sure why?) - resetSPI(); - resetSPI(); - - // Configure SPI as master, enable - // Bits we want in MR: master, disable mode fault detection, variable peripheral select - m_SPI->SPI_MR = SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PS; - - enableSPI(); - - // Send everything out in 8 bit chunks, other sizes appear to work, poorly... - readyTransferBits(8); - } - - // latch the CS select - void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } - - // release the CS select - void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } - - // wait until all queued up data has been written - void waitFully() { while((m_SPI->SPI_SR & SPI_SR_TXEMPTY) == 0); } - - // write a byte out via SPI (returns immediately on writing register) - static void writeByte(uint8_t b) { - writeBits<8>(b); - } - - // write a word out via SPI (returns immediately on writing register) - static void writeWord(uint16_t w) { - writeBits<16>(w); - } - - // A raw set of writing byte values, assumes setup/init/waiting done elsewhere - static void writeBytesValueRaw(uint8_t value, int len) { - while(len--) { writeByte(value); } - } - - // A full cycle of writing a value for len bytes, including select, release, and waiting - void writeBytesValue(uint8_t value, int len) { - select(); writeBytesValueRaw(value, len); release(); - } - - template void writeBytes(register uint8_t *data, int len) { - uint8_t *end = data + len; - select(); - // could be optimized to write 16bit words out instead of 8bit bytes - while(data != end) { - writeByte(D::adjust(*data++)); - } - D::postBlock(len); - waitFully(); - release(); - } - - void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } - - // write a single bit out, which bit from the passed in byte is determined by template parameter - // not the most efficient mechanism in the world - but should be enough for sm16716 and friends - template inline void writeBit(uint8_t b) { - // need to wait for all exisiting data to go out the door, first - waitFully(); - disableSPI(); - if(b & (1 << BIT)) { - FastPin<_DATA_PIN>::hi(); - } else { - FastPin<_DATA_PIN>::lo(); - } - - FastPin<_CLOCK_PIN>::hi(); - FastPin<_CLOCK_PIN>::lo(); - enableSPI(); - } - - // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template - // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping - template void writePixels(PixelController pixels) { - select(); - int len = pixels.mLen; - - if(FLAGS & FLAG_START_BIT) { - while(pixels.has(1)) { - writeBits<9>((1<<8) | D::adjust(pixels.loadAndScale0())); - writeByte(D::adjust(pixels.loadAndScale1())); - writeByte(D::adjust(pixels.loadAndScale2())); - pixels.advanceData(); - pixels.stepDithering(); - } - } else { - while(pixels.has(1)) { - writeByte(D::adjust(pixels.loadAndScale0())); - writeByte(D::adjust(pixels.loadAndScale1())); - writeByte(D::adjust(pixels.loadAndScale2())); - pixels.advanceData(); - pixels.stepDithering(); - } - } - D::postBlock(len); - release(); - } -}; - -#endif - -#endif diff --git a/fastspi_avr.h b/fastspi_avr.h deleted file mode 100644 index 6470f37d..00000000 --- a/fastspi_avr.h +++ /dev/null @@ -1,300 +0,0 @@ -#ifndef __INC_FASTSPI_AVR_H -#define __INC_FASTSPI_AVR_H - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Hardware SPI support using USART registers and friends -// -// TODO: Complete/test implementation - right now this doesn't work -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -// uno/mini/duemilanove -#if defined(AVR_HARDWARE_SPI) -#if defined(UBRR0) -template -class AVRUSARTSPIOutput { - Selectable *m_pSelect; - -public: - AVRUSARTSPIOutput() { m_pSelect = NULL; } - AVRUSARTSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } - void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } - - void init() { - UBRR0 = 0; - UCSR0A = 1<::setOutput(); - FastPin<_DATA_PIN>::setOutput(); - - UCSR0C = _BV (UMSEL00) | _BV (UMSEL01); // Master SPI mode - UCSR0B = _BV (TXEN0) | _BV (RXEN0); // transmit enable and receive enable - - // must be done last, see page 206 - UBRR0 = 3; // 2 Mhz clock rate - } - - static void stop() { - // TODO: stop the uart spi output - } - - static void wait() __attribute__((always_inline)) { while(!(UCSR0A & (1<>8); writeByte(w&0xFF); } - - template inline static void writeBit(uint8_t b) { - if(b && (1 << BIT)) { - FastPin<_DATA_PIN>::hi(); - } else { - FastPin<_DATA_PIN>::lo(); - } - - FastPin<_CLOCK_PIN>::hi(); - FastPin<_CLOCK_PIN>::lo(); - } - - void select() { if(m_pSelect != NULL) { m_pSelect->select(); } } // FastPin<_SELECT_PIN>::hi(); } - void release() { - // wait for all transmissions to finish - while ((UCSR0A & (1 <release(); } // FastPin<_SELECT_PIN>::hi(); - } - - static void writeBytesValueRaw(uint8_t value, int len) { - while(len--) { writeByte(value); } - } - - void writeBytesValue(uint8_t value, int len) { - select(); - while(len--) { - writeByte(value); - } - release(); - } - - // Write a block of n uint8_ts out - template void writeBytes(register uint8_t *data, int len) { - uint8_t *end = data + len; - select(); - while(data != end) { - // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM) - writeByte(D::adjust(*data++)); delaycycles<3>(); - } - D::postBlock(len); - release(); - } - - void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } - - // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template - // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping - template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - uint8_t *end = data + len; - PixelController pixels(data, scale, true, advance, skip); - select(); - while(data != end) { - if(FLAGS & FLAG_START_BIT) { - writeBit<0>(1); - } - writeByte(D::adjust(pixels.loadAndScale0())); - writeByte(D::adjust(pixels.loadAndScale1())); - writeByte(D::adjust(pixels.loadAndScale2())); - pixels.advanceData(); - pixels.stepDithering(); - data += (3+skip); - } - D::postBlock(len); - release(); - } - - // template instantiations for writeBytes 3 - template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - writeBytes3(data, len, scale, advance, skip); - } - template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - writeBytes3<0, D, RGB_ORDER>(data, len, scale, advance, skip); - } - template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - writeBytes3<0, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); - } - void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { - writeBytes3<0, DATA_NOP, RGB>(data, len, scale, advance, skip); - } - -}; - -#endif - -#if defined(SPSR) - -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Hardware SPI support using SPDR registers and friends -// -// Technically speaking, this uses the AVR SPI registers. This will work on the Teensy 3.0 because Paul made a set of compatability -// classes that map the AVR SPI registers to ARM's, however this caps the performance of output. -// -// TODO: implement ARMHardwareSPIOutput -// -////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -template -class AVRHardwareSPIOutput { - Selectable *m_pSelect; - bool mWait; -public: - AVRHardwareSPIOutput() { m_pSelect = NULL; mWait = false;} - AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } - void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } - - void setSPIRate() { - SPCR &= ~ ( (1<= 128) { SPCR |= (1<= 64) { SPCR |= (1<= 32) { SPCR |= (1<= 16) { SPCR |= (1<= 8) { SPCR |= (1<= 4) { /* do nothing - default rate */ } - else { b2x = true; } - - if(b2x) { SPSR |= (1<::setOutput(); - FastPin<_CLOCK_PIN>::setOutput(); -#ifdef SPI_SELECT - // Make sure the slave select line is set to output, or arduino will block us - FastPin::setOutput(); - FastPin::lo(); -#endif - release(); - - SPCR |= ((1<= 128) { SPCR |= (1<= 64) { SPCR |= (1<= 32) { SPCR |= (1<= 16) { SPCR |= (1<= 8) { SPCR |= (1<= 4) { /* do nothing - default rate */ } - else { b2x = true; } - - if(b2x) { SPSR |= (1<>8); writeByte(w&0xFF); } - - static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPDR=b; shouldWait(true); } - static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPDR=b; shouldWait(true); wait(); } - static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPDR=b; shouldWait(true); } - - template inline static void writeBit(uint8_t b) { - SPCR &= ~(1 << SPE); - if(b & (1 << BIT)) { - FastPin<_DATA_PIN>::hi(); - } else { - FastPin<_DATA_PIN>::lo(); - } - - FastPin<_CLOCK_PIN>::hi(); - FastPin<_CLOCK_PIN>::lo(); - SPCR |= 1 << SPE; - shouldWait(false); - } - - void select() { if(m_pSelect != NULL) { m_pSelect->select(); } } // FastPin<_SELECT_PIN>::hi(); } - void release() { if(m_pSelect != NULL) { m_pSelect->release(); } } // FastPin<_SELECT_PIN>::lo(); } - - static void writeBytesValueRaw(uint8_t value, int len) { - while(len--) { writeByte(value); } - } - - void writeBytesValue(uint8_t value, int len) { - //setSPIRate(); - select(); - while(len--) { - writeByte(value); - } - release(); - } - - // Write a block of n uint8_ts out - template void writeBytes(register uint8_t *data, int len) { - //setSPIRate(); - uint8_t *end = data + len; - select(); - while(data != end) { - // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM) - writeByte(D::adjust(*data++)); delaycycles<3>(); - } - release(); - } - - void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } - - // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template - // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping - template void writePixels(PixelController pixels) { - //setSPIRate(); - int len = pixels.mLen; - - select(); - while(pixels.has(1)) { - if(FLAGS & FLAG_START_BIT) { - writeBit<0>(1); - writeBytePostWait(D::adjust(pixels.loadAndScale0())); - writeBytePostWait(D::adjust(pixels.loadAndScale1())); - writeBytePostWait(D::adjust(pixels.loadAndScale2())); - } else { - writeByte(D::adjust(pixels.loadAndScale0())); - writeByte(D::adjust(pixels.loadAndScale1())); - writeByte(D::adjust(pixels.loadAndScale2())); - } - - pixels.advanceData(); - pixels.stepDithering(); - } - D::postBlock(len); - release(); - } -}; -#endif - -#else -// #define FORCE_SOFTWARE_SPI -#endif - -#endif diff --git a/fastspi_types.h b/fastspi_types.h new file mode 100644 index 00000000..e0de6de3 --- /dev/null +++ b/fastspi_types.h @@ -0,0 +1,37 @@ +#ifndef __INC_FASTSPI_TYPES_H +#define __INC_FASTSPI_TYPES_H + +// Some helper macros for getting at mis-ordered byte values +#define SPI_B0 (RGB_BYTE0(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) +#define SPI_B1 (RGB_BYTE1(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) +#define SPI_B2 (RGB_BYTE2(RGB_ORDER) + (MASK_SKIP_BITS & SKIP)) +#define SPI_ADVANCE (3 + (MASK_SKIP_BITS & SKIP)) + +/// Some of the SPI controllers will need to perform a transform on each byte before doing +/// anyting with it. Creating a class of this form and passing it in as a template parameter to +/// writeBytes/writeBytes3 below will ensure that the body of this method will get called on every +/// byte worked on. Recommendation, make the adjust method aggressively inlined. +/// +/// TODO: Convinience macro for building these +class DATA_NOP { +public: + static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data) { return data; } + static __attribute__((always_inline)) inline uint8_t adjust(register uint8_t data, register uint8_t scale) { return scale8(data, scale); } + static __attribute__((always_inline)) inline void postBlock(int len) {} +}; + +#define FLAG_START_BIT 0x80 +#define MASK_SKIP_BITS 0x3F + +// Clock speed dividers +#define SPEED_DIV_2 2 +#define SPEED_DIV_4 4 +#define SPEED_DIV_8 8 +#define SPEED_DIV_16 16 +#define SPEED_DIV_32 32 +#define SPEED_DIV_64 64 +#define SPEED_DIV_128 128 + +#define MAX_DATA_RATE 0 + +#endif diff --git a/hsv2rgb.cpp b/hsv2rgb.cpp index 0844d1f2..203d1db6 100644 --- a/hsv2rgb.cpp +++ b/hsv2rgb.cpp @@ -1,7 +1,6 @@ #include -#include "lib8tion.h" -#include "hsv2rgb.h" +#include "FastLED.h" // Functions to convert HSV colors to RGB colors. // @@ -71,29 +70,29 @@ void hsv2rgb_raw_C (const struct CHSV & hsv, struct CRGB & rgb) // Convert hue, saturation and brightness ( HSV/HSB ) to RGB // "Dimming" is used on saturation and brightness to make // the output more visually linear. - + // Apply dimming curves uint8_t value = APPLY_DIMMING( hsv.val); uint8_t saturation = hsv.sat; - + // The brightness floor is minimum number that all of // R, G, and B will be set to. uint8_t invsat = APPLY_DIMMING( 255 - saturation); uint8_t brightness_floor = (value * invsat) / 256; - + // The color amplitude is the maximum amount of R, G, and B // that will be added on top of the brightness_floor to // create the specific hue desired. uint8_t color_amplitude = value - brightness_floor; - + // Figure out which section of the hue wheel we're in, // and how far offset we are withing that section uint8_t section = hsv.hue / HSV_SECTION_3; // 0..2 uint8_t offset = hsv.hue % HSV_SECTION_3; // 0..63 - + uint8_t rampup = offset; // 0..63 uint8_t rampdown = (HSV_SECTION_3 - 1) - offset; // 63..0 - + // We now scale rampup and rampdown to a 0-255 range -- at least // in theory, but here's where architecture-specific decsions // come in to play: @@ -113,25 +112,25 @@ void hsv2rgb_raw_C (const struct CHSV & hsv, struct CRGB & rgb) // faster to NOT multiply the ramp values by four, and just to // divide the resulting product by 64 (instead of 256). // Moral of the story: trust your profiler, not your insticts. - + // Since there's an AVR assembly version elsewhere, we'll // assume what we're on an architecture where any number of // bit shifts has roughly the same cost, and we'll remove the // redundant math at the source level: - + // // scale up to 255 range // //rampup *= 4; // 0..252 // //rampdown *= 4; // 0..252 - + // compute color-amplitude-scaled-down versions of rampup and rampdown uint8_t rampup_amp_adj = (rampup * color_amplitude) / (256 / 4); uint8_t rampdown_amp_adj = (rampdown * color_amplitude) / (256 / 4); - + // add brightness_floor offset to everything uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor; uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor; - - + + if( section ) { if( section == 1) { // section 1: 0x40..0x7F @@ -158,22 +157,22 @@ void hsv2rgb_raw_C (const struct CHSV & hsv, struct CRGB & rgb) void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb) { uint8_t hue, saturation, value; - + hue = hsv.hue; saturation = hsv.sat; value = hsv.val; - + // Saturation more useful the other way around saturation = 255 - saturation; uint8_t invsat = APPLY_DIMMING( saturation ); - + // Apply dimming curves value = APPLY_DIMMING( value ); - + // The brightness floor is minimum number that all of // R, G, and B will be set to, which is value * invsat uint8_t brightness_floor; - + asm volatile( "mul %[value], %[invsat] \n" "mov %[brightness_floor], r1 \n" @@ -182,22 +181,22 @@ void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb) [invsat] "r" (invsat) : "r0", "r1" ); - + // The color amplitude is the maximum amount of R, G, and B // that will be added on top of the brightness_floor to // create the specific hue desired. uint8_t color_amplitude = value - brightness_floor; - + // Figure how far we are offset into the section of the // color wheel that we're in uint8_t offset = hsv.hue & (HSV_SECTION_3 - 1); // 0..63 uint8_t rampup = offset * 4; // 0..252 - - + + // compute color-amplitude-scaled-down versions of rampup and rampdown uint8_t rampup_amp_adj; uint8_t rampdown_amp_adj; - + asm volatile( "mul %[rampup], %[color_amplitude] \n" "mov %[rampup_amp_adj], r1 \n" @@ -210,13 +209,13 @@ void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb) : [color_amplitude] "r" (color_amplitude) : "r0", "r1" ); - - + + // add brightness_floor offset to everything uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor; uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor; - - + + // keep gcc from using "X" as the index register for storing // results back in the return structure. AVR's X register can't // do "std X+q, rnn", but the Y and Z registers can. @@ -224,8 +223,8 @@ void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb) // extra instructions. Simply killing X here seems to help it // try Y or Z first. asm volatile( "" : : : "r26", "r27" ); - - + + if( hue & 0x80 ) { // section 2: 0x80..0xBF rgb.r = rampup_adj_with_floor; @@ -244,7 +243,7 @@ void hsv2rgb_raw_avr(const struct CHSV & hsv, struct CRGB & rgb) rgb.b = brightness_floor; } } - + cleanup_R1(); } // End of AVR asm implementation @@ -288,18 +287,18 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb) // G2: Whether to divide all greens by two. // Depends GREATLY on your particular LEDs const uint8_t G2 = 0; - + // Gscale: what to scale green down by. // Depends GREATLY on your particular LEDs const uint8_t Gscale = 0; - + uint8_t hue = hsv.hue; uint8_t sat = hsv.sat; uint8_t val = hsv.val; - + uint8_t offset = hue & 0x1F; // 0..31 - + // offset8 = offset * 8 uint8_t offset8 = offset; { @@ -309,11 +308,11 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb) asm volatile(""); offset8 <<= 1; } - + uint8_t third = scale8( offset8, (256 / 3)); - + uint8_t r, g, b; - + if( ! (hue & 0x80) ) { // 0XX if( ! (hue & 0x40) ) { @@ -417,12 +416,12 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb) } } } - + // This is one of the good places to scale the green down, // although the client can scale green down as well. if( G2 ) g = g >> 1; if( Gscale ) g = scale8_video_LEAVING_R1_DIRTY( g, Gscale); - + // Scale down colors if we're desaturated at all // and add the brightness_floor to r, g, and b. if( sat != 255 ) { @@ -431,7 +430,7 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb) uint8_t desat = 255 - sat; desat = scale8( desat, desat); - + uint8_t brightness_floor = desat; r += brightness_floor; g += brightness_floor; @@ -440,11 +439,11 @@ void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb) // Now scale everything down if we're at value < 255. if( val != 255 ) { - + val = scale8_video_LEAVING_R1_DIRTY( val, val); nscale8x3_video( r, g, b, val); } - + // Here we have the old AVR "missing std X+n" problem again // It turns out that fixing it winds up costing more than // not fixing it. diff --git a/led_sysdefs.h b/led_sysdefs.h index e16ce2db..29bced42 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -2,91 +2,21 @@ #define __INC_LED_SYSDEFS_H #if defined(__MK20DX128__) || defined(__MK20DX256__) - -#define FASTLED_TEENSY3 -#define FASTLED_ARM -#define FASTLED_ACCURATE_CLOCK -#ifndef INTERRUPT_THRESHOLD -#define INTERRUPT_THRESHOLD 1 -#endif -#if (F_CPU == 96000000) -#define CLK_DBL 1 -#endif - +// Include k20/T3 headers +#include "platforms/arm/k20/led_sysdefs_arm_k20.h" #elif defined(__SAM3X8E__) - -#define FASTLED_ARM - -// Setup DUE timer defines/channels/etc... -#ifndef DUE_TIMER_CHANNEL -#define DUE_TIMER_GROUP 0 -#endif - -#ifndef DUE_TIMER_CHANNEL -#define DUE_TIMER_CHANNEL 0 -#endif - -#define DUE_TIMER ((DUE_TIMER_GROUP==0) ? TC0 : ((DUE_TIMER_GROUP==1) ? TC1 : TC2)) -#define DUE_TIMER_ID (ID_TC0 + (DUE_TIMER_GROUP*3) + DUE_TIMER_CHANNEL) -#define DUE_TIMER_VAL (DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_CV << 1) -#define DUE_TIMER_RUNNING ((DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_SR & TC_SR_CLKSTA) != 0) - +// Include sam/due headers +#include "platforms/arm/sam/led_sysdefs_arm_sam.h" #else - -#define FASTLED_AVR -#define FASTLED_ACCURATE_CLOCK -#ifndef INTERRUPT_THRESHOLD -#define INTERRUPT_THRESHOLD 2 +// AVR platforms +#include "platforms/avr/led_sysdefs_avr.h" #endif -#endif - -#ifndef CLK_DBL -#define CLK_DBL 0 -#endif -#if defined(FASTLED_AVR) || defined(FASTLED_TEENSY3) -#include -#include // for cli/se definitions - -// Define the rgister types -#if defined(ARDUINO) // && ARDUINO < 150 -typedef volatile uint8_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ -typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ -#endif - -#else -// reuseing/abusing cli/sei defs for due -#define cli() __disable_irq(); __disable_fault_irq(); -#define sei() __enable_irq(); __enable_fault_irq(); - -#endif - -#if 0 -#if defined(ARDUINO) && defined(FASTLED_AVR) && ARDUINO >= 157 -#error Arduion versions 1.5.7 and later not yet supported by FastLED for AVR -#endif - -#if defined(ARDUINO) && defined (FASTLED_AVR) && (__GNUC__ == 4) && (__GNUC_MINOR__ > 7) -#error gcc versions 4.8 and above are not yet supported by FastLED for AVR -#endif -#endif // Arduino.h needed for convinience functions digitalPinToPort/BitMask/portOutputRegister and the pinMode methods. #include -// Scaling macro choice -#if defined(LIB8_ATTINY) -# define INLINE_SCALE(B, SCALE) delaycycles<3>() -# warning "No hardware multiply, inline brightness scaling disabled" -#else -# define INLINE_SCALE(B, SCALE) B = scale8_video(B, SCALE) -#endif - #define CLKS_PER_US (F_CPU/1000000) -#ifndef INTERRUPT_THRESHOLD -#define INTERRUPT_THRESHOLD 1 -#endif - #endif diff --git a/lib8tion.h b/lib8tion.h index 4edf7bf3..cdb3980f 100644 --- a/lib8tion.h +++ b/lib8tion.h @@ -1,3 +1,7 @@ +#ifndef __INC_LED_SYSDEFS_H +#error WTH? led_sysdefs needs to be included first +#endif + #ifndef __INC_LIB8TION_H #define __INC_LIB8TION_H @@ -109,7 +113,7 @@ faster and five times smaller than Arduino's built-in generic 32-bit sqrt routine. sqrt16( uint16_t x ) == sqrt( x) - + - Dimming and brightening functions for 8-bit light values. dim8_video( x) == scale8_video( x, x) @@ -145,7 +149,7 @@ Sine wave beat generators can specify a low and high range for the output. Sawtooth wave beat generators always range 0-255 or 0-65535. - beatsin8( BPM, low8, high8) + beatsin8( BPM, low8, high8) = (sine(beatphase) * (high8-low8)) + low8 beatsin16( BPM, low16, high16) = (sine(beatphase) * (high16-low16)) + low16 @@ -1679,16 +1683,16 @@ LIB8STATIC uint8_t sqrt16(uint16_t x) if( x <= 1) { return x; } - + uint8_t low = 1; // lower bound uint8_t hi, mid; - + if( x > 7904) { hi = 255; } else { hi = (x >> 5) + 8; // initial estimate for upper bound } - + do { mid = (low + hi) >> 1; if ((uint16_t)(mid * mid) > x) { @@ -1700,7 +1704,7 @@ LIB8STATIC uint8_t sqrt16(uint16_t x) low = mid + 1; } } while (hi >= low); - + return low - 1; } @@ -1796,7 +1800,7 @@ LIB8STATIC uint16_t beat16( accum88 beats_per_minute) { // Convert simple 8-bit BPM's to full Q8.8 accum88's if needed if( beats_per_minute < 256) beats_per_minute <<= 8; - + // BPM is 'beats per minute', or 'beats per 60000ms'. // To avoid using the (slower) division operator, we // want to convert 'beats per 60000ms' to 'beats per 65536ms', diff --git a/octows2811_controller.h b/octows2811_controller.h deleted file mode 100644 index dd6c0b92..00000000 --- a/octows2811_controller.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef __INC_OCTOWS2811_CONTROLLER_H -#define __INC_OCTOWS2811_CONTROLLER_H - -#ifdef USE_OCTOWS2811 - -// #include "OctoWS2811.h" - -template -class COctoWS2811Controller : public CLEDController { - OctoWS2811 *pocto; - uint8_t *drawbuffer,*framebuffer; - - void _init(int nLeds) { - if(pocto == NULL) { - drawbuffer = (uint8_t*)malloc(nLeds * 8 * 3); - framebuffer = (uint8_t*)malloc(nLeds * 8 * 3); - switch(RGB_ORDER) { - case RGB: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RGB); break; - case RBG: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RBG); break; - case GBR: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_GBR); break; - case GRB: - default: - pocto = new OctoWS2811(nLeds, framebuffer,drawbuffer, WS2811_GRB); break; - } - pocto->begin(); - } - } -public: - COctoWS2811Controller() { pocto = NULL; } - - - 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 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() ); - - uint8_t *pData = drawbuffer; - while(nLeds--) { - Lines b; - - for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale0(i); } - transpose8x1_MSB(b.bytes,pData); pData += 8; - for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale1(i); } - transpose8x1_MSB(b.bytes,pData); pData += 8; - for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale2(i); } - transpose8x1_MSB(b.bytes,pData); pData += 8; - pixels.stepDithering(); - pixels.advanceData(); - } - - pocto->show(); - } -}; - -#endif - -#endif diff --git a/platforms.h b/platforms.h new file mode 100644 index 00000000..9f1c7579 --- /dev/null +++ b/platforms.h @@ -0,0 +1,15 @@ +#ifndef __INC_PLATFORMS_H +#define __INC_PLATFORMS_H + +#if defined(__MK20DX128__) || defined(__MK20DX256__) +// Include k20/T3 headers +#include "platforms/arm/k20/fastled_arm_k20.h" +#elif defined(__SAM3X8E__) +// Include sam/due headers +#include "platforms/arm/sam/fastled_arm_sam.h" +#else +// AVR platforms +#include "platforms/avr/fastled_avr.h" +#endif + +#endif diff --git a/platforms/arm/k20/clockless_arm_k20.h b/platforms/arm/k20/clockless_arm_k20.h new file mode 100644 index 00000000..d96c9bb2 --- /dev/null +++ b/platforms/arm/k20/clockless_arm_k20.h @@ -0,0 +1,130 @@ +#ifndef __INC_CLOCKLESS_ARM_K20_H +#define __INC_CLOCKLESS_ARM_K20_H + +// Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 +// See clockless.h for detailed info on how the template parameters are used. +#if defined(FASTLED_TEENSY3) + +template +class ClocklessController : public CLEDController { + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait mWait; +public: + virtual void init() { + FastPin::setOutput(); + mPinMask = FastPin::mask(); + mPort = FastPin::port(); + } + + 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 pixels(rgbdata, nLeds, scale, getDither()); + + mWait.wait(); + showRGBInternal(pixels); + mWait.mark(); + } + + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + PixelController 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 pixels(rgbdata, nLeds, scale, getDither()); + mWait.wait(); + showRGBInternal(pixels); + mWait.mark(); + } +#endif + + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) { + for(register uint32_t i = BITS-1; i > 0; i--) { + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + FastPin::fastset(port, hi); + if(b&0x80) { + while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); + FastPin::fastset(port, lo); + } else { + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); + FastPin::fastset(port, lo); + } + b <<= 1; + } + + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + FastPin::fastset(port, hi); + + if(b&0x80) { + while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); + FastPin::fastset(port, lo); + } else { + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); + FastPin::fastset(port, lo); + } + } + + // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then + // gcc will use register Y for the this pointer. + static uint32_t showRGBInternal(PixelController & pixels) { + // Get access to the clock + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + ARM_DWT_CYCCNT = 0; + + register data_ptr_t port = FastPin::port(); + register data_t hi = *port | FastPin::mask();; + register data_t lo = *port & ~FastPin::mask();; + *port = lo; + + // Setup the pixel controller and load/scale the first byte + pixels.preStepFirstByteDithering(); + register uint8_t b = pixels.loadAndScale0(); + + cli(); + uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + + while(pixels.has(1)) { + pixels.stepDithering(); + cli(); + // if interrupts took longer than 45µs, punt on the current frame + if(ARM_DWT_CYCCNT > next_mark) { + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + } + + // 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(); + sei(); + }; + + return ARM_DWT_CYCCNT; + } +}; +#endif + +#endif diff --git a/platforms/arm/k20/clockless_block_arm_k20.h b/platforms/arm/k20/clockless_block_arm_k20.h new file mode 100644 index 00000000..63dc5030 --- /dev/null +++ b/platforms/arm/k20/clockless_block_arm_k20.h @@ -0,0 +1,344 @@ +#ifndef __INC_BLOCK_CLOCKLESS_ARM_K20_H +#define __INC_BLOCK_CLOCKLESS_ARM_K20_H + +// Definition for a single channel clockless controller for the k20 family of chips, like that used in the teensy 3.0/3.1 +// See clockless.h for detailed info on how the template parameters are used. +#if defined(FASTLED_TEENSY3) +#define HAS_BLOCKLESS 1 + +#define PORTC_FIRST_PIN 15 +#define PORTD_FIRST_PIN 2 +#define HAS_PORTDC 1 + +#define PORT_MASK (((1< +class InlineBlockClocklessController : public CLEDController { + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait mWait; +public: + virtual void init() { + if(FIRST_PIN == PORTC_FIRST_PIN) { // PORTC + switch(LANES) { + case 12: FastPin<30>::setOutput(); + case 11: FastPin<29>::setOutput(); + case 10: FastPin<27>::setOutput(); + case 9: FastPin<28>::setOutput(); + case 8: FastPin<12>::setOutput(); + case 7: FastPin<11>::setOutput(); + case 6: FastPin<13>::setOutput(); + case 5: FastPin<10>::setOutput(); + case 4: FastPin<9>::setOutput(); + case 3: FastPin<23>::setOutput(); + case 2: FastPin<22>::setOutput(); + case 1: FastPin<15>::setOutput(); + } + } else if(FIRST_PIN == PORTD_FIRST_PIN) { // PORTD + switch(LANES) { + 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(); + } + } + mPinMask = FastPin::mask(); + mPort = FastPin::port(); + } + + 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 pixels(rgbdata,nLeds, scale, getDither() ); + mWait.wait(); + showRGBInternal(pixels,nLeds); + mWait.mark(); + } + + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + MultiPixelController 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) { + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); + mWait.wait(); + showRGBInternal(pixels,nLeds); + mWait.mark(); + } +#endif + + + typedef union { + uint8_t bytes[16]; + uint16_t shorts[8]; + uint32_t raw[4]; + } Lines; + + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { + register Lines b2; + if(LANES>8) { + transpose8<1,2>(b.bytes,b2.bytes); + transpose8<1,2>(b.bytes+8,b2.bytes+1); + } else { + transpose8x1(b.bytes,b2.bytes); + } + register uint8_t d = pixels.template getd(pixels); + register uint8_t scale = pixels.template getscale(pixels); + + for(register uint32_t i = 0; i < (LANES/2); i++) { + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; + *FastPin::sport() = PORT_MASK; + + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); + if(LANES>8) { + *FastPin::cport() = ((~b2.shorts[i]) & PORT_MASK); + } else { + *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); + } + + while((next_mark - ARM_DWT_CYCCNT) > (T3)); + *FastPin::cport() = PORT_MASK; + + b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); + b.bytes[i+(LANES/2)] = pixels.template loadAndScale(pixels,i,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(pixels,LANES-1,d,scale); + } + + for(register uint32_t i = LANES/2; i < 8; i++) { + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; + *FastPin::sport() = PORT_MASK; + + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); + if(LANES>8) { + *FastPin::cport() = ((~b2.shorts[i]) & PORT_MASK); + } else { + *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); + } + + while((next_mark - ARM_DWT_CYCCNT) > (T3)); + *FastPin::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 &allpixels, int nLeds) { + // Get access to the clock + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + ARM_DWT_CYCCNT = 0; + + // Setup the pixel controller and load/scale the first byte + allpixels.preStepFirstByteDithering(); + register Lines b0; + + allpixels.preStepFirstByteDithering(); + 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--) { + cli(); + // if interrupts took longer than 45µs, punt on the current frame + if(ARM_DWT_CYCCNT > next_mark) { + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + } + allpixels.stepDithering(); + + // Write first byte, read next byte + writeBits<8+XTRA0,1>(next_mark, b0, allpixels); + + // Write second byte, read 3rd byte + writeBits<8+XTRA0,2>(next_mark, b0, allpixels); + allpixels.advanceData(); + + // Write third byte + writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + sei(); + }; + + return ARM_DWT_CYCCNT; + } +}; + +#define DLANES (MIN(__LANES,16)) +#define PMASK ((1<<(DLANES))-1) +#define PMASK_HI (PMASK>>8 & 0xFF) +#define PMASK_LO (PMASK & 0xFF) + +template +class SixteenWayInlineBlockClocklessController : public CLEDController { + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait 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 pixels(rgbdata,nLeds, scale, getDither() ); + mWait.wait(); + showRGBInternal(pixels,nLeds); + mWait.mark(); + } + + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + MultiPixelController 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) { + MultiPixelController pixels(rgbdata,nLeds, scale, getDither() ); + mWait.wait(); + showRGBInternal(pixels,nLeds); + mWait.mark(); + } +#endif + + + typedef union { + uint8_t bytes[16]; + uint16_t shorts[8]; + uint32_t raw[4]; + } Lines; + + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &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(pixels); + register uint8_t scale = pixels.template getscale(pixels); + + for(register uint32_t i = 0; (i < DLANES) && (i < 8); i++) { + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; + *FastPin::sport() = PMASK_LO; + *FastPin::sport() = PMASK_HI; + + while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); + *FastPin::cport() = ((~b2.bytes[7-i]) & PMASK_LO); + *FastPin::cport() = ((~b2.bytes[15-i]) & PMASK_HI); + + while((next_mark - ARM_DWT_CYCCNT) > (T3)); + *FastPin::cport() = PMASK_LO; + *FastPin::cport() = PMASK_HI; + + b.bytes[i] = pixels.template loadAndScale(pixels,i,d,scale); + if(DLANES==16 || (DLANES>8 && ((i+8) < DLANES))) { + b.bytes[i+8] = pixels.template loadAndScale(pixels,i+8,d,scale); + } + } + } + + + + // 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 &allpixels, int nLeds) { + // Get access to the clock + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + ARM_DWT_CYCCNT = 0; + + // Setup the pixel controller and load/scale the first byte + allpixels.preStepFirstByteDithering(); + register Lines b0; + + allpixels.preStepFirstByteDithering(); + for(int i = 0; i < DLANES; i++) { + b0.bytes[i] = allpixels.loadAndScale0(i); + } + + cli(); + uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + + while(nLeds--) { + allpixels.stepDithering(); + cli(); + // if interrupts took longer than 45µs, punt on the current frame + if(ARM_DWT_CYCCNT > next_mark) { + if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + } + // Write first byte, read next byte + writeBits<8+XTRA0,1>(next_mark, b0, allpixels); + + // Write second byte, read 3rd byte + writeBits<8+XTRA0,2>(next_mark, b0, allpixels); + allpixels.advanceData(); + + // Write third byte + writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + sei(); + }; + + return ARM_DWT_CYCCNT; + } +}; +#endif + +#endif diff --git a/platforms/arm/k20/fastled_arm_k20.h b/platforms/arm/k20/fastled_arm_k20.h new file mode 100644 index 00000000..48565ec5 --- /dev/null +++ b/platforms/arm/k20/fastled_arm_k20.h @@ -0,0 +1,14 @@ +#ifndef __INC_FASTLED_ARM_K20_H +#define __INC_FASTLED_ARM_K20_H + +// Include the k20 headers +#include "bitswap.h" +#include "delay.h" +#include "fastpin_arm_k20.h" +#include "fastspi_arm_k20.h" +#include "octows2811_controller.h" +#include "smartmatrix_t3.h" +#include "clockless_arm_k20.h" +#include "clockless_block_arm_k20.h" + +#endif diff --git a/platforms/arm/k20/fastpin_arm_k20.h b/platforms/arm/k20/fastpin_arm_k20.h new file mode 100644 index 00000000..edbbd5b9 --- /dev/null +++ b/platforms/arm/k20/fastpin_arm_k20.h @@ -0,0 +1,118 @@ +#ifndef __FASTPIN_ARM_K20_H +#define __FASTPIN_ARM_K20_H + +#if defined(FORCE_SOFTWARE_PINS) +#warning "Software pin support forced, pin access will be sloightly slower." +#define NO_HARDWARE_PIN_SUPPORT +#undef HAS_HARDWARE_PIN_SUPPORT + +#else + + +/// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this +/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found +/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. +/// The registers are data output, set output, clear output, toggle output, input, and direction +template class _ARMPIN { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } + inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } + inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { _PTOR::r() = _MASK; } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } + inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } + inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } + inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } + inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } + inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } +}; + +/// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC +/// does a poor job of optimizing around these accesses so they are not being used just yet. +template class _ARMPIN_BITBAND { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } + inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } + inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { *_PTOR::template rx<_BIT>() = 1; } + + 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)) { *_PDOR::template rx<_BIT>() = val; } + + inline static port_t hival() __attribute__ ((always_inline)) { return 1; } + inline static port_t loval() __attribute__ ((always_inline)) { return 0; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } + inline static port_t mask() __attribute__ ((always_inline)) { return 1; } +}; + +// Macros for k20 pin access/definition +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) + +#define _R(T) struct __gen_struct_ ## T +#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } \ + template static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } }; +#define _IO32(L) _RD32(GPIO ## L ## _PDOR); _RD32(GPIO ## L ## _PSOR); _RD32(GPIO ## L ## _PCOR); _RD32(GPIO ## L ## _PTOR); _RD32(GPIO ## L ## _PDIR); _RD32(GPIO ## L ## _PDDR); + +#define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin : public _ARMPIN {}; \ + template<> class FastPinBB : public _ARMPIN_BITBAND {}; + +// Actual pin definitions +#if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY) + +_IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); + +#define MAX_PIN 33 +_DEFPIN_ARM(0, 16, B); _DEFPIN_ARM(1, 17, B); _DEFPIN_ARM(2, 0, D); _DEFPIN_ARM(3, 12, A); +_DEFPIN_ARM(4, 13, A); _DEFPIN_ARM(5, 7, D); _DEFPIN_ARM(6, 4, D); _DEFPIN_ARM(7, 2, D); +_DEFPIN_ARM(8, 3, D); _DEFPIN_ARM(9, 3, C); _DEFPIN_ARM(10, 4, C); _DEFPIN_ARM(11, 6, C); +_DEFPIN_ARM(12, 7, C); _DEFPIN_ARM(13, 5, C); _DEFPIN_ARM(14, 1, D); _DEFPIN_ARM(15, 0, C); +_DEFPIN_ARM(16, 0, B); _DEFPIN_ARM(17, 1, B); _DEFPIN_ARM(18, 3, B); _DEFPIN_ARM(19, 2, B); +_DEFPIN_ARM(20, 5, D); _DEFPIN_ARM(21, 6, D); _DEFPIN_ARM(22, 1, C); _DEFPIN_ARM(23, 2, C); +_DEFPIN_ARM(24, 5, A); _DEFPIN_ARM(25, 19, B); _DEFPIN_ARM(26, 1, E); _DEFPIN_ARM(27, 9, C); +_DEFPIN_ARM(28, 8, C); _DEFPIN_ARM(29, 10, C); _DEFPIN_ARM(30, 11, C); _DEFPIN_ARM(31, 0, E); +_DEFPIN_ARM(32, 18, B); _DEFPIN_ARM(33, 4, A); + +#define SPI_DATA 11 +#define SPI_CLOCK 13 +#define SPI1 (*(SPI_t *)0x4002D000) + +#if defined(__MK20DX256__) +#define SPI2_DATA 7 +#define SPI2_CLOCK 14 +#endif + +#define FASTLED_TEENSY3 +#define ARM_HARDWARE_SPI +#define HAS_HARDWARE_PIN_SUPPORT +#endif + +#endif // FORCE_SOFTWARE_PINS + +#endif // __INC_FASTPIN_ARM_K20 diff --git a/platforms/arm/k20/fastspi_arm_k20.h b/platforms/arm/k20/fastspi_arm_k20.h new file mode 100644 index 00000000..ad9598ae --- /dev/null +++ b/platforms/arm/k20/fastspi_arm_k20.h @@ -0,0 +1,375 @@ +#ifndef __INC_FASTSPI_ARM_H +#define __INC_FASTSPI_ARM_H + + +#if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY) + +// Version 1.20 renamed SPI_t to KINETISK_SPI_t +#if TEENSYDUINO >= 120 +#define SPI_t KINETISK_SPI_t +#endif + +#ifndef SPI_PUSHR_CONT +#define SPI_PUSHR_CONT SPIX.PUSHR_CONT +#define SPI_PUSHR_CTAS(X) SPIX.PUSHR_CTAS(X) +#define SPI_PUSHR_EOQ SPIX.PUSHR_EOQ +#define SPI_PUSHR_CTCNT SPIX.PUSHR_CTCNT +#define SPI_PUSHR_PCS(X) SPIX.PUSHR_PCS(X) +#endif + +// Template function that, on compilation, expands to a constant representing the highest bit set in a byte. Right now, +// if no bits are set (value is 0), it returns 0, which is also the value returned if the lowest bit is the only bit +// set (the zero-th bit). Unclear if I will want this to change at some point. +template class BitWork { + public: + static int highestBit() __attribute__((always_inline)) { return (VAL & 1 << BIT) ? BIT : BitWork::highestBit(); } +}; +template class BitWork { + public: + static int highestBit() __attribute__((always_inline)) { return 0; } +}; + +#define MAX(A, B) (( (A) > (B) ) ? (A) : (B)) + +#define USE_CONT 0 + +// Templated function to translate a clock divider value into the prescalar, scalar, and clock doubling setting for the world. +template void getScalars(uint32_t & preScalar, uint32_t & scalar, uint32_t & dbl) { + switch(VAL) { + // Handle the dbl clock cases + case 0: case 1: + case 2: preScalar = 0; scalar = 0; dbl = 1; break; + case 3: preScalar = 1; scalar = 0; dbl = 1; break; + case 5: preScalar = 2; scalar = 0; dbl = 1; break; + case 7: preScalar = 3; scalar = 0; dbl = 1; break; + + // Handle the scalar value 6 cases (since it's not a power of two, it won't get caught + // below) + case 9: preScalar = 1; scalar = 2; dbl = 1; break; + case 18: case 19: preScalar = 1; scalar = 2; dbl = 0; break; + + case 15: preScalar = 2; scalar = 2; dbl = 1; break; + case 30: case 31: preScalar = 2; scalar = 2; dbl = 0; break; + + case 21: case 22: case 23: preScalar = 3; scalar = 2; dbl = 1; break; + case 42: case 43: case 44: case 45: case 46: case 47: preScalar = 3; scalar = 2; dbl = 0; break; + default: { + int p2 = BitWork::highestBit(); + int p3 = BitWork::highestBit(); + int p5 = BitWork::highestBit(); + int p7 = BitWork::highestBit(); + + int w2 = 2 * (1 << p2); + int w3 = (VAL/3) > 0 ? 3 * (1 << p3) : 0; + int w5 = (VAL/5) > 0 ? 5 * (1 << p5) : 0; + int w7 = (VAL/7) > 0 ? 7 * (1 << p7) : 0; + + int maxval = MAX(MAX(w2, w3), MAX(w5, w7)); + + if(w2 == maxval) { preScalar = 0; scalar = p2; } + else if(w3 == maxval) { preScalar = 1; scalar = p3; } + else if(w5 == maxval) { preScalar = 2; scalar = p5; } + else if(w7 == maxval) { preScalar = 3; scalar = p7; } + + dbl = 0; + if(scalar == 0) { dbl = 1; } + else if(scalar < 3) { scalar--; } + } + } + return; +} + +#define SPIX (*(SPI_t*)pSPIX) + +template +class ARMHardwareSPIOutput { + Selectable *m_pSelect; + + // Borrowed from the teensy3 SPSR emulation code + static inline void enable_pins(void) __attribute__((always_inline)) { + //serial_print("enable_pins\n"); + if(_DATA_PIN == 11) { + CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); + CORE_PIN12_CONFIG = PORT_PCR_MUX(2); + CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); + } else if(_DATA_PIN == 7) { + CORE_PIN7_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); + CORE_PIN8_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); + CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2); + } + } + + // Borrowed from the teensy3 SPSR emulation code + static inline void disable_pins(void) __attribute__((always_inline)) { + //serial_print("disable_pins\n"); + if(_DATA_PIN == 11) { + CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); + CORE_PIN12_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); + CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); + } else if(_DATA_PIN == 7) { + CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); + CORE_PIN8_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); + CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); + } +} +public: + ARMHardwareSPIOutput() { m_pSelect = NULL; } + ARMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } + + static inline void update_ctar0(uint32_t ctar) __attribute__((always_inline)) { + if (SPIX.CTAR0 == ctar) return; + uint32_t mcr = SPIX.MCR; + if (mcr & SPI_MCR_MDIS) { + SPIX.CTAR0 = ctar; + } else { + SPIX.MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT; + SPIX.CTAR0 = ctar; + + SPIX.MCR = mcr; + } + } + + static inline void update_ctar1(uint32_t ctar) __attribute__((always_inline)) { + if (SPIX.CTAR1 == ctar) return; + uint32_t mcr = SPIX.MCR; + if (mcr & SPI_MCR_MDIS) { + SPIX.CTAR1 = ctar; + } else { + SPIX.MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT; + SPIX.CTAR1 = ctar; + SPIX.MCR = mcr; + + } + } + + void setSPIRate() { + // Configure CTAR0, defaulting to 8 bits and CTAR1, defaulting to 16 bits + uint32_t _PBR = 0; + uint32_t _BR = 0; + uint32_t _CSSCK = 0; + uint32_t _DBR = 0; + + // if(_SPI_CLOCK_DIVIDER >= 256) { _PBR = 0; _BR = _CSSCK = 7; _DBR = 0; } // osc/256 + // else if(_SPI_CLOCK_DIVIDER >= 128) { _PBR = 0; _BR = _CSSCK = 6; _DBR = 0; } // osc/128 + // else if(_SPI_CLOCK_DIVIDER >= 64) { _PBR = 0; _BR = _CSSCK = 5; _DBR = 0; } // osc/64 + // else if(_SPI_CLOCK_DIVIDER >= 32) { _PBR = 0; _BR = _CSSCK = 4; _DBR = 0; } // osc/32 + // else if(_SPI_CLOCK_DIVIDER >= 16) { _PBR = 0; _BR = _CSSCK = 3; _DBR = 0; } // osc/16 + // else if(_SPI_CLOCK_DIVIDER >= 8) { _PBR = 0; _BR = _CSSCK = 1; _DBR = 0; } // osc/8 + // else if(_SPI_CLOCK_DIVIDER >= 7) { _PBR = 3; _BR = _CSSCK = 0; _DBR = 1; } // osc/7 + // else if(_SPI_CLOCK_DIVIDER >= 5) { _PBR = 2; _BR = _CSSCK = 0; _DBR = 1; } // osc/5 + // else if(_SPI_CLOCK_DIVIDER >= 4) { _PBR = 0; _BR = _CSSCK = 0; _DBR = 0; } // osc/4 + // else if(_SPI_CLOCK_DIVIDER >= 3) { _PBR = 1; _BR = _CSSCK = 0; _DBR = 1; } // osc/3 + // else { _PBR = 0; _BR = _CSSCK = 0; _DBR = 1; } // osc/2 + + getScalars<_SPI_CLOCK_DIVIDER>(_PBR, _BR, _DBR); + _CSSCK = _BR; + + uint32_t ctar0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(_PBR) | SPI_CTAR_BR(_BR) | SPI_CTAR_CSSCK(_CSSCK); + uint32_t ctar1 = SPI_CTAR_FMSZ(15) | SPI_CTAR_PBR(_PBR) | SPI_CTAR_BR(_BR) | SPI_CTAR_CSSCK(_CSSCK); + +#if USE_CONT == 1 + ctar0 |= SPI_CTAR_CPHA | SPI_CTAR_CPOL; + ctar1 |= SPI_CTAR_CPHA | SPI_CTAR_CPOL; +#endif + + if(_DBR) { + ctar0 |= SPI_CTAR_DBR; + ctar1 |= SPI_CTAR_DBR; + } + + update_ctar0(ctar0); + update_ctar1(ctar1); + + } + + void init() { + // set the pins to output + FastPin<_DATA_PIN>::setOutput(); + FastPin<_CLOCK_PIN>::setOutput(); + release(); + + // Enable SPI0 clock + uint32_t sim6 = SIM_SCGC6; + if((SPI_t*)pSPIX == &SPI0) { + if (!(sim6 & SIM_SCGC6_SPI0)) { + //serial_print("init1\n"); + SIM_SCGC6 = sim6 | SIM_SCGC6_SPI0; + SPIX.CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1); + } + } else if((SPI_t*)pSPIX == &SPI1) { + if (!(sim6 & SIM_SCGC6_SPI1)) { + //serial_print("init1\n"); + SIM_SCGC6 = sim6 | SIM_SCGC6_SPI1; + SPIX.CTAR0 = SPI_CTAR_FMSZ(7) | SPI_CTAR_PBR(1) | SPI_CTAR_BR(1); + } + } + setSPIRate(); + + // Configure SPI as the master and enable + SPIX.MCR |= SPI_MCR_MSTR; // | SPI_MCR_CONT_SCKE); + SPIX.MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT); + + enable_pins(); + } + + static void waitFully() __attribute__((always_inline)) { + while( (SPIX.SR & 0xF000) > 0); + while (!(SPIX.SR & SPI_SR_TCF)); + SPIX.SR |= (SPI_SR_TCF | SPI_SR_EOQF); + } + + static bool needwait() __attribute__((always_inline)) { return (SPIX.SR & 0x4000); } + static void wait() __attribute__((always_inline)) { while( (SPIX.SR & 0x4000) ); } + static void wait1() __attribute__((always_inline)) { while( (SPIX.SR & 0xF000) >= 0x2000); } + + enum ECont { CONT, NOCONT }; + enum EWait { PRE, POST, NONE }; + enum ELast { NOTLAST, LAST }; + +#if USE_CONT == 1 + #define CM CONT +#else + #define CM NOCONT +#endif + #define WM PRE + + template class Write { + public: + static void writeWord(uint16_t w) __attribute__((always_inline)) { + if(WAIT_STATE == PRE) { wait(); } + SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) | + ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) | + SPI_PUSHR_CTAS(1) | (w & 0xFFFF); + if(WAIT_STATE == POST) { wait(); } + } + + static void writeByte(uint8_t b) __attribute__((always_inline)) { + if(WAIT_STATE == PRE) { wait(); } + SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) | + ((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) | + SPI_PUSHR_CTAS(0) | (b & 0xFF); + if(WAIT_STATE == POST) { wait(); } + } + }; + + static void writeWord(uint16_t w) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } + static void writeWordNoWait(uint16_t w) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } + + static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); } + static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); wait(); } + static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); } + + static void writeWordCont(uint16_t w) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } + static void writeWordContNoWait(uint16_t w) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); } + + static void writeByteCont(uint8_t b) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); } + static void writeByteContPostWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); wait(); } + static void writeByteContNoWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); } + + // not the most efficient mechanism in the world - but should be enough for sm16716 and friends + template inline static void writeBit(uint8_t b) { + uint32_t ctar1_save = SPIX.CTAR1; + + // Clear out the FMSZ bits, reset them for 1 bit transferd for the start bit + uint32_t ctar1 = (ctar1_save & (~SPI_CTAR_FMSZ(15))) | SPI_CTAR_FMSZ(0); + update_ctar1(ctar1); + + writeWord( (b & (1 << BIT)) != 0); + + update_ctar1(ctar1_save); + } + + void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } + void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } + + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { Write::writeByte(value); } + } + + void writeBytesValue(uint8_t value, int len) { + setSPIRate(); + select(); + while(len--) { + writeByte(value); + } + waitFully(); + release(); + } + + // Write a block of n uint8_ts out + template void writeBytes(register uint8_t *data, int len) { + setSPIRate(); + uint8_t *end = data + len; + select(); + // could be optimized to write 16bit words out instead of 8bit bytes + while(data != end) { + writeByte(D::adjust(*data++)); + } + D::postBlock(len); + waitFully(); + release(); + } + + void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } + + // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template + // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping + template void writePixels(PixelController pixels) { + // setSPIRate(); + select(); + int len = pixels.mLen; + + // Setup the pixel controller + if((FLAGS & FLAG_START_BIT) == 0) { + //If no start bit stupiditiy, write out as many 16-bit blocks as we can + while(pixels.has(2)) { + // Load and write out the first two bytes + if(WM == NONE) { wait1(); } + Write::writeWord(D::adjust(pixels.loadAndScale0()) << 8 | D::adjust(pixels.loadAndScale1())); + + // Load and write out the next two bytes (step dithering, advance data in between since we + // cross pixels here) + Write::writeWord(D::adjust(pixels.loadAndScale2()) << 8 | D::adjust(pixels.stepAdvanceAndLoadAndScale0())); + + // Load and write out the next two bytes + Write::writeWord(D::adjust(pixels.loadAndScale1()) << 8 | D::adjust(pixels.loadAndScale2())); + pixels.stepDithering(); + pixels.advanceData(); + } + + if(pixels.has(1)) { + if(WM == NONE) { wait1(); } + // write out the rest as alternating 16/8-bit blocks (likely to be just one) + Write::writeWord(D::adjust(pixels.loadAndScale0()) << 8 | D::adjust(pixels.loadAndScale1())); + Write::writeByte(D::adjust(pixels.loadAndScale2())); + } + + D::postBlock(len); + waitFully(); + } else if(FLAGS & FLAG_START_BIT) { + uint32_t ctar1_save = SPIX.CTAR1; + + // Clear out the FMSZ bits, reset them for 9 bits transferd for the start bit + uint32_t ctar1 = (ctar1_save & (~SPI_CTAR_FMSZ(15))) | SPI_CTAR_FMSZ(8); + update_ctar1(ctar1); + + while(pixels.has(1)) { + writeWord( 0x100 | D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + pixels.advanceData(); + pixels.stepDithering(); + } + D::postBlock(len); + waitFully(); + + // restore ctar1 + update_ctar1(ctar1_save); + } + release(); + } +}; +#endif + +#endif diff --git a/platforms/arm/k20/led_sysdefs_arm_k20.h b/platforms/arm/k20/led_sysdefs_arm_k20.h new file mode 100644 index 00000000..abed80f9 --- /dev/null +++ b/platforms/arm/k20/led_sysdefs_arm_k20.h @@ -0,0 +1,26 @@ +#ifndef __INC_LED_SYSDEFS_ARM_K20_H +#define __INC_LED_SYSDEFS_ARM_K20_H + +#define FASTLED_TEENSY3 +#define FASTLED_ARM +#define FASTLED_ACCURATE_CLOCK + +#ifndef INTERRUPT_THRESHOLD +#define INTERRUPT_THRESHOLD 1 +#endif + +#if (F_CPU == 96000000) +#define CLK_DBL 1 +#endif + +// Get some system include files +#include +#include // for cli/se definitions + +// Define the rgister types +#if defined(ARDUINO) // && ARDUINO < 150 +typedef volatile uint8_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ +typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ +#endif + +#endif diff --git a/platforms/arm/k20/octows2811_controller.h b/platforms/arm/k20/octows2811_controller.h new file mode 100644 index 00000000..dd6c0b92 --- /dev/null +++ b/platforms/arm/k20/octows2811_controller.h @@ -0,0 +1,91 @@ +#ifndef __INC_OCTOWS2811_CONTROLLER_H +#define __INC_OCTOWS2811_CONTROLLER_H + +#ifdef USE_OCTOWS2811 + +// #include "OctoWS2811.h" + +template +class COctoWS2811Controller : public CLEDController { + OctoWS2811 *pocto; + uint8_t *drawbuffer,*framebuffer; + + void _init(int nLeds) { + if(pocto == NULL) { + drawbuffer = (uint8_t*)malloc(nLeds * 8 * 3); + framebuffer = (uint8_t*)malloc(nLeds * 8 * 3); + switch(RGB_ORDER) { + case RGB: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RGB); break; + case RBG: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_RBG); break; + case GBR: pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, WS2811_GBR); break; + case GRB: + default: + pocto = new OctoWS2811(nLeds, framebuffer,drawbuffer, WS2811_GRB); break; + } + pocto->begin(); + } + } +public: + COctoWS2811Controller() { pocto = NULL; } + + + 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 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() ); + + uint8_t *pData = drawbuffer; + while(nLeds--) { + Lines b; + + for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale0(i); } + transpose8x1_MSB(b.bytes,pData); pData += 8; + for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale1(i); } + transpose8x1_MSB(b.bytes,pData); pData += 8; + for(int i = 0; i < 8; i++) { b.bytes[i] = pixels.loadAndScale2(i); } + transpose8x1_MSB(b.bytes,pData); pData += 8; + pixels.stepDithering(); + pixels.advanceData(); + } + + pocto->show(); + } +}; + +#endif + +#endif diff --git a/platforms/arm/k20/smartmatrix_t3.h b/platforms/arm/k20/smartmatrix_t3.h new file mode 100644 index 00000000..ba77d149 --- /dev/null +++ b/platforms/arm/k20/smartmatrix_t3.h @@ -0,0 +1,79 @@ +#ifndef __INC_SMARTMATRIX_T3_H +#define __INC_SMARTMATRIX_T3_H + +#ifdef SmartMatrix_h +#include + +extern SmartMatrix *pSmartMatrix; + +// note - dmx simple must be included before FastSPI for this code to be enabled +class CSmartMatrixController : public CLEDController { + SmartMatrix matrix; + +public: + // initialize the LED controller + virtual void init() { + // Initialize 32x32 LED Matrix + matrix.begin(); + matrix.setBrightness(255); + matrix.setColorCorrection(ccNone); + + // Clear screen + clearLeds(0); + matrix.swapBuffers(); + pSmartMatrix = &matrix; + } + + // 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 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(); + } + 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 pixels(data, nLeds, scale, getDither()); +#ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER + rgb24 *md = matrix.getRealBackBuffer(); +#else + rgb24 *md = matrix.backBuffer(); +#endif + while(nLeds--) { + md->red = pixels.loadAndScale0(); + md->green = pixels.loadAndScale1(); + md->blue = pixels.loadAndScale2(); + md++; + pixels.advanceData(); + pixels.stepDithering(); + } + matrix.swapBuffers(); +#ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER + matrix.setBackBuffer((rgb24*)data); +#endif + } + +#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 +}; + +#endif + +#endif diff --git a/platforms/arm/sam/clockless_arm_sam.h b/platforms/arm/sam/clockless_arm_sam.h new file mode 100644 index 00000000..6924cc9d --- /dev/null +++ b/platforms/arm/sam/clockless_arm_sam.h @@ -0,0 +1,134 @@ +#ifndef __INC_CLOCKLESS_ARM_SAM_H +#define __INC_CLOCKLESS_ARM_SAM_H + +// Definition for a single channel clockless controller for the sam family of arm chips, like that used in the due and rfduino +// See clockless.h for detailed info on how the template parameters are used. + +#if defined(__SAM3X8E__) + + +#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) + +template +class ClocklessController : public CLEDController { + typedef typename FastPinBB::port_ptr_t data_ptr_t; + typedef typename FastPinBB::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait mWait; +public: + virtual void init() { + FastPinBB::setOutput(); + mPinMask = FastPinBB::mask(); + mPort = FastPinBB::port(); + } + + 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 pixels(rgbdata, nLeds, scale, getDither()); + mWait.wait(); + showRGBInternal(pixels); + mWait.mark(); + } + + virtual void show(const struct CRGB *rgbdata, int nLeds, CRGB scale) { + PixelController 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 pixels(rgbdata, nLeds, scale, getDither()); + mWait.wait(); + showRGBInternal(pixels); + sei(); + mWait.mark(); + } +#endif + + + template __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; + // while(VAL < (TOTAL*10)) { bShift=true; } + // if(bShift) { next_mark = (VAL-TOTAL); }; + + for(register uint32_t i = BITS; i > 0; i--) { + // wait to start the bit, then set the pin high + while(DUE_TIMER_VAL < next_mark); + next_mark = (DUE_TIMER_VAL+TOTAL); + *port = 1; + + // how long we want to wait next depends on whether or not our bit is set to 1 or 0 + if(b&0x80) { + // we're a 1, wait until there's less than T3 clocks left + while((next_mark - DUE_TIMER_VAL) > (T3)); + } else { + // we're a 0, wait until there's less than (T2+T3+slop) clocks left in this bit + while((next_mark - DUE_TIMER_VAL) > (T2+T3+6+TADJUST+TADJUST)); + } + *port=0; + b <<= 1; + } + } + +#define FORCE_REFERENCE(var) asm volatile( "" : : "r" (var) ) + // 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 & pixels) { + // Setup and start the clock + TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1); + pmc_enable_periph_clk(DUE_TIMER_ID); + TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); + + register data_ptr_t port asm("r7") = FastPinBB::port(); FORCE_REFERENCE(port); + *port = 0; + + // Setup the pixel controller and load/scale the first byte + pixels.preStepFirstByteDithering(); + register uint8_t b = pixels.loadAndScale0(); + + uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); + while(pixels.has(1)) { + pixels.stepDithering(); + + cli(); + if(DUE_TIMER_VAL > next_mark) { + if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; } + } + + writeBits<8+XTRA0>(next_mark, port, b); + + b = pixels.loadAndScale1(); + writeBits<8+XTRA0>(next_mark, port,b); + + b = pixels.loadAndScale2(); + writeBits<8+XTRA0>(next_mark, port,b); + + b = pixels.advanceAndLoadAndScale0(); + sei(); + }; + + TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); + return DUE_TIMER_VAL; + } +}; + +#endif + +#endif diff --git a/platforms/arm/sam/clockless_block_arm_sam.h b/platforms/arm/sam/clockless_block_arm_sam.h new file mode 100644 index 00000000..51eb1b92 --- /dev/null +++ b/platforms/arm/sam/clockless_block_arm_sam.h @@ -0,0 +1,193 @@ + #ifndef __INC_BLOCK_CLOCKLESS_H +#define __INC_BLOCK_CLOCKLESS_H + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point +// is where the line is raised hi. The second pointsnt is where the line is dropped low for a zero. The third point is where the +// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(__SAM3X8E__) +#define PORT_MASK (((1< +class InlineBlockClocklessController : public CLEDController { + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait mWait; +public: + virtual void init() { + if(FIRST_PIN == PORTA_FIRST_PIN) { + switch(LANES) { + case 8: FastPin<31>::setOutput(); + case 7: FastPin<58>::setOutput(); + case 6: FastPin<100>::setOutput(); + case 5: FastPin<59>::setOutput(); + case 4: FastPin<60>::setOutput(); + case 3: FastPin<61>::setOutput(); + case 2: FastPin<68>::setOutput(); + case 1: FastPin<69>::setOutput(); + } + } else if(FIRST_PIN == PORTD_FIRST_PIN) { + switch(LANES) { + case 8: FastPin<11>::setOutput(); + case 7: FastPin<29>::setOutput(); + case 6: FastPin<15>::setOutput(); + case 5: FastPin<14>::setOutput(); + case 4: FastPin<28>::setOutput(); + case 3: FastPin<27>::setOutput(); + case 2: FastPin<26>::setOutput(); + case 1: FastPin<25>::setOutput(); + } + } else if(FIRST_PIN == PORTB_FIRST_PIN) { + switch(LANES) { + case 8: FastPin<97>::setOutput(); + case 7: FastPin<96>::setOutput(); + case 6: FastPin<95>::setOutput(); + case 5: FastPin<94>::setOutput(); + case 4: FastPin<93>::setOutput(); + case 3: FastPin<92>::setOutput(); + case 2: FastPin<91>::setOutput(); + case 1: FastPin<90>::setOutput(); + } + } + mPinMask = FastPin::mask(); + mPort = FastPin::port(); + } + + 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 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 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(rgbdata, nLeds, scale, getDither())); + mWait.mark(); + } +#endif + + template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, MultiPixelController &pixels) { // , register uint32_t & b2) { + register Lines b2; + transpose8x1(b.bytes,b2.bytes); + + register uint8_t d = pixels.template getd(pixels); + register uint8_t scale = pixels.template getscale(pixels); + + for(uint32_t i = 0; (i < LANES) && (i<8); i++) { + while(DUE_TIMER_VAL < next_mark); + next_mark = (DUE_TIMER_VAL+TOTAL); + + *FastPin::sport() = PORT_MASK; + + while((next_mark - DUE_TIMER_VAL) > (T2+T3+6)); + *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; + + while((next_mark - (DUE_TIMER_VAL)) > T3); + *FastPin::cport() = PORT_MASK; + + b3.bytes[i] = pixels.template loadAndScale(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::sport() = PORT_MASK; + + while((next_mark - DUE_TIMER_VAL) > (T2+T3+6)); + *FastPin::cport() = (~b2.bytes[7-i]) & PORT_MASK; + + while((next_mark - DUE_TIMER_VAL) > T3); + *FastPin::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 &allpixels, int nLeds) { + // Serial.println("Entering show"); + // Setup the pixel controller and load/scale the first byte + Lines b0,b1,b2; + + allpixels.preStepFirstByteDithering(); + for(int i = 0; i < LANES; i++) { + b0.bytes[i] = allpixels.loadAndScale0(i); + } + + // Setup and start the clock + TC_Configure(DUE_TIMER,DUE_TIMER_CHANNEL,TC_CMR_TCCLKS_TIMER_CLOCK1); + pmc_enable_periph_clk(DUE_TIMER_ID); + TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); + + cli(); + uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); + while(nLeds--) { + allpixels.stepDithering(); + cli(); + if(DUE_TIMER_VAL > next_mark) { + if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { + sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; + } + } + + // Write first byte, read next byte + writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); + + // Write second byte, read 3rd byte + writeBits<8+XTRA0,2>(next_mark, b1, b2, allpixels); + + allpixels.advanceData(); + // Write third byte + writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + sei(); + } + + return DUE_TIMER_VAL; + } + + +}; + +#endif + +#endif diff --git a/platforms/arm/sam/fastled_arm_sam.h b/platforms/arm/sam/fastled_arm_sam.h new file mode 100644 index 00000000..51e2f37c --- /dev/null +++ b/platforms/arm/sam/fastled_arm_sam.h @@ -0,0 +1,11 @@ +#ifndef __INC_FASTLED_ARM_SAM_H +#define __INC_FASTLED_ARM_SAM_H + +// Include the sam headers +#include "delay.h" +#include "fastpin_arm_sam.h" +#include "fastspi_arm_sam.h" +#include "clockless_arm_sam.h" +#include "clockless_block_arm_sam.h" + +#endif diff --git a/platforms/arm/sam/fastpin_arm_sam.h b/platforms/arm/sam/fastpin_arm_sam.h new file mode 100644 index 00000000..e1a36990 --- /dev/null +++ b/platforms/arm/sam/fastpin_arm_sam.h @@ -0,0 +1,132 @@ +#ifndef __INC_FASTPIN_ARM_SAM_H +#define __INC_FASTPIN_ARM_SAM_H + +#if defined(FORCE_SOFTWARE_PINS) +#warning "Software pin support forced, pin access will be sloightly slower." +#define NO_HARDWARE_PIN_SUPPORT +#undef HAS_HARDWARE_PIN_SUPPORT + +#else + + +/// Template definition for arduino due style ARM pins, providing direct access to the various GPIO registers. Note that this +/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found +/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. +/// The registers are data register, set output register, clear output register, set data direction register +template class _DUEPIN { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } + inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } + inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { _PDOR::r() ^= _MASK; } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } + inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } + inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } + inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_PSOR::r(); } + inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_PCOR::r(); } + inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } +}; + + +/// Template definition for DUE style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC +/// does a poor job of optimizing around these accesses so they are not being used just yet. +template class _DUEPIN_BITBAND { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } + inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } + inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() ^= 1; } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } + inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + inline static port_t hival() __attribute__ ((always_inline)) { return 1; } + inline static port_t loval() __attribute__ ((always_inline)) { return 0; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } + inline static port_t mask() __attribute__ ((always_inline)) { return 1; } +}; + +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) + +#define _R(T) struct __gen_struct_ ## T +#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } \ + template static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } }; +#define DUE_IO32(L) _RD32(REG_PIO ## L ## _ODSR); _RD32(REG_PIO ## L ## _SODR); _RD32(REG_PIO ## L ## _CODR); _RD32(REG_PIO ## L ## _OER); + +#define _DEFPIN_DUE(PIN, BIT, L) template<> class FastPin : public _DUEPIN {}; \ + template<> class FastPinBB : public _DUEPIN_BITBAND {}; + +#if defined(__SAM3X8E__) + +DUE_IO32(A); +DUE_IO32(B); +DUE_IO32(C); +DUE_IO32(D); + +#define MAX_PIN 78 +_DEFPIN_DUE(0, 8, A); _DEFPIN_DUE(1, 9, A); _DEFPIN_DUE(2, 25, B); _DEFPIN_DUE(3, 28, C); +_DEFPIN_DUE(4, 26, C); _DEFPIN_DUE(5, 25, C); _DEFPIN_DUE(6, 24, C); _DEFPIN_DUE(7, 23, C); +_DEFPIN_DUE(8, 22, C); _DEFPIN_DUE(9, 21, C); _DEFPIN_DUE(10, 29, C); _DEFPIN_DUE(11, 7, D); +_DEFPIN_DUE(12, 8, D); _DEFPIN_DUE(13, 27, B); _DEFPIN_DUE(14, 4, D); _DEFPIN_DUE(15, 5, D); +_DEFPIN_DUE(16, 13, A); _DEFPIN_DUE(17, 12, A); _DEFPIN_DUE(18, 11, A); _DEFPIN_DUE(19, 10, A); +_DEFPIN_DUE(20, 12, B); _DEFPIN_DUE(21, 13, B); _DEFPIN_DUE(22, 26, B); _DEFPIN_DUE(23, 14, A); +_DEFPIN_DUE(24, 15, A); _DEFPIN_DUE(25, 0, D); _DEFPIN_DUE(26, 1, D); _DEFPIN_DUE(27, 2, D); +_DEFPIN_DUE(28, 3, D); _DEFPIN_DUE(29, 6, D); _DEFPIN_DUE(30, 9, D); _DEFPIN_DUE(31, 7, A); +_DEFPIN_DUE(32, 10, D); _DEFPIN_DUE(33, 1, C); _DEFPIN_DUE(34, 2, C); _DEFPIN_DUE(35, 3, C); +_DEFPIN_DUE(36, 4, C); _DEFPIN_DUE(37, 5, C); _DEFPIN_DUE(38, 6, C); _DEFPIN_DUE(39, 7, C); +_DEFPIN_DUE(40, 8, C); _DEFPIN_DUE(41, 9, C); _DEFPIN_DUE(42, 19, A); _DEFPIN_DUE(43, 20, A); +_DEFPIN_DUE(44, 19, C); _DEFPIN_DUE(45, 18, C); _DEFPIN_DUE(46, 17, C); _DEFPIN_DUE(47, 16, C); +_DEFPIN_DUE(48, 15, C); _DEFPIN_DUE(49, 14, C); _DEFPIN_DUE(50, 13, C); _DEFPIN_DUE(51, 12, C); +_DEFPIN_DUE(52, 21, B); _DEFPIN_DUE(53, 14, B); _DEFPIN_DUE(54, 16, A); _DEFPIN_DUE(55, 24, A); +_DEFPIN_DUE(56, 23, A); _DEFPIN_DUE(57, 22, A); _DEFPIN_DUE(58, 6, A); _DEFPIN_DUE(59, 4, A); +_DEFPIN_DUE(60, 3, A); _DEFPIN_DUE(61, 2, A); _DEFPIN_DUE(62, 17, B); _DEFPIN_DUE(63, 18, B); +_DEFPIN_DUE(64, 19, B); _DEFPIN_DUE(65, 20, B); _DEFPIN_DUE(66, 15, B); _DEFPIN_DUE(67, 16, B); +_DEFPIN_DUE(68, 1, A); _DEFPIN_DUE(69, 0, A); _DEFPIN_DUE(70, 17, A); _DEFPIN_DUE(71, 18, A); +_DEFPIN_DUE(72, 30, C); _DEFPIN_DUE(73, 21, A); _DEFPIN_DUE(74, 25, A); _DEFPIN_DUE(75, 26, A); +_DEFPIN_DUE(76, 27, A); _DEFPIN_DUE(77, 28, A); _DEFPIN_DUE(78, 23, B); + +// digix pins +_DEFPIN_DUE(90, 0, B); _DEFPIN_DUE(91, 1, B); _DEFPIN_DUE(92, 2, B); _DEFPIN_DUE(93, 3, B); +_DEFPIN_DUE(94, 4, B); _DEFPIN_DUE(95, 5, B); _DEFPIN_DUE(96, 6, B); _DEFPIN_DUE(97, 7, B); +_DEFPIN_DUE(98, 8, B); _DEFPIN_DUE(99, 9, B); _DEFPIN_DUE(100, 5, A); _DEFPIN_DUE(101, 22, B); +_DEFPIN_DUE(102, 23, B); _DEFPIN_DUE(103, 24, B); _DEFPIN_DUE(104, 27, C); _DEFPIN_DUE(105, 20, C); +_DEFPIN_DUE(106, 11, C); _DEFPIN_DUE(107, 10, C); _DEFPIN_DUE(108, 21, A); _DEFPIN_DUE(109, 30, C); +_DEFPIN_DUE(110, 29, B); _DEFPIN_DUE(111, 30, B); _DEFPIN_DUE(112, 31, B); _DEFPIN_DUE(113, 28, B); + +#define SPI_DATA 75 +#define SPI_CLOCK 76 +#define ARM_HARDWARE_SPI +#define HAS_HARDWARE_PIN_SUPPORT + +#endif + +#endif // FORCE_SOFTWARE_PINS + +#endif // __INC_FASTPIN_ARM_SAM_H diff --git a/platforms/arm/sam/fastspi_arm_sam.h b/platforms/arm/sam/fastspi_arm_sam.h new file mode 100644 index 00000000..d756c221 --- /dev/null +++ b/platforms/arm/sam/fastspi_arm_sam.h @@ -0,0 +1,160 @@ +#ifndef __INC_FASTSPI_ARM_SAM_H +#define __INC_FASTSPI_ARM_SAM_H + +#if defined(__SAM3X8E__) +#define m_SPI ((Spi*)SPI0) + +template +class SAMHardwareSPIOutput { + Selectable *m_pSelect; + + static inline void waitForEmpty() { while ((m_SPI->SPI_SR & SPI_SR_TDRE) == 0); } + + void enableConfig() { m_SPI->SPI_WPMR &= ~SPI_WPMR_WPEN; } + void disableConfig() { m_SPI->SPI_WPMR |= SPI_WPMR_WPEN; } + + void enableSPI() { m_SPI->SPI_CR = SPI_CR_SPIEN; } + void disableSPI() { m_SPI->SPI_CR = SPI_CR_SPIDIS; } + void resetSPI() { m_SPI->SPI_CR = SPI_CR_SWRST; } + + static inline void readyTransferBits(register uint32_t bits) { + bits -= 8; + // don't change the number of transfer bits while data is still being transferred from TDR to the shift register + waitForEmpty(); + m_SPI->SPI_CSR[0] = SPI_CSR_NCPHA | SPI_CSR_CSAAT | (bits << SPI_CSR_BITS_Pos) | SPI_CSR_DLYBCT(1) | SPI_CSR_SCBR(_SPI_CLOCK_DIVIDER); + } + + template static inline void writeBits(uint16_t w) { + waitForEmpty(); + m_SPI->SPI_TDR = (uint32_t)w | SPI_PCS(0); + } + +public: + SAMHardwareSPIOutput() { m_pSelect = NULL; } + SAMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + + // set the object representing the selectable + void setSelect(Selectable *pSelect) { /* TODO */ } + + // initialize the SPI subssytem + void init() { + // m_SPI = SPI0; + + // set the output pins master out, master in, clock. Note doing this here because I still don't + // know how I want to expose this type of functionality in FastPin. + PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_DATA_PIN>::mask(), PIO_DEFAULT); + PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_DATA_PIN-1>::mask(), PIO_DEFAULT); + PIO_Configure(PIOA, PIO_PERIPH_A, FastPin<_CLOCK_PIN>::mask(), PIO_DEFAULT); + + release(); + + // Configure the SPI clock, divider between 1-255 + // SCBR = _SPI_CLOCK_DIVIDER + pmc_enable_periph_clk(ID_SPI0); + disableSPI(); + + // reset twice (what the sam code does, not sure why?) + resetSPI(); + resetSPI(); + + // Configure SPI as master, enable + // Bits we want in MR: master, disable mode fault detection, variable peripheral select + m_SPI->SPI_MR = SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PS; + + enableSPI(); + + // Send everything out in 8 bit chunks, other sizes appear to work, poorly... + readyTransferBits(8); + } + + // latch the CS select + void inline select() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->select(); } } + + // release the CS select + void inline release() __attribute__((always_inline)) { if(m_pSelect != NULL) { m_pSelect->release(); } } + + // wait until all queued up data has been written + void waitFully() { while((m_SPI->SPI_SR & SPI_SR_TXEMPTY) == 0); } + + // write a byte out via SPI (returns immediately on writing register) + static void writeByte(uint8_t b) { + writeBits<8>(b); + } + + // write a word out via SPI (returns immediately on writing register) + static void writeWord(uint16_t w) { + writeBits<16>(w); + } + + // A raw set of writing byte values, assumes setup/init/waiting done elsewhere + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { writeByte(value); } + } + + // A full cycle of writing a value for len bytes, including select, release, and waiting + void writeBytesValue(uint8_t value, int len) { + select(); writeBytesValueRaw(value, len); release(); + } + + template void writeBytes(register uint8_t *data, int len) { + uint8_t *end = data + len; + select(); + // could be optimized to write 16bit words out instead of 8bit bytes + while(data != end) { + writeByte(D::adjust(*data++)); + } + D::postBlock(len); + waitFully(); + release(); + } + + void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } + + // write a single bit out, which bit from the passed in byte is determined by template parameter + // not the most efficient mechanism in the world - but should be enough for sm16716 and friends + template inline void writeBit(uint8_t b) { + // need to wait for all exisiting data to go out the door, first + waitFully(); + disableSPI(); + if(b & (1 << BIT)) { + FastPin<_DATA_PIN>::hi(); + } else { + FastPin<_DATA_PIN>::lo(); + } + + FastPin<_CLOCK_PIN>::hi(); + FastPin<_CLOCK_PIN>::lo(); + enableSPI(); + } + + // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template + // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping + template void writePixels(PixelController pixels) { + select(); + int len = pixels.mLen; + + if(FLAGS & FLAG_START_BIT) { + while(pixels.has(1)) { + writeBits<9>((1<<8) | D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + pixels.advanceData(); + pixels.stepDithering(); + } + } else { + while(pixels.has(1)) { + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + pixels.advanceData(); + pixels.stepDithering(); + } + } + D::postBlock(len); + release(); + } +}; + +#endif + +#endif diff --git a/platforms/arm/sam/led_sysdefs_arm_sam.h b/platforms/arm/sam/led_sysdefs_arm_sam.h new file mode 100644 index 00000000..e45f9609 --- /dev/null +++ b/platforms/arm/sam/led_sysdefs_arm_sam.h @@ -0,0 +1,30 @@ +#ifndef __INC_LED_SYSDEFS_ARM_SAM_H +#define __INC_LED_SYSDEFS_ARM_SAM_H + + +#define FASTLED_ARM + +// Setup DUE timer defines/channels/etc... +#ifndef DUE_TIMER_CHANNEL +#define DUE_TIMER_GROUP 0 +#endif + +#ifndef DUE_TIMER_CHANNEL +#define DUE_TIMER_CHANNEL 0 +#endif + +#define DUE_TIMER ((DUE_TIMER_GROUP==0) ? TC0 : ((DUE_TIMER_GROUP==1) ? TC1 : TC2)) +#define DUE_TIMER_ID (ID_TC0 + (DUE_TIMER_GROUP*3) + DUE_TIMER_CHANNEL) +#define DUE_TIMER_VAL (DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_CV << 1) +#define DUE_TIMER_RUNNING ((DUE_TIMER->TC_CHANNEL[DUE_TIMER_CHANNEL].TC_SR & TC_SR_CLKSTA) != 0) + +#ifndef INTERRUPT_THRESHOLD +#define INTERRUPT_THRESHOLD 1 +#endif + +// reuseing/abusing cli/sei defs for due +#define cli() __disable_irq(); __disable_fault_irq(); +#define sei() __enable_irq(); __enable_fault_irq(); + + +#endif diff --git a/platforms/avr/clockless_trinket.h b/platforms/avr/clockless_trinket.h new file mode 100644 index 00000000..4630719d --- /dev/null +++ b/platforms/avr/clockless_trinket.h @@ -0,0 +1,370 @@ +#ifndef __INC_CLOCKLESS_TRINKET_H +#define __INC_CLOCKLESS_TRINKET_H + +#include "controller.h" +#include "lib8tion.h" +#include // for cli/se definitions + +#if defined(FASTLED_AVR) + +// Scaling macro choice +#ifndef TRINKET_SCALE +#define TRINKET_SCALE 1 +// whether or not to use dithering +#define DITHER 1 +#endif + +#define US_PER_TICK (64 / (F_CPU/1000000)) + +// Variations on the functions in delay.h - w/a loop var passed in to preserve registers across calls by the optimizer/compiler +template inline void _dc(register uint8_t & loopvar); + +template inline void _dc_AVR(register uint8_t & loopvar) { + _dc(loopvar); + // The convolution in here is to ensure that the state of the carry flag coming into the delay loop is preserved + asm __volatile__ ( "BRCS L_PC%=\n\t" + " LDI %[loopvar], %[_LOOP]\n\tL_%=: DEC %[loopvar]\n\t BRNE L_%=\n\tBREQ L_DONE%=\n\t" + "L_PC%=: LDI %[loopvar], %[_LOOP]\n\tLL_%=: DEC %[loopvar]\n\t BRNE LL_%=\n\tBSET 0\n\t" + "L_DONE%=:\n\t" + : + [loopvar] "+a" (loopvar) : [_LOOP] "M" (_LOOP) : ); +} + +template __attribute__((always_inline)) inline void _dc(register uint8_t & loopvar) { + _dc_AVR(loopvar); +} +template<> __attribute__((always_inline)) inline void _dc<-6>(register uint8_t & loopvar) {} +template<> __attribute__((always_inline)) inline void _dc<-5>(register uint8_t & loopvar) {} +template<> __attribute__((always_inline)) inline void _dc<-4>(register uint8_t & loopvar) {} +template<> __attribute__((always_inline)) inline void _dc<-3>(register uint8_t & loopvar) {} +template<> __attribute__((always_inline)) inline void _dc<-2>(register uint8_t & loopvar) {} +template<> __attribute__((always_inline)) inline void _dc<-1>(register uint8_t & loopvar) {} +template<> __attribute__((always_inline)) inline void _dc<0>(register uint8_t & loopvar) {} +template<> __attribute__((always_inline)) inline void _dc<1>(register uint8_t & loopvar) {asm __volatile__("mov r0,r0":::);} +template<> __attribute__((always_inline)) inline void _dc<2>(register uint8_t & loopvar) {asm __volatile__("rjmp .+0":::);} +template<> __attribute__((always_inline)) inline void _dc<3>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<1>(loopvar); } +template<> __attribute__((always_inline)) inline void _dc<4>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<2>(loopvar); } +template<> __attribute__((always_inline)) inline void _dc<5>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<3>(loopvar); } +template<> __attribute__((always_inline)) inline void _dc<6>(register uint8_t & loopvar) { _dc<2>(loopvar); _dc<2>(loopvar); _dc<2>(loopvar);} +template<> __attribute__((always_inline)) inline void _dc<7>(register uint8_t & loopvar) { _dc<4>(loopvar); _dc<3>(loopvar); } +template<> __attribute__((always_inline)) inline void _dc<8>(register uint8_t & loopvar) { _dc<4>(loopvar); _dc<4>(loopvar); } +template<> __attribute__((always_inline)) inline void _dc<9>(register uint8_t & loopvar) { _dc<5>(loopvar); _dc<4>(loopvar); } +template<> __attribute__((always_inline)) inline void _dc<10>(register uint8_t & loopvar) { _dc<6>(loopvar); _dc<4>(loopvar); } + +#define D1(ADJ) _dc(loopvar); +#define D2(ADJ) _dc(loopvar); +#define D3(ADJ) (T3-(AVR_PIN_CYCLES(DATA_PIN)+ADJ)>0) ? _dc(loopvar) : _dc<0>(loopvar); + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Base template for clockless controllers. These controllers have 3 control points in their cycle for each bit. The first point +// is where the line is raised hi. The second point is where the line is dropped low for a zero. The third point is where the +// line is dropped low for a one. T1, T2, and T3 correspond to the timings for those three in clock cycles. +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class ClocklessController : public CLEDController { + typedef typename FastPin::port_ptr_t data_ptr_t; + typedef typename FastPin::port_t data_t; + + CMinWait mWait; +public: + virtual void init() { + FastPin::setOutput(); + } + + 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 pixels(data, nLeds, scale, getDither(), advance, skip); + + mWait.wait(); + cli(); + + showRGBInternal(pixels); + + sei(); + mWait.mark(); + } +#define USE_ASM_MACROS + +// The variables that our various asm statemetns use. The same block of variables needs to be declared for +// all the asm blocks because GCC is pretty stupid and it would clobber variables happily or optimize code away too aggressively +#define ASM_VARS : /* write variables */ \ + [count] "+x" (count), \ + [data] "+z" (data), \ + [b0] "+a" (b0), \ + [b1] "+a" (b1), \ + [b2] "+a" (b2), \ + [scale_base] "+a" (scale_base), \ + [loopvar] "+a" (loopvar), \ + [d0] "+r" (d0), \ + [d1] "+r" (d1), \ + [d2] "+r" (d2) \ + : /* use variables */ \ + [ADV] "r" (advanceBy), \ + [hi] "r" (hi), \ + [lo] "r" (lo), \ + [s0] "r" (s0), \ + [s1] "r" (s1), \ + [s2] "r" (s2), \ + [PORT] "M" (FastPin::port()-0x20), \ + [O0] "M" (RGB_BYTE0(RGB_ORDER)), \ + [O1] "M" (RGB_BYTE1(RGB_ORDER)), \ + [O2] "M" (RGB_BYTE2(RGB_ORDER)) \ + : /* clobber registers */ + + +// 1 cycle, write hi to the port +#define HI1 if((int)(FastPin::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[hi]" ASM_VARS ); } else { *FastPin::port()=hi; } +// 1 cycle, write lo to the port +#define LO1 if((int)(FastPin::port())-0x20 < 64) { asm __volatile__("out %[PORT], %[lo]" ASM_VARS ); } else { *FastPin::port()=lo; } +// 2 cycles, sbrs on flipping the lne to lo if we're pushing out a 0 +#define QLO2(B, N) asm __volatile__("sbrs %[" #B "], " #N ASM_VARS ); LO1; +// load a byte from ram into the given var with the given offset +#define LD2(B,O) asm __volatile__("ldd %[" #B "], Z + %[" #O "]" ASM_VARS ); +// 4 cycles - load a byte from ram into the scaling scratch space with the given offset, clear the target var, clear carry +#define LDSCL4(B,O) asm __volatile__("ldd %[scale_base], Z + %[" #O "]\n\tclr %[" #B "]\n\tclc" ASM_VARS ); +// 2 cycles - perform one step of the scaling (if a given bit is set in scale, add scale-base to the scratch space) +#define SCALE02(B, N) asm __volatile__("sbrc %[s0], " #N "\n\tadd %[" #B "], %[scale_base]" ASM_VARS ); +#define SCALE12(B, N) asm __volatile__("sbrc %[s1], " #N "\n\tadd %[" #B "], %[scale_base]" ASM_VARS ); +#define SCALE22(B, N) asm __volatile__("sbrc %[s2], " #N "\n\tadd %[" #B "], %[scale_base]" ASM_VARS ); + +// apply dithering value before we do anything with scale_base +#define PRESCALE4(D) if(DITHER) { asm __volatile__("cpse %[scale_base], __zero_reg__\n\t add %[scale_base],%[" #D "]\n\tbrcc L_%=\n\tldi %[scale_base], 0xFF\n\tL_%=:\n\t" ASM_VARS); } \ + else { _dc<4>(loopvar); } + +// Do the add for the prescale +#define PRESCALEA2(D) if(DITHER) { asm __volatile__("cpse %[scale_base], __zero_reg__\n\t add %[scale_base],%[" #D "]\n\t" ASM_VARS); } \ + else { _dc<2>(loopvar); } +// Do the clamp for the prescale, clear carry when we're done - NOTE: Must ensure carry flag state is preserved! +#define PRESCALEB3(D) if(DITHER) { asm __volatile__("brcc L_%=\n\tldi %[scale_base], 0xFF\n\tL_%=:\n\tCLC" ASM_VARS); } \ + else { _dc<3>(loopvar); } + + +// 1 cycle - rotate right, pulling in from carry +#define ROR1(B) asm __volatile__("ror %[" #B "]" ASM_VARS ); +// 1 cycle, clear the carry bit +#define CLC1 asm __volatile__("clc" ASM_VARS ); +// 1 cycle, move one register to another +#define MOV1(B1, B2) asm __volatile__("mov %[" #B1 "], %[" #B2 "]" ASM_VARS ); +// 4 cycles, rotate, clear carry, scale next bit +#define RORSC04(B, N) ROR1(B) CLC1 SCALE02(B, N) +#define RORSC14(B, N) ROR1(B) CLC1 SCALE12(B, N) +#define RORSC24(B, N) ROR1(B) CLC1 SCALE22(B, N) +// 4 cycles, scale bit, rotate, clear carry +#define SCROR04(B, N) SCALE02(B,N) ROR1(B) CLC1 +#define SCROR14(B, N) SCALE12(B,N) ROR1(B) CLC1 +#define SCROR24(B, N) SCALE22(B,N) ROR1(B) CLC1 + +///////////////////////////////////////////////////////////////////////////////////// +// Loop life cycle + +// dither adjustment macro - should be kept in sync w/what's in stepDithering +#define ADJDITHER2(D, E) D = E - D; + +// #define xstr(a) str(a) +// #define str(a) #a +// #define ADJDITHER2(D,E) asm __volatile__("subi %[" #D "], " xstr(DUSE) "\n\tand %[" #D "], %[" #E "]\n\t" ASM_VARS); + +// define the beginning of the loop +#define LOOP asm __volatile__("1:" ASM_VARS ); +// define the end of the loop +#define DONE asm __volatile__("2:" ASM_VARS ); + +// 2 cycles - increment the data pointer +#define IDATA2 asm __volatile__("add %A[data], %[ADV]\n\tadc %B[data], __zero_reg__" ASM_VARS ); +// 2 cycles - decrement the counter +#define DCOUNT2 asm __volatile__("sbiw %[count], 1" ASM_VARS ); +// 2 cycles - jump to the beginning of the loop +#define JMPLOOP2 asm __volatile__("rjmp 1b" ASM_VARS ); +// 2 cycles - jump out of the loop +#define BRLOOP1 asm __volatile__("breq 2f" ASM_VARS ); + +#define DADVANCE 3 +#define DUSE (0xFF - (DADVANCE-1)) + + // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then + // gcc will use register Y for the this pointer. + static void __attribute__ ((always_inline)) showRGBInternal(PixelController & pixels) { + uint8_t *data = (uint8_t*)pixels.mData; + data_ptr_t port = FastPin::port(); + data_t mask = FastPin::mask(); + uint8_t scale_base = 0; + + // register uint8_t *end = data + nLeds; + data_t hi = *port | mask; + data_t lo = *port & ~mask; + *port = lo; + + uint8_t b0 = 0; + uint8_t b1 = 0; + uint8_t b2 = 0; + + // Setup the pixel controller and load/scale the first byte + pixels.preStepFirstByteDithering(); + b0 = pixels.loadAndScale0(); + + // pull the dithering/adjustment values out of the pixels object for direct asm access + + uint8_t advanceBy = pixels.advanceBy(); + uint16_t count = pixels.mLen; + + uint8_t s0 = pixels.mScale.raw[RO(0)]; + uint8_t s1 = pixels.mScale.raw[RO(1)]; + uint8_t s2 = pixels.mScale.raw[RO(2)]; + uint8_t d0 = pixels.d[RO(0)]; + uint8_t d1 = pixels.d[RO(1)]; + uint8_t d2 = pixels.d[RO(2)]; + uint8_t e0 = pixels.e[RO(0)]; + uint8_t e1 = pixels.e[RO(1)]; + uint8_t e2 = pixels.e[RO(2)]; + + uint8_t loopvar=0; + + TCCR0A |= 0x30; + OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); + TIFR0 = 0x04; + { + while(count--) + { + // Loop beginning, does some stuff that's outside of the pixel write cycle, namely incrementing d0-2 and masking off + // by the E values (see the definition ) + // LOOP; + ADJDITHER2(d0,e0); + ADJDITHER2(d1,e1); + ADJDITHER2(d2,e2); + + cli(); + + if(TIFR0 & 0x04) { + sei(); + TCCR0A &= ~0x30; + return; + } + hi = *port | mask; + lo = *port & ~mask; + + // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 + // The values in the D1/D2/D3 indicate how many cycles the previous column takes + // to allow things to line back up. + // + // While writing out byte 0, we're loading up byte 1, applying the dithering adjustment, + // then scaling it using 8 cycles of shift/add interleaved in between writing the bits + // out. When doing byte 1, we're doing the above for byte 2. When we're doing byte 2, + // we're cycling back around and doing the above for byte 0. +#if TRINKET_SCALE + // Inline scaling - RGB ordering + HI1 D1(1) QLO2(b0, 7) LDSCL4(b1,O1) D2(4) LO1 PRESCALEA2(d1) D3(2) + HI1 D1(1) QLO2(b0, 6) PRESCALEB3(d1) D2(3) LO1 SCALE12(b1,0) D3(2) + HI1 D1(1) QLO2(b0, 5) RORSC14(b1,1) D2(4) LO1 ROR1(b1) CLC1 D3(2) + HI1 D1(1) QLO2(b0, 4) SCROR14(b1,2) D2(4) LO1 SCALE12(b1,3) D3(2) + HI1 D1(1) QLO2(b0, 3) RORSC14(b1,4) D2(4) LO1 ROR1(b1) CLC1 D3(2) + HI1 D1(1) QLO2(b0, 2) SCROR14(b1,5) D2(4) LO1 SCALE12(b1,6) D3(2) + HI1 D1(1) QLO2(b0, 1) RORSC14(b1,7) D2(4) LO1 ROR1(b1) CLC1 D3(2) + HI1 D1(1) QLO2(b0, 0) D2(0) LO1 D3(0) + switch(XTRA0) { + case 4: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); + case 3: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); + case 2: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); + case 1: HI1 D1(1) QLO2(b0,0) D2(0) LO1 D3(0); + } + HI1 D1(1) QLO2(b1, 7) LDSCL4(b2,O2) D2(4) LO1 PRESCALEA2(d2) D3(2) + HI1 D1(1) QLO2(b1, 6) PRESCALEB3(d2) D2(3) LO1 SCALE22(b2,0) D3(2) + HI1 D1(1) QLO2(b1, 5) RORSC24(b2,1) D2(4) LO1 ROR1(b2) CLC1 D3(2) + HI1 D1(1) QLO2(b1, 4) SCROR24(b2,2) D2(4) LO1 SCALE22(b2,3) D3(2) + HI1 D1(1) QLO2(b1, 3) RORSC24(b2,4) D2(4) LO1 ROR1(b2) CLC1 D3(2) + HI1 D1(1) QLO2(b1, 2) SCROR24(b2,5) D2(4) LO1 SCALE22(b2,6) D3(2) + HI1 D1(1) QLO2(b1, 1) RORSC24(b2,7) D2(4) LO1 ROR1(b2) CLC1 D3(2) + HI1 D1(1) QLO2(b1, 0) IDATA2 CLC1 D2(3) LO1 D3(0) + switch(XTRA0) { + case 4: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); + case 3: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); + case 2: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); + case 1: HI1 D1(1) QLO2(b1,0) D2(0) LO1 D3(0); + } + HI1 D1(1) QLO2(b2, 7) LDSCL4(b0,O0) D2(4) LO1 PRESCALEA2(d0) D3(2) + HI1 D1(1) QLO2(b2, 6) PRESCALEB3(d0) D2(3) LO1 SCALE02(b0,0) D3(2) + HI1 D1(1) QLO2(b2, 5) RORSC04(b0,1) D2(4) LO1 ROR1(b0) CLC1 D3(2) + HI1 D1(1) QLO2(b2, 4) SCROR04(b0,2) D2(4) LO1 SCALE02(b0,3) D3(2) + HI1 D1(1) QLO2(b2, 3) RORSC04(b0,4) D2(4) LO1 ROR1(b0) CLC1 D3(2) + HI1 D1(1) QLO2(b2, 2) SCROR04(b0,5) D2(4) LO1 SCALE02(b0,6) D3(2) + HI1 D1(1) QLO2(b2, 1) RORSC04(b0,7) D2(4) LO1 ROR1(b0) CLC1 D3(2) + // HI1 D1(1) QLO2(b2, 0) DCOUNT2 BRLOOP1 D2(3) LO1 D3(2) JMPLOOP2 + HI1 D1(1) QLO2(b2, 0) D2(0) LO1 + switch(XTRA0) { + case 4: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; + case 3: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; + case 2: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; + case 1: D3(0) HI1 D1(1) QLO2(b1,0) D2(0) LO1; + } + D3(12); +#else + // no inline scaling - non-straight RGB ordering + HI1 D1(1) QLO2(b0, 7) LD2(b1,O1) D2(2) LO1 D3(0) + HI1 D1(1) QLO2(b0, 6) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b0, 5) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b0, 4) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b0, 3) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b0, 2) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b0, 1) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b0, 0) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b1, 7) LD2(b2,O2) D2(2) LO1 D3(0) + HI1 D1(1) QLO2(b1, 6) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b1, 5) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b1, 4) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b1, 3) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b1, 2) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b1, 1) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b1, 0) IDATA2 D2(2) LO1 D3(0) + HI1 D1(1) QLO2(b2, 7) LD2(b0,O0) D2(2) LO1 D3(0) + HI1 D1(1) QLO2(b2, 6) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b2, 5) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b2, 4) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b2, 3) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b2, 2) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b2, 1) D2(0) LO1 D3(0) + HI1 D1(1) QLO2(b2, 0) D2(0) LO1 D3(0) +#endif + // set the counter mark + OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); + TIFR0 = 0x04; + sei(); + } + } + + // stop using the clock juggler + TCCR0A &= ~0x30; + } + +#ifdef SUPPORT_ARGB + virtual void showARGB(struct CARGB *data, int nLeds) { + // TODO: IMPLEMENTME + } +#endif +}; + +#endif + +#endif diff --git a/platforms/avr/fastled_avr.h b/platforms/avr/fastled_avr.h new file mode 100644 index 00000000..4c9b842e --- /dev/null +++ b/platforms/avr/fastled_avr.h @@ -0,0 +1,9 @@ +#ifndef __INC_FASTLED_AVR_H +#define __INC_FASTLED_AVR_H + +#include "delay.h" +#include "fastpin_avr.h" +#include "fastspi_avr.h" +#include "clockless_trinket.h" + +#endif diff --git a/platforms/avr/fastpin_avr.h b/platforms/avr/fastpin_avr.h new file mode 100644 index 00000000..f5354a9d --- /dev/null +++ b/platforms/avr/fastpin_avr.h @@ -0,0 +1,208 @@ +#ifndef __INC_FASTPIN_AVR_H +#define __INC_FASTPIN_AVR_H + +#if defined(FORCE_SOFTWARE_PINS) +#warning "Software pin support forced, pin access will be sloightly slower." +#define NO_HARDWARE_PIN_SUPPORT +#undef HAS_HARDWARE_PIN_SUPPORT + +#else + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define AVR_PIN_CYCLES(_PIN) (((_PIN >= 62 ) || (_PIN>=42 && _PIN<=49) || (_PIN>=14 && _PIN <=17) || (_PIN>=6 && _PIN <=9)) ? 2 : 1) +#else +#define AVR_PIN_CYCLES(_PIN) ((_PIN >= 24) ? 2 : 1) +#endif + + +/// Class definition for a Pin where we know the port registers at compile time for said pin. This allows us to make +/// a lot of optimizations, as the inlined hi/lo methods will devolve to a single io register write/bitset. +template class _AVRPIN { +public: + typedef volatile uint8_t * port_ptr_t; + typedef uint8_t port_t; + + inline static void setOutput() { _DDR::r() |= _MASK; } + inline static void setInput() { _DDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { _PORT::r() |= _MASK; } + inline static void lo() __attribute__ ((always_inline)) { _PORT::r() &= ~_MASK; } + inline static void set(register uint8_t val) __attribute__ ((always_inline)) { _PORT::r() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { _PIN::r() = _MASK; } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } + inline static void fastset(register port_ptr_t port, register uint8_t val) __attribute__ ((always_inline)) { set(val); } + + inline static port_t hival() __attribute__ ((always_inline)) { return _PORT::r() | _MASK; } + inline static port_t loval() __attribute__ ((always_inline)) { return _PORT::r() & ~_MASK; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PORT::r(); } + inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } +}; + + + +/// AVR definitions for pins. Getting around the fact that I can't pass GPIO register addresses in as template arguments by instead creating +/// a custom type for each GPIO register with a single, static, aggressively inlined function that returns that specific GPIO register. A similar +/// trick is used a bit further below for the ARM GPIO registers (of which there are far more than on AVR!) +typedef volatile uint8_t & reg8_t; +#define _R(T) struct __gen_struct_ ## T +#define _RD8(T) struct __gen_struct_ ## T { static inline reg8_t r() { return T; }}; +#define _IO(L) _RD8(DDR ## L); _RD8(PORT ## L); _RD8(PIN ## L); +#define _DEFPIN_AVR(_PIN, MASK, L) template<> class FastPin<_PIN> : public _AVRPIN<_PIN, MASK, _R(PORT ## L), _R(DDR ## L), _R(PIN ## L)> {}; + +#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) +_IO(B); + +_DEFPIN_AVR(0, 0x01, B); _DEFPIN_AVR(1, 0x02, B); _DEFPIN_AVR(2, 0x04, B); _DEFPIN_AVR(3, 0x08, B); +_DEFPIN_AVR(4, 0x10, B); _DEFPIN_AVR(5, 0x20, B); + +#define HAS_HARDWARE_PIN_SUPPORT 1 + +#elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) +_IO(A); _IO(B); + +_DEFPIN_AVR(0, 0x01, A); _DEFPIN_AVR(1, 0x02, A); _DEFPIN_AVR(2, 0x04, A); _DEFPIN_AVR(3, 0x08, A); +_DEFPIN_AVR(4, 0x10, A); _DEFPIN_AVR(5, 0x20, A); _DEFPIN_AVR(6, 0x40, A); _DEFPIN_AVR(7, 0x80, A); +_DEFPIN_AVR(8, 0x04, B); _DEFPIN_AVR(9, 0x02, B); _DEFPIN_AVR(10, 0x01, B); + +#define HAS_HARDWARE_PIN_SUPPORT 1 + +#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) +// Accelerated port definitions for arduino avrs +_IO(D); _IO(B); _IO(C); + +#define MAX_PIN 19 +_DEFPIN_AVR( 0, 0x01, D); _DEFPIN_AVR( 1, 0x02, D); _DEFPIN_AVR( 2, 0x04, D); _DEFPIN_AVR( 3, 0x08, D); +_DEFPIN_AVR( 4, 0x10, D); _DEFPIN_AVR( 5, 0x20, D); _DEFPIN_AVR( 6, 0x40, D); _DEFPIN_AVR( 7, 0x80, D); +_DEFPIN_AVR( 8, 0x01, B); _DEFPIN_AVR( 9, 0x02, B); _DEFPIN_AVR(10, 0x04, B); _DEFPIN_AVR(11, 0x08, B); +_DEFPIN_AVR(12, 0x10, B); _DEFPIN_AVR(13, 0x20, B); _DEFPIN_AVR(14, 0x01, C); _DEFPIN_AVR(15, 0x02, C); +_DEFPIN_AVR(16, 0x04, C); _DEFPIN_AVR(17, 0x08, C); _DEFPIN_AVR(18, 0x10, C); _DEFPIN_AVR(19, 0x20, C); + +#define SPI_DATA 11 +#define SPI_CLOCK 13 +#define SPI_SELECT 10 +#define AVR_HARDWARE_SPI 1 +#define HAS_HARDWARE_PIN_SUPPORT 1 + +#elif defined(__AVR_ATmega1284P__) + +_IO(A); _IO(B); _IO(C); _IO(D); + +_DEFPIN_AVR(0, 1<<0, D); _DEFPIN_AVR(1, 1<<1, D); _DEFPIN_AVR(2, 1<<2, B); _DEFPIN_AVR(3, 1<<3, B); +_DEFPIN_AVR(4, 1<<0, B); _DEFPIN_AVR(5, 1<<1, B); _DEFPIN_AVR(6, 1<<2, D); _DEFPIN_AVR(7, 1<<3, D); +_DEFPIN_AVR(8, 1<<5, D); _DEFPIN_AVR(9, 1<<6, D); _DEFPIN_AVR(10, 1<<4, B); _DEFPIN_AVR(11, 1<<5, B); +_DEFPIN_AVR(12, 1<<6, B); _DEFPIN_AVR(13, 1<<7, B); _DEFPIN_AVR(14, 1<<7, A); _DEFPIN_AVR(15, 1<<6, A); +_DEFPIN_AVR(16, 1<<5, A); _DEFPIN_AVR(17, 1<<4, A); _DEFPIN_AVR(18, 1<<3, A); _DEFPIN_AVR(19, 1<<2, A); +_DEFPIN_AVR(20, 1<<1, A); _DEFPIN_AVR(21, 1<<0, A); _DEFPIN_AVR(22, 1<<0, C); _DEFPIN_AVR(23, 1<<1, C); +_DEFPIN_AVR(24, 1<<2, C); _DEFPIN_AVR(25, 1<<3, C); _DEFPIN_AVR(26, 1<<4, C); _DEFPIN_AVR(27, 1<<5, C); +_DEFPIN_AVR(28, 1<<6, C); _DEFPIN_AVR(29, 1<<7, C); _DEFPIN_AVR(30, 1<<4, D); _DEFPIN_AVR(31, 1<<7, D); + +#define SPI_DATA 11 +#define SPI_CLOCK 13 +#define SPI_SELECT 10 +#define AVR_HARDWARE_SPI 1 +#define HAS_HARDWARE_PIN_SUPPORT 1 + +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +// megas + +_IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); _IO(G); _IO(H); _IO(J); _IO(K); _IO(L); + +#define MAX_PIN 69 +_DEFPIN_AVR(0, 1, E); _DEFPIN_AVR(1, 2, E); _DEFPIN_AVR(2, 16, E); _DEFPIN_AVR(3, 32, E); +_DEFPIN_AVR(4, 32, G); _DEFPIN_AVR(5, 8, E); _DEFPIN_AVR(6, 8, H); _DEFPIN_AVR(7, 16, H); +_DEFPIN_AVR(8, 32, H); _DEFPIN_AVR(9, 64, H); _DEFPIN_AVR(10, 16, B); _DEFPIN_AVR(11, 32, B); +_DEFPIN_AVR(12, 64, B); _DEFPIN_AVR(13, 128, B); _DEFPIN_AVR(14, 2, J); _DEFPIN_AVR(15, 1, J); +_DEFPIN_AVR(16, 2, H); _DEFPIN_AVR(17, 1, H); _DEFPIN_AVR(18, 8, D); _DEFPIN_AVR(19, 4, D); +_DEFPIN_AVR(20, 2, D); _DEFPIN_AVR(21, 1, D); _DEFPIN_AVR(22, 1, A); _DEFPIN_AVR(23, 2, A); +_DEFPIN_AVR(24, 4, A); _DEFPIN_AVR(25, 8, A); _DEFPIN_AVR(26, 16, A); _DEFPIN_AVR(27, 32, A); +_DEFPIN_AVR(28, 64, A); _DEFPIN_AVR(29, 128, A); _DEFPIN_AVR(30, 128, C); _DEFPIN_AVR(31, 64, C); +_DEFPIN_AVR(32, 32, C); _DEFPIN_AVR(33, 16, C); _DEFPIN_AVR(34, 8, C); _DEFPIN_AVR(35, 4, C); +_DEFPIN_AVR(36, 2, C); _DEFPIN_AVR(37, 1, C); _DEFPIN_AVR(38, 128, D); _DEFPIN_AVR(39, 4, G); +_DEFPIN_AVR(40, 2, G); _DEFPIN_AVR(41, 1, G); _DEFPIN_AVR(42, 128, L); _DEFPIN_AVR(43, 64, L); +_DEFPIN_AVR(44, 32, L); _DEFPIN_AVR(45, 16, L); _DEFPIN_AVR(46, 8, L); _DEFPIN_AVR(47, 4, L); +_DEFPIN_AVR(48, 2, L); _DEFPIN_AVR(49, 1, L); _DEFPIN_AVR(50, 8, B); _DEFPIN_AVR(51, 4, B); +_DEFPIN_AVR(52, 2, B); _DEFPIN_AVR(53, 1, B); _DEFPIN_AVR(54, 1, F); _DEFPIN_AVR(55, 2, F); +_DEFPIN_AVR(56, 4, F); _DEFPIN_AVR(57, 8, F); _DEFPIN_AVR(58, 16, F); _DEFPIN_AVR(59, 32, F); +_DEFPIN_AVR(60, 64, F); _DEFPIN_AVR(61, 128, F); _DEFPIN_AVR(62, 1, K); _DEFPIN_AVR(63, 2, K); +_DEFPIN_AVR(64, 4, K); _DEFPIN_AVR(65, 8, K); _DEFPIN_AVR(66, 16, K); _DEFPIN_AVR(67, 32, K); +_DEFPIN_AVR(68, 64, K); _DEFPIN_AVR(69, 128, K); + +#define SPI_DATA 51 +#define SPI_CLOCK 52 +#define SPI_SELECT 53 +#define AVR_HARDWARE_SPI 1 +#define HAS_HARDWARE_PIN_SUPPORT 1 + +// Leonardo, teensy, blinkm +#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) + +// teensy defs +_IO(B); _IO(C); _IO(D); _IO(E); _IO(F); + +#define MAX_PIN 23 +_DEFPIN_AVR(0, 1, B); _DEFPIN_AVR(1, 2, B); _DEFPIN_AVR(2, 4, B); _DEFPIN_AVR(3, 8, B); +_DEFPIN_AVR(4, 128, B); _DEFPIN_AVR(5, 1, D); _DEFPIN_AVR(6, 2, D); _DEFPIN_AVR(7, 4, D); +_DEFPIN_AVR(8, 8, D); _DEFPIN_AVR(9, 64, C); _DEFPIN_AVR(10, 128, C); _DEFPIN_AVR(11, 64, D); +_DEFPIN_AVR(12, 128, D); _DEFPIN_AVR(13, 16, B); _DEFPIN_AVR(14, 32, B); _DEFPIN_AVR(15, 64, B); +_DEFPIN_AVR(16, 128, F); _DEFPIN_AVR(17, 64, F); _DEFPIN_AVR(18, 32, F); _DEFPIN_AVR(19, 16, F); +_DEFPIN_AVR(20, 2, F); _DEFPIN_AVR(21, 1, F); _DEFPIN_AVR(22, 16, D); _DEFPIN_AVR(23, 32, D); + +#define SPI_DATA 2 +#define SPI_CLOCK 1 +#define SPI_SELECT 0 +#define AVR_HARDWARE_SPI 1 +#define HAS_HARDWARE_PIN_SUPPORT 1 + +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +// teensy++ 2 defs + +_IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); + +#define MAX_PIN 45 +_DEFPIN_AVR(0, 1, D); _DEFPIN_AVR(1, 2, D); _DEFPIN_AVR(2, 4, D); _DEFPIN_AVR(3, 8, D); +_DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 32, D); _DEFPIN_AVR(6, 64, D); _DEFPIN_AVR(7, 128, D); +_DEFPIN_AVR(8, 1, E); _DEFPIN_AVR(9, 2, E); _DEFPIN_AVR(10, 1, C); _DEFPIN_AVR(11, 2, C); +_DEFPIN_AVR(12, 4, C); _DEFPIN_AVR(13, 8, C); _DEFPIN_AVR(14, 16, C); _DEFPIN_AVR(15, 32, C); +_DEFPIN_AVR(16, 64, C); _DEFPIN_AVR(17, 128, C); _DEFPIN_AVR(18, 64, E); _DEFPIN_AVR(19, 128, E); +_DEFPIN_AVR(20, 1, B); _DEFPIN_AVR(21, 2, B); _DEFPIN_AVR(22, 4, B); _DEFPIN_AVR(23, 8, B); +_DEFPIN_AVR(24, 16, B); _DEFPIN_AVR(25, 32, B); _DEFPIN_AVR(26, 64, B); _DEFPIN_AVR(27, 128, B); +_DEFPIN_AVR(28, 1, A); _DEFPIN_AVR(29, 2, A); _DEFPIN_AVR(30, 4, A); _DEFPIN_AVR(31, 8, A); +_DEFPIN_AVR(32, 16, A); _DEFPIN_AVR(33, 32, A); _DEFPIN_AVR(34, 64, A); _DEFPIN_AVR(35, 128, A); +_DEFPIN_AVR(36, 16, E); _DEFPIN_AVR(37, 32, E); _DEFPIN_AVR(38, 1, F); _DEFPIN_AVR(39, 2, F); +_DEFPIN_AVR(40, 4, F); _DEFPIN_AVR(41, 8, F); _DEFPIN_AVR(42, 16, F); _DEFPIN_AVR(43, 32, F); +_DEFPIN_AVR(44, 64, F); _DEFPIN_AVR(45, 128, F); + +#define SPI_DATA 22 +#define SPI_CLOCK 21 +#define SPI_SELECT 20 +#define AVR_HARDWARE_SPI 1 +#define HAS_HARDWARE_PIN_SUPPORT 1 + +#elif defined(__AVR_ATmega32U4__) + +// leonard defs +_IO(B); _IO(C); _IO(D); _IO(E); _IO(F); + +#define MAX_PIN 23 +_DEFPIN_AVR(0, 4, D); _DEFPIN_AVR(1, 8, D); _DEFPIN_AVR(2, 2, D); _DEFPIN_AVR(3, 1, D); +_DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 64, C); _DEFPIN_AVR(6, 128, D); _DEFPIN_AVR(7, 64, E); +_DEFPIN_AVR(8, 16, B); _DEFPIN_AVR(9, 32, B); _DEFPIN_AVR(10, 64, B); _DEFPIN_AVR(11, 128, B); +_DEFPIN_AVR(12, 64, D); _DEFPIN_AVR(13, 128, C); _DEFPIN_AVR(14, 8, B); _DEFPIN_AVR(15, 2, B); +_DEFPIN_AVR(16, 4, B); _DEFPIN_AVR(17, 1, B); _DEFPIN_AVR(18, 128, F); _DEFPIN_AVR(19, 64, F); +_DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_AVR(23, 0, F); + +#define SPI_DATA 16 +#define SPI_CLOCK 15 +#define AVR_HARDWARE_SPI 1 +#define HAS_HARDWARE_PIN_SUPPORT 1 + +#endif + +#endif // FORCE_SOFTWARE_PINS + +#endif // __INC_FASTPIN_AVR_H diff --git a/platforms/avr/fastspi_avr.h b/platforms/avr/fastspi_avr.h new file mode 100644 index 00000000..6470f37d --- /dev/null +++ b/platforms/avr/fastspi_avr.h @@ -0,0 +1,300 @@ +#ifndef __INC_FASTSPI_AVR_H +#define __INC_FASTSPI_AVR_H + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Hardware SPI support using USART registers and friends +// +// TODO: Complete/test implementation - right now this doesn't work +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// uno/mini/duemilanove +#if defined(AVR_HARDWARE_SPI) +#if defined(UBRR0) +template +class AVRUSARTSPIOutput { + Selectable *m_pSelect; + +public: + AVRUSARTSPIOutput() { m_pSelect = NULL; } + AVRUSARTSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } + + void init() { + UBRR0 = 0; + UCSR0A = 1<::setOutput(); + FastPin<_DATA_PIN>::setOutput(); + + UCSR0C = _BV (UMSEL00) | _BV (UMSEL01); // Master SPI mode + UCSR0B = _BV (TXEN0) | _BV (RXEN0); // transmit enable and receive enable + + // must be done last, see page 206 + UBRR0 = 3; // 2 Mhz clock rate + } + + static void stop() { + // TODO: stop the uart spi output + } + + static void wait() __attribute__((always_inline)) { while(!(UCSR0A & (1<>8); writeByte(w&0xFF); } + + template inline static void writeBit(uint8_t b) { + if(b && (1 << BIT)) { + FastPin<_DATA_PIN>::hi(); + } else { + FastPin<_DATA_PIN>::lo(); + } + + FastPin<_CLOCK_PIN>::hi(); + FastPin<_CLOCK_PIN>::lo(); + } + + void select() { if(m_pSelect != NULL) { m_pSelect->select(); } } // FastPin<_SELECT_PIN>::hi(); } + void release() { + // wait for all transmissions to finish + while ((UCSR0A & (1 <release(); } // FastPin<_SELECT_PIN>::hi(); + } + + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { writeByte(value); } + } + + void writeBytesValue(uint8_t value, int len) { + select(); + while(len--) { + writeByte(value); + } + release(); + } + + // Write a block of n uint8_ts out + template void writeBytes(register uint8_t *data, int len) { + uint8_t *end = data + len; + select(); + while(data != end) { + // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM) + writeByte(D::adjust(*data++)); delaycycles<3>(); + } + D::postBlock(len); + release(); + } + + void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } + + // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template + // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping + template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + uint8_t *end = data + len; + PixelController pixels(data, scale, true, advance, skip); + select(); + while(data != end) { + if(FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + } + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + pixels.advanceData(); + pixels.stepDithering(); + data += (3+skip); + } + D::postBlock(len); + release(); + } + + // template instantiations for writeBytes 3 + template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + writeBytes3(data, len, scale, advance, skip); + } + template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + writeBytes3<0, D, RGB_ORDER>(data, len, scale, advance, skip); + } + template void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + writeBytes3<0, DATA_NOP, RGB_ORDER>(data, len, scale, advance, skip); + } + void writeBytes3(register uint8_t *data, int len, register uint8_t scale, bool advance=true, uint8_t skip=0) { + writeBytes3<0, DATA_NOP, RGB>(data, len, scale, advance, skip); + } + +}; + +#endif + +#if defined(SPSR) + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Hardware SPI support using SPDR registers and friends +// +// Technically speaking, this uses the AVR SPI registers. This will work on the Teensy 3.0 because Paul made a set of compatability +// classes that map the AVR SPI registers to ARM's, however this caps the performance of output. +// +// TODO: implement ARMHardwareSPIOutput +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +class AVRHardwareSPIOutput { + Selectable *m_pSelect; + bool mWait; +public: + AVRHardwareSPIOutput() { m_pSelect = NULL; mWait = false;} + AVRHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; } + void setSelect(Selectable *pSelect) { m_pSelect = pSelect; } + + void setSPIRate() { + SPCR &= ~ ( (1<= 128) { SPCR |= (1<= 64) { SPCR |= (1<= 32) { SPCR |= (1<= 16) { SPCR |= (1<= 8) { SPCR |= (1<= 4) { /* do nothing - default rate */ } + else { b2x = true; } + + if(b2x) { SPSR |= (1<::setOutput(); + FastPin<_CLOCK_PIN>::setOutput(); +#ifdef SPI_SELECT + // Make sure the slave select line is set to output, or arduino will block us + FastPin::setOutput(); + FastPin::lo(); +#endif + release(); + + SPCR |= ((1<= 128) { SPCR |= (1<= 64) { SPCR |= (1<= 32) { SPCR |= (1<= 16) { SPCR |= (1<= 8) { SPCR |= (1<= 4) { /* do nothing - default rate */ } + else { b2x = true; } + + if(b2x) { SPSR |= (1<>8); writeByte(w&0xFF); } + + static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPDR=b; shouldWait(true); } + static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPDR=b; shouldWait(true); wait(); } + static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPDR=b; shouldWait(true); } + + template inline static void writeBit(uint8_t b) { + SPCR &= ~(1 << SPE); + if(b & (1 << BIT)) { + FastPin<_DATA_PIN>::hi(); + } else { + FastPin<_DATA_PIN>::lo(); + } + + FastPin<_CLOCK_PIN>::hi(); + FastPin<_CLOCK_PIN>::lo(); + SPCR |= 1 << SPE; + shouldWait(false); + } + + void select() { if(m_pSelect != NULL) { m_pSelect->select(); } } // FastPin<_SELECT_PIN>::hi(); } + void release() { if(m_pSelect != NULL) { m_pSelect->release(); } } // FastPin<_SELECT_PIN>::lo(); } + + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { writeByte(value); } + } + + void writeBytesValue(uint8_t value, int len) { + //setSPIRate(); + select(); + while(len--) { + writeByte(value); + } + release(); + } + + // Write a block of n uint8_ts out + template void writeBytes(register uint8_t *data, int len) { + //setSPIRate(); + uint8_t *end = data + len; + select(); + while(data != end) { + // a slight touch of delay here helps optimize the timing of the status register check loop (not used on ARM) + writeByte(D::adjust(*data++)); delaycycles<3>(); + } + release(); + } + + void writeBytes(register uint8_t *data, int len) { writeBytes(data, len); } + + // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template + // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping + template void writePixels(PixelController pixels) { + //setSPIRate(); + int len = pixels.mLen; + + select(); + while(pixels.has(1)) { + if(FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + writeBytePostWait(D::adjust(pixels.loadAndScale0())); + writeBytePostWait(D::adjust(pixels.loadAndScale1())); + writeBytePostWait(D::adjust(pixels.loadAndScale2())); + } else { + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + } + + pixels.advanceData(); + pixels.stepDithering(); + } + D::postBlock(len); + release(); + } +}; +#endif + +#else +// #define FORCE_SOFTWARE_SPI +#endif + +#endif diff --git a/platforms/avr/led_sysdefs_avr.h b/platforms/avr/led_sysdefs_avr.h new file mode 100644 index 00000000..19cfabee --- /dev/null +++ b/platforms/avr/led_sysdefs_avr.h @@ -0,0 +1,21 @@ +#ifndef __INC_LED_SYSDEFS_AVR_H +#define __INC_LED_SYSDEFS_AVR_H + +#define FASTLED_AVR +#define FASTLED_ACCURATE_CLOCK + +#ifndef INTERRUPT_THRESHOLD +#define INTERRUPT_THRESHOLD 2 +#endif + +#include +#include // for cli/se definitions + +// Define the rgister types +#if defined(ARDUINO) // && ARDUINO < 150 +typedef volatile uint8_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ +typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ +#endif + + +#endif diff --git a/preview_changes.txt b/preview_changes.txt index 84407524..e69dd3cb 100644 --- a/preview_changes.txt +++ b/preview_changes.txt @@ -6,4 +6,4 @@ FastLED 3.1 preview changes: * interrupt friendly code on teensy 3/3.1 * interrupt friendly code on AVR * interrupt friendly code on the due - +* code re-org for future wider platform support diff --git a/smartmatrix_t3.h b/smartmatrix_t3.h deleted file mode 100644 index ba77d149..00000000 --- a/smartmatrix_t3.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef __INC_SMARTMATRIX_T3_H -#define __INC_SMARTMATRIX_T3_H - -#ifdef SmartMatrix_h -#include - -extern SmartMatrix *pSmartMatrix; - -// note - dmx simple must be included before FastSPI for this code to be enabled -class CSmartMatrixController : public CLEDController { - SmartMatrix matrix; - -public: - // initialize the LED controller - virtual void init() { - // Initialize 32x32 LED Matrix - matrix.begin(); - matrix.setBrightness(255); - matrix.setColorCorrection(ccNone); - - // Clear screen - clearLeds(0); - matrix.swapBuffers(); - pSmartMatrix = &matrix; - } - - // 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 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(); - } - 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 pixels(data, nLeds, scale, getDither()); -#ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER - rgb24 *md = matrix.getRealBackBuffer(); -#else - rgb24 *md = matrix.backBuffer(); -#endif - while(nLeds--) { - md->red = pixels.loadAndScale0(); - md->green = pixels.loadAndScale1(); - md->blue = pixels.loadAndScale2(); - md++; - pixels.advanceData(); - pixels.stepDithering(); - } - matrix.swapBuffers(); -#ifdef SMART_MATRIX_CAN_TRIPLE_BUFFER - matrix.setBackBuffer((rgb24*)data); -#endif - } - -#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 -}; - -#endif - -#endif diff --git a/wiring.cpp b/wiring.cpp index d9efc8f6..7d62e4bf 100644 --- a/wiring.cpp +++ b/wiring.cpp @@ -1,6 +1,7 @@ #include "FastLED.h" -#ifdef FASTLED_AVR + +#if defined(FASTLED_AVR) && !defined(TEENSYDUINO) && !defined(LIB8_ATTINY) extern "C" { // the prescaler is set so that timer0 ticks every 64 clock cycles, and the // the overflow handler is called every 256 ticks. -- cgit v1.2.3 From 0be759147b0a7049e8cd3d6a09c889b3461fba97 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Tue, 18 Nov 2014 12:07:41 -0500 Subject: Greatly improved randomness of random8 with just one add operation. It's always worth visually inspecting the data. --- lib8tion.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib8tion.h b/lib8tion.h index d7eaa380..eb3f5c8a 100644 --- a/lib8tion.h +++ b/lib8tion.h @@ -523,12 +523,11 @@ LIB8STATIC int8_t avg7( int8_t i, int8_t j) // scale8: scale one byte by a second one, which is treated as // the numerator of a fraction whose denominator is 256 // In other words, it computes i * (scale / 256) -// 4 clocks AVR, 2 clocks ARM +// 4 clocks AVR with MUL, 2 clocks ARM LIB8STATIC uint8_t scale8( uint8_t i, fract8 scale) { #if SCALE8_C == 1 - return - ((int)i * (int)(scale) ) >> 8; + return ((uint16_t)i * (uint16_t)(scale) ) >> 8; #elif SCALE8_AVRASM == 1 #if defined(LIB8_ATTINY) uint8_t work=0; @@ -1110,8 +1109,8 @@ LIB8STATIC uint8_t brighten8_lin( uint8_t x ) // A 16-bit PNRG good enough for LED animations // X(n+1) = (2053 * X(n)) + 13849) -#define RAND16_2053 2053 -#define RAND16_13849 13849 +#define RAND16_2053 ((uint16_t)(2053)) +#define RAND16_13849 ((uint16_t)(13849)) extern uint16_t rand16seed;// = RAND16_SEED; @@ -1119,7 +1118,10 @@ extern uint16_t rand16seed;// = RAND16_SEED; LIB8STATIC uint8_t random8() { rand16seed = (rand16seed * RAND16_2053) + RAND16_13849; - return rand16seed; + // return the sum of the high and low bytes, for better + // mixing and non-sequential correlation + return (uint8_t)(((uint8_t)(rand16seed & 0xFF)) + + ((uint8_t)(rand16seed >> 8))); } LIB8STATIC uint16_t random16() -- cgit v1.2.3 From 63570c966d65fe417ef659ced3d589393aef4dfe Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Wed, 19 Nov 2014 14:58:53 -0800 Subject: Fix A5 support on the leonardo --- platforms/avr/fastpin_avr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/avr/fastpin_avr.h b/platforms/avr/fastpin_avr.h index f5354a9d..f223de10 100644 --- a/platforms/avr/fastpin_avr.h +++ b/platforms/avr/fastpin_avr.h @@ -194,7 +194,7 @@ _DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 64, C); _DEFPIN_AVR(6, 128, D); _DEFPIN_AV _DEFPIN_AVR(8, 16, B); _DEFPIN_AVR(9, 32, B); _DEFPIN_AVR(10, 64, B); _DEFPIN_AVR(11, 128, B); _DEFPIN_AVR(12, 64, D); _DEFPIN_AVR(13, 128, C); _DEFPIN_AVR(14, 8, B); _DEFPIN_AVR(15, 2, B); _DEFPIN_AVR(16, 4, B); _DEFPIN_AVR(17, 1, B); _DEFPIN_AVR(18, 128, F); _DEFPIN_AVR(19, 64, F); -_DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_AVR(23, 0, F); +_DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_AVR(23, 1, F); #define SPI_DATA 16 #define SPI_CLOCK 15 -- cgit v1.2.3 From 78f6b7a4f48e24cd32a2402ca0c6cab8207dd7c1 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Fri, 21 Nov 2014 23:44:11 -0800 Subject: We only need to see the FastLED version warning once, thank you very much --- FastLED.cpp | 1 + FastLED.h | 2 ++ colorutils.cpp | 1 + hsv2rgb.cpp | 1 + lib8tion.cpp | 1 + noise.cpp | 1 + power_mgt.cpp | 1 + wiring.cpp | 1 + 8 files changed, 9 insertions(+) diff --git a/FastLED.cpp b/FastLED.cpp index 077efbe3..821f1e2f 100644 --- a/FastLED.cpp +++ b/FastLED.cpp @@ -1,3 +1,4 @@ +#define FASTLED_INTERNAL #include "FastLED.h" #if defined(__SAM3X8E__) diff --git a/FastLED.h b/FastLED.h index 951d105f..2bce7ded 100644 --- a/FastLED.h +++ b/FastLED.h @@ -8,7 +8,9 @@ #define str(s) #s #define FASTLED_VERSION 3001000 +#ifndef FASTLED_INTERNAL #warning FastLED version 3001000 (Not really a warning, just telling you here.) +#endif #ifndef __PROG_TYPES_COMPAT__ #define __PROG_TYPES_COMPAT__ diff --git a/colorutils.cpp b/colorutils.cpp index d16bf2e4..4a4d53a4 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -1,3 +1,4 @@ +#define FASTLED_INTERNAL #define __PROG_TYPES_COMPAT__ #include diff --git a/hsv2rgb.cpp b/hsv2rgb.cpp index 203d1db6..8a6d0575 100644 --- a/hsv2rgb.cpp +++ b/hsv2rgb.cpp @@ -1,3 +1,4 @@ +#define FASTLED_INTERNAL #include #include "FastLED.h" diff --git a/lib8tion.cpp b/lib8tion.cpp index d7d6b13e..557fa005 100644 --- a/lib8tion.cpp +++ b/lib8tion.cpp @@ -1,3 +1,4 @@ +#define FASTLED_INTERNAL #include #define RAND16_SEED 1337 diff --git a/noise.cpp b/noise.cpp index 4342a20c..0ad00c74 100644 --- a/noise.cpp +++ b/noise.cpp @@ -1,3 +1,4 @@ +#define FASTLED_INTERNAL #include #ifdef FASTLED_AVR diff --git a/power_mgt.cpp b/power_mgt.cpp index 46befd6e..c9367147 100644 --- a/power_mgt.cpp +++ b/power_mgt.cpp @@ -1,3 +1,4 @@ +#define FASTLED_INTERNAL #include "FastLED.h" #include "power_mgt.h" diff --git a/wiring.cpp b/wiring.cpp index 7d62e4bf..a3ee6d15 100644 --- a/wiring.cpp +++ b/wiring.cpp @@ -1,3 +1,4 @@ +#define FASTLED_INTERNAL #include "FastLED.h" -- cgit v1.2.3 From d51d5c7ce1ffeba8739cd0faaaaf5e8379a9176d Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 24 Nov 2014 12:10:58 -0800 Subject: Shut off version warning in color palettes --- colorpalettes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colorpalettes.cpp b/colorpalettes.cpp index 8cec8980..dea16f77 100644 --- a/colorpalettes.cpp +++ b/colorpalettes.cpp @@ -1,6 +1,6 @@ #ifndef __INC_COLORPALETTES_H #define __INC_COLORPALETTES_H - +#define FASTLED_INTERNAL #include "FastLED.h" #include "colorutils.h" #include "colorpalettes.h" -- cgit v1.2.3 From c2f9d3159ae858e6ca2af118cb3666f9a05d560f Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 24 Nov 2014 12:11:38 -0800 Subject: Add configuration option for allowing/disallowing interrupts. Disable by default for AVR, block out AVR implementation of wiring functions. --- fastled_config.h | 7 ++++++ led_sysdefs.h | 2 ++ platforms.h | 2 ++ platforms/arm/k20/clockless_arm_k20.h | 7 +++++- platforms/arm/k20/clockless_block_arm_k20.h | 37 +++++++++++++++++++++++++---- platforms/arm/k20/led_sysdefs_arm_k20.h | 5 ++++ platforms/arm/sam/clockless_arm_sam.h | 4 ++++ platforms/arm/sam/clockless_block_arm_sam.h | 7 ++++++ platforms/arm/sam/led_sysdefs_arm_sam.h | 5 ++++ platforms/avr/clockless_trinket.h | 20 +++++++++++++++- platforms/avr/led_sysdefs_avr.h | 14 +++++++++++ wiring.cpp | 4 ++++ 12 files changed, 108 insertions(+), 6 deletions(-) diff --git a/fastled_config.h b/fastled_config.h index 3e5a8c4e..e085f61a 100644 --- a/fastled_config.h +++ b/fastled_config.h @@ -9,4 +9,11 @@ // Use this option only for debugging bitbang'd spi access or to work around bugs in hardware // spi access. Forces use of bit-banged spi, even on pins that has hardware SPI available. // #define FORCE_SOFTWARE_SPI + +// Use this to force FastLED to allow interrupts in the clockless chipsets (or to force it to +// disallow), overriding the default on platforms that support this. Set the value to 1 to +// allow interrupts or 0 to disallow them. +// #define FASTLED_ALLOW_INTERRUPTS 1 +// #define FASTLED_ALLOW_INTERRUPTS 0 + #endif diff --git a/led_sysdefs.h b/led_sysdefs.h index 29bced42..3e7ebaa2 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -1,6 +1,8 @@ #ifndef __INC_LED_SYSDEFS_H #define __INC_LED_SYSDEFS_H +#include "fastled_config.h" + #if defined(__MK20DX128__) || defined(__MK20DX256__) // Include k20/T3 headers #include "platforms/arm/k20/led_sysdefs_arm_k20.h" diff --git a/platforms.h b/platforms.h index 9f1c7579..5b34ddc0 100644 --- a/platforms.h +++ b/platforms.h @@ -1,6 +1,8 @@ #ifndef __INC_PLATFORMS_H #define __INC_PLATFORMS_H +#include "fastled_config.h" + #if defined(__MK20DX128__) || defined(__MK20DX256__) // Include k20/T3 headers #include "platforms/arm/k20/fastled_arm_k20.h" diff --git a/platforms/arm/k20/clockless_arm_k20.h b/platforms/arm/k20/clockless_arm_k20.h index d96c9bb2..53b6f85b 100644 --- a/platforms/arm/k20/clockless_arm_k20.h +++ b/platforms/arm/k20/clockless_arm_k20.h @@ -97,17 +97,20 @@ protected: pixels.preStepFirstByteDithering(); register uint8_t b = pixels.loadAndScale0(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + #endif while(pixels.has(1)) { pixels.stepDithering(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); // if interrupts took longer than 45µs, punt on the current frame if(ARM_DWT_CYCCNT > next_mark) { if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } } - + #endif // Write first byte, read next byte writeBits<8+XTRA0>(next_mark, port, hi, lo, b); b = pixels.loadAndScale1(); @@ -119,7 +122,9 @@ protected: // Write third byte, read 1st byte of next pixel writeBits<8+XTRA0>(next_mark, port, hi, lo, b); b = pixels.advanceAndLoadAndScale0(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) sei(); + #endif }; return ARM_DWT_CYCCNT; diff --git a/platforms/arm/k20/clockless_block_arm_k20.h b/platforms/arm/k20/clockless_block_arm_k20.h index 63dc5030..bebbf0d7 100644 --- a/platforms/arm/k20/clockless_block_arm_k20.h +++ b/platforms/arm/k20/clockless_block_arm_k20.h @@ -88,9 +88,9 @@ public: typedef union { - uint8_t bytes[16]; - uint16_t shorts[8]; - uint32_t raw[4]; + uint8_t bytes[12]; + uint16_t shorts[6]; + uint32_t raw[3]; } Lines; template __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, MultiPixelController &pixels) { // , register uint32_t & b2) { @@ -132,11 +132,11 @@ public: while(ARM_DWT_CYCCNT < next_mark); next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; *FastPin::sport() = PORT_MASK; - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); if(LANES>8) { *FastPin::cport() = ((~b2.shorts[i]) & PORT_MASK); } else { + // b2.bytes[0] = 0; *FastPin::cport() = ((~b2.bytes[7-i]) & PORT_MASK); } @@ -144,6 +144,21 @@ public: *FastPin::cport() = PORT_MASK; } + + + // while(ARM_DWT_CYCCNT < next_mark); + // next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3; + // *FastPin::sport() = PORT_MASK; + // + // while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6)); + // if(LANES>8) { + // *FastPin::cport() = ((~b2.shorts[7]) & PORT_MASK); + // } else { + // *FastPin::cport() = PORT_MASK; // ((~b2.bytes[7-i]) & PORT_MASK); + // } + // + // while((next_mark - ARM_DWT_CYCCNT) > (T3)); + // *FastPin::cport() = PORT_MASK; } @@ -165,15 +180,19 @@ public: b0.bytes[i] = allpixels.loadAndScale0(i); } + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + #endif while(nLeds--) { + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); // if interrupts took longer than 45µs, punt on the current frame if(ARM_DWT_CYCCNT > next_mark) { if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-5)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } } + #endif allpixels.stepDithering(); // Write first byte, read next byte @@ -185,7 +204,9 @@ public: // Write third byte writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + #if (FASTLED_ALLOW_INTERRUPTS == 1) sei(); + #endif }; return ARM_DWT_CYCCNT; @@ -314,16 +335,21 @@ public: b0.bytes[i] = allpixels.loadAndScale0(i); } + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + #endif while(nLeds--) { allpixels.stepDithering(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); // if interrupts took longer than 45µs, punt on the current frame if(ARM_DWT_CYCCNT > next_mark) { if((ARM_DWT_CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } } + #endif + // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, allpixels); @@ -333,7 +359,10 @@ public: // Write third byte writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + + #if (FASTLED_ALLOW_INTERRUPTS == 1) sei(); + #endif }; return ARM_DWT_CYCCNT; diff --git a/platforms/arm/k20/led_sysdefs_arm_k20.h b/platforms/arm/k20/led_sysdefs_arm_k20.h index abed80f9..e0a8a979 100644 --- a/platforms/arm/k20/led_sysdefs_arm_k20.h +++ b/platforms/arm/k20/led_sysdefs_arm_k20.h @@ -9,6 +9,11 @@ #define INTERRUPT_THRESHOLD 1 #endif +// Default to allowing interrupts +#ifndef FASTLED_ALLOW_INTERRUPTS +#define FASTLED_ALLOW_INTERRUPTS 1 +#endif + #if (F_CPU == 96000000) #define CLK_DBL 1 #endif diff --git a/platforms/arm/sam/clockless_arm_sam.h b/platforms/arm/sam/clockless_arm_sam.h index 6924cc9d..ebc8c0ad 100644 --- a/platforms/arm/sam/clockless_arm_sam.h +++ b/platforms/arm/sam/clockless_arm_sam.h @@ -107,10 +107,12 @@ protected: while(pixels.has(1)) { pixels.stepDithering(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); if(DUE_TIMER_VAL > next_mark) { if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; } } + #endif writeBits<8+XTRA0>(next_mark, port, b); @@ -121,7 +123,9 @@ protected: writeBits<8+XTRA0>(next_mark, port,b); b = pixels.advanceAndLoadAndScale0(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) sei(); + #endif }; TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); diff --git a/platforms/arm/sam/clockless_block_arm_sam.h b/platforms/arm/sam/clockless_block_arm_sam.h index 51eb1b92..128617a2 100644 --- a/platforms/arm/sam/clockless_block_arm_sam.h +++ b/platforms/arm/sam/clockless_block_arm_sam.h @@ -159,16 +159,20 @@ public: pmc_enable_periph_clk(DUE_TIMER_ID); TC_Start(DUE_TIMER,DUE_TIMER_CHANNEL); + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); + #endif uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL)); while(nLeds--) { allpixels.stepDithering(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); if(DUE_TIMER_VAL > next_mark) { if((DUE_TIMER_VAL - next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL); return DUE_TIMER_VAL; } } + #endif // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, b1, allpixels); @@ -179,7 +183,10 @@ public: allpixels.advanceData(); // Write third byte writeBits<8+XTRA0,0>(next_mark, b2, b0, allpixels); + + #if (FASTLED_ALLOW_INTERRUPTS == 1) sei(); + #endif } return DUE_TIMER_VAL; diff --git a/platforms/arm/sam/led_sysdefs_arm_sam.h b/platforms/arm/sam/led_sysdefs_arm_sam.h index e45f9609..a6ef12bb 100644 --- a/platforms/arm/sam/led_sysdefs_arm_sam.h +++ b/platforms/arm/sam/led_sysdefs_arm_sam.h @@ -22,6 +22,11 @@ #define INTERRUPT_THRESHOLD 1 #endif +// Default to allowing interrupts +#ifndef FASTLED_ALLOW_INTERRUPTS +#define FASTLED_ALLOW_INTERRUPTS 1 +#endif + // reuseing/abusing cli/sei defs for due #define cli() __disable_irq(); __disable_fault_irq(); #define sei() __enable_irq(); __enable_fault_irq(); diff --git a/platforms/avr/clockless_trinket.h b/platforms/avr/clockless_trinket.h index 4630719d..fd831319 100644 --- a/platforms/avr/clockless_trinket.h +++ b/platforms/avr/clockless_trinket.h @@ -104,6 +104,16 @@ protected: showRGBInternal(pixels); + // 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)); + if(microsTaken > 1024) { + MS_COUNTER += (microsTaken >> 10); + } else { + MS_COUNTER++; + } + #endif + sei(); mWait.mark(); } @@ -243,9 +253,11 @@ protected: uint8_t loopvar=0; + #if (FASTLED_ALLOW_INTERRUPTS == 1) TCCR0A |= 0x30; OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); TIFR0 = 0x04; + #endif { while(count--) { @@ -256,8 +268,8 @@ protected: ADJDITHER2(d1,e1); ADJDITHER2(d2,e2); + #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); - if(TIFR0 & 0x04) { sei(); TCCR0A &= ~0x30; @@ -265,6 +277,7 @@ protected: } hi = *port | mask; lo = *port & ~mask; + #endif // Sum of the clock counts across each row should be 10 for 8Mhz, WS2811 // The values in the D1/D2/D3 indicate how many cycles the previous column takes @@ -347,15 +360,20 @@ protected: HI1 D1(1) QLO2(b2, 1) D2(0) LO1 D3(0) HI1 D1(1) QLO2(b2, 0) D2(0) LO1 D3(0) #endif + + #if (FASTLED_ALLOW_INTERRUPTS == 1) // set the counter mark OCR0B = (uint8_t)(TCNT0 + ((WAIT_TIME-INTERRUPT_THRESHOLD)/US_PER_TICK)); TIFR0 = 0x04; sei(); + #endif } } + #if (FASTLED_ALLOW_INTERRUPTS == 1) // stop using the clock juggler TCCR0A &= ~0x30; + #endif } #ifdef SUPPORT_ARGB diff --git a/platforms/avr/led_sysdefs_avr.h b/platforms/avr/led_sysdefs_avr.h index 19cfabee..e4972c7d 100644 --- a/platforms/avr/led_sysdefs_avr.h +++ b/platforms/avr/led_sysdefs_avr.h @@ -18,4 +18,18 @@ typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile u #endif +// Default to disallowing interrupts (may want to gate this on teensy2 vs. other arm platforms, since the +// teensy2 has a good, fast millis interrupt implementation) +#ifndef FASTLED_ALLOW_INTERRUPTS +#define FASTLED_ALLOW_INTERRUPTS 0 +#endif + +# if defined(CORE_TEENSY) +extern volatile unsigned long timer0_millis_count; +# define MS_COUNTER timer0_millis_count +# else +extern volatile unsigned long timer0_millis; +# define MS_COUNTER timer0_millis +# endif + #endif diff --git a/wiring.cpp b/wiring.cpp index a3ee6d15..62317b2a 100644 --- a/wiring.cpp +++ b/wiring.cpp @@ -1,6 +1,7 @@ #define FASTLED_INTERNAL #include "FastLED.h" +#if 0 #if defined(FASTLED_AVR) && !defined(TEENSYDUINO) && !defined(LIB8_ATTINY) extern "C" { @@ -230,3 +231,6 @@ void init() } }; #endif + +#endif + -- cgit v1.2.3 From 832c1bcdecb41b00a8897f364a244aad96a5dc2f Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Mon, 24 Nov 2014 12:13:09 -0800 Subject: Prefix config defines with FASTLED_ to make sure we don't conflict with anything else. --- examples/FirstLight/FirstLight.ino | 6 +++--- fastled_config.h | 4 ++-- fastspi.h | 2 +- platforms/arm/k20/fastpin_arm_k20.h | 4 ++-- platforms/arm/sam/fastpin_arm_sam.h | 4 ++-- platforms/avr/fastpin_avr.h | 4 ++-- platforms/avr/fastspi_avr.h | 2 +- release_notes.md | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/FirstLight/FirstLight.ino b/examples/FirstLight/FirstLight.ino index 928c7bbd..beec2986 100644 --- a/examples/FirstLight/FirstLight.ino +++ b/examples/FirstLight/FirstLight.ino @@ -1,8 +1,8 @@ // Use if you want to force the software SPI subsystem to be used for some reason (generally, you don't) -// #define FORCE_SOFTWARE_SPI +// #define FASTLED_FORCE_SOFTWARE_SPI // Use if you want to force non-accelerated pin access (hint: you really don't, it breaks lots of things) -// #define FORCE_SOFTWARE_SPI -// #define FORCE_SOFTWARE_PINS +// #define FASTLED_FORCE_SOFTWARE_SPI +// #define FASTLED_FORCE_SOFTWARE_PINS #include "FastLED.h" /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/fastled_config.h b/fastled_config.h index e085f61a..d7a0a8d9 100644 --- a/fastled_config.h +++ b/fastled_config.h @@ -4,11 +4,11 @@ // Use this option only for debugging pin access and forcing software pin access. Note that // software pin access only works in Arduino based environments. Forces use of digitalWrite // methods for pin access vs. direct hardware port access -// #define FORCE_SOFTWARE_PINS +// #define FASTLED_FORCE_SOFTWARE_PINS // Use this option only for debugging bitbang'd spi access or to work around bugs in hardware // spi access. Forces use of bit-banged spi, even on pins that has hardware SPI available. -// #define FORCE_SOFTWARE_SPI +// #define FASTLED_FORCE_SOFTWARE_SPI // Use this to force FastLED to allow interrupts in the clockless chipsets (or to force it to // disallow), overriding the default on platforms that support this. Set the value to 1 to diff --git a/fastspi.h b/fastspi.h index 4c247157..d64a0984 100644 --- a/fastspi.h +++ b/fastspi.h @@ -27,7 +27,7 @@ class SPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_ template class SoftwareSPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; -#ifndef FORCE_SOFTWARE_SPI +#ifndef FASTLED_FORCE_SOFTWARE_SPI #if defined(SPI_DATA) && defined(SPI_CLOCK) #if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY) diff --git a/platforms/arm/k20/fastpin_arm_k20.h b/platforms/arm/k20/fastpin_arm_k20.h index edbbd5b9..99666a49 100644 --- a/platforms/arm/k20/fastpin_arm_k20.h +++ b/platforms/arm/k20/fastpin_arm_k20.h @@ -1,7 +1,7 @@ #ifndef __FASTPIN_ARM_K20_H #define __FASTPIN_ARM_K20_H -#if defined(FORCE_SOFTWARE_PINS) +#if defined(FASTLED_FORCE_SOFTWARE_PINS) #warning "Software pin support forced, pin access will be sloightly slower." #define NO_HARDWARE_PIN_SUPPORT #undef HAS_HARDWARE_PIN_SUPPORT @@ -113,6 +113,6 @@ _DEFPIN_ARM(32, 18, B); _DEFPIN_ARM(33, 4, A); #define HAS_HARDWARE_PIN_SUPPORT #endif -#endif // FORCE_SOFTWARE_PINS +#endif // FASTLED_FORCE_SOFTWARE_PINS #endif // __INC_FASTPIN_ARM_K20 diff --git a/platforms/arm/sam/fastpin_arm_sam.h b/platforms/arm/sam/fastpin_arm_sam.h index e1a36990..a370e753 100644 --- a/platforms/arm/sam/fastpin_arm_sam.h +++ b/platforms/arm/sam/fastpin_arm_sam.h @@ -1,7 +1,7 @@ #ifndef __INC_FASTPIN_ARM_SAM_H #define __INC_FASTPIN_ARM_SAM_H -#if defined(FORCE_SOFTWARE_PINS) +#if defined(FASTLED_FORCE_SOFTWARE_PINS) #warning "Software pin support forced, pin access will be sloightly slower." #define NO_HARDWARE_PIN_SUPPORT #undef HAS_HARDWARE_PIN_SUPPORT @@ -127,6 +127,6 @@ _DEFPIN_DUE(110, 29, B); _DEFPIN_DUE(111, 30, B); _DEFPIN_DUE(112, 31, B); _DEFP #endif -#endif // FORCE_SOFTWARE_PINS +#endif // FASTLED_FORCE_SOFTWARE_PINS #endif // __INC_FASTPIN_ARM_SAM_H diff --git a/platforms/avr/fastpin_avr.h b/platforms/avr/fastpin_avr.h index f223de10..fdae2598 100644 --- a/platforms/avr/fastpin_avr.h +++ b/platforms/avr/fastpin_avr.h @@ -1,7 +1,7 @@ #ifndef __INC_FASTPIN_AVR_H #define __INC_FASTPIN_AVR_H -#if defined(FORCE_SOFTWARE_PINS) +#if defined(FASTLED_FORCE_SOFTWARE_PINS) #warning "Software pin support forced, pin access will be sloightly slower." #define NO_HARDWARE_PIN_SUPPORT #undef HAS_HARDWARE_PIN_SUPPORT @@ -203,6 +203,6 @@ _DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_A #endif -#endif // FORCE_SOFTWARE_PINS +#endif // FASTLED_FORCE_SOFTWARE_PINS #endif // __INC_FASTPIN_AVR_H diff --git a/platforms/avr/fastspi_avr.h b/platforms/avr/fastspi_avr.h index 6470f37d..7f0b731b 100644 --- a/platforms/avr/fastspi_avr.h +++ b/platforms/avr/fastspi_avr.h @@ -294,7 +294,7 @@ public: #endif #else -// #define FORCE_SOFTWARE_SPI +// #define FASTLED_FORCE_SOFTWARE_SPI #endif #endif diff --git a/release_notes.md b/release_notes.md index c88bc403..fa3ffbaf 100644 --- a/release_notes.md +++ b/release_notes.md @@ -91,7 +91,7 @@ FastLED2 * Enforce intra-frame timing for ws2801s * SM16716 support * Add #define FAST_SPI_INTERRUPTS_WRITE_PINS to make sure world is ok w/interrupts and SPI -* Add #define FORCE_SOFTWARE_SPI for those times when you absolutely don't want to use hardware SPI, ev +* Add #define FASTLED_FORCE_SOFTWARE_SPI for those times when you absolutely don't want to use hardware SPI, ev en if you're using the hardware SPI pins * Add pin definitions for the arduino megas - should fix ws2811 support * Add pin definitions for the leonardo - should fix spi support and pin mappings -- cgit v1.2.3 From 727022725a959162229badd58c8050ac92827a95 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Tue, 25 Nov 2014 12:25:58 -0500 Subject: Add ((weak)) attribute to forward declaration of user-supplied XY function --- colorutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colorutils.cpp b/colorutils.cpp index 4a4d53a4..bac21851 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -353,7 +353,7 @@ CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest, uint16_t count, fra // Forward declaration of the function "XY" which must be provided by // the application for use in two-dimensional filter functions. -uint16_t XY( uint8_t, uint8_t); +uint16_t XY( uint8_t, uint8_t) __attribute__ ((weak)); // blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors. -- cgit v1.2.3 From 07a5834c65ecd78cdef5d32b5b43d9c7b767b8d1 Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Tue, 25 Nov 2014 12:31:58 -0500 Subject: Fix off-by-one error in array blend functions. --- colorutils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/colorutils.cpp b/colorutils.cpp index bac21851..9e5808fc 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -267,7 +267,7 @@ CRGB blend( const CRGB& p1, const CRGB& p2, fract8 amountOfP2 ) CRGB* blend( const CRGB* src1, const CRGB* src2, CRGB* dest, uint16_t count, fract8 amountOfsrc2 ) { - for( uint16_t i = count; i; i--) { + for( uint16_t i = 0; i < count; i++) { dest[i] = blend(src1[i], src2[i], amountOfsrc2); } return dest; @@ -343,7 +343,7 @@ CHSV blend( const CHSV& p1, const CHSV& p2, fract8 amountOfP2, TGradientDirectio CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest, uint16_t count, fract8 amountOfsrc2, TGradientDirectionCode directionCode ) { - for( uint16_t i = count; i; i--) { + for( uint16_t i = 0; i < count; i++) { dest[i] = blend(src1[i], src2[i], amountOfsrc2, directionCode); } return dest; -- cgit v1.2.3 From 770905b264092106c18da218b46d035aa789205a Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Tue, 25 Nov 2014 12:53:21 -0500 Subject: Fix for lerp8by8 and lerp16by16 when rangestart and rangeend are inverted. --- lib8tion.h | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/lib8tion.h b/lib8tion.h index eb3f5c8a..3b913ecd 100644 --- a/lib8tion.h +++ b/lib8tion.h @@ -1419,13 +1419,29 @@ void * memset8 ( void * ptr, uint8_t value, uint16_t num ) __attribute__ ((noinl // linear interpolation, such as could be used for Perlin noise, etc. // +// A note on the structure of the lerp functions: +// The cases for b>a and b<=a are handled separately for +// speed: without knowing the relative order of a and b, +// the value (a-b) might be overflow the width of a or b, +// and have to be promoted to a wider, slower type. +// To avoid that, we separate the two cases, and are able +// to do all the math in the same width as the arguments, +// which is much faster and smaller on AVR. + // linear interpolation between two unsigned 8-bit values, // with 8-bit fraction LIB8STATIC uint8_t lerp8by8( uint8_t a, uint8_t b, fract8 frac) { - uint8_t delta = b - a; - uint8_t scaled = scale8( delta, frac); - uint8_t result = a + scaled; + uint8_t result; + if( b > a) { + uint8_t delta = b - a; + uint8_t scaled = scale8( delta, frac); + result = a + scaled; + } else { + uint8_t delta = a - b; + uint8_t scaled = scale8( delta, frac); + result = a - scaled; + } return result; } @@ -1433,23 +1449,19 @@ LIB8STATIC uint8_t lerp8by8( uint8_t a, uint8_t b, fract8 frac) // with 16-bit fraction LIB8STATIC uint16_t lerp16by16( uint16_t a, uint16_t b, fract16 frac) { - uint16_t delta = b - a; - uint32_t prod = (uint32_t)delta * (uint32_t)frac; - uint16_t scaled = prod >> 16; - uint16_t result = a + scaled; + uint16_t result; + if( b > a ) { + uint16_t delta = b - a; + uint32_t scaled = scale16(delta, frac); + result = a + scaled; + } else { + uint16_t delta = a - b; + uint16_t scaled = scale16( delta, frac); + result = a - scaled; + } return result; } - -// A note on the structure of lerp16by8 (and lerp15by8) : -// The cases for b>a and b<=a are handled separately for -// speed: without knowing the relative order of a and b, -// the value (a-b) might be a signed 17-bit value, which -// would have to be stored in a 32-bit signed int and -// processed as such. To avoid that, we separate the -// two cases, and are able to do all the math with 16-bit -// unsigned values, which is much faster and smaller on AVR. - // linear interpolation between two unsigned 16-bit values, // with 8-bit fraction LIB8STATIC uint16_t lerp16by8( uint16_t a, uint16_t b, fract8 frac) -- cgit v1.2.3 From 170d28275ae9728522696357f856148b9554693f Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Thu, 27 Nov 2014 01:08:48 -0500 Subject: Removed 'weak' attribte from forward reference to XY, as it allows (oops) compilation to succeed without an XY function linked in, even when one is needed. I'll switch it back when we start providing a default XY function. --- colorutils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/colorutils.cpp b/colorutils.cpp index 9e5808fc..13113b28 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -353,7 +353,7 @@ CHSV* blend( const CHSV* src1, const CHSV* src2, CHSV* dest, uint16_t count, fra // Forward declaration of the function "XY" which must be provided by // the application for use in two-dimensional filter functions. -uint16_t XY( uint8_t, uint8_t) __attribute__ ((weak)); +uint16_t XY( uint8_t, uint8_t);// __attribute__ ((weak)); // blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors. -- cgit v1.2.3 From 29327e44b76f83e53c5e7dfbc8ed04fc82396acb Mon Sep 17 00:00:00 2001 From: Mark Kriegsman Date: Thu, 27 Nov 2014 01:19:07 -0500 Subject: Made rainbow slightly brighter. No 'Rainbow Bright' jokes, please. --- colorutils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/colorutils.cpp b/colorutils.cpp index 13113b28..16433f45 100644 --- a/colorutils.cpp +++ b/colorutils.cpp @@ -38,9 +38,9 @@ void fill_rainbow( struct CRGB * pFirstLED, int numToFill, CHSV hsv; hsv.hue = initialhue; hsv.val = 255; - hsv.sat = 255; + hsv.sat = 240; for( int i = 0; i < numToFill; i++) { - hsv2rgb_rainbow( hsv, pFirstLED[i]); + pFirstLED[i] = hsv; hsv.hue += deltahue; } } @@ -52,7 +52,7 @@ void fill_rainbow( struct CHSV * targetArray, int numToFill, CHSV hsv; hsv.hue = initialhue; hsv.val = 255; - hsv.sat = 255; + hsv.sat = 240; for( int i = 0; i < numToFill; i++) { targetArray[i] = hsv; hsv.hue += deltahue; -- cgit v1.2.3 From 3630190d99ac23efaa69c3015271e86eb5c7e991 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sat, 29 Nov 2014 10:42:01 -0800 Subject: Gate FASTLED_ACCURATE_CLOCK on whether or not interrupts are allowed. --- platforms/arm/k20/led_sysdefs_arm_k20.h | 5 ++++- platforms/arm/sam/led_sysdefs_arm_sam.h | 4 ++++ platforms/avr/led_sysdefs_avr.h | 5 ++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/platforms/arm/k20/led_sysdefs_arm_k20.h b/platforms/arm/k20/led_sysdefs_arm_k20.h index e0a8a979..ed87c026 100644 --- a/platforms/arm/k20/led_sysdefs_arm_k20.h +++ b/platforms/arm/k20/led_sysdefs_arm_k20.h @@ -3,7 +3,6 @@ #define FASTLED_TEENSY3 #define FASTLED_ARM -#define FASTLED_ACCURATE_CLOCK #ifndef INTERRUPT_THRESHOLD #define INTERRUPT_THRESHOLD 1 @@ -14,6 +13,10 @@ #define FASTLED_ALLOW_INTERRUPTS 1 #endif +#if FASTLED_ALLOW_INTERRUPTS == 1 +#define FASTLED_ACCURATE_CLOCK +#endif + #if (F_CPU == 96000000) #define CLK_DBL 1 #endif diff --git a/platforms/arm/sam/led_sysdefs_arm_sam.h b/platforms/arm/sam/led_sysdefs_arm_sam.h index a6ef12bb..20bf4600 100644 --- a/platforms/arm/sam/led_sysdefs_arm_sam.h +++ b/platforms/arm/sam/led_sysdefs_arm_sam.h @@ -27,6 +27,10 @@ #define FASTLED_ALLOW_INTERRUPTS 1 #endif +#if FASTLED_ALLOW_INTERRUPTS == 1 +#define FASTLED_ACCURATE_CLOCK +#endif + // reuseing/abusing cli/sei defs for due #define cli() __disable_irq(); __disable_fault_irq(); #define sei() __enable_irq(); __enable_fault_irq(); diff --git a/platforms/avr/led_sysdefs_avr.h b/platforms/avr/led_sysdefs_avr.h index e4972c7d..ebba81aa 100644 --- a/platforms/avr/led_sysdefs_avr.h +++ b/platforms/avr/led_sysdefs_avr.h @@ -2,7 +2,6 @@ #define __INC_LED_SYSDEFS_AVR_H #define FASTLED_AVR -#define FASTLED_ACCURATE_CLOCK #ifndef INTERRUPT_THRESHOLD #define INTERRUPT_THRESHOLD 2 @@ -24,6 +23,10 @@ typedef volatile uint8_t RwReg; /**< Read-Write 8-bit register (volatile u #define FASTLED_ALLOW_INTERRUPTS 0 #endif +#if FASTLED_ALLOW_INTERRUPTS == 1 +#define FASTLED_ACCURATE_CLOCK +#endif + # if defined(CORE_TEENSY) extern volatile unsigned long timer0_millis_count; # define MS_COUNTER timer0_millis_count -- cgit v1.2.3 From d19495b3c2f266081723f0e140da78b102674016 Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sat, 29 Nov 2014 22:04:23 -0800 Subject: .gitignore html/ folder (contains gh-pages branch) --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..5ccff1a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +html/ -- cgit v1.2.3 From 9719d9de8a56f84deaf56b1f737f1ec5676bc8ed Mon Sep 17 00:00:00 2001 From: Daniel Garcia Date: Sun, 30 Nov 2014 21:19:35 -0800 Subject: Adding beginnings of doxygen documentation. --- docs/.Doxyfile.swp | Bin 0 -> 126976 bytes docs/Doxyfile | 2331 ++++++++++++++++++++++++++++++++++++++++++++++++++++ docs/mainpage.dox | 10 + 3 files changed, 2341 insertions(+) create mode 100644 docs/.Doxyfile.swp create mode 100644 docs/Doxyfile create mode 100644 docs/mainpage.dox diff --git a/docs/.Doxyfile.swp b/docs/.Doxyfile.swp new file mode 100644 index 00000000..d223ba7d Binary files /dev/null and b/docs/.Doxyfile.swp differ diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 00000000..951463b8 --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,2331 @@ +# Doxyfile 1.8.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "FastLED" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 3.1 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html/docs/3.1 + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra stylesheet files is of importance (e.g. the last +# stylesheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /