This commit is contained in:
Alex
2019-06-13 14:03:00 +03:00
parent 53b74e6db4
commit 7612db75b1
496 changed files with 202963 additions and 24 deletions

View File

@@ -0,0 +1,318 @@
#ifndef __INC_M0_CLOCKLESS_H
#define __INC_M0_CLOCKLESS_H
struct M0ClocklessData {
uint8_t d[3];
uint8_t e[3];
uint8_t adj;
uint8_t pad;
uint32_t s[3];
};
template<int HI_OFFSET, int LO_OFFSET, int T1, int T2, int T3, EOrder RGB_ORDER, int WAIT_TIME>int
showLedData(volatile uint32_t *_port, uint32_t _bitmask, const uint8_t *_leds, uint32_t num_leds, struct M0ClocklessData *pData) {
// Lo register variables
register uint32_t scratch=0;
register struct M0ClocklessData *base = pData;
register volatile uint32_t *port = _port;
register uint32_t d=0;
register uint32_t counter=num_leds;
register uint32_t bn=0;
register uint32_t b=0;
register uint32_t bitmask = _bitmask;
// high register variable
register const uint8_t *leds = _leds;
#if (FASTLED_SCALE8_FIXED == 1)
pData->s[0]++;
pData->s[1]++;
pData->s[2]++;
#endif
asm __volatile__ (
///////////////////////////////////////////////////////////////////////////
//
// asm macro definitions - used to assemble the clockless output
//
".ifnotdef fl_delay_def;"
#ifdef FASTLED_ARM_M0_PLUS
" .set fl_is_m0p, 1;"
" .macro m0pad;"
" nop;"
" .endm;"
#else
" .set fl_is_m0p, 0;"
" .macro m0pad;"
" .endm;"
#endif
" .set fl_delay_def, 1;"
" .set fl_delay_mod, 4;"
" .if fl_is_m0p == 1;"
" .set fl_delay_mod, 3;"
" .endif;"
" .macro fl_delay dtime, reg=r0;"
" .if (\\dtime > 0);"
" .set dcycle, (\\dtime / fl_delay_mod);"
" .set dwork, (dcycle * fl_delay_mod);"
" .set drem, (\\dtime - dwork);"
" .rept (drem);"
" nop;"
" .endr;"
" .if dcycle > 0;"
" mov \\reg, #dcycle;"
" delayloop_\\@:;"
" sub \\reg, #1;"
" bne delayloop_\\@;"
" .if fl_is_m0p == 0;"
" nop;"
" .endif;"
" .endif;"
" .endif;"
" .endm;"
" .macro mod_delay dtime,b1,b2,reg;"
" .set adj, (\\b1 + \\b2);"
" .if adj < \\dtime;"
" .set dtime2, (\\dtime - adj);"
" fl_delay dtime2, \\reg;"
" .endif;"
" .endm;"
// check the bit and drop the line low if it isn't set
" .macro qlo4 b,bitmask,port,loff ;"
" lsl \\b, #1 ;"
" bcs skip_\\@ ;"
" str \\bitmask, [\\port, \\loff] ;"
" skip_\\@: ;"
" m0pad;"
" .endm ;"
// set the pin hi or low (determined by the offset passed in )
" .macro qset2 bitmask,port,loff;"
" str \\bitmask, [\\port, \\loff];"
" m0pad;"
" .endm;"
// Load up the next led byte to work with, put it in bn
" .macro loadleds3 leds, bn, rled, scratch;"
" mov \\scratch, \\leds;"
" ldrb \\bn, [\\scratch, \\rled];"
" .endm;"
// check whether or not we should dither
" .macro loaddither7 bn,d,base,rdither;"
" ldrb \\d, [\\base, \\rdither];"
" lsl \\d, #24;" //; shift high for the qadd w/bn
" lsl \\bn, #24;" //; shift high for the qadd w/d
" bne chkskip_\\@;" //; if bn==0, clear d;"
" eor \\d, \\d;" //; clear d;"
" m0pad;"
" chkskip_\\@:;"
" .endm;"
// Do the qadd8 for dithering -- there's two versions of this. The m0 version
// takes advantage of the 3 cycle branch to do two things after the branch,
// while keeping timing constant. The m0+, however, branches in 2 cycles, so
// we have to work around that a bit more. This is one of the few times
// where the m0 will actually be _more_ efficient than the m0+
" .macro dither5 bn,d;"
" .syntax unified;"
" .if fl_is_m0p == 0;"
" adds \\bn, \\d;" // do the add
" bcc dither5_1_\\@;"
" mvns \\bn, \\bn;" // set the low 24bits ot 1's
" lsls \\bn, \\bn, #24;" // move low 8 bits to the high bits
" dither5_1_\\@:;"
" nop;" // nop to keep timing in line
" .else;"
" adds \\bn, \\d;" // do the add"
" bcc dither5_2_\\@;"
" mvns \\bn, \\bn;" // set the low 24bits ot 1's
" dither5_2_\\@:;"
" bcc dither5_3_\\@;"
" lsls \\bn, \\bn, #24;" // move low 8 bits to the high bits
" dither5_3_\\@:;"
" .endif;"
" .syntax divided;"
" .endm;"
// Do our scaling
" .macro scale4 bn, base, scale, scratch;"
" ldr \\scratch, [\\base, \\scale];"
" lsr \\bn, \\bn, #24;" // bring bn back down to its low 8 bits
" mul \\bn, \\scratch;" // do the multiply
" .endm;"
// swap bn into b
" .macro swapbbn1 b,bn;"
" lsl \\b, \\bn, #16;" // put the 8 bits we want for output high
" .endm;"
// adjust the dithering value for the next time around (load e from memory
// to do the math)
" .macro adjdither7 base,d,rled,eoffset,scratch;"
" ldrb \\d, [\\base, \\rled];"
" ldrb \\scratch,[\\base,\\eoffset];" // load e
" .syntax unified;"
" subs \\d, \\scratch, \\d;" // d=e-d
" .syntax divided;"
" strb \\d, [\\base, \\rled];" // save d
" .endm;"
// increment the led pointer (base+6 has what we're incrementing by)
" .macro incleds3 leds, base, scratch;"
" ldrb \\scratch, [\\base, #6];" // load incremen
" add \\leds, \\leds, \\scratch;" // update leds pointer
" .endm;"
// compare and loop
" .macro cmploop5 counter,label;"
" .syntax unified;"
" subs \\counter, #1;"
" .syntax divided;"
" beq done_\\@;"
" m0pad;"
" b \\label;"
" done_\\@:;"
" .endm;"
" .endif;"
);
#define M0_ASM_ARGS : \
[leds] "+h" (leds), \
[counter] "+l" (counter), \
[scratch] "+l" (scratch), \
[d] "+l" (d), \
[bn] "+l" (bn), \
[b] "+l" (b) \
: \
[port] "l" (port), \
[base] "l" (base), \
[bitmask] "l" (bitmask), \
[hi_off] "I" (HI_OFFSET), \
[lo_off] "I" (LO_OFFSET), \
[led0] "I" (RO(0)), \
[led1] "I" (RO(1)), \
[led2] "I" (RO(2)), \
[e0] "I" (3+RO(0)), \
[e1] "I" (3+RO(1)), \
[e2] "I" (3+RO(2)), \
[scale0] "I" (4*(2+RO(0))), \
[scale1] "I" (4*(2+RO(1))), \
[scale2] "I" (4*(2+RO(2))), \
[T1] "I" (T1), \
[T2] "I" (T2), \
[T3] "I" (T3) \
:
/////////////////////////////////////////////////////////////////////////
// now for some convinience macros to make building our lines a bit cleaner
#define LOOP " loop_%=:"
#define HI2 " qset2 %[bitmask], %[port], %[hi_off];"
#define D1 " mod_delay %c[T1],2,0,%[scratch];"
#define QLO4 " qlo4 %[b],%[bitmask],%[port], %[lo_off];"
#define LOADLEDS3(X) " loadleds3 %[leds], %[bn], %[led" #X "] ,%[scratch];"
#define D2(ADJ) " mod_delay %c[T2],4," #ADJ ",%[scratch];"
#define LO2 " qset2 %[bitmask], %[port], %[lo_off];"
#define D3(ADJ) " mod_delay %c[T3],2," #ADJ ",%[scratch];"
#define LOADDITHER7(X) " loaddither7 %[bn], %[d], %[base], %[led" #X "];"
#define DITHER5 " dither5 %[bn], %[d];"
#define SCALE4(X) " scale4 %[bn], %[base], %[scale" #X "], %[scratch];"
#define SWAPBBN1 " swapbbn1 %[b], %[bn];"
#define ADJDITHER7(X) " adjdither7 %[base],%[d],%[led" #X "],%[e" #X "],%[scratch];"
#define INCLEDS3 " incleds3 %[leds],%[base],%[scratch];"
#define CMPLOOP5 " cmploop5 %[counter], loop_%=;"
#define NOTHING ""
#if !(defined(SEI_CHK) && (FASTLED_ALLOW_INTERRUPTS == 1))
// We're not allowing interrupts - run the entire loop in asm to keep things
// as tight as possible. In an ideal world, we should be pushing out ws281x
// leds (or other 3-wire leds) with zero gaps between pixels.
asm __volatile__ (
// pre-load byte 0
LOADLEDS3(0) LOADDITHER7(0) DITHER5 SCALE4(0) ADJDITHER7(0) SWAPBBN1
// loop over writing out the data
LOOP
// Write out byte 0, prepping byte 1
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 LOADLEDS3(1) D2(3) LO2 D3(0)
HI2 D1 QLO4 LOADDITHER7(1) D2(7) LO2 D3(0)
HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
HI2 D1 QLO4 SCALE4(1) D2(4) LO2 D3(0)
HI2 D1 QLO4 ADJDITHER7(1) D2(7) LO2 D3(0)
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(0)
// Write out byte 1, prepping byte 2
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 LOADLEDS3(2) D2(3) LO2 D3(0)
HI2 D1 QLO4 LOADDITHER7(2) D2(7) LO2 D3(0)
HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
HI2 D1 QLO4 SCALE4(2) D2(4) LO2 D3(0)
HI2 D1 QLO4 ADJDITHER7(2) D2(7) LO2 D3(0)
HI2 D1 QLO4 INCLEDS3 D2(3) LO2 D3(0)
HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(0)
// Write out byte 2, prepping byte 0
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 LOADLEDS3(0) D2(3) LO2 D3(0)
HI2 D1 QLO4 LOADDITHER7(0) D2(7) LO2 D3(0)
HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
HI2 D1 QLO4 SCALE4(0) D2(4) LO2 D3(0)
HI2 D1 QLO4 ADJDITHER7(0) D2(7) LO2 D3(0)
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(5) CMPLOOP5
M0_ASM_ARGS
);
#else
// We're allowing interrupts - track the loop outside the asm code, to allow
// inserting the interrupt overrun checks.
asm __volatile__ (
// pre-load byte 0
LOADLEDS3(0) LOADDITHER7(0) DITHER5 SCALE4(0) ADJDITHER7(0) SWAPBBN1
M0_ASM_ARGS);
do {
asm __volatile__ (
// Write out byte 0, prepping byte 1
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 LOADLEDS3(1) D2(3) LO2 D3(0)
HI2 D1 QLO4 LOADDITHER7(1) D2(7) LO2 D3(0)
HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
HI2 D1 QLO4 SCALE4(1) D2(4) LO2 D3(0)
HI2 D1 QLO4 ADJDITHER7(1) D2(7) LO2 D3(0)
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(0)
// Write out byte 1, prepping byte 2
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 LOADLEDS3(2) D2(3) LO2 D3(0)
HI2 D1 QLO4 LOADDITHER7(2) D2(7) LO2 D3(0)
HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
HI2 D1 QLO4 SCALE4(2) D2(4) LO2 D3(0)
HI2 D1 QLO4 ADJDITHER7(2) D2(7) LO2 D3(0)
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(0)
// Write out byte 2, prepping byte 0
HI2 D1 QLO4 INCLEDS3 D2(3) LO2 D3(0)
HI2 D1 QLO4 LOADLEDS3(0) D2(3) LO2 D3(0)
HI2 D1 QLO4 LOADDITHER7(0) D2(7) LO2 D3(0)
HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
HI2 D1 QLO4 SCALE4(0) D2(4) LO2 D3(0)
HI2 D1 QLO4 ADJDITHER7(0) D2(7) LO2 D3(0)
HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(5)
M0_ASM_ARGS
);
SEI_CHK; INNER_SEI; --counter; CLI_CHK;
} while(counter);
#endif
return num_leds;
}
#endif

View File

@@ -0,0 +1,61 @@
#ifndef __INC_CLOCKLESS_ARM_D21
#define __INC_CLOCKLESS_ARM_D21
#include "../common/m0clockless.h"
FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPinBB<DATA_PIN>::setOutput();
mPinMask = FastPinBB<DATA_PIN>::mask();
mPort = FastPinBB<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
if(!showRGBInternal(pixels)) {
sei(); delayMicroseconds(WAIT_TIME); cli();
showRGBInternal(pixels);
}
sei();
mWait.mark();
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
struct M0ClocklessData data;
data.d[0] = pixels.d[0];
data.d[1] = pixels.d[1];
data.d[2] = pixels.d[2];
data.s[0] = pixels.mScale[0];
data.s[1] = pixels.mScale[1];
data.s[2] = pixels.mScale[2];
data.e[0] = pixels.e[0];
data.e[1] = pixels.e[1];
data.e[2] = pixels.e[2];
data.adj = pixels.mAdvance;
typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
return showLedData<8,4,T1,T2,T3,RGB_ORDER, WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
}
};
FASTLED_NAMESPACE_END
#endif // __INC_CLOCKLESS_ARM_D21

View File

@@ -0,0 +1,7 @@
#ifndef __INC_FASTLED_ARM_D21_H
#define __INC_FASTLED_ARM_D21_H
#include "fastpin_arm_d21.h"
#include "clockless_arm_d21.h"
#endif

View File

@@ -0,0 +1,176 @@
#ifndef __INC_FASTPIN_ARM_SAM_H
#define __INC_FASTPIN_ARM_SAM_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 STM32 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<uint8_t PIN, uint8_t _BIT, uint32_t _MASK, int _GRP> class _ARMPIN {
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
#if 0
inline static void setOutput() {
if(_BIT<8) {
_CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
} else {
_CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
}
}
inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
#endif
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)) { PORT->Group[_GRP].OUTSET.reg = _MASK; }
inline static void lo() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTCLR.reg = _MASK; }
// inline static void lo() __attribute__ ((always_inline)) { PORT->Group[_GRP].BSRR = (_MASK<<16); }
inline static void set(register port_t val) __attribute__ ((always_inline)) { PORT->Group[_GRP].OUT.reg = val; }
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
inline static void toggle() __attribute__ ((always_inline)) { PORT->Group[_GRP].OUTTGL.reg = _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 PORT->Group[_GRP].OUT.reg | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return PORT->Group[_GRP].OUT.reg & ~_MASK; }
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUT.reg; }
inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUTSET.reg; }
inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &PORT->Group[_GRP].OUTCLR.reg; }
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
};
#define _R(T) struct __gen_struct_ ## T
#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile PortGroup * r() { return T; } };
#define _IO32(L) _RD32(GPIO ## L)
#define _DEFPIN_ARM(PIN, L, BIT) template<> class FastPin<PIN> : public _ARMPIN<PIN, BIT, 1 << BIT, L> {};
// Actual pin definitions
#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS)
#define MAX_PIN 17
_DEFPIN_ARM( 8,1,23);
_DEFPIN_ARM( 0,1, 9); _DEFPIN_ARM( 1,1, 8); _DEFPIN_ARM( 2,1, 2); _DEFPIN_ARM( 3,1, 3);
_DEFPIN_ARM( 6,0, 5); _DEFPIN_ARM( 9,0, 6); _DEFPIN_ARM(10,0, 7); _DEFPIN_ARM(12,0, 2);
_DEFPIN_ARM(A6,1, 9); _DEFPIN_ARM(A7,1, 8); _DEFPIN_ARM(A5,1, 2); _DEFPIN_ARM(A4,1, 3);
_DEFPIN_ARM(A1,0, 5); _DEFPIN_ARM(A2,0, 6); _DEFPIN_ARM(A3,0, 7); _DEFPIN_ARM(A0,0, 2);
#define HAS_HARDWARE_PIN_SUPPORT 1
#elif defined(ARDUINO_SAMD_ZERO)
#define MAX_PIN 42
_DEFPIN_ARM( 0,0,10); _DEFPIN_ARM( 1,0,11); _DEFPIN_ARM( 2,0, 8); _DEFPIN_ARM( 3,0, 9);
_DEFPIN_ARM( 4,0,14); _DEFPIN_ARM( 5,0,15); _DEFPIN_ARM( 6,0,20); _DEFPIN_ARM( 7,0,21);
_DEFPIN_ARM( 8,0, 6); _DEFPIN_ARM( 9,0, 7); _DEFPIN_ARM(10,0,18); _DEFPIN_ARM(11,0,16);
_DEFPIN_ARM(12,0,19); _DEFPIN_ARM(13,0,17); _DEFPIN_ARM(14,0, 2); _DEFPIN_ARM(15,1, 8);
_DEFPIN_ARM(16,1, 9); _DEFPIN_ARM(17,0, 4); _DEFPIN_ARM(18,0, 5); _DEFPIN_ARM(19,1, 2);
_DEFPIN_ARM(20,0,22); _DEFPIN_ARM(21,0,23); _DEFPIN_ARM(22,0,12); _DEFPIN_ARM(23,1,11);
_DEFPIN_ARM(24,1,10); _DEFPIN_ARM(25,1, 3); _DEFPIN_ARM(26,0,27); _DEFPIN_ARM(27,0,28);
_DEFPIN_ARM(28,0,24); _DEFPIN_ARM(29,0,25); _DEFPIN_ARM(30,1,22); _DEFPIN_ARM(31,1,23);
_DEFPIN_ARM(32,0,22); _DEFPIN_ARM(33,0,23); _DEFPIN_ARM(34,0,19); _DEFPIN_ARM(35,0,16);
_DEFPIN_ARM(36,0,18); _DEFPIN_ARM(37,0,17); _DEFPIN_ARM(38,0,13); _DEFPIN_ARM(39,0,21);
_DEFPIN_ARM(40,0, 6); _DEFPIN_ARM(41,0, 7); _DEFPIN_ARM(42,0, 3);
#define SPI_DATA 24
#define SPI_CLOCK 23
#define HAS_HARDWARE_PIN_SUPPORT 1
#elif defined(ARDUINO_SODAQ_AUTONOMO)
#define MAX_PIN 56
_DEFPIN_ARM( 0,0, 9); _DEFPIN_ARM( 1,0,10); _DEFPIN_ARM( 2,0,11); _DEFPIN_ARM( 3,1,10);
_DEFPIN_ARM( 4,1,11); _DEFPIN_ARM( 5,1,12); _DEFPIN_ARM( 6,1,13); _DEFPIN_ARM( 7,1,14);
_DEFPIN_ARM( 8,1,15); _DEFPIN_ARM( 9,0,14); _DEFPIN_ARM(10,0,15); _DEFPIN_ARM(11,0,16);
_DEFPIN_ARM(12,0,17); _DEFPIN_ARM(13,0,18); _DEFPIN_ARM(14,0,19); _DEFPIN_ARM(15,1,16);
_DEFPIN_ARM(16,0, 8); _DEFPIN_ARM(17,0,28); _DEFPIN_ARM(18,1,17); _DEFPIN_ARM(19,0, 2);
_DEFPIN_ARM(20,0, 6); _DEFPIN_ARM(21,0, 5); _DEFPIN_ARM(22,0, 4); _DEFPIN_ARM(23,1, 9);
_DEFPIN_ARM(24,1, 8); _DEFPIN_ARM(25,1, 7); _DEFPIN_ARM(26,1, 6); _DEFPIN_ARM(27,1, 5);
_DEFPIN_ARM(28,1, 4); _DEFPIN_ARM(29,0, 7); _DEFPIN_ARM(30,1, 3); _DEFPIN_ARM(31,1, 2);
_DEFPIN_ARM(32,1, 1); _DEFPIN_ARM(33,1, 0); _DEFPIN_ARM(34,0, 3); _DEFPIN_ARM(35,0, 3);
_DEFPIN_ARM(36,1,30); _DEFPIN_ARM(37,1,31); _DEFPIN_ARM(38,1,22); _DEFPIN_ARM(39,1,23);
_DEFPIN_ARM(40,0,12); _DEFPIN_ARM(41,0,13); _DEFPIN_ARM(42,0,22); _DEFPIN_ARM(43,0,23);
_DEFPIN_ARM(44,0,20); _DEFPIN_ARM(45,0,21); _DEFPIN_ARM(46,0,27); _DEFPIN_ARM(47,0,24);
_DEFPIN_ARM(48,0,25); _DEFPIN_ARM(49,1,13); _DEFPIN_ARM(50,1,14); _DEFPIN_ARM(51,0,17);
_DEFPIN_ARM(52,0,18); _DEFPIN_ARM(53,1,12); _DEFPIN_ARM(54,1,13); _DEFPIN_ARM(55,1,14);
_DEFPIN_ARM(56,1,15);
#define SPI_DATA 44
#define SPI_CLOCK 45
#define HAS_HARDWARE_PIN_SUPPORT 1
#elif defined(ARDUINO_SAMD_WINO)
#define MAX_PIN 22
_DEFPIN_ARM( 0, 0, 23); _DEFPIN_ARM( 1, 0, 22); _DEFPIN_ARM( 2, 0, 16); _DEFPIN_ARM( 3, 0, 17);
_DEFPIN_ARM( 4, 0, 18); _DEFPIN_ARM( 5, 0, 19); _DEFPIN_ARM( 6, 0, 24); _DEFPIN_ARM( 7, 0, 25);
_DEFPIN_ARM( 8, 0, 27); _DEFPIN_ARM( 9, 0, 28); _DEFPIN_ARM( 10, 0, 30); _DEFPIN_ARM( 11, 0, 31);
_DEFPIN_ARM( 12, 0, 15); _DEFPIN_ARM( 13, 0, 14); _DEFPIN_ARM( 14, 0, 2); _DEFPIN_ARM( 15, 0, 3);
_DEFPIN_ARM( 16, 0, 4); _DEFPIN_ARM( 17, 0, 5); _DEFPIN_ARM( 18, 0, 6); _DEFPIN_ARM( 19, 0, 7);
_DEFPIN_ARM( 20, 0, 8); _DEFPIN_ARM( 21, 0, 9); _DEFPIN_ARM( 22, 0, 10); _DEFPIN_ARM( 23, 0, 11);
#define HAS_HARDWARE_PIN_SUPPORT 1
#elif defined(ARDUINO_SAMD_MKR1000)
#define MAX_PIN 22
_DEFPIN_ARM( 0, 0, 22); _DEFPIN_ARM( 1, 0, 23); _DEFPIN_ARM( 2, 0, 10); _DEFPIN_ARM( 3, 0, 11);
_DEFPIN_ARM( 4, 1, 10); _DEFPIN_ARM( 5, 1, 11); _DEFPIN_ARM( 6, 0, 20); _DEFPIN_ARM( 7, 0, 21);
_DEFPIN_ARM( 8, 0, 16); _DEFPIN_ARM( 9, 0, 17); _DEFPIN_ARM( 10, 0, 19); _DEFPIN_ARM( 11, 0, 8);
_DEFPIN_ARM( 12, 0, 9); _DEFPIN_ARM( 13, 1, 23); _DEFPIN_ARM( 14, 1, 22); _DEFPIN_ARM( 15, 0, 2);
_DEFPIN_ARM( 16, 1, 2); _DEFPIN_ARM( 17, 1, 3); _DEFPIN_ARM( 18, 0, 4); _DEFPIN_ARM( 19, 0, 5);
_DEFPIN_ARM( 20, 0, 6); _DEFPIN_ARM( 21, 0, 7);
#define SPI_DATA 8
#define SPI_CLOCK 9
#define HAS_HARDWARE_PIN_SUPPORT 1
#elif defined(ARDUINO_GEMMA_M0)
#define MAX_PIN 4
_DEFPIN_ARM( 0, 0, 4); _DEFPIN_ARM( 1, 0, 2); _DEFPIN_ARM( 2, 0, 5);
_DEFPIN_ARM( 3, 0, 0); _DEFPIN_ARM( 4, 0, 1);
#define HAS_HARDWARE_PIN_SUPPORT 1
#elif defined(ADAFRUIT_TRINKET_M0)
#define MAX_PIN 5
_DEFPIN_ARM( 0, 0, 8); _DEFPIN_ARM( 1, 0, 2); _DEFPIN_ARM( 2, 0, 9);
_DEFPIN_ARM( 3, 0, 7); _DEFPIN_ARM( 4, 0, 6);
#define SPI_DATA 4
#define SPI_CLOCK 3
#define HAS_HARDWARE_PIN_SUPPORT 1
#endif
#endif // FASTLED_FORCE_SOFTWARE_PINS
FASTLED_NAMESPACE_END
#endif // __INC_FASTPIN_ARM_SAM_H

View File

@@ -0,0 +1,26 @@
#ifndef __INC_LED_SYSDEFS_ARM_D21_H
#define __INC_LED_SYSDEFS_ARM_D21_H
#define FASTLED_ARM
#define FASTLED_ARM_M0_PLUS
#ifndef INTERRUPT_THRESHOLD
#define INTERRUPT_THRESHOLD 1
#endif
// Default to allowing interrupts
#ifndef FASTLED_ALLOW_INTERRUPTS
#define FASTLED_ALLOW_INTERRUPTS 0
#endif
#if FASTLED_ALLOW_INTERRUPTS == 1
#define FASTLED_ACCURATE_CLOCK
#endif
// reusing/abusing cli/sei defs for due
#define cli() __disable_irq();
#define sei() __enable_irq();
#endif

View File

@@ -0,0 +1,124 @@
#ifndef __INC_CLOCKLESS_ARM_K20_H
#define __INC_CLOCKLESS_ARM_K20_H
FASTLED_NAMESPACE_BEGIN
// 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 FASTLED_HAS_CLOCKLESS 1
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPin<DATA_PIN>::setOutput();
mPinMask = FastPin<DATA_PIN>::mask();
mPort = FastPin<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
if(!showRGBInternal(pixels)) {
sei(); delayMicroseconds(WAIT_TIME); cli();
showRGBInternal(pixels);
}
mWait.mark();
}
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
for(register uint32_t i = BITS-1; i > 0; i--) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
FastPin<DATA_PIN>::fastset(port, hi);
if(b&0x80) {
while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::fastset(port, lo);
} else {
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::fastset(port, lo);
}
b <<= 1;
}
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
FastPin<DATA_PIN>::fastset(port, hi);
if(b&0x80) {
while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::fastset(port, lo);
} else {
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::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<RGB_ORDER> 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<DATA_PIN>::port();
register data_t hi = *port | FastPin<DATA_PIN>::mask();;
register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
*port = lo;
// Setup the pixel controller and load/scale the first byte
pixels.preStepFirstByteDithering();
register uint8_t b = pixels.loadAndScale0();
cli();
uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
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 0; }
}
hi = *port | FastPin<DATA_PIN>::mask();
lo = *port & ~FastPin<DATA_PIN>::mask();
#endif
// Write first byte, read next byte
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.loadAndScale1();
// Write second byte, read 3rd byte
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.loadAndScale2();
// Write third byte, read 1st byte of next pixel
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.advanceAndLoadAndScale0();
#if (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
#endif
};
sei();
return ARM_DWT_CYCCNT;
}
};
#endif
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,330 @@
#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 FASTLED_HAS_BLOCKLESS 1
#define PORTC_FIRST_PIN 15
#define PORTD_FIRST_PIN 2
#define HAS_PORTDC 1
#define PORT_MASK (((1<<LANES)-1) & ((FIRST_PIN==2) ? 0xFF : 0xFFF))
#define MIN(X,Y) (((X)<(Y)) ? (X):(Y))
#define USED_LANES ((FIRST_PIN==2) ? MIN(LANES,8) : MIN(LANES,12))
#include <kinetis.h>
FASTLED_NAMESPACE_BEGIN
template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 40>
class InlineBlockClocklessController : public 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;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
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);
#if FASTLED_ALLOW_INTERRUPTS == 0
// Adjust the timer
long microsTaken = CLKS_TO_MICROS(clocks);
MS_COUNTER += (1 + (microsTaken / 1000));
#endif
mWait.mark();
}
virtual void init() {
if(FIRST_PIN == PORTC_FIRST_PIN) { // PORTC
switch(USED_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(USED_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<FIRST_PIN>::mask();
mPort = FastPin<FIRST_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
typedef union {
uint8_t bytes[12];
uint16_t shorts[6];
uint32_t raw[3];
} Lines;
template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, 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);
}
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(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK);
} else {
*FastPin<FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PORT_MASK);
}
while((next_mark - ARM_DWT_CYCCNT) > (T3));
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
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(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK);
} else {
// b2.bytes[0] = 0;
*FastPin<FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PORT_MASK);
}
while((next_mark - ARM_DWT_CYCCNT) > (T3));
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
}
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
// 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 < USED_LANES; i++) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
cli();
uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
while(allpixels.has(1)) {
#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
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
};
return ARM_DWT_CYCCNT;
}
};
#define PMASK ((1<<(LANES))-1)
#define PMASK_HI (PMASK>>8 & 0xFF)
#define PMASK_LO (PMASK & 0xFF)
template <uint8_t LANES, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class SixteenWayInlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PMASK> {
typedef typename FastPin<PORTC_FIRST_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<PORTC_FIRST_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
static_assert(LANES <= 16, "Maximum of 16 lanes for Teensy parallel controllers!");
// FastPin<30>::setOutput();
// FastPin<29>::setOutput();
// FastPin<27>::setOutput();
// FastPin<28>::setOutput();
switch(LANES) {
case 16: FastPin<12>::setOutput();
case 15: FastPin<11>::setOutput();
case 14: FastPin<13>::setOutput();
case 13: FastPin<10>::setOutput();
case 12: FastPin<9>::setOutput();
case 11: FastPin<23>::setOutput();
case 10: FastPin<22>::setOutput();
case 9: FastPin<15>::setOutput();
case 8: FastPin<5>::setOutput();
case 7: FastPin<21>::setOutput();
case 6: FastPin<20>::setOutput();
case 5: FastPin<6>::setOutput();
case 4: FastPin<8>::setOutput();
case 3: FastPin<7>::setOutput();
case 2: FastPin<14>::setOutput();
case 1: FastPin<2>::setOutput();
}
}
virtual void showPixels(PixelController<RGB_ORDER, LANES, PMASK> & pixels) {
mWait.wait();
uint32_t clocks = showRGBInternal(pixels);
#if FASTLED_ALLOW_INTERRUPTS == 0
// Adjust the timer
long microsTaken = CLKS_TO_MICROS(clocks);
MS_COUNTER += (1 + (microsTaken / 1000));
#endif
mWait.mark();
}
typedef union {
uint8_t bytes[16];
uint16_t shorts[8];
uint32_t raw[4];
} Lines;
template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, PixelController<RGB_ORDER,LANES, PMASK> &pixels) { // , register uint32_t & b2) {
register Lines b2;
transpose8x1(b.bytes,b2.bytes);
transpose8x1(b.bytes+8,b2.bytes+8);
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
for(register uint32_t i = 0; (i < LANES) && (i < 8); i++) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<PORTD_FIRST_PIN>::sport() = PMASK_LO;
*FastPin<PORTC_FIRST_PIN>::sport() = PMASK_HI;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6));
*FastPin<PORTD_FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PMASK_LO);
*FastPin<PORTC_FIRST_PIN>::cport() = ((~b2.bytes[15-i]) & PMASK_HI);
while((next_mark - ARM_DWT_CYCCNT) > (T3));
*FastPin<PORTD_FIRST_PIN>::cport() = PMASK_LO;
*FastPin<PORTC_FIRST_PIN>::cport() = PMASK_HI;
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
if(LANES==16 || (LANES>8 && ((i+8) < LANES))) {
b.bytes[i+8] = pixels.template loadAndScale<PX>(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(PixelController<RGB_ORDER,LANES, PMASK> &allpixels) {
// 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(allpixels.has(1)) {
allpixels.stepDithering();
#if 0 && (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);
// 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 0 && (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
#endif
};
sei();
return ARM_DWT_CYCCNT;
}
};
FASTLED_NAMESPACE_END
#endif
#endif

View File

@@ -0,0 +1,13 @@
#ifndef __INC_FASTLED_ARM_K20_H
#define __INC_FASTLED_ARM_K20_H
// Include the k20 headers
#include "fastpin_arm_k20.h"
#include "fastspi_arm_k20.h"
#include "octows2811_controller.h"
#include "ws2812serial_controller.h"
#include "smartmatrix_t3.h"
#include "clockless_arm_k20.h"
#include "clockless_block_arm_k20.h"
#endif

View File

@@ -0,0 +1,120 @@
#ifndef __FASTPIN_ARM_K20_H
#define __FASTPIN_ARM_K20_H
FASTLED_NAMESPACE_BEGIN
#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
#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<uint8_t PIN, uint32_t _MASK, typename _PDOR, typename _PSOR, typename _PCOR, typename _PTOR, typename _PDIR, typename _PDDR> 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<uint8_t PIN, int _BIT, typename _PDOR, typename _PSOR, typename _PCOR, typename _PTOR, typename _PDIR, typename _PDDR> 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<int BIT> 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<PIN> : public _ARMPIN<PIN, 1 << BIT, _R(GPIO ## L ## _PDOR), _R(GPIO ## L ## _PSOR), _R(GPIO ## L ## _PCOR), \
_R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {}; \
template<> class FastPinBB<PIN> : public _ARMPIN_BITBAND<PIN, BIT, _R(GPIO ## L ## _PDOR), _R(GPIO ## L ## _PSOR), _R(GPIO ## L ## _PCOR), \
_R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {};
// 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)
#define SPI2_DATA 7
#define SPI2_CLOCK 14
#define FASTLED_TEENSY3
#define ARM_HARDWARE_SPI
#define HAS_HARDWARE_PIN_SUPPORT
#endif
#endif // FASTLED_FORCE_SOFTWARE_PINS
FASTLED_NAMESPACE_END
#endif // __INC_FASTPIN_ARM_K20

View File

@@ -0,0 +1,466 @@
#ifndef __INC_FASTSPI_ARM_H
#define __INC_FASTSPI_ARM_H
FASTLED_NAMESPACE_BEGIN
#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 KINETISK_SPI0
#define KINETISK_SPI0 SPI0
#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<int VAL, int BIT> class BitWork {
public:
static int highestBit() __attribute__((always_inline)) { return (VAL & 1 << BIT) ? BIT : BitWork<VAL, BIT-1>::highestBit(); }
};
template<int VAL> class BitWork<VAL, 0> {
public:
static int highestBit() __attribute__((always_inline)) { return 0; }
};
#define MAX(A, B) (( (A) > (B) ) ? (A) : (B))
#define USE_CONT 0
// intra-frame backup data
struct SPIState {
uint32_t _ctar0,_ctar1;
uint32_t pins[4];
};
// extern SPIState gState;
// Templated function to translate a clock divider value into the prescalar, scalar, and clock doubling setting for the world.
template <int VAL> 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<VAL/2, 15>::highestBit();
int p3 = BitWork<VAL/3, 15>::highestBit();
int p5 = BitWork<VAL/5, 15>::highestBit();
int p7 = BitWork<VAL/7, 15>::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 <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER, uint32_t pSPIX>
class ARMHardwareSPIOutput {
Selectable *m_pSelect;
SPIState gState;
// Borrowed from the teensy3 SPSR emulation code -- note, enabling pin 7 disables pin 11 (and vice versa),
// and likewise enabling pin 14 disables pin 13 (and vice versa)
inline void enable_pins(void) __attribute__((always_inline)) {
//serial_print("enable_pins\n");
switch(_DATA_PIN) {
case 7:
CORE_PIN7_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
case 11:
CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
}
switch(_CLOCK_PIN) {
case 13:
CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
case 14:
CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
}
}
// Borrowed from the teensy3 SPSR emulation code. We disable the pins that we're using, and restore the state on the pins that we aren't using
inline void disable_pins(void) __attribute__((always_inline)) {
switch(_DATA_PIN) {
case 7: CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN11_CONFIG = gState.pins[1]; break;
case 11: CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN7_CONFIG = gState.pins[0]; break;
}
switch(_CLOCK_PIN) {
case 13: CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN14_CONFIG = gState.pins[3]; break;
case 14: CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN13_CONFIG = gState.pins[2]; break;
}
}
static inline void update_ctars(uint32_t ctar0, uint32_t ctar1) __attribute__((always_inline)) {
if(SPIX.CTAR0 == ctar0 && SPIX.CTAR1 == ctar1) return;
uint32_t mcr = SPIX.MCR;
if(mcr & SPI_MCR_MDIS) {
SPIX.CTAR0 = ctar0;
SPIX.CTAR1 = ctar1;
} else {
SPIX.MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT;
SPIX.CTAR0 = ctar0;
SPIX.CTAR1 = ctar1;
SPIX.MCR = mcr;
}
}
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_ctars(ctar0,ctar1);
}
void inline save_spi_state() __attribute__ ((always_inline)) {
// save ctar data
gState._ctar0 = SPIX.CTAR0;
gState._ctar1 = SPIX.CTAR1;
// save data for the not-us pins
gState.pins[0] = CORE_PIN7_CONFIG;
gState.pins[1] = CORE_PIN11_CONFIG;
gState.pins[2] = CORE_PIN13_CONFIG;
gState.pins[3] = CORE_PIN14_CONFIG;
}
void inline restore_spi_state() __attribute__ ((always_inline)) {
// restore ctar data
update_ctars(gState._ctar0,gState._ctar1);
// restore data for the not-us pins (not necessary because disable_pins will do this)
// CORE_PIN7_CONFIG = gState.pins[0];
// CORE_PIN11_CONFIG = gState.pins[1];
// CORE_PIN13_CONFIG = gState.pins[2];
// CORE_PIN14_CONFIG = gState.pins[3];
}
public:
ARMHardwareSPIOutput() { m_pSelect = NULL; }
ARMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
void init() {
// set the pins to output
FastPin<_DATA_PIN>::setOutput();
FastPin<_CLOCK_PIN>::setOutput();
// Enable SPI0 clock
uint32_t sim6 = SIM_SCGC6;
if((SPI_t*)pSPIX == &KINETISK_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);
}
}
// Configure SPI as the master and enable
SPIX.MCR |= SPI_MCR_MSTR; // | SPI_MCR_CONT_SCKE);
SPIX.MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT);
// pin/spi configuration happens on select
}
static void waitFully() __attribute__((always_inline)) {
// Wait for the last byte to get shifted into the register
bool empty = false;
do {
cli();
if ((SPIX.SR & 0xF000) > 0) {
// reset the TCF flag
SPIX.SR |= SPI_SR_TCF;
} else {
empty = true;
}
sei();
} while (!empty);
// wait for the TCF flag to get set
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<ECont CONT_STATE, EWait WAIT_STATE, ELast LAST_STATE> class Write {
public:
static void writeWord(uint16_t w) __attribute__((always_inline)) {
if(WAIT_STATE == PRE) { wait(); }
cli();
SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) |
((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
SPI_PUSHR_CTAS(1) | (w & 0xFFFF);
SPIX.SR |= SPI_SR_TCF;
sei();
if(WAIT_STATE == POST) { wait(); }
}
static void writeByte(uint8_t b) __attribute__((always_inline)) {
if(WAIT_STATE == PRE) { wait(); }
cli();
SPIX.PUSHR = ((LAST_STATE == LAST) ? SPI_PUSHR_EOQ : 0) |
((CONT_STATE == CONT) ? SPI_PUSHR_CONT : 0) |
SPI_PUSHR_CTAS(0) | (b & 0xFF);
SPIX.SR |= SPI_SR_TCF;
sei();
if(WAIT_STATE == POST) { wait(); }
}
};
static void writeWord(uint16_t w) __attribute__((always_inline)) { wait(); cli(); SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF; sei(); }
static void writeWordNoWait(uint16_t w) __attribute__((always_inline)) { cli(); SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF; sei(); }
static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); cli(); SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF; sei(); }
static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { cli(); SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF);SPIX.SR |= SPI_SR_TCF; sei(); wait(); }
static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { cli(); SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF; sei(); }
static void writeWordCont(uint16_t w) __attribute__((always_inline)) { wait(); cli(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF; sei(); }
static void writeWordContNoWait(uint16_t w) __attribute__((always_inline)) { cli(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF; sei();}
static void writeByteCont(uint8_t b) __attribute__((always_inline)) { wait(); cli(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF; sei(); }
static void writeByteContPostWait(uint8_t b) __attribute__((always_inline)) { cli(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF; sei(); wait(); }
static void writeByteContNoWait(uint8_t b) __attribute__((always_inline)) { cli(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF; sei(); }
// not the most efficient mechanism in the world - but should be enough for sm16716 and friends
template <uint8_t BIT> 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)) {
save_spi_state();
if(m_pSelect != NULL) { m_pSelect->select(); }
setSPIRate();
enable_pins();
}
void inline release() __attribute__((always_inline)) {
disable_pins();
if(m_pSelect != NULL) { m_pSelect->release(); }
restore_spi_state();
}
static void writeBytesValueRaw(uint8_t value, int len) {
while(len--) { Write<CM, WM, NOTLAST>::writeByte(value); }
}
void writeBytesValue(uint8_t value, int len) {
select();
while(len--) {
writeByte(value);
}
waitFully();
release();
}
// Write a block of n uint8_ts out
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();
}
void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(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 <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
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<CM, WM, NOTLAST>::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<CM, WM, NOTLAST>::writeWord(D::adjust(pixels.loadAndScale2()) << 8 | D::adjust(pixels.stepAdvanceAndLoadAndScale0()));
// Load and write out the next two bytes
Write<CM, WM, NOTLAST>::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<CM, WM, NOTLAST>::writeWord(D::adjust(pixels.loadAndScale0()) << 8 | D::adjust(pixels.loadAndScale1()));
Write<CM, WM, NOTLAST>::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
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,46 @@
#ifndef __INC_LED_SYSDEFS_ARM_K20_H
#define __INC_LED_SYSDEFS_ARM_K20_H
#define FASTLED_TEENSY3
#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 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
extern volatile uint32_t systick_millis_count;
# define MS_COUNTER systick_millis_count
// Default to using PROGMEM, since TEENSY3 provides it
// even though all it does is ignore it. Just being
// conservative here in case TEENSY3 changes.
#ifndef FASTLED_USE_PROGMEM
#define FASTLED_USE_PROGMEM 1
#endif
#endif

View File

@@ -0,0 +1,66 @@
#ifndef __INC_OCTOWS2811_CONTROLLER_H
#define __INC_OCTOWS2811_CONTROLLER_H
#ifdef USE_OCTOWS2811
// #include "OctoWS2811.h"
FASTLED_NAMESPACE_BEGIN
template<EOrder RGB_ORDER = GRB, uint8_t CHIP = WS2811_800kHz>
class COctoWS2811Controller : public CPixelLEDController<RGB_ORDER, 8, 0xFF> {
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);
// byte ordering is handled in show by the pixel controller
int config = WS2811_RGB;
config |= CHIP;
pocto = new OctoWS2811(nLeds, framebuffer, drawbuffer, config);
pocto->begin();
}
}
public:
COctoWS2811Controller() { pocto = NULL; }
virtual void init() { /* do nothing yet */ }
typedef union {
uint8_t bytes[8];
uint32_t raw[2];
} Lines;
virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> & pixels) {
_init(pixels.size());
uint8_t *pData = drawbuffer;
while(pixels.has(1)) {
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();
}
};
FASTLED_NAMESPACE_END
#endif
#endif

View File

@@ -0,0 +1,55 @@
#ifndef __INC_SMARTMATRIX_T3_H
#define __INC_SMARTMATRIX_T3_H
#ifdef SmartMatrix_h
#include <SmartMatrix.h>
FASTLED_NAMESPACE_BEGIN
extern SmartMatrix *pSmartMatrix;
// note - dmx simple must be included before FastSPI for this code to be enabled
class CSmartMatrixController : public CPixelLEDController<RGB_ORDER> {
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;
}
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
if(SMART_MATRIX_CAN_TRIPLE_BUFFER) {
rgb24 *md = matrix.getRealBackBuffer();
} else {
rgb24 *md = matrix.backBuffer();
}
while(pixels.has(1)) {
md->red = pixels.loadAndScale0();
md->green = pixels.loadAndScale1();
md->blue = pixels.loadAndScale2();
md++;
pixels.advanceData();
pixels.stepDithering();
}
matrix.swapBuffers();
if(SMART_MATRIX_CAN_TRIPLE_BUFFER && pixels.advanceBy() > 0) {
matrix.setBackBuffer(pixels.mData);
}
}
};
FASTLED_NAMESPACE_END
#endif
#endif

View File

@@ -0,0 +1,46 @@
#ifndef __INC_WS2812SERIAL_CONTROLLER_H
#define __INC_WS2812SERIAL_CONTROLLER_H
#ifdef USE_WS2812SERIAL
FASTLED_NAMESPACE_BEGIN
template<int DATA_PIN, EOrder RGB_ORDER>
class CWS2812SerialController : public CPixelLEDController<RGB_ORDER, 8, 0xFF> {
WS2812Serial *pserial;
uint8_t *drawbuffer,*framebuffer;
void _init(int nLeds) {
if (pserial == NULL) {
drawbuffer = (uint8_t*)malloc(nLeds * 3);
framebuffer = (uint8_t*)malloc(nLeds * 12);
pserial = new WS2812Serial(nLeds, framebuffer, drawbuffer, DATA_PIN, WS2812_RGB);
pserial->begin();
}
}
public:
CWS2812SerialController() { pserial = NULL; }
virtual void init() { /* do nothing yet */ }
virtual void showPixels(PixelController<RGB_ORDER, 8, 0xFF> & pixels) {
_init(pixels.size());
uint8_t *p = drawbuffer;
while(pixels.has(1)) {
*p++ = pixels.loadAndScale0();
*p++ = pixels.loadAndScale1();
*p++ = pixels.loadAndScale2();
pixels.stepDithering();
pixels.advanceData();
}
pserial->show();
}
};
FASTLED_NAMESPACE_END
#endif // USE_WS2812SERIAL
#endif // __INC_WS2812SERIAL_CONTROLLER_H

View File

@@ -0,0 +1,124 @@
#ifndef __INC_CLOCKLESS_ARM_K66_H
#define __INC_CLOCKLESS_ARM_K66_H
FASTLED_NAMESPACE_BEGIN
// Definition for a single channel clockless controller for the k66 family of chips, like that used in the teensy 3.6
// See clockless.h for detailed info on how the template parameters are used.
#if defined(FASTLED_TEENSY3)
#define FASTLED_HAS_CLOCKLESS 1
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPin<DATA_PIN>::setOutput();
mPinMask = FastPin<DATA_PIN>::mask();
mPort = FastPin<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
if(!showRGBInternal(pixels)) {
sei(); delayMicroseconds(WAIT_TIME); cli();
showRGBInternal(pixels);
}
mWait.mark();
}
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
for(register uint32_t i = BITS-1; i > 0; i--) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
FastPin<DATA_PIN>::fastset(port, hi);
if(b&0x80) {
while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::fastset(port, lo);
} else {
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::fastset(port, lo);
}
b <<= 1;
}
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
FastPin<DATA_PIN>::fastset(port, hi);
if(b&0x80) {
while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::fastset(port, lo);
} else {
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
FastPin<DATA_PIN>::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<RGB_ORDER> 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<DATA_PIN>::port();
register data_t hi = *port | FastPin<DATA_PIN>::mask();;
register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
*port = lo;
// Setup the pixel controller and load/scale the first byte
pixels.preStepFirstByteDithering();
register uint8_t b = pixels.loadAndScale0();
cli();
uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
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 0; }
}
hi = *port | FastPin<DATA_PIN>::mask();
lo = *port & ~FastPin<DATA_PIN>::mask();
#endif
// Write first byte, read next byte
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.loadAndScale1();
// Write second byte, read 3rd byte
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.loadAndScale2();
// Write third byte, read 1st byte of next pixel
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.advanceAndLoadAndScale0();
#if (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
#endif
};
sei();
return ARM_DWT_CYCCNT;
}
};
#endif
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,344 @@
#ifndef __INC_BLOCK_CLOCKLESS_ARM_K66_H
#define __INC_BLOCK_CLOCKLESS_ARM_K66_H
// Definition for a single channel clockless controller for the k66 family of chips, like that used in the teensy 3.6
// See clockless.h for detailed info on how the template parameters are used.
#if defined(FASTLED_TEENSY3)
#define FASTLED_HAS_BLOCKLESS 1
#define PORTB_FIRST_PIN 0
#define PORTC_FIRST_PIN 15
#define PORTD_FIRST_PIN 2
#define HAS_PORTDC 1
#define LANE_MASK (((1<<LANES)-1) & ((FIRST_PIN==2) ? 0xFF : 0xFFF))
#define PORT_SHIFT(P) ((P) << ((FIRST_PIN==0) ? 16 : 0))
#define PORT_MASK PORT_SHIFT(LANE_MASK)
#define MIN(X,Y) (((X)<(Y)) ? (X):(Y))
#define USED_LANES ((FIRST_PIN!=15) ? MIN(LANES,8) : MIN(LANES,12))
#include <kinetis.h>
FASTLED_NAMESPACE_BEGIN
template <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 40>
class InlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, LANE_MASK> {
typedef typename FastPin<FIRST_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<FIRST_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual int size() { return CLEDController::size() * LANES; }
virtual void showPixels(PixelController<RGB_ORDER, LANES, LANE_MASK> & pixels) {
mWait.wait();
uint32_t clocks = showRGBInternal(pixels);
#if FASTLED_ALLOW_INTERRUPTS == 0
// Adjust the timer
long microsTaken = CLKS_TO_MICROS(clocks);
MS_COUNTER += (1 + (microsTaken / 1000));
#endif
mWait.mark();
}
virtual void init() {
if(FIRST_PIN == PORTC_FIRST_PIN) { // PORTC
switch(USED_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(USED_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();
}
} else if (FIRST_PIN == PORTB_FIRST_PIN) { // PORTB
switch (USED_LANES) {
case 8: FastPin<45>::setOutput();
case 7: FastPin<44>::setOutput();
case 6: FastPin<46>::setOutput();
case 5: FastPin<43>::setOutput();
case 4: FastPin<30>::setOutput();
case 3: FastPin<29>::setOutput();
case 2: FastPin<1>::setOutput();
case 1: FastPin<0>::setOutput();
}
}
mPinMask = FastPin<FIRST_PIN>::mask();
mPort = FastPin<FIRST_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
typedef union {
uint8_t bytes[12];
uint16_t shorts[6];
uint32_t raw[3];
} Lines;
template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, PixelController<RGB_ORDER, LANES, LANE_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);
}
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(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK);
} else {
*FastPin<FIRST_PIN>::cport() = (PORT_SHIFT(~b2.bytes[7-i]) & PORT_MASK);
}
while((next_mark - ARM_DWT_CYCCNT) > (T3));
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
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(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000))));
if(USED_LANES>8) {
*FastPin<FIRST_PIN>::cport() = ((~b2.shorts[i]) & PORT_MASK);
} else {
// b2.bytes[0] = 0;
*FastPin<FIRST_PIN>::cport() = (PORT_SHIFT(~b2.bytes[7-i]) & PORT_MASK);
}
while((next_mark - ARM_DWT_CYCCNT) > (T3));
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
}
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, LANE_MASK> &allpixels) {
// 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 < USED_LANES; i++) {
b0.bytes[i] = allpixels.loadAndScale0(i);
}
cli();
uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3);
while(allpixels.has(1)) {
#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
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
};
return ARM_DWT_CYCCNT;
}
};
#define PMASK ((1<<(LANES))-1)
#define PMASK_HI (PMASK>>8 & 0xFF)
#define PMASK_LO (PMASK & 0xFF)
template <uint8_t LANES, int T1, int T2, int T3, EOrder RGB_ORDER = GRB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class SixteenWayInlineBlockClocklessController : public CPixelLEDController<RGB_ORDER, LANES, PMASK> {
typedef typename FastPin<PORTC_FIRST_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<PORTC_FIRST_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
static_assert(LANES <= 16, "Maximum of 16 lanes for Teensy parallel controllers!");
// FastPin<30>::setOutput();
// FastPin<29>::setOutput();
// FastPin<27>::setOutput();
// FastPin<28>::setOutput();
switch(LANES) {
case 16: FastPin<12>::setOutput();
case 15: FastPin<11>::setOutput();
case 14: FastPin<13>::setOutput();
case 13: FastPin<10>::setOutput();
case 12: FastPin<9>::setOutput();
case 11: FastPin<23>::setOutput();
case 10: FastPin<22>::setOutput();
case 9: FastPin<15>::setOutput();
case 8: FastPin<5>::setOutput();
case 7: FastPin<21>::setOutput();
case 6: FastPin<20>::setOutput();
case 5: FastPin<6>::setOutput();
case 4: FastPin<8>::setOutput();
case 3: FastPin<7>::setOutput();
case 2: FastPin<14>::setOutput();
case 1: FastPin<2>::setOutput();
}
}
virtual void showPixels(PixelController<RGB_ORDER, LANES, PMASK> & pixels) {
mWait.wait();
uint32_t clocks = showRGBInternal(pixels);
#if FASTLED_ALLOW_INTERRUPTS == 0
// Adjust the timer
long microsTaken = CLKS_TO_MICROS(clocks);
MS_COUNTER += (1 + (microsTaken / 1000));
#endif
mWait.mark();
}
typedef union {
uint8_t bytes[16];
uint16_t shorts[8];
uint32_t raw[4];
} Lines;
template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, PixelController<RGB_ORDER,LANES, PMASK> &pixels) { // , register uint32_t & b2) {
register Lines b2;
transpose8x1(b.bytes,b2.bytes);
transpose8x1(b.bytes+8,b2.bytes+8);
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
for(register uint32_t i = 0; (i < LANES) && (i < 8); i++) {
while(ARM_DWT_CYCCNT < next_mark);
next_mark = ARM_DWT_CYCCNT + (T1+T2+T3)-3;
*FastPin<PORTD_FIRST_PIN>::sport() = PMASK_LO;
*FastPin<PORTC_FIRST_PIN>::sport() = PMASK_HI;
while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+6));
*FastPin<PORTD_FIRST_PIN>::cport() = ((~b2.bytes[7-i]) & PMASK_LO);
*FastPin<PORTC_FIRST_PIN>::cport() = ((~b2.bytes[15-i]) & PMASK_HI);
while((next_mark - ARM_DWT_CYCCNT) > (T3));
*FastPin<PORTD_FIRST_PIN>::cport() = PMASK_LO;
*FastPin<PORTC_FIRST_PIN>::cport() = PMASK_HI;
b.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
if(LANES==16 || (LANES>8 && ((i+8) < LANES))) {
b.bytes[i+8] = pixels.template loadAndScale<PX>(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(PixelController<RGB_ORDER,LANES, PMASK> &allpixels) {
// 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(allpixels.has(1)) {
allpixels.stepDithering();
#if 0 && (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);
// 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 0 && (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
#endif
};
sei();
return ARM_DWT_CYCCNT;
}
};
FASTLED_NAMESPACE_END
#endif
#endif

