diff options
author | Daniel Garcia <danielgarcia@gmail.com> | 2016-05-22 15:39:05 +0300 |
---|---|---|
committer | Daniel Garcia <danielgarcia@gmail.com> | 2016-05-22 15:39:05 +0300 |
commit | baceb63c180d0947a4d505e6458c437f7097bd6d (patch) | |
tree | 64ce6b543cf75b636e9238ad8726b4ce496c9243 | |
parent | 20e5042e9f868c0c56ce08571e0cc3344af9e8f4 (diff) |
Tweak 4-way parallel output to work on pins 12-15 on esp8266 - keep blocked out for now, needs some more testing.
-rw-r--r-- | bitswap.h | 2 | ||||
-rw-r--r-- | platforms/esp/8266/clockless_block_esp8266.h | 139 | ||||
-rw-r--r-- | platforms/esp/8266/clockless_esp8266.h | 62 | ||||
-rw-r--r-- | platforms/esp/8266/fastpin_esp8266.h | 23 |
4 files changed, 110 insertions, 116 deletions
@@ -168,6 +168,8 @@ __attribute__((always_inline)) inline void slowswap(unsigned char *A, unsigned c } } +void transpose8x1_noinline(unsigned char *A, unsigned char *B); + /// Simplified form of bits rotating function. Based on code found here - http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt - rotating /// data into LSB for a faster write (the code using this data can happily walk the array backwards) __attribute__((always_inline)) inline void transpose8x1(unsigned char *A, unsigned char *B) { diff --git a/platforms/esp/8266/clockless_block_esp8266.h b/platforms/esp/8266/clockless_block_esp8266.h index 03c334e6..7ef284e7 100644 --- a/platforms/esp/8266/clockless_block_esp8266.h +++ b/platforms/esp/8266/clockless_block_esp8266.h @@ -4,14 +4,14 @@ #define FASTLED_HAS_BLOCKLESS 1 #define PORTA_FIRST_PIN 0 -#define PORT_MASK (((1<<LANES)-1) & 0xFFFF) +#define PORT_MASK (((1<<LANES)-1) & 0x0000FFFFL) #define MIN(X,Y) (((X)<(Y)) ? (X):(Y)) #define USED_LANES (MIN(LANES,16)) #define LAST_PIN (FIRST_PIN + USED_LANES - 1) FASTLED_NAMESPACE_BEGIN -template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 40> +template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 5> class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PORT_MASK> { typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t; typedef typename FastPin<FIRST_PIN>::port_t data_t; @@ -23,15 +23,22 @@ public: virtual int size() { return CLEDController::size() * LANES; } virtual void showPixels(PixelController<RGB_ORDER, LANES, PORT_MASK> & pixels) { - mWait.wait(); - uint32_t clocks = showRGBInternal(pixels); + // mWait.wait(); + /*uint32_t clocks = */ + int cnt=2; + while(!showRGBInternal(pixels) && cnt--) { + os_intr_unlock(); + delayMicroseconds(WAIT_TIME * 10); + os_intr_lock(); + showRGBInternal(pixels); + } // #if FASTLED_ALLOW_INTTERUPTS == 0 // Adjust the timer // long microsTaken = CLKS_TO_MICROS(clocks); // MS_COUNTER += (1 + (microsTaken / 1000)); // #endif - mWait.mark(); + // mWait.mark(); } template<int PIN> static void initPin() { @@ -41,116 +48,89 @@ public: } virtual void init() { - initPin<0>(); - initPin<1>(); - initPin<2>(); - initPin<3>(); - initPin<4>(); - initPin<5>(); - initPin<6>(); - initPin<7>(); - initPin<8>(); - initPin<9>(); - initPin<10>(); - initPin<11>(); + // initPin<0>(); + // initPin<1>(); + // initPin<2>(); + // initPin<3>(); + // initPin<4>(); + // initPin<5>(); + // initPin<6>(); + // initPin<7>(); + // initPin<8>(); + // initPin<9>(); + // initPin<10>(); + // initPin<11>(); initPin<12>(); initPin<13>(); initPin<14>(); initPin<15>(); mPinMask = FastPin<FIRST_PIN>::mask(); mPort = FastPin<FIRST_PIN>::port(); + + // Serial.print("Mask is "); Serial.println(PORT_MASK); } virtual uint16_t getMaxRefreshRate() const { return 400; } typedef union { - uint8_t bytes[12]; - uint16_t shorts[6]; - uint32_t raw[3]; + uint8_t bytes[8]; + uint16_t shorts[4]; + uint32_t raw[2]; } Lines; -#define ESP_ADJUST (2*(F_CPU/24000000)) +#define ESP_ADJUST 0 // (2*(F_CPU/24000000)) +#define ESP_ADJUST2 0 template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, PixelController<RGB_ORDER, LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) { - register Lines b2; - if(USED_LANES>8) { - transpose8<1,2>(b.bytes,b2.bytes); - transpose8<1,2>(b.bytes+8,b2.bytes+1); - } else { - transpose8x1(b.bytes,b2.bytes); - } + Lines b2 = b; + transpose8x1_noinline(b.bytes,b2.bytes); + register uint8_t d = pixels.template getd<PX>(pixels); register uint8_t scale = pixels.template getscale<PX>(pixels); - for(register uint32_t i = 0; i < (USED_LANES/2); i++) { - while(__clock_cycles() < next_mark); - next_mark = __clock_cycles() + (T1+T2+T3)-3; - *FastPin<FIRST_PIN>::sport() = PORT_MASK; + for(register uint32_t i = 0; i < USED_LANES; i++) { + while((int32_t)(next_mark - __clock_cycles()) > 0); + next_mark = __clock_cycles() + (T1+T2+T3) + ESP_ADJUST; + *FastPin<FIRST_PIN>::sport() = PORT_MASK << FIRST_PIN; - while((next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST)); - if(USED_LANES>8) { - *FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK) << FIRST_PIN; - } else { - *FastPin<FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN; - } + while((int32_t)(next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST2)); + *FastPin<FIRST_PIN>::cport() = ((uint32_t)(~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN; - while((next_mark - __clock_cycles()) > (T3)); - *FastPin<FIRST_PIN>::cport() = PORT_MASK; + while((int32_t)(next_mark - __clock_cycles()) > (T3 + ESP_ADJUST)); + *FastPin<FIRST_PIN>::cport() = PORT_MASK << FIRST_PIN; b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale); - b.bytes[i+(USED_LANES/2)] = pixels.template loadAndScale<PX>(pixels,i+(USED_LANES/2),d,scale); - } - - // if folks use an odd numnber of lanes, get the last byte's value here - if(USED_LANES & 0x01) { - b.bytes[USED_LANES-1] = pixels.template loadAndScale<PX>(pixels,USED_LANES-1,d,scale); } - for(register uint32_t i = USED_LANES/2; i < 8; i++) { - while(__clock_cycles() < next_mark); - next_mark = __clock_cycles() + (T1+T2+T3)-3; - *FastPin<FIRST_PIN>::sport() = PORT_MASK; - while((next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST)); - if(USED_LANES>8) { - *FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK) << FIRST_PIN; - } else { - // b2.bytes[0] = 0; - *FastPin<FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN; - } + for(register uint32_t i = USED_LANES; i < 8; i++) { + while((int32_t)(next_mark - __clock_cycles()) > 0); + next_mark = __clock_cycles() + (T1+T2+T3) + ESP_ADJUST; + *FastPin<FIRST_PIN>::sport() = PORT_MASK << FIRST_PIN; - while((next_mark - __clock_cycles()) > (T3)); - *FastPin<FIRST_PIN>::cport() = PORT_MASK; + while((int32_t)(next_mark - __clock_cycles()) > (T2+T3+ESP_ADJUST2)); + *FastPin<FIRST_PIN>::cport() = ((uint32_t)(~b2.bytes[7-i]) & PORT_MASK) << FIRST_PIN; + while((int32_t)(next_mark - __clock_cycles()) > (T3 + ESP_ADJUST)); + *FastPin<FIRST_PIN>::cport() = PORT_MASK << FIRST_PIN; } } // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then // gcc will use register Y for the this pointer. static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) { - // Get access to the clock - uint32_t _start = __clock_cycles(); // Setup the pixel controller and load/scale the first byte - allpixels.preStepFirstByteDithering(); - register Lines b0; + Lines b0; - allpixels.preStepFirstByteDithering(); for(int i = 0; i < USED_LANES; i++) { b0.bytes[i] = allpixels.loadAndScale0(i); } + allpixels.preStepFirstByteDithering(); os_intr_lock(); - uint32_t next_mark = __clock_cycles() + (T1+T2+T3); + uint32_t _start = __clock_cycles(); + uint32_t next_mark = _start; while(allpixels.has(1)) { - #if (FASTLED_ALLOW_INTERRUPTS == 1) - os_intr_lock(); - // if interrupts took longer than 45µs, punt on the current frame - if(__clock_cycles() > next_mark) { - if((__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return __clock_cycles(); } - } - #endif - allpixels.stepDithering(); - // Write first byte, read next byte writeBits<8+XTRA0,1>(next_mark, b0, allpixels); @@ -160,9 +140,20 @@ public: // Write third byte writeBits<8+XTRA0,0>(next_mark, b0, allpixels); + #if (FASTLED_ALLOW_INTERRUPTS == 1) os_intr_unlock(); #endif + + allpixels.stepDithering(); + + #if (FASTLED_ALLOW_INTERRUPTS == 1) + os_intr_lock(); + // if interrupts took longer than 45µs, punt on the current frame + if((int32_t)(__clock_cycles()-next_mark) > 0) { + if((int32_t)(__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { os_intr_unlock(); return 0; } + } + #endif }; os_intr_unlock(); diff --git a/platforms/esp/8266/clockless_esp8266.h b/platforms/esp/8266/clockless_esp8266.h index 7d2fe454..668a8ad1 100644 --- a/platforms/esp/8266/clockless_esp8266.h +++ b/platforms/esp/8266/clockless_esp8266.h @@ -9,7 +9,7 @@ __attribute__ ((always_inline)) inline static uint32_t __clock_cycles() { return cyc; } -#ifndef FASTLED_INTERRUPT_RETRY_COUNT +#ifndef FASTLED_INTERRUPT_RETRY_COUNT #define FASTLED_INTERRUPT_RETRY_COUNT 2 #endif @@ -46,34 +46,23 @@ protected: // mWait.mark(); } -#define _ESP_ADJ (6) - template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint8_t b) { - for(register uint32_t i = BITS; i > 0; i--) { - while(__clock_cycles() < next_mark); +#define _ESP_ADJ (0) +#define _ESP_ADJ2 (0) + + template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint32_t b) { + b = ~b; b <<= 24; + for(register uint32_t i = BITS; i > 0; i--) { + while((int32_t)(next_mark - __clock_cycles()) > 0); next_mark = __clock_cycles() + (T1+T2+T3 + _ESP_ADJ); FastPin<DATA_PIN>::hi(); - if(b&0x80) { - while((next_mark - __clock_cycles()) > (T3 + _ESP_ADJ)); - FastPin<DATA_PIN>::lo(); - } else { - while((next_mark - __clock_cycles()) > (T2+T3 + 40)); - FastPin<DATA_PIN>::lo(); - } - b <<= 1; - } + while((int32_t)(next_mark - __clock_cycles()) > (T2+T3 + _ESP_ADJ2)); + if(b & 0x80000000L) { FastPin<DATA_PIN>::lo(); } + b <<= 1; - // while(__clock_cycles() < next_mark); - // next_mark = __clock_cycles() + (T1+T2+T3); - // FastPin<DATA_PIN>::hi(); - // - // if(b&0x80) { - // while((next_mark - __clock_cycles()) > (T3+(2*(F_CPU/24000000)))); - // FastPin<DATA_PIN>::lo(); - // } else { - // while((next_mark - __clock_cycles()) > (T2+T3+(2*(F_CPU/24000000)))); - // FastPin<DATA_PIN>::lo(); - // } + while((int32_t)(next_mark - __clock_cycles()) > (T3 + _ESP_ADJ)); + FastPin<DATA_PIN>::lo(); + } } // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then @@ -81,20 +70,12 @@ protected: static uint32_t ICACHE_RAM_ATTR showRGBInternal(PixelController<RGB_ORDER> pixels) { // Setup the pixel controller and load/scale the first byte pixels.preStepFirstByteDithering(); - register uint8_t b = pixels.loadAndScale0(); - + register uint32_t b = pixels.loadAndScale0(); + pixels.preStepFirstByteDithering(); os_intr_lock(); uint32_t start = __clock_cycles(); uint32_t next_mark = start + (T1+T2+T3 + _ESP_ADJ); while(pixels.has(1)) { - pixels.stepDithering(); - #if (FASTLED_ALLOW_INTERRUPTS == 1) - os_intr_lock(); - // if interrupts took longer than 45µs, punt on the current frame - if(__clock_cycles() > next_mark) { - if((__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; } - } - #endif // Write first byte, read next byte writeBits<8+XTRA0>(next_mark, b); b = pixels.loadAndScale1(); @@ -106,9 +87,20 @@ protected: // Write third byte, read 1st byte of next pixel writeBits<8+XTRA0>(next_mark, b); b = pixels.advanceAndLoadAndScale0(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) os_intr_unlock(); #endif + + pixels.stepDithering(); + + #if (FASTLED_ALLOW_INTERRUPTS == 1) + os_intr_lock(); + // if interrupts took longer than 45µs, punt on the current frame + if((int32_t)(__clock_cycles()-next_mark) > 0) { + if((int32_t)(__clock_cycles()-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; } + } + #endif }; os_intr_unlock(); diff --git a/platforms/esp/8266/fastpin_esp8266.h b/platforms/esp/8266/fastpin_esp8266.h index 04993493..5d4534f8 100644 --- a/platforms/esp/8266/fastpin_esp8266.h +++ b/platforms/esp/8266/fastpin_esp8266.h @@ -2,6 +2,15 @@ FASTLED_NAMESPACE_BEGIN +struct FASTLED_ESP_IO { + volatile uint32_t _GPO; + volatile uint32_t _GPOS; + volatile uint32_t _GPOC; +}; + +#define _GPB (*(FASTLED_ESP_IO*)(0x60000000+(0x300))) + + template<uint8_t PIN, uint32_t MASK> class _ESPPIN { public: @@ -11,13 +20,13 @@ public: inline static void setOutput() { pinMode(PIN, OUTPUT); } inline static void setInput() { pinMode(PIN, INPUT); } - inline static void hi() __attribute__ ((always_inline)) { if(PIN < 16) { GPOS = MASK; } else { GP16O |= MASK; } } - inline static void lo() __attribute__ ((always_inline)) { if(PIN < 16) { GPOC = MASK; } else { GP16O &= ~MASK; } } - inline static void set(register port_t val) __attribute__ ((always_inline)) { if(PIN < 16) { GPO = val; } else { GP16O = val; }} + inline static void hi() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOS = MASK; } else { GP16O |= MASK; } } + inline static void lo() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPOC = MASK; } else { GP16O &= ~MASK; } } + inline static void set(register port_t val) __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO = val; } else { GP16O = val; }} inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } - inline static void toggle() __attribute__ ((always_inline)) { if(PIN < 16) { GPO ^= MASK; } else { GP16O ^= MASK; } } + inline static void toggle() __attribute__ ((always_inline)) { if(PIN < 16) { _GPB._GPO ^= MASK; } else { GP16O ^= MASK; } } inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } @@ -25,9 +34,9 @@ public: inline static port_t hival() __attribute__ ((always_inline)) { if (PIN<16) { return GPO | MASK; } else { return GP16O | MASK; } } inline static port_t loval() __attribute__ ((always_inline)) { if (PIN<16) { return GPO & ~MASK; } else { return GP16O & ~MASK; } } - inline static port_ptr_t port() __attribute__ ((always_inline)) { if(PIN<16) { return &GPO; } else { return &GP16O; } } - inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &GPOS; } // there is no GP160 support for this - inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &GPOC; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { if(PIN<16) { return &_GPB._GPO; } else { return &GP16O; } } + inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPB._GPOS; } // there is no GP160 support for this + inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPB._GPOC; } inline static port_t mask() __attribute__ ((always_inline)) { return MASK; } inline static bool isset() __attribute__ ((always_inline)) { return (PIN < 16) ? (GPO & MASK) : (GP16O & MASK); } |