First commit.
This commit is contained in:
@ -0,0 +1,214 @@
|
||||
#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 <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 = 50>
|
||||
class FlexibleInlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, __FL_T4_MASK> {
|
||||
|
||||
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<WAIT_TIME> 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<P>::setOutput(); \
|
||||
m_bitOffsets[m_nActualLanes++] = FastPin<P>::pinbit(); \
|
||||
m_nWriteMask |= FastPin<P>::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<RGB_ORDER, LANES, __FL_T4_MASK> & 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<int BITS,int PX> __attribute__ ((always_inline)) inline void writeBits(register uint32_t & next_mark, register _outlines & b, PixelController<RGB_ORDER, LANES, __FL_T4_MASK> &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<PX>(pixels);
|
||||
register uint8_t scale = pixels.template getscale<PX>(pixels);
|
||||
|
||||
int x = 0;
|
||||
for(uint32_t i = 8; i > 0;) {
|
||||
i--;
|
||||
while(ARM_DWT_CYCCNT < next_mark);
|
||||
*FastPin<FIRST_PIN>::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<FIRST_PIN>::cport() = out;
|
||||
|
||||
out = m_nWriteMask;
|
||||
while((next_mark - ARM_DWT_CYCCNT) > m_offsets[2]);
|
||||
*FastPin<FIRST_PIN>::cport() = out;
|
||||
|
||||
// Read and store up to two bytes
|
||||
if (x < m_nActualLanes) {
|
||||
b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale<PX>(pixels,x,d,scale);
|
||||
x++;
|
||||
if (x < m_nActualLanes) {
|
||||
b.bytes[m_bitOffsets[x]] = pixels.template loadAndScale<PX>(pixels,x,d,scale);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t showRGBInternal(PixelController<RGB_ORDER,LANES, __FL_T4_MASK> &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<template<uint8_t DATA_PIN, EOrder RGB_ORDER> class CHIPSET, uint8_t DATA_PIN, int NUM_LANES, EOrder RGB_ORDER=GRB>
|
||||
class __FIBCC : public FlexibleInlineBlockClocklessController<NUM_LANES,DATA_PIN,CHIPSET<DATA_PIN,RGB_ORDER>::__T1(),CHIPSET<DATA_PIN,RGB_ORDER>::__T2(),CHIPSET<DATA_PIN,RGB_ORDER>::__T3(),RGB_ORDER,CHIPSET<DATA_PIN,RGB_ORDER>::__XTRA0(),CHIPSET<DATA_PIN,RGB_ORDER>::__FLIP(),CHIPSET<DATA_PIN,RGB_ORDER>::__WAIT_TIME()> {};
|
||||
|
||||
#define __FASTLED_HAS_FIBCC 1
|
||||
|
||||
#endif //defined(FASTLED_TEENSY4)
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
@ -0,0 +1,128 @@
|
||||
#ifndef __INC_CLOCKLESS_ARM_MXRT1062_H
|
||||
#define __INC_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 FASTLED_HAS_CLOCKLESS 1
|
||||
|
||||
#define _FASTLED_NS_TO_DWT(_NS) (((F_CPU_ACTUAL>>16)*(_NS)) / (1000000000UL>>16))
|
||||
|
||||
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
|
||||
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
|
||||
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
|
||||
typedef typename FastPin<DATA_PIN>::port_t data_t;
|
||||
|
||||
data_t mPinMask;
|
||||
data_ptr_t mPort;
|
||||
CMinWait<WAIT_TIME> mWait;
|
||||
uint32_t off[3];
|
||||
|
||||
public:
|
||||
static constexpr int __DATA_PIN() { return DATA_PIN; }
|
||||
static constexpr int __T1() { return T1; }
|
||||
static constexpr int __T2() { return T2; }
|
||||
static constexpr int __T3() { return T3; }
|
||||
static constexpr EOrder __RGB_ORDER() { return RGB_ORDER; }
|
||||
static constexpr int __XTRA0() { return XTRA0; }
|
||||
static constexpr bool __FLIP() { return FLIP; }
|
||||
static constexpr int __WAIT_TIME() { return WAIT_TIME; }
|
||||
|
||||
virtual void init() {
|
||||
FastPin<DATA_PIN>::setOutput();
|
||||
mPinMask = FastPin<DATA_PIN>::mask();
|
||||
mPort = FastPin<DATA_PIN>::port();
|
||||
FastPin<DATA_PIN>::lo();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
|
||||
mWait.wait();
|
||||
if(!showRGBInternal(pixels)) {
|
||||
sei(); delayMicroseconds(WAIT_TIME); cli();
|
||||
showRGBInternal(pixels);
|
||||
}
|
||||
mWait.mark();
|
||||
}
|
||||
|
||||
template<int BITS> __attribute__ ((always_inline)) inline void writeBits(register uint32_t & next_mark, register uint32_t & b) {
|
||||
for(register uint32_t i = BITS-1; i > 0; i--) {
|
||||
while(ARM_DWT_CYCCNT < next_mark);
|
||||
next_mark = ARM_DWT_CYCCNT + off[0];
|
||||
FastPin<DATA_PIN>::hi();
|
||||
if(b&0x80) {
|
||||
while((next_mark - ARM_DWT_CYCCNT) > off[1]);
|
||||
FastPin<DATA_PIN>::lo();
|
||||
} else {
|
||||
while((next_mark - ARM_DWT_CYCCNT) > off[2]);
|
||||
FastPin<DATA_PIN>::lo();
|
||||
}
|
||||
b <<= 1;
|
||||
}
|
||||
|
||||
while(ARM_DWT_CYCCNT < next_mark);
|
||||
next_mark = ARM_DWT_CYCCNT + off[1];
|
||||
FastPin<DATA_PIN>::hi();
|
||||
|
||||
if(b&0x80) {
|
||||
while((next_mark - ARM_DWT_CYCCNT) > off[2]);
|
||||
FastPin<DATA_PIN>::lo();
|
||||
} else {
|
||||
while((next_mark - ARM_DWT_CYCCNT) > off[2]);
|
||||
FastPin<DATA_PIN>::lo();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
|
||||
uint32_t start = ARM_DWT_CYCCNT;
|
||||
|
||||
// Setup the pixel controller and load/scale the first byte
|
||||
pixels.preStepFirstByteDithering();
|
||||
register uint32_t b = pixels.loadAndScale0();
|
||||
|
||||
cli();
|
||||
off[0] = _FASTLED_NS_TO_DWT(T1+T2+T3);
|
||||
off[1] = _FASTLED_NS_TO_DWT(T2+T3);
|
||||
off[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 + off[0];
|
||||
|
||||
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_off) { sei(); return ARM_DWT_CYCCNT - start; }
|
||||
}
|
||||
#endif
|
||||
// Write first byte, read next byte
|
||||
writeBits<8+XTRA0>(next_mark, b);
|
||||
b = pixels.loadAndScale1();
|
||||
|
||||
// Write second byte, read 3rd byte
|
||||
writeBits<8+XTRA0>(next_mark, b);
|
||||
b = pixels.loadAndScale2();
|
||||
|
||||
// Write third byte, read 1st byte of next pixel
|
||||
writeBits<8+XTRA0>(next_mark, b);
|
||||
b = pixels.advanceAndLoadAndScale0();
|
||||
#if (FASTLED_ALLOW_INTERRUPTS == 1)
|
||||
sei();
|
||||
#endif
|
||||
};
|
||||
|
||||
sei();
|
||||
return ARM_DWT_CYCCNT - start;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
@ -0,0 +1,12 @@
|
||||
#ifndef __INC_FASTLED_ARM_MXRT1062_H
|
||||
#define __INC_FASTLED_ARM_MXRT1062_H
|
||||
|
||||
#include "fastpin_arm_mxrt1062.h"
|
||||
#include "fastspi_arm_mxrt1062.h"
|
||||
#include "../k20/octows2811_controller.h"
|
||||
#include "../k20/ws2812serial_controller.h"
|
||||
#include "../k20/smartmatrix_t3.h"
|
||||
#include "clockless_arm_mxrt1062.h"
|
||||
#include "block_clockless_arm_mxrt1062.h"
|
||||
|
||||
#endif
|
@ -0,0 +1,91 @@
|
||||
#ifndef __FASTPIN_ARM_MXRT1062_H
|
||||
#define __FASTPIN_ARM_MXRT1062_H
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
#if defined(FASTLED_FORCE_SOFTWARE_PINS)
|
||||
#warning "Software pin support forced, pin access will be slightly slower."
|
||||
#define NO_HARDWARE_PIN_SUPPORT
|
||||
#undef HAS_HARDWARE_PIN_SUPPORT
|
||||
|
||||
#else
|
||||
|
||||
/// Template definition for teensy 4.0 style ARM pins, providing direct access to the various GPIO registers. Note that this
|
||||
/// uses the full port GPIO registers. It calls through to pinMode for setting input/output on pins
|
||||
/// The registers are data output, set output, clear output, toggle output, input, and direction
|
||||
template<uint8_t PIN, uint32_t _BIT, uint32_t _MASK, typename _GPIO_DR, typename _GPIO_DR_SET, typename _GPIO_DR_CLEAR, typename _GPIO_DR_TOGGLE> 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)) { _GPIO_DR_SET::r() = _MASK; }
|
||||
inline static void lo() __attribute__ ((always_inline)) { _GPIO_DR_CLEAR::r() = _MASK; }
|
||||
inline static void set(register port_t val) __attribute__ ((always_inline)) { _GPIO_DR::r() = val; }
|
||||
|
||||
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
|
||||
|
||||
inline static void toggle() __attribute__ ((always_inline)) { _GPIO_DR_TOGGLE::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 _GPIO_DR::r() | _MASK; }
|
||||
inline static port_t loval() __attribute__ ((always_inline)) { return _GPIO_DR::r() & ~_MASK; }
|
||||
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_GPIO_DR::r(); }
|
||||
inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO_DR_SET::r(); }
|
||||
inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO_DR_CLEAR::r(); }
|
||||
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
|
||||
inline static uint32_t pinbit() __attribute__ ((always_inline)) { return _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; } };
|
||||
#define _FL_IO(L) _RD32(GPIO ## L ## _DR); _RD32(GPIO ## L ## _DR_SET); _RD32(GPIO ## L ## _DR_CLEAR); _RD32(GPIO ## L ## _DR_TOGGLE); _FL_DEFINE_PORT(L, _R(GPIO ## L ## _DR));
|
||||
|
||||
// From the teensy core - it looks like there's the "default set" of port registers at GPIO1-5 - but then there
|
||||
// are a mirrored set for GPIO1-4 at GPIO6-9, which in the teensy core is referred to as "fast" - while the pin definitiosn
|
||||
// at https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=193716&viewfull=1#post193716
|
||||
// refer to GPIO1-4, we're going to use GPIO6-9 in the definitions below because the fast registers are what
|
||||
// the teensy core is using internally
|
||||
#define _FL_DEFPIN(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, BIT, 1 << BIT, _R(GPIO ## L ## _DR), _R(GPIO ## L ## _DR_SET), _R(GPIO ## L ## _DR_CLEAR), _R(GPIO ## L ## _DR_TOGGLE)> {};
|
||||
|
||||
#if defined(FASTLED_TEENSY4) && defined(CORE_TEENSY)
|
||||
_FL_IO(1); _FL_IO(2); _FL_IO(3); _FL_IO(4); _FL_IO(5);
|
||||
_FL_IO(6); _FL_IO(7); _FL_IO(8); _FL_IO(9);
|
||||
|
||||
#define MAX_PIN 39
|
||||
_FL_DEFPIN( 0, 3,6); _FL_DEFPIN( 1, 2,6); _FL_DEFPIN( 2, 4,9); _FL_DEFPIN( 3, 5,9);
|
||||
_FL_DEFPIN( 4, 6,9); _FL_DEFPIN( 5, 8,9); _FL_DEFPIN( 6,10,7); _FL_DEFPIN( 7,17,7);
|
||||
_FL_DEFPIN( 8,16,7); _FL_DEFPIN( 9,11,7); _FL_DEFPIN(10, 0,7); _FL_DEFPIN(11, 2,7);
|
||||
_FL_DEFPIN(12, 1,7); _FL_DEFPIN(13, 3,7); _FL_DEFPIN(14,18,6); _FL_DEFPIN(15,19,6);
|
||||
_FL_DEFPIN(16,23,6); _FL_DEFPIN(17,22,6); _FL_DEFPIN(18,17,6); _FL_DEFPIN(19,16,6);
|
||||
_FL_DEFPIN(20,26,6); _FL_DEFPIN(21,27,6); _FL_DEFPIN(22,24,6); _FL_DEFPIN(23,25,6);
|
||||
_FL_DEFPIN(24,12,6); _FL_DEFPIN(25,13,6); _FL_DEFPIN(26,30,6); _FL_DEFPIN(27,31,6);
|
||||
_FL_DEFPIN(28,18,8); _FL_DEFPIN(29,31,9); _FL_DEFPIN(30,23,8); _FL_DEFPIN(31,22,8);
|
||||
_FL_DEFPIN(32,12,7); _FL_DEFPIN(33, 7,9); _FL_DEFPIN(34,15,8); _FL_DEFPIN(35,14,8);
|
||||
_FL_DEFPIN(36,13,8); _FL_DEFPIN(37,12,8); _FL_DEFPIN(38,17,8); _FL_DEFPIN(39,16,8);
|
||||
|
||||
#define HAS_HARDWARE_PIN_SUPPORT
|
||||
|
||||
#define ARM_HARDWARE_SPI
|
||||
#define SPI_DATA 11
|
||||
#define SPI_CLOCK 13
|
||||
|
||||
#define SPI1_DATA 26
|
||||
#define SPI1_CLOCK 27
|
||||
|
||||
#define SPI2_DATA 35
|
||||
#define SPI2_CLOCK 37
|
||||
|
||||
#endif // defined FASTLED_TEENSY4
|
||||
|
||||
#endif // FASTLED_FORCE_SOFTWARE_PINSs
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
|
||||
#endif
|
@ -0,0 +1,140 @@
|
||||
#ifndef __INC_FASTSPI_ARM_MXRT1062_H
|
||||
#define __INC_FASTSPI_ARM_MXRT1062_H
|
||||
|
||||
FASTLED_NAMESPACE_BEGIN
|
||||
|
||||
#if defined (FASTLED_TEENSY4) && defined(ARM_HARDWARE_SPI)
|
||||
#include <SPI.h>
|
||||
|
||||
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_RATE, SPIClass & _SPIObject, int _SPI_INDEX>
|
||||
class Teesy4HardwareSPIOutput {
|
||||
Selectable *m_pSelect;
|
||||
uint32_t m_bitCount;
|
||||
uint32_t m_bitData;
|
||||
inline IMXRT_LPSPI_t & port() __attribute__((always_inline)) {
|
||||
switch(_SPI_INDEX) {
|
||||
case 0:
|
||||
return IMXRT_LPSPI4_S;
|
||||
case 1:
|
||||
return IMXRT_LPSPI3_S;
|
||||
case 2:
|
||||
return IMXRT_LPSPI1_S;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
Teesy4HardwareSPIOutput() { m_pSelect = NULL; m_bitCount = 0;}
|
||||
Teesy4HardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; m_bitCount = 0;}
|
||||
|
||||
// set the object representing the selectable -- ignore for now
|
||||
void setSelect(Selectable *pSelect) { /* TODO */ }
|
||||
|
||||
// initialize the SPI subssytem
|
||||
void init() { _SPIObject.begin(); }
|
||||
|
||||
// latch the CS select
|
||||
void inline select() __attribute__((always_inline)) {
|
||||
// begin the SPI transaction
|
||||
_SPIObject.beginTransaction(SPISettings(_SPI_CLOCK_RATE, MSBFIRST, SPI_MODE0));
|
||||
if(m_pSelect != NULL) { m_pSelect->select(); }
|
||||
}
|
||||
|
||||
// release the CS select
|
||||
void inline release() __attribute__((always_inline)) {
|
||||
if(m_pSelect != NULL) { m_pSelect->release(); }
|
||||
_SPIObject.endTransaction();
|
||||
}
|
||||
|
||||
// wait until all queued up data has been written
|
||||
static void waitFully() { /* TODO */ }
|
||||
|
||||
// write a byte out via SPI (returns immediately on writing register) -
|
||||
void inline writeByte(uint8_t b) __attribute__((always_inline)) {
|
||||
if(m_bitCount == 0) {
|
||||
_SPIObject.transfer(b);
|
||||
} else {
|
||||
// There's been a bit of data written, add that to the output as well
|
||||
uint32_t outData = (m_bitData << 8) | b;
|
||||
uint32_t tcr = port().TCR;
|
||||
port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ((8+m_bitCount) - 1); // turn on 9 bit mode
|
||||
port().TDR = outData; // output 9 bit data.
|
||||
while ((port().RSR & LPSPI_RSR_RXEMPTY)) ; // wait while the RSR fifo is empty...
|
||||
port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ((8) - 1); // turn back on 8 bit mode
|
||||
port().RDR;
|
||||
m_bitCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// write a word out via SPI (returns immediately on writing register)
|
||||
void inline writeWord(uint16_t w) __attribute__((always_inline)) {
|
||||
writeByte(((w>>8) & 0xFF));
|
||||
_SPIObject.transfer(w & 0xFF);
|
||||
}
|
||||
|
||||
// A raw set of writing byte values, assumes setup/init/waiting done elsewhere
|
||||
static void writeBytesValueRaw(uint8_t value, int len) {
|
||||
while(len--) { _SPIObject.transfer(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();
|
||||
}
|
||||
|
||||
// A full cycle of writing a value for len bytes, including select, release, and waiting
|
||||
template <class D> 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();
|
||||
}
|
||||
|
||||
// A full cycle of writing a value for len bytes, including select, release, and waiting
|
||||
void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); }
|
||||
|
||||
// write a single bit out, which bit from the passed in byte is determined by template parameter
|
||||
template <uint8_t BIT> inline void writeBit(uint8_t b) {
|
||||
m_bitData = (m_bitData<<1) | ((b&(1<<BIT)) != 0);
|
||||
// If this is the 8th bit we've collected, just write it out raw
|
||||
register uint32_t bc = m_bitCount;
|
||||
bc = (bc + 1) & 0x07;
|
||||
if (!bc) {
|
||||
m_bitCount = 0;
|
||||
_SPIObject.transfer(m_bitData);
|
||||
}
|
||||
m_bitCount = bc;
|
||||
}
|
||||
|
||||
// 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 <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
|
||||
select();
|
||||
int len = pixels.mLen;
|
||||
|
||||
while(pixels.has(1)) {
|
||||
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();
|
||||
}
|
||||
D::postBlock(len);
|
||||
release();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
FASTLED_NAMESPACE_END
|
||||
#endif
|
@ -0,0 +1,43 @@
|
||||
#ifndef __INC_LED_SYSDEFS_ARM_MXRT1062_H
|
||||
#define __INC_LED_SYSDEFS_ARM_MXRT1062_H
|
||||
|
||||
#define FASTLED_TEENSY4
|
||||
#define FASTLED_ARM
|
||||
|
||||
#ifndef INTERRUPT_THRESHOLD
|
||||
#define INTERRUPT_THRESHOLD 1
|
||||
#endif
|
||||
|
||||
// Default to allowing interrupts
|
||||
#ifndef FASTLED_ALLOW_INTERRUPTS
|
||||
#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
|
||||
|
||||
// Get some system include files
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h> // for cli/se definitions
|
||||
|
||||
// Define the register types
|
||||
#if defined(ARDUINO) // && ARDUINO < 150
|
||||
typedef volatile uint32_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */
|
||||
typedef volatile uint32_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */
|
||||
#endif
|
||||
|
||||
// extern volatile uint32_t systick_millis_count;
|
||||
// # define MS_COUNTER systick_millis_count
|
||||
|
||||
// Teensy4 provides progmem
|
||||
#ifndef FASTLED_USE_PROGMEM
|
||||
#define FASTLED_USE_PROGMEM 1
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user