View File

@@ -0,0 +1,14 @@
#ifndef __INC_FASTLED_ARM_K66_H
#define __INC_FASTLED_ARM_K66_H
// Include the k66 headers
#include "fastpin_arm_k66.h"
#include "fastspi_arm_k66.h"
#include "../k20/octows2811_controller.h"
#include "../k20/ws2812serial_controller.h"
#include "../k20/smartmatrix_t3.h"
#include "clockless_arm_k66.h"
#include "clockless_block_arm_k66.h"
#endif

View File

@@ -0,0 +1,128 @@
#ifndef __FASTPIN_ARM_K66_H
#define __FASTPIN_ARM_K66_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 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<uint8_t PIN, uint32_t _MASK, typename _PDOR, typename _PSOR, typename _PCOR, typename _PTOR, typename _PDIR, typename _PDDR> 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<uint8_t PIN, int _BIT, typename _PDOR, typename _PSOR, typename _PCOR, typename _PTOR, typename _PDIR, typename _PDDR> 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<int BIT> 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<PIN> : public _ARMPIN<PIN, 1 << BIT, _R(GPIO ## L ## _PDOR), _R(GPIO ## L ## _PSOR), _R(GPIO ## L ## _PCOR), \
_R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {}; \
template<> class FastPinBB<PIN> : public _ARMPIN_BITBAND<PIN, BIT, _R(GPIO ## L ## _PDOR), _R(GPIO ## L ## _PSOR), _R(GPIO ## L ## _PCOR), \
_R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {};
// Actual pin definitions
#if defined(FASTLED_TEENSY3) && defined(CORE_TEENSY)
_IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E);
#define MAX_PIN 63
_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, 26, E); _DEFPIN_ARM(25, 5, A); _DEFPIN_ARM(26, 14, A); _DEFPIN_ARM(27, 15, A);
_DEFPIN_ARM(28, 16, A); _DEFPIN_ARM(29, 18, B); _DEFPIN_ARM(30, 19, B); _DEFPIN_ARM(31, 10, B);
_DEFPIN_ARM(32, 11, B); _DEFPIN_ARM(33, 24, E); _DEFPIN_ARM(34, 25, E); _DEFPIN_ARM(35, 8, C);
_DEFPIN_ARM(36, 9, C); _DEFPIN_ARM(37, 10, C); _DEFPIN_ARM(38, 11, C); _DEFPIN_ARM(39, 17, A);
_DEFPIN_ARM(40, 28, A); _DEFPIN_ARM(41, 29, A); _DEFPIN_ARM(42, 26, A); _DEFPIN_ARM(43, 20, B);
_DEFPIN_ARM(44, 22, B); _DEFPIN_ARM(45, 23, B); _DEFPIN_ARM(46, 21, B); _DEFPIN_ARM(47, 8, D);
_DEFPIN_ARM(48, 9, D); _DEFPIN_ARM(49, 4, B); _DEFPIN_ARM(50, 5, B); _DEFPIN_ARM(51, 14, D);
_DEFPIN_ARM(52, 13, D); _DEFPIN_ARM(53, 12, D); _DEFPIN_ARM(54, 15, D); _DEFPIN_ARM(55, 11, D);
_DEFPIN_ARM(56, 10, E); _DEFPIN_ARM(57, 11, E); _DEFPIN_ARM(58, 0, E); _DEFPIN_ARM(59, 1, E);
_DEFPIN_ARM(60, 2, E); _DEFPIN_ARM(61, 3, E); _DEFPIN_ARM(62, 4, E); _DEFPIN_ARM(63, 5, E);
#define SPI_DATA 11
#define SPI_CLOCK 13
#define SPI2_DATA 7
#define SPI2_CLOCK 14
#define FASTLED_TEENSY3
#define ARM_HARDWARE_SPI
#define HAS_HARDWARE_PIN_SUPPORT
#endif
#endif // FASTLED_FORCE_SOFTWARE_PINS
FASTLED_NAMESPACE_END
#endif // __INC_FASTPIN_ARM_K66

View File

@@ -0,0 +1,470 @@
#ifndef __INC_FASTSPI_ARM_H
#define __INC_FASTSPI_ARM_H
//
// copied from k20 code
// changed SPI1 define to KINETISK_SPI1
// TODO: add third alternative MOSI pin (28) and CLOCK pin (27)
// TODO: add alternative pins for SPI1
// TODO: add SPI2 output
//
FASTLED_NAMESPACE_BEGIN
#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 KINETISK_SPI0
#define KINETISK_SPI0 SPI0
#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<int VAL, int BIT> class BitWork {
public:
static int highestBit() __attribute__((always_inline)) { return (VAL & 1 << BIT) ? BIT : BitWork<VAL, BIT-1>::highestBit(); }
};
template<int VAL> class BitWork<VAL, 0> {
public:
static int highestBit() __attribute__((always_inline)) { return 0; }
};
#define MAX(A, B) (( (A) > (B) ) ? (A) : (B))
#define USE_CONT 0
// intra-frame backup data
struct SPIState {
uint32_t _ctar0,_ctar1;
uint32_t pins[4];
};
// extern SPIState gState;
// Templated function to translate a clock divider value into the prescalar, scalar, and clock doubling setting for the world.
template <int VAL> 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<VAL/2, 15>::highestBit();
int p3 = BitWork<VAL/3, 15>::highestBit();
int p5 = BitWork<VAL/5, 15>::highestBit();
int p7 = BitWork<VAL/7, 15>::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 <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER, uint32_t pSPIX>
class ARMHardwareSPIOutput {
Selectable *m_pSelect;
SPIState gState;
// Borrowed from the teensy3 SPSR emulation code -- note, enabling pin 7 disables pin 11 (and vice versa),
// and likewise enabling pin 14 disables pin 13 (and vice versa)
inline void enable_pins(void) __attribute__((always_inline)) {
//serial_print("enable_pins\n");
switch(_DATA_PIN) {
case 7:
CORE_PIN7_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
case 11:
CORE_PIN11_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
}
switch(_CLOCK_PIN) {
case 13:
CORE_PIN13_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
case 14:
CORE_PIN14_CONFIG = PORT_PCR_DSE | PORT_PCR_MUX(2);
CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
break;
}
}
// Borrowed from the teensy3 SPSR emulation code. We disable the pins that we're using, and restore the state on the pins that we aren't using
inline void disable_pins(void) __attribute__((always_inline)) {
switch(_DATA_PIN) {
case 7: CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN11_CONFIG = gState.pins[1]; break;
case 11: CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN7_CONFIG = gState.pins[0]; break;
}
switch(_CLOCK_PIN) {
case 13: CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN14_CONFIG = gState.pins[3]; break;
case 14: CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1); CORE_PIN13_CONFIG = gState.pins[2]; break;
}
}
static inline void update_ctars(uint32_t ctar0, uint32_t ctar1) __attribute__((always_inline)) {
if(SPIX.CTAR0 == ctar0 && SPIX.CTAR1 == ctar1) return;
uint32_t mcr = SPIX.MCR;
if(mcr & SPI_MCR_MDIS) {
SPIX.CTAR0 = ctar0;
SPIX.CTAR1 = ctar1;
} else {
SPIX.MCR = mcr | SPI_MCR_MDIS | SPI_MCR_HALT;
SPIX.CTAR0 = ctar0;
SPIX.CTAR1 = ctar1;
SPIX.MCR = mcr;
}
}
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_ctars(ctar0,ctar1);
}
void inline save_spi_state() __attribute__ ((always_inline)) {
// save ctar data
gState._ctar0 = SPIX.CTAR0;
gState._ctar1 = SPIX.CTAR1;
// save data for the not-us pins
gState.pins[0] = CORE_PIN7_CONFIG;
gState.pins[1] = CORE_PIN11_CONFIG;
gState.pins[2] = CORE_PIN13_CONFIG;
gState.pins[3] = CORE_PIN14_CONFIG;
}
void inline restore_spi_state() __attribute__ ((always_inline)) {
// restore ctar data
update_ctars(gState._ctar0,gState._ctar1);
// restore data for the not-us pins (not necessary because disable_pins will do this)
// CORE_PIN7_CONFIG = gState.pins[0];
// CORE_PIN11_CONFIG = gState.pins[1];
// CORE_PIN13_CONFIG = gState.pins[2];
// CORE_PIN14_CONFIG = gState.pins[3];
}
public:
ARMHardwareSPIOutput() { m_pSelect = NULL; }
ARMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
void init() {
// set the pins to output
FastPin<_DATA_PIN>::setOutput();
FastPin<_CLOCK_PIN>::setOutput();
// Enable SPI0 clock
uint32_t sim6 = SIM_SCGC6;
if((SPI_t*)pSPIX == &KINETISK_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 == &KINETISK_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);
}
}
// Configure SPI as the master and enable
SPIX.MCR |= SPI_MCR_MSTR; // | SPI_MCR_CONT_SCKE);
SPIX.MCR &= ~(SPI_MCR_MDIS | SPI_MCR_HALT);
// pin/spi configuration happens on select
}
static void waitFully() __attribute__((always_inline)) {
// Wait for the last byte to get shifted into the register
bool empty = false;
do {
cli();
if ((SPIX.SR & 0xF000) > 0) {
// reset the TCF flag
SPIX.SR |= SPI_SR_TCF;
} else {
empty = true;
}
sei();
} while (!empty);
// wait for the TCF flag to get set
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<ECont CONT_STATE, EWait WAIT_STATE, ELast LAST_STATE> 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);
SPIX.SR |= SPI_SR_TCF;
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);
SPIX.SR |= SPI_SR_TCF;
if(WAIT_STATE == POST) { wait(); }
}
};
static void writeWord(uint16_t w) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF;}
static void writeWordNoWait(uint16_t w) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF;}
static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF;}
static void writeBytePostWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF);SPIX.SR |= SPI_SR_TCF; wait(); }
static void writeByteNoWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF;}
static void writeWordCont(uint16_t w) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF;}
static void writeWordContNoWait(uint16_t w) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | (w & 0xFFFF); SPIX.SR |= SPI_SR_TCF;}
static void writeByteCont(uint8_t b) __attribute__((always_inline)) { wait(); SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF;}
static void writeByteContPostWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF;wait(); }
static void writeByteContNoWait(uint8_t b) __attribute__((always_inline)) { SPIX.PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(0) | (b & 0xFF); SPIX.SR |= SPI_SR_TCF;}
// not the most efficient mechanism in the world - but should be enough for sm16716 and friends
template <uint8_t BIT> 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)) {
save_spi_state();
if(m_pSelect != NULL) { m_pSelect->select(); }
setSPIRate();
enable_pins();
}
void inline release() __attribute__((always_inline)) {
disable_pins();
if(m_pSelect != NULL) { m_pSelect->release(); }
restore_spi_state();
}
static void writeBytesValueRaw(uint8_t value, int len) {
while(len--) { Write<CM, WM, NOTLAST>::writeByte(value); }
}
void writeBytesValue(uint8_t value, int len) {
select();
while(len--) {
writeByte(value);
}
waitFully();
release();
}
// Write a block of n uint8_ts out
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();
}
void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(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 <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
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<CM, WM, NOTLAST>::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<CM, WM, NOTLAST>::writeWord(D::adjust(pixels.loadAndScale2()) << 8 | D::adjust(pixels.stepAdvanceAndLoadAndScale0()));
// Load and write out the next two bytes
Write<CM, WM, NOTLAST>::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<CM, WM, NOTLAST>::writeWord(D::adjust(pixels.loadAndScale0()) << 8 | D::adjust(pixels.loadAndScale1()));
Write<CM, WM, NOTLAST>::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
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,46 @@
#ifndef __INC_LED_SYSDEFS_ARM_K66_H
#define __INC_LED_SYSDEFS_ARM_K66_H
#define FASTLED_TEENSY3
#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 == 192000000)
#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 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
extern volatile uint32_t systick_millis_count;
# define MS_COUNTER systick_millis_count
// Default to using PROGMEM, since TEENSY3 provides it
// even though all it does is ignore it. Just being
// conservative here in case TEENSY3 changes.
#ifndef FASTLED_USE_PROGMEM
#define FASTLED_USE_PROGMEM 1
#endif
#endif

View File

@@ -0,0 +1,65 @@
#ifndef __INC_CLOCKLESS_ARM_KL26
#define __INC_CLOCKLESS_ARM_KL26
#include "../common/m0clockless.h"
FASTLED_NAMESPACE_BEGIN
#define FASTLED_HAS_CLOCKLESS 1
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPinBB<DATA_PIN>::setOutput();
mPinMask = FastPinBB<DATA_PIN>::mask();
mPort = FastPinBB<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
uint32_t clocks = showRGBInternal(pixels);
if(!clocks) {
sei(); delayMicroseconds(WAIT_TIME); cli();
clocks = showRGBInternal(pixels);
}
long microsTaken = CLKS_TO_MICROS(clocks * ((T1 + T2 + T3) * 24));
MS_COUNTER += (microsTaken / 1000);
sei();
mWait.mark();
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
struct M0ClocklessData data;
data.d[0] = pixels.d[0];
data.d[1] = pixels.d[1];
data.d[2] = pixels.d[2];
data.s[0] = pixels.mScale[0];
data.s[1] = pixels.mScale[1];
data.s[2] = pixels.mScale[2];
data.e[0] = pixels.e[0];
data.e[1] = pixels.e[1];
data.e[2] = pixels.e[2];
data.adj = pixels.mAdvance;
typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
return showLedData<4,8,T1,T2,T3,RGB_ORDER, WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
// return 0; // 0x00FFFFFF - _VAL;
}
};
FASTLED_NAMESPACE_END
#endif // __INC_CLOCKLESS_ARM_KL26

