#ifndef __INC_BLOCK_CLOCKLESS_ARM_MXRT1062_H #define __INC_BLOCK_CLOCKLESS_ARM_MXRT1062_H FASTLED_NAMESPACE_BEGIN // Definition for a single channel clockless controller for the teensy4 // See clockless.h for detailed info on how the template parameters are used. #if defined(FASTLED_TEENSY4) #define __FL_T4_MASK ((1<<(LANES))-1) template class FlexibleInlineBlockClocklessController : public CPixelLEDController { uint8_t m_bitOffsets[16]; uint8_t m_nActualLanes; uint8_t m_nLowBit; uint8_t m_nHighBit; uint32_t m_nWriteMask; uint8_t m_nOutBlocks; uint32_t m_offsets[3]; CMinWait mWait; public: virtual int size() { return CLEDController::size() * m_nActualLanes; } // For each pin, if we've hit our lane count, break, otherwise set the pin to output, // store the bit offset in our offset array, add this pin to the write mask, and if this // pin ends a block sequence, then break out of the switch as well #define _BLOCK_PIN(P) case P: { \ if(m_nActualLanes == LANES) break; \ FastPin

::setOutput(); \ m_bitOffsets[m_nActualLanes++] = FastPin

::pinbit(); \ m_nWriteMask |= FastPin

::mask(); \ if( P == 27 || P == 7 || P == 30) break; \ } virtual void init() { // pre-initialize memset(m_bitOffsets,0,16); m_nActualLanes = 0; m_nLowBit = 33; m_nHighBit = 0; m_nWriteMask = 0; // setup the bits and data tracking for parallel output switch(FIRST_PIN) { // GPIO6 block output _BLOCK_PIN( 1); _BLOCK_PIN( 0); _BLOCK_PIN(24); _BLOCK_PIN(25); _BLOCK_PIN(19); _BLOCK_PIN(18); _BLOCK_PIN(14); _BLOCK_PIN(15); _BLOCK_PIN(17); _BLOCK_PIN(16); _BLOCK_PIN(22); _BLOCK_PIN(23); _BLOCK_PIN(20); _BLOCK_PIN(21); _BLOCK_PIN(26); _BLOCK_PIN(27); // GPIO7 block output _BLOCK_PIN(10); _BLOCK_PIN(12); _BLOCK_PIN(11); _BLOCK_PIN(13); _BLOCK_PIN( 6); _BLOCK_PIN( 9); _BLOCK_PIN(32); _BLOCK_PIN( 8); _BLOCK_PIN( 7); // GPIO 37 block output _BLOCK_PIN(37); _BLOCK_PIN(36); _BLOCK_PIN(35); _BLOCK_PIN(34); _BLOCK_PIN(39); _BLOCK_PIN(38); _BLOCK_PIN(28); _BLOCK_PIN(31); _BLOCK_PIN(30); } for(int i = 0; i < m_nActualLanes; i++) { if(m_bitOffsets[i] < m_nLowBit) { m_nLowBit = m_bitOffsets[i]; } if(m_bitOffsets[i] > m_nHighBit) { m_nHighBit = m_bitOffsets[i]; } } m_nOutBlocks = (m_nHighBit + 8)/8; } virtual void showPixels(PixelController & pixels) { mWait.wait(); #if FASTLED_ALLOW_INTERRUPTS == 0 uint32_t clocks = showRGBInternal(pixels); // Adjust the timer long microsTaken = CLKS_TO_MICROS(clocks); MS_COUNTER += (1 + (microsTaken / 1000)); #else showRGBInternal(pixels); #endif mWait.mark(); } typedef union { uint8_t bytes[32]; uint8_t bg[4][8]; uint16_t shorts[16]; uint32_t raw[8]; } _outlines; template __attribute__ ((always_inline)) inline void writeBits(register uint32_t & next_mark, register _outlines & b, PixelController &pixels) { _outlines b2; transpose8x1(b.bg[3], b2.bg[3]); transpose8x1(b.bg[2], b2.bg[2]); transpose8x1(b.bg[1], b2.bg[1]); transpose8x1(b.bg[0], b2.bg[0]); register uint8_t d = pixels.template getd(pixels); register uint8_t scale = pixels.template getscale(pixels); int x = 0; for(uint32_t i = 8; i > 0;) { i--; while(ARM_DWT_CYCCNT < next_mark); *FastPin::sport() = m_nWriteMask; next_mark = ARM_DWT_CYCCNT + m_offsets[0]; uint32_t out = (b2.bg[3][i] << 24) | (b2.bg[2][i] << 16) | (b2.bg[1][i] << 8) | b2.bg[0][i]; out = ((~out) & m_nWriteMask); while((next_mark - ARM_DWT_CYCCNT) > m_offsets[1]); *FastPin::cport() = out; out = m_nWriteMask; while((next_mark - ARM_DWT_CYCCNT) > m_offsets[2]); *FastPin::cport() = out; // Read and store up to two bytes if (x < m_nActualLanes) { b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale(pixels,x,d,scale); x++; if (x < m_nActualLanes) { b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale(pixels,x,d,scale); x++; } } } } uint32_t showRGBInternal(PixelController &allpixels) { allpixels.preStepFirstByteDithering(); _outlines b0; uint32_t start = ARM_DWT_CYCCNT; for(int i = 0; i < m_nActualLanes; i++) { b0.bytes[m_bitOffsets[i]] = allpixels.loadAndScale0(i); } cli(); m_offsets[0] = _FASTLED_NS_TO_DWT(T1+T2+T3); m_offsets[1] = _FASTLED_NS_TO_DWT(T2+T3); m_offsets[2] = _FASTLED_NS_TO_DWT(T3); uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD)); uint32_t next_mark = ARM_DWT_CYCCNT + m_offsets[0]; while(allpixels.has(1)) { 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_off) { sei(); return ARM_DWT_CYCCNT - start; } } #endif // 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); #if (FASTLED_ALLOW_INTERRUPTS == 1) sei(); #endif } sei(); return ARM_DWT_CYCCNT - start; } }; template class CHIPSET, uint8_t DATA_PIN, int NUM_LANES, EOrder RGB_ORDER=GRB> class __FIBCC : public FlexibleInlineBlockClocklessController::__T1(),CHIPSET::__T2(),CHIPSET::__T3(),RGB_ORDER,CHIPSET::__XTRA0(),CHIPSET::__FLIP(),CHIPSET::__WAIT_TIME()> {}; #define __FASTLED_HAS_FIBCC 1 #endif //defined(FASTLED_TEENSY4) FASTLED_NAMESPACE_END #endif