View File

@@ -0,0 +1,10 @@
#ifndef __INC_FASTLED_ARM_KL26_H
#define __INC_FASTLED_ARM_KL26_H
// Include the k20 headers
#include "fastpin_arm_kl26.h"
#include "fastspi_arm_kl26.h"
#include "clockless_arm_kl26.h"
#include "../k20/ws2812serial_controller.h"
#endif

View File

@@ -0,0 +1,88 @@
#ifndef __FASTPIN_ARM_KL26_H
#define __FASTPIN_ARM_KL26_H
FASTLED_NAMESPACE_BEGIN
#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
#else
/// Template definition for teensy LC 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<uint8_t PIN, uint32_t _MASK, typename _PDOR, typename _PSOR, typename _PCOR, typename _PTOR, typename _PDIR, typename _PDDR> 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; }
};
// Macros for kl26 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<int BIT> static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } };
#define _IO32(L) _RD32(FGPIO ## L ## _PDOR); _RD32(FGPIO ## L ## _PSOR); _RD32(FGPIO ## L ## _PCOR); _RD32(GPIO ## L ## _PTOR); _RD32(FGPIO ## L ## _PDIR); _RD32(FGPIO ## L ## _PDDR);
#define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << BIT, _R(FGPIO ## L ## _PDOR), _R(FGPIO ## L ## _PSOR), _R(FGPIO ## L ## _PCOR), \
_R(GPIO ## L ## _PTOR), _R(FGPIO ## L ## _PDIR), _R(FGPIO ## L ## _PDDR)> {}; \
/* template<> class FastPinBB<PIN> : public _ARMPIN_BITBAND<PIN, BIT, _R(GPIO ## L ## _PDOR), _R(GPIO ## L ## _PSOR), _R(GPIO ## L ## _PCOR), \
_R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {}; */
// Actual pin definitions
#if defined(FASTLED_TEENSYLC) && defined(CORE_TEENSY)
_IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E);
#define MAX_PIN 26
_DEFPIN_ARM(0, 16, B); _DEFPIN_ARM(1, 17, B); _DEFPIN_ARM(2, 0, D); _DEFPIN_ARM(3, 1, A);
_DEFPIN_ARM(4, 2, 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, 20, E); _DEFPIN_ARM(25, 21, E); _DEFPIN_ARM(26, 30, E);
#define SPI_DATA 11
#define SPI_CLOCK 13
// #define SPI1 (*(SPI_t *)0x4002D000)
#define SPI2_DATA 0
#define SPI2_CLOCK 20
#define HAS_HARDWARE_PIN_SUPPORT
#endif
#endif // FASTLED_FORCE_SOFTWARE_PINS
FASTLED_NAMESPACE_END
#endif // __INC_FASTPIN_ARM_K20

View File

@@ -0,0 +1,252 @@
#ifndef __INC_FASTSPI_ARM_KL26_H
#define __INC_FASTSPI_ARM_KL26_h
FASTLED_NAMESPACE_BEGIN
template <int VAL> void getScalars(uint8_t & sppr, uint8_t & spr) {
if(VAL > 4096) { sppr=7; spr=8; }
else if(VAL > 3584) { sppr=6; spr=8; }
else if(VAL > 3072) { sppr=5; spr=8; }
else if(VAL > 2560) { sppr=4; spr=8; }
else if(VAL > 2048) { sppr=7; spr=7; }
else if(VAL > 2048) { sppr=3; spr=8; }
else if(VAL > 1792) { sppr=6; spr=7; }
else if(VAL > 1536) { sppr=5; spr=7; }
else if(VAL > 1536) { sppr=2; spr=8; }
else if(VAL > 1280) { sppr=4; spr=7; }
else if(VAL > 1024) { sppr=7; spr=6; }
else if(VAL > 1024) { sppr=3; spr=7; }
else if(VAL > 1024) { sppr=1; spr=8; }
else if(VAL > 896) { sppr=6; spr=6; }
else if(VAL > 768) { sppr=5; spr=6; }
else if(VAL > 768) { sppr=2; spr=7; }
else if(VAL > 640) { sppr=4; spr=6; }
else if(VAL > 512) { sppr=7; spr=5; }
else if(VAL > 512) { sppr=3; spr=6; }
else if(VAL > 512) { sppr=1; spr=7; }
else if(VAL > 512) { sppr=0; spr=8; }
else if(VAL > 448) { sppr=6; spr=5; }
else if(VAL > 384) { sppr=5; spr=5; }
else if(VAL > 384) { sppr=2; spr=6; }
else if(VAL > 320) { sppr=4; spr=5; }
else if(VAL > 256) { sppr=7; spr=4; }
else if(VAL > 256) { sppr=3; spr=5; }
else if(VAL > 256) { sppr=1; spr=6; }
else if(VAL > 256) { sppr=0; spr=7; }
else if(VAL > 224) { sppr=6; spr=4; }
else if(VAL > 192) { sppr=5; spr=4; }
else if(VAL > 192) { sppr=2; spr=5; }
else if(VAL > 160) { sppr=4; spr=4; }
else if(VAL > 128) { sppr=7; spr=3; }
else if(VAL > 128) { sppr=3; spr=4; }
else if(VAL > 128) { sppr=1; spr=5; }
else if(VAL > 128) { sppr=0; spr=6; }
else if(VAL > 112) { sppr=6; spr=3; }
else if(VAL > 96) { sppr=5; spr=3; }
else if(VAL > 96) { sppr=2; spr=4; }
else if(VAL > 80) { sppr=4; spr=3; }
else if(VAL > 64) { sppr=7; spr=2; }
else if(VAL > 64) { sppr=3; spr=3; }
else if(VAL > 64) { sppr=1; spr=4; }
else if(VAL > 64) { sppr=0; spr=5; }
else if(VAL > 56) { sppr=6; spr=2; }
else if(VAL > 48) { sppr=5; spr=2; }
else if(VAL > 48) { sppr=2; spr=3; }
else if(VAL > 40) { sppr=4; spr=2; }
else if(VAL > 32) { sppr=7; spr=1; }
else if(VAL > 32) { sppr=3; spr=2; }
else if(VAL > 32) { sppr=1; spr=3; }
else if(VAL > 32) { sppr=0; spr=4; }
else if(VAL > 28) { sppr=6; spr=1; }
else if(VAL > 24) { sppr=5; spr=1; }
else if(VAL > 24) { sppr=2; spr=2; }
else if(VAL > 20) { sppr=4; spr=1; }
else if(VAL > 16) { sppr=7; spr=0; }
else if(VAL > 16) { sppr=3; spr=1; }
else if(VAL > 16) { sppr=1; spr=2; }
else if(VAL > 16) { sppr=0; spr=3; }
else if(VAL > 14) { sppr=6; spr=0; }
else if(VAL > 12) { sppr=5; spr=0; }
else if(VAL > 12) { sppr=2; spr=1; }
else if(VAL > 10) { sppr=4; spr=0; }
else if(VAL > 8) { sppr=3; spr=0; }
else if(VAL > 8) { sppr=1; spr=1; }
else if(VAL > 8) { sppr=0; spr=2; }
else if(VAL > 6) { sppr=2; spr=0; }
else if(VAL > 4) { sppr=1; spr=0; }
else if(VAL > 4) { sppr=0; spr=1; }
else /* if(VAL > 2) */ { sppr=0; spr=0; }
}
#define SPIX (*(KINETISL_SPI_t*)pSPIX)
#define ARM_HARDWARE_SPI
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER, uint32_t pSPIX>
class ARMHardwareSPIOutput {
Selectable *m_pSelect;
static inline void enable_pins(void) __attribute__((always_inline)) {
switch(_DATA_PIN) {
case 0: CORE_PIN0_CONFIG = PORT_PCR_MUX(2); break;
case 1: CORE_PIN1_CONFIG = PORT_PCR_MUX(5); break;
case 7: CORE_PIN7_CONFIG = PORT_PCR_MUX(2); break;
case 8: CORE_PIN8_CONFIG = PORT_PCR_MUX(5); break;
case 11: CORE_PIN11_CONFIG = PORT_PCR_MUX(2); break;
case 12: CORE_PIN12_CONFIG = PORT_PCR_MUX(5); break;
case 21: CORE_PIN21_CONFIG = PORT_PCR_MUX(2); break;
}
switch(_CLOCK_PIN) {
case 13: CORE_PIN13_CONFIG = PORT_PCR_MUX(2); break;
case 14: CORE_PIN14_CONFIG = PORT_PCR_MUX(2); break;
case 20: CORE_PIN20_CONFIG = PORT_PCR_MUX(2); break;
}
}
static inline void disable_pins(void) __attribute((always_inline)) {
switch(_DATA_PIN) {
case 0: CORE_PIN0_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 1: CORE_PIN1_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 7: CORE_PIN7_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 8: CORE_PIN8_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 11: CORE_PIN11_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 12: CORE_PIN12_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 21: CORE_PIN21_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
}
switch(_CLOCK_PIN) {
case 13: CORE_PIN13_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 14: CORE_PIN14_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
case 20: CORE_PIN20_CONFIG = PORT_PCR_SRE | PORT_PCR_MUX(1); break;
}
}
void setSPIRate() {
uint8_t sppr, spr;
getScalars<_SPI_CLOCK_DIVIDER>(sppr, spr);
// Set the speed
SPIX.BR = SPI_BR_SPPR(sppr) | SPI_BR_SPR(spr);
// Also, force 8 bit transfers (don't want to juggle 8/16 since that flushes the world)
SPIX.C2 = 0;
SPIX.C1 |= SPI_C1_SPE;
}
public:
ARMHardwareSPIOutput() { m_pSelect = NULL; }
ARMHardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; }
// set the object representing the selectable
void setSelect(Selectable *pSelect) { m_pSelect = pSelect; }
// initialize the SPI subssytem
void init() {
FastPin<_DATA_PIN>::setOutput();
FastPin<_CLOCK_PIN>::setOutput();
// Enable the SPI clocks
uint32_t sim4 = SIM_SCGC4;
if ((pSPIX == 0x40076000) && !(sim4 & SIM_SCGC4_SPI0)) {
SIM_SCGC4 = sim4 | SIM_SCGC4_SPI0;
}
if ( (pSPIX == 0x40077000) && !(sim4 & SIM_SCGC4_SPI1)) {
SIM_SCGC4 = sim4 | SIM_SCGC4_SPI1;
}
SPIX.C1 = SPI_C1_MSTR | SPI_C1_SPE;
SPIX.C2 = 0;
SPIX.BR = SPI_BR_SPPR(1) | SPI_BR_SPR(0);
}
// latch the CS select
void inline select() __attribute__((always_inline)) {
if(m_pSelect != NULL) { m_pSelect->select(); }
setSPIRate();
enable_pins();
}
// release the CS select
void inline release() __attribute__((always_inline)) {
disable_pins();
if(m_pSelect != NULL) { m_pSelect->release(); }
}
// Wait for the world to be clear
static void wait() __attribute__((always_inline)) { while(!(SPIX.S & SPI_S_SPTEF)); }
// wait until all queued up data has been written
void waitFully() { wait(); }
// not the most efficient mechanism in the world - but should be enough for sm16716 and friends
template <uint8_t BIT> inline static void writeBit(uint8_t b) { /* TODO */ }
// write a byte out via SPI (returns immediately on writing register)
static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); SPIX.DL = b; }
// write a word out via SPI (returns immediately on writing register)
static void writeWord(uint16_t w) __attribute__((always_inline)) { writeByte(w>>8); writeByte(w & 0xFF); }
// A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes)
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) {
setSPIRate();
select();
while(len--) {
writeByte(value);
}
waitFully();
release();
}
// A full cycle of writing a raw block of data out, including select, release, and waiting
template <class D> 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_NOP>(data, len); }
template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
int len = pixels.mLen;
select();
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()));
} else {
writeByte(D::adjust(pixels.loadAndScale0()));
writeByte(D::adjust(pixels.loadAndScale1()));
writeByte(D::adjust(pixels.loadAndScale2()));
}
pixels.advanceData();
pixels.stepDithering();
}
D::postBlock(len);
release();
}
};
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,47 @@
#ifndef __INC_LED_SYSDEFS_ARM_KL26_H
#define __INC_LED_SYSDEFS_ARM_KL26_H
#define FASTLED_TEENSYLC
#define FASTLED_ARM
#define FASTLED_ARM_M0_PLUS
#ifndef INTERRUPT_THRESHOLD
#define INTERRUPT_THRESHOLD 1
#endif
#define FASTLED_SPI_BYTE_ONLY
// 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 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
extern volatile uint32_t systick_millis_count;
# define MS_COUNTER systick_millis_count
// Default to using PROGMEM since TEENSYLC provides it
// even though all it does is ignore it. Just being
// conservative here in case TEENSYLC changes.
#ifndef FASTLED_USE_PROGMEM
#define FASTLED_USE_PROGMEM 1
#endif
#endif

View File

@@ -0,0 +1,83 @@
#ifndef __INC_CLOCKLESS_ARM_NRF51
#define __INC_CLOCKLESS_ARM_NRF51
#if defined(NRF51)
#include <nrf51_bitfields.h>
#define FASTLED_HAS_CLOCKLESS 1
#if (FASTLED_ALLOW_INTERRUPTS==1)
#define SEI_CHK LED_TIMER->CC[0] = (WAIT_TIME * (F_CPU/1000000)); LED_TIMER->TASKS_CLEAR; LED_TIMER->EVENTS_COMPARE[0] = 0;
#define CLI_CHK cli(); if(LED_TIMER->EVENTS_COMPARE[0]) { LED_TIMER->TASKS_STOP = 1; return 0; }
#define INNER_SEI sei();
#else
#define SEI_CHK
#define CLI_CHK
#define INNER_SEI delaycycles<1>();
#endif
#include "../common/m0clockless.h"
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 75>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPinBB<DATA_PIN>::setOutput();
mPinMask = FastPinBB<DATA_PIN>::mask();
mPort = FastPinBB<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
cli();
if(!showRGBInternal(pixels)) {
sei(); delayMicroseconds(WAIT_TIME); cli();
showRGBInternal(pixels);
}
sei();
mWait.mark();
}
// This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
// gcc will use register Y for the this pointer.
static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
struct M0ClocklessData data;
data.d[0] = pixels.d[0];
data.d[1] = pixels.d[1];
data.d[2] = pixels.d[2];
data.s[0] = pixels.mScale[0];
data.s[1] = pixels.mScale[1];
data.s[2] = pixels.mScale[2];
data.e[0] = pixels.e[0];
data.e[1] = pixels.e[1];
data.e[2] = pixels.e[2];
data.adj = pixels.mAdvance;
typename FastPin<DATA_PIN>::port_ptr_t portBase = FastPin<DATA_PIN>::port();
// timer mode w/prescaler of 0
LED_TIMER->MODE = TIMER_MODE_MODE_Timer;
LED_TIMER->PRESCALER = 0;
LED_TIMER->EVENTS_COMPARE[0] = 0;
LED_TIMER->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
LED_TIMER->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk;
LED_TIMER->TASKS_START = 1;
int ret = showLedData<4,8,T1,T2,T3,RGB_ORDER,WAIT_TIME>(portBase, FastPin<DATA_PIN>::mask(), pixels.mData, pixels.mLen, &data);
LED_TIMER->TASKS_STOP = 1;
return ret; // 0x00FFFFFF - _VAL;
}
};
#endif // NRF51
#endif // __INC_CLOCKLESS_ARM_NRF51

View File

@@ -0,0 +1,9 @@
#ifndef __INC_FASTLED_ARM_NRF51_H
#define __INC_FASTLED_ARM_NRF51_H
// Include the k20 headers
#include "fastpin_arm_nrf51.h"
#include "fastspi_arm_nrf51.h"
#include "clockless_arm_nrf51.h"
#endif

View File

@@ -0,0 +1,119 @@
#ifndef __FASTPIN_ARM_NRF51_H
#define __FASTPIN_ARM_NRF51_H
#if defined(NRF51)
/// 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
#if 0
template<uint8_t PIN, uint32_t _MASK, typename _DIRSET, typename _DIRCLR, typename _OUTSET, typename _OUTCLR, typename _OUT> class _ARMPIN {
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
inline static void setOutput() { _DIRSET::r() = _MASK; }
inline static void setInput() { _DIRCLR::r() = _MASK; }
inline static void hi() __attribute__ ((always_inline)) { _OUTSET::r() = _MASK; }
inline static void lo() __attribute__ ((always_inline)) { _OUTCLR::r() = _MASK; }
inline static void set(register port_t val) __attribute__ ((always_inline)) { _OUT::r() = val; }
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
inline static void toggle() __attribute__ ((always_inline)) { _OUT::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 _OUT::r() | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return _OUT::r() & ~_MASK; }
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_OUT::r(); }
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
};
#define ADDR(X) *(volatile uint32_t*)X
#define NR_GPIO_ADDR(base,offset) (*(volatile uint32_t *))((uint32_t)(base + offset))
#define NR_DIRSET ADDR(0x50000518UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x518)
#define NR_DIRCLR ADDR(0x5000051CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x51C)
#define NR_OUTSET ADDR(0x50000508UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x508)
#define NR_OUTCLR ADDR(0x5000050CUL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x50C)
#define NR_OUT ADDR(0x50000504UL) // NR_GPIO_ADDR(NRF_GPIO_BASE, 0x504)
#define _RD32_NRF(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; }};
_RD32_NRF(NR_DIRSET);
_RD32_NRF(NR_DIRCLR);
_RD32_NRF(NR_OUTSET);
_RD32_NRF(NR_OUTCLR);
_RD32_NRF(NR_OUT);
#define _DEFPIN_ARM(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN, \
_R(NR_DIRSET), _R(NR_DIRCLR), _R(NR_OUTSET), _R(NR_OUTCLR), _R(NR_OUT)> {};
#else
typedef struct { /*!< GPIO Structure */
// __I uint32_t RESERVED0[321];
__IO uint32_t OUT; /*!< Write GPIO port. */
__IO uint32_t OUTSET; /*!< Set individual bits in GPIO port. */
__IO uint32_t OUTCLR; /*!< Clear individual bits in GPIO port. */
__I uint32_t IN; /*!< Read GPIO port. */
__IO uint32_t DIR; /*!< Direction of GPIO pins. */
__IO uint32_t DIRSET; /*!< DIR set register. */
__IO uint32_t DIRCLR; /*!< DIR clear register. */
__I uint32_t RESERVED1[120];
__IO uint32_t PIN_CNF[32]; /*!< Configuration of GPIO pins. */
} FL_NRF_GPIO_Type;
#define FL_NRF_GPIO_BASE 0x50000504UL
#define FL_NRF_GPIO ((FL_NRF_GPIO_Type *) FL_NRF_GPIO_BASE)
template<uint8_t PIN, uint32_t _MASK> class _ARMPIN {
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
inline static void setOutput() { FL_NRF_GPIO->DIRSET = _MASK; }
inline static void setInput() { FL_NRF_GPIO->DIRCLR = _MASK; }
inline static void hi() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTSET = _MASK; }
inline static void lo() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUTCLR= _MASK; }
inline static void set(register port_t val) __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT = val; }
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
inline static void toggle() __attribute__ ((always_inline)) { FL_NRF_GPIO->OUT ^= _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 FL_NRF_GPIO->OUT | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return FL_NRF_GPIO->OUT & ~_MASK; }
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &FL_NRF_GPIO->OUT; }
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
inline static bool isset() __attribute__ ((always_inline)) { return (FL_NRF_GPIO->IN & _MASK) != 0; }
};
#define _DEFPIN_ARM(PIN) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << PIN> {};
#endif
// Actual pin definitions
#define MAX_PIN 31
_DEFPIN_ARM(0); _DEFPIN_ARM(1); _DEFPIN_ARM(2); _DEFPIN_ARM(3);
_DEFPIN_ARM(4); _DEFPIN_ARM(5); _DEFPIN_ARM(6); _DEFPIN_ARM(7);
_DEFPIN_ARM(8); _DEFPIN_ARM(9); _DEFPIN_ARM(10); _DEFPIN_ARM(11);
_DEFPIN_ARM(12); _DEFPIN_ARM(13); _DEFPIN_ARM(14); _DEFPIN_ARM(15);
_DEFPIN_ARM(16); _DEFPIN_ARM(17); _DEFPIN_ARM(18); _DEFPIN_ARM(19);
_DEFPIN_ARM(20); _DEFPIN_ARM(21); _DEFPIN_ARM(22); _DEFPIN_ARM(23);
_DEFPIN_ARM(24); _DEFPIN_ARM(25); _DEFPIN_ARM(26); _DEFPIN_ARM(27);
_DEFPIN_ARM(28); _DEFPIN_ARM(29); _DEFPIN_ARM(30); _DEFPIN_ARM(31);
#define HAS_HARDWARE_PIN_SUPPORT
#endif
#endif

View File

@@ -0,0 +1,150 @@
#ifndef __INC_FASTSPI_NRF_H
#define __INC_FASTSPI_NRF_H
#ifdef NRF51
#ifndef FASTLED_FORCE_SOFTWARE_SPI
#define FASTLED_ALL_PINS_HARDWARE_SPI
// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should
// be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the
// idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead)
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
class NRF51SPIOutput {
struct saveData {
uint32_t sck;
uint32_t mosi;
uint32_t miso;
uint32_t freq;
uint32_t enable;
} mSavedData;
void saveSPIData() {
mSavedData.sck = NRF_SPI0->PSELSCK;
mSavedData.mosi = NRF_SPI0->PSELMOSI;
mSavedData.miso = NRF_SPI0->PSELMISO;
mSavedData.freq = NRF_SPI0->FREQUENCY;
mSavedData.enable = NRF_SPI0->ENABLE;
}
void restoreSPIData() {
NRF_SPI0->PSELSCK = mSavedData.sck;
NRF_SPI0->PSELMOSI = mSavedData.mosi;
NRF_SPI0->PSELMISO = mSavedData.miso;
NRF_SPI0->FREQUENCY = mSavedData.freq;
mSavedData.enable = NRF_SPI0->ENABLE;
}
public:
NRF51SPIOutput() { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
NRF51SPIOutput(Selectable *pSelect) { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
// set the object representing the selectable
void setSelect(Selectable *pSelect) { /* TODO */ }
// initialize the SPI subssytem
void init() {
FastPin<_DATA_PIN>::setOutput();
FastPin<_CLOCK_PIN>::setOutput();
NRF_SPI0->PSELSCK = _CLOCK_PIN;
NRF_SPI0->PSELMOSI = _DATA_PIN;
NRF_SPI0->PSELMISO = 0xFFFFFFFF;
NRF_SPI0->FREQUENCY = 0x80000000;
NRF_SPI0->ENABLE = 1;
NRF_SPI0->EVENTS_READY = 0;
}
// latch the CS select
void select() { saveSPIData(); init(); }
// release the CS select
void release() { shouldWait(); restoreSPIData(); }
static bool shouldWait(bool wait = false) __attribute__((always_inline)) __attribute__((always_inline)) {
// static bool sWait=false;
// bool oldWait = sWait;
// sWait = wait;
// never going to bother with waiting since we're always running the spi clock at max speed on the rfduino
// TODO: When we set clock rate, implement/fix waiting properly, otherwise the world hangs up
return false;
}
// wait until all queued up data has been written
static void waitFully() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
static void wait() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
// write a byte out via SPI (returns immediately on writing register)
static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); NRF_SPI0->TXD = b; NRF_SPI0->INTENCLR; shouldWait(true); }
// write a word out via SPI (returns immediately on writing register)
static void writeWord(uint16_t w) __attribute__((always_inline)){ writeByte(w>>8); writeByte(w & 0xFF); }
// A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes)
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();
while(len--) {
writeByte(value);
}
waitFully();
release();
}
// A full cycle of writing a raw block of data out, including select, release, and waiting
template<class D> void writeBytes(uint8_t *data, int len) {
uint8_t *end = data + len;
select();
while(data != end) {
writeByte(D::adjust(*data++));
}
D::postBlock(len);
waitFully();
release();
}
void writeBytes(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 static void writeBit(uint8_t b) {
waitFully();
NRF_SPI0->ENABLE = 0;
if(b & 1<<BIT) {
FastPin<_DATA_PIN>::hi();
} else {
FastPin<_DATA_PIN>::lo();
}
FastPin<_CLOCK_PIN>::toggle();
FastPin<_CLOCK_PIN>::toggle();
NRF_SPI0->ENABLE = 1;
}
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);
waitFully();
release();
}
};
#endif
#endif
#endif

View File

@@ -0,0 +1,46 @@
#ifndef __LED_SYSDEFS_ARM_NRF51
#define __LED_SYSDEFS_ARM_NRF51
#ifndef NRF51
#define NRF51
#endif
#define LED_TIMER NRF_TIMER1
#define FASTLED_NO_PINMAP
#define FASTLED_HAS_CLOCKLESS
#define FASTLED_SPI_BYTE_ONLY
#define FASTLED_ARM
#define FASTLED_ARM_M0
#ifndef F_CPU
#define F_CPU 16000000
#endif
#include <stdint.h>
#include <nrf51.h>
#include <core_cm0.h>
typedef volatile uint32_t RoReg;
typedef volatile uint32_t RwReg;
typedef uint32_t prog_uint32_t;
typedef uint8_t boolean;
#define PROGMEM
#define NO_PROGMEM
#define NEED_CXX_BITS
// Default to NOT using PROGMEM here
#ifndef FASTLED_USE_PROGMEM
#define FASTLED_USE_PROGMEM 0
#endif
#ifndef FASTLED_ALLOW_INTERRUPTS
#define FASTLED_ALLOW_INTERRUPTS 1
#endif
#define cli() __disable_irq();
#define sei() __enable_irq();
#endif

View File

@@ -0,0 +1,120 @@
#ifndef __INC_CLOCKLESS_ARM_SAM_H
#define __INC_CLOCKLESS_ARM_SAM_H
FASTLED_NAMESPACE_BEGIN
// 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 FASTLED_HAS_CLOCKLESS 1
template <uint8_t DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPinBB<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPinBB<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPinBB<DATA_PIN>::setOutput();
mPinMask = FastPinBB<DATA_PIN>::mask();
mPort = FastPinBB<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
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 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<RGB_ORDER> 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<DATA_PIN>::port(); FORCE_REFERENCE(port);
*port = 0;
// Setup the pixel controller and load/scale the first byte
pixels.preStepFirstByteDithering();
uint8_t b = pixels.loadAndScale0();
uint32_t next_mark = (DUE_TIMER_VAL + (TOTAL));
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 0; }
}
#endif
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();
#if (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
#endif
};
TC_Stop(DUE_TIMER,DUE_TIMER_CHANNEL);
return DUE_TIMER_VAL;
}
};
#endif
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,184 @@
#ifndef __INC_BLOCK_CLOCKLESS_H
#define __INC_BLOCK_CLOCKLESS_H
FASTLED_NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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<<LANES)-1) & ((FIRST_PIN==2) ? 0xFF : 0xFF))
#define FASTLED_HAS_BLOCKLESS 1
#define PORTD_FIRST_PIN 25
#define PORTA_FIRST_PIN 69
#define PORTB_FIRST_PIN 90
typedef union {
uint8_t bytes[8];
uint32_t raw[2];
} Lines;
#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 <uint8_t LANES, int FIRST_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class InlineBlockClocklessController : public 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;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual int size() { return CLEDController::size() * LANES; }
virtual void init() {
static_assert(LANES <= 8, "Maximum of 8 lanes for Due parallel controllers!");
if(FIRST_PIN == PORTA_FIRST_PIN) {
switch(LANES) {
case 8: FastPin<31>::setOutput();
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<FIRST_PIN>::mask();
mPort = FastPin<FIRST_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
virtual void showPixels(PixelController<RGB_ORDER, LANES, PORT_MASK> & pixels) {
mWait.wait();
showRGBInternal(pixels);
sei();
mWait.mark();
}
static uint32_t showRGBInternal(PixelController<RGB_ORDER, LANES, PORT_MASK> &allpixels) {
// Serial.println("Entering show");
int nLeds = allpixels.mLen;
// Setup the pixel controller and load/scale the first byte
Lines b0,b1,b2;
allpixels.preStepFirstByteDithering();
for(uint8_t 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);
#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);
// 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);
#if (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
#endif
}
return DUE_TIMER_VAL;
}
template<int BITS,int PX> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register Lines & b, Lines & b3, PixelController<RGB_ORDER,LANES, PORT_MASK> &pixels) { // , register uint32_t & b2) {
Lines b2;
transpose8x1(b.bytes,b2.bytes);
register uint8_t d = pixels.template getd<PX>(pixels);
register uint8_t scale = pixels.template getscale<PX>(pixels);
for(uint32_t i = 0; (i < LANES) && (i<8); i++) {
while(DUE_TIMER_VAL < next_mark);
next_mark = (DUE_TIMER_VAL+TOTAL);
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
*FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
while((next_mark - (DUE_TIMER_VAL)) > T3);
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
b3.bytes[i] = pixels.template loadAndScale<PX>(pixels,i,d,scale);
}
for(uint32_t i = LANES; i < 8; i++) {
while(DUE_TIMER_VAL < next_mark);
next_mark = (DUE_TIMER_VAL+TOTAL);
*FastPin<FIRST_PIN>::sport() = PORT_MASK;
while((next_mark - DUE_TIMER_VAL) > (T2+T3+6));
*FastPin<FIRST_PIN>::cport() = (~b2.bytes[7-i]) & PORT_MASK;
while((next_mark - DUE_TIMER_VAL) > T3);
*FastPin<FIRST_PIN>::cport() = PORT_MASK;
}
}
};
#endif
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,10 @@
#ifndef __INC_FASTLED_ARM_SAM_H
#define __INC_FASTLED_ARM_SAM_H
// Include the sam headers
#include "fastpin_arm_sam.h"
#include "fastspi_arm_sam.h"
#include "clockless_arm_sam.h"
#include "clockless_block_arm_sam.h"
#endif

View File

@@ -0,0 +1,137 @@
#ifndef __INC_FASTPIN_ARM_SAM_H
#define __INC_FASTPIN_ARM_SAM_H
FASTLED_NAMESPACE_BEGIN
#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
#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<uint8_t PIN, uint32_t _MASK, typename _PDOR, typename _PSOR, typename _PCOR, typename _PDDR> 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<uint8_t PIN, uint32_t _BIT, typename _PDOR, typename _PSOR, typename _PCOR, typename _PDDR> 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<int BIT> 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<PIN> : public _DUEPIN<PIN, 1 << BIT, _R(REG_PIO ## L ## _ODSR), _R(REG_PIO ## L ## _SODR), _R(REG_PIO ## L ## _CODR), \
_R(GPIO ## L ## _OER)> {}; \
template<> class FastPinBB<PIN> : public _DUEPIN_BITBAND<PIN, BIT, _R(REG_PIO ## L ## _ODSR), _R(REG_PIO ## L ## _SODR), _R(REG_PIO ## L ## _CODR), \
_R(GPIO ## L ## _OER)> {};
#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 // FASTLED_FORCE_SOFTWARE_PINS
FASTLED_NAMESPACE_END
#endif // __INC_FASTPIN_ARM_SAM_H

View File

@@ -0,0 +1,163 @@
#ifndef __INC_FASTSPI_ARM_SAM_H
#define __INC_FASTSPI_ARM_SAM_H
FASTLED_NAMESPACE_BEGIN
#if defined(__SAM3X8E__)
#define m_SPI ((Spi*)SPI0)
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
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<int BITS> 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 <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();
}
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
// not the most efficient mechanism in the world - but should be enough for sm16716 and friends
template <uint8_t BIT> 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 <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> 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
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,39 @@
#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
// Default to allowing interrupts
#ifndef FASTLED_ALLOW_INTERRUPTS
#define FASTLED_ALLOW_INTERRUPTS 1
#endif
#if FASTLED_ALLOW_INTERRUPTS == 1
#define FASTLED_ACCURATE_CLOCK
#endif
// reusing/abusing cli/sei defs for due
#define cli() __disable_irq(); __disable_fault_irq();
#define sei() __enable_irq(); __enable_fault_irq();
#endif

View File

@@ -0,0 +1,126 @@
#ifndef __INC_CLOCKLESS_ARM_STM32_H
#define __INC_CLOCKLESS_ARM_STM32_H
FASTLED_NAMESPACE_BEGIN
// Definition for a single channel clockless controller for the stm32 family of chips, like that used in the spark core
// See clockless.h for detailed info on how the template parameters are used.
#define FASTLED_HAS_CLOCKLESS 1
template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
typedef typename FastPin<DATA_PIN>::port_t data_t;
data_t mPinMask;
data_ptr_t mPort;
CMinWait<WAIT_TIME> mWait;
public:
virtual void init() {
FastPin<DATA_PIN>::setOutput();
mPinMask = FastPin<DATA_PIN>::mask();
mPort = FastPin<DATA_PIN>::port();
}
virtual uint16_t getMaxRefreshRate() const { return 400; }
protected:
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mWait.wait();
if(!showRGBInternal(pixels)) {
sei(); delayMicroseconds(WAIT_TIME); cli();
showRGBInternal(pixels);
}
mWait.mark();
}
#define _CYCCNT (*(volatile uint32_t*)(0xE0001004UL))
template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b) {
for(register uint32_t i = BITS-1; i > 0; i--) {
while(_CYCCNT < (T1+T2+T3-20));
FastPin<DATA_PIN>::fastset(port, hi);
_CYCCNT = 4;
if(b&0x80) {
while(_CYCCNT < (T1+T2-20));
FastPin<DATA_PIN>::fastset(port, lo);
} else {
while(_CYCCNT < (T1-10));
FastPin<DATA_PIN>::fastset(port, lo);
}
b <<= 1;
}
while(_CYCCNT < (T1+T2+T3-20));
FastPin<DATA_PIN>::fastset(port, hi);
_CYCCNT = 4;
if(b&0x80) {
while(_CYCCNT < (T1+T2-20));
FastPin<DATA_PIN>::fastset(port, lo);
} else {
while(_CYCCNT < (T1-10));
FastPin<DATA_PIN>::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<RGB_ORDER> pixels) {
// Get access to the clock
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0;
register data_ptr_t port = FastPin<DATA_PIN>::port();
register data_t hi = *port | FastPin<DATA_PIN>::mask();;
register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
*port = lo;
// Setup the pixel controller and load/scale the first byte
pixels.preStepFirstByteDithering();
register uint8_t b = pixels.loadAndScale0();
cli();
uint32_t next_mark = (T1+T2+T3);
DWT->CYCCNT = 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(DWT->CYCCNT > next_mark) {
if((DWT->CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
}
hi = *port | FastPin<DATA_PIN>::mask();
lo = *port & ~FastPin<DATA_PIN>::mask();
#endif
// Write first byte, read next byte
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.loadAndScale1();
// Write second byte, read 3rd byte
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.loadAndScale2();
// Write third byte, read 1st byte of next pixel
writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
b = pixels.advanceAndLoadAndScale0();
#if (FASTLED_ALLOW_INTERRUPTS == 1)
sei();
#endif
};
sei();
return DWT->CYCCNT;
}
};
FASTLED_NAMESPACE_END
#endif

View File

@@ -0,0 +1,9 @@
#ifndef __INC_FASTLED_ARM_SAM_H
#define __INC_FASTLED_ARM_SAM_H
// Include the sam headers
#include "fastpin_arm_stm32.h"
// #include "fastspi_arm_stm32.h"
#include "clockless_arm_stm32.h"
#endif

View File

@@ -0,0 +1,105 @@
#ifndef __FASTPIN_ARM_STM32_H
#define __FASTPIN_ARM_STM32_H
FASTLED_NAMESPACE_BEGIN
#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
#else
/// Template definition for STM32 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<uint8_t PIN, uint8_t _BIT, uint32_t _MASK, typename _GPIO> class _ARMPIN {
public:
typedef volatile uint32_t * port_ptr_t;
typedef uint32_t port_t;
#if 0
inline static void setOutput() {
if(_BIT<8) {
_CRL::r() = (_CRL::r() & (0xF << (_BIT*4)) | (0x1 << (_BIT*4));
} else {
_CRH::r() = (_CRH::r() & (0xF << ((_BIT-8)*4))) | (0x1 << ((_BIT-8)*4));
}
}
inline static void setInput() { /* TODO */ } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; }
#endif
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::r()->BSRR = _MASK; }
inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BRR = _MASK; }
// inline static void lo() __attribute__ ((always_inline)) { _GPIO::r()->BSRR = (_MASK<<16); }
inline static void set(register port_t val) __attribute__ ((always_inline)) { _GPIO::r()->ODR = val; }
inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); }
inline static void toggle() __attribute__ ((always_inline)) { if(_GPIO::r()->ODR & _MASK) { lo(); } else { hi(); } }
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::r()->ODR | _MASK; }
inline static port_t loval() __attribute__ ((always_inline)) { return _GPIO::r()->ODR & ~_MASK; }
inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_GPIO::r()->ODR; }
inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO::r()->BSRR; }
inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO::r()->BRR; }
inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; }
};
#define _R(T) struct __gen_struct_ ## T
#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline volatile GPIO_TypeDef * r() { return T; } };
#define _IO32(L) _RD32(GPIO ## L)
#define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, BIT, 1 << BIT, _R(GPIO ## L)> {};
// Actual pin definitions
#if defined(SPARK)
_IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); _IO32(F); _IO32(G);
#define MAX_PIN 19
_DEFPIN_ARM(0, 7, B);
_DEFPIN_ARM(1, 6, B);
_DEFPIN_ARM(2, 5, B);
_DEFPIN_ARM(3, 4, B);
_DEFPIN_ARM(4, 3, B);
_DEFPIN_ARM(5, 15, A);
_DEFPIN_ARM(6, 14, A);
_DEFPIN_ARM(7, 13, A);
_DEFPIN_ARM(8, 8, A);
_DEFPIN_ARM(9, 9, A);
_DEFPIN_ARM(10, 0, A);
_DEFPIN_ARM(11, 1, A);
_DEFPIN_ARM(12, 4, A);
_DEFPIN_ARM(13, 5, A);
_DEFPIN_ARM(14, 6, A);
_DEFPIN_ARM(15, 7, A);
_DEFPIN_ARM(16, 0, B);
_DEFPIN_ARM(17, 1, B);
_DEFPIN_ARM(18, 3, A);
_DEFPIN_ARM(19, 2, A);
#define SPI_DATA 15
#define SPI_CLOCK 13
#define HAS_HARDWARE_PIN_SUPPORT
#endif
#endif // FASTLED_FORCE_SOFTWARE_PINS
FASTLED_NAMESPACE_END
#endif // __INC_FASTPIN_ARM_STM32

View File

@@ -0,0 +1,47 @@
#ifndef __INC_LED_SYSDEFS_ARM_SAM_H
#define __INC_LED_SYSDEFS_ARM_SAM_H
#include <application.h>
#define FASTLED_NAMESPACE_BEGIN namespace NSFastLED {
#define FASTLED_NAMESPACE_END }
#define FASTLED_USING_NAMESPACE using namespace NSFastLED;
#define FASTLED_ARM
#ifndef INTERRUPT_THRESHOLD
#define INTERRUPT_THRESHOLD 1
#endif
// Default to allowing interrupts
#ifndef FASTLED_ALLOW_INTERRUPTS
#define FASTLED_ALLOW_INTERRUPTS 0
#endif
#if FASTLED_ALLOW_INTERRUPTS == 1
#define FASTLED_ACCURATE_CLOCK
#endif
// reusing/abusing cli/sei defs for due
#define cli() __disable_irq(); __disable_fault_irq();
#define sei() __enable_irq(); __enable_fault_irq();
// pgmspace definitions
#define PROGMEM
#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
#define pgm_read_dword_near(addr) pgm_read_dword(addr)
// Default to NOT using PROGMEM here
#ifndef FASTLED_USE_PROGMEM
#define FASTLED_USE_PROGMEM 0
#endif
// data type defs
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) */
#define FASTLED_NO_PINMAP
#define F_CPU 72000000
#endif