mirror of
https://github.com/gunner47/GyverLamp.git
synced 2025-08-09 01:40:59 +03:00
add
This commit is contained in:
318
libraries/FastLED-3.2.0/platforms/arm/common/m0clockless.h
Normal file
318
libraries/FastLED-3.2.0/platforms/arm/common/m0clockless.h
Normal 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
|
@@ -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
|
@@ -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
|
176
libraries/FastLED-3.2.0/platforms/arm/d21/fastpin_arm_d21.h
Normal file
176
libraries/FastLED-3.2.0/platforms/arm/d21/fastpin_arm_d21.h
Normal 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
|
@@ -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
|
124
libraries/FastLED-3.2.0/platforms/arm/k20/clockless_arm_k20.h
Normal file
124
libraries/FastLED-3.2.0/platforms/arm/k20/clockless_arm_k20.h
Normal 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
|
@@ -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
|
13
libraries/FastLED-3.2.0/platforms/arm/k20/fastled_arm_k20.h
Normal file
13
libraries/FastLED-3.2.0/platforms/arm/k20/fastled_arm_k20.h
Normal 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
|
120
libraries/FastLED-3.2.0/platforms/arm/k20/fastpin_arm_k20.h
Normal file
120
libraries/FastLED-3.2.0/platforms/arm/k20/fastpin_arm_k20.h
Normal 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
|
466
libraries/FastLED-3.2.0/platforms/arm/k20/fastspi_arm_k20.h
Normal file
466
libraries/FastLED-3.2.0/platforms/arm/k20/fastspi_arm_k20.h
Normal 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
|
@@ -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
|
@@ -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
|
55
libraries/FastLED-3.2.0/platforms/arm/k20/smartmatrix_t3.h
Normal file
55
libraries/FastLED-3.2.0/platforms/arm/k20/smartmatrix_t3.h
Normal 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
|
@@ -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
|
124
libraries/FastLED-3.2.0/platforms/arm/k66/clockless_arm_k66.h
Normal file
124
libraries/FastLED-3.2.0/platforms/arm/k66/clockless_arm_k66.h
Normal 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
|
@@ -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
|
14
libraries/FastLED-3.2.0/platforms/arm/k66/fastled_arm_k66.h
Normal file
14
libraries/FastLED-3.2.0/platforms/arm/k66/fastled_arm_k66.h
Normal 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
|
||||
|
128
libraries/FastLED-3.2.0/platforms/arm/k66/fastpin_arm_k66.h
Normal file
128
libraries/FastLED-3.2.0/platforms/arm/k66/fastpin_arm_k66.h
Normal 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
|
470
libraries/FastLED-3.2.0/platforms/arm/k66/fastspi_arm_k66.h
Normal file
470
libraries/FastLED-3.2.0/platforms/arm/k66/fastspi_arm_k66.h
Normal 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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
252
libraries/FastLED-3.2.0/platforms/arm/kl26/fastspi_arm_kl26.h
Normal file
252
libraries/FastLED-3.2.0/platforms/arm/kl26/fastspi_arm_kl26.h
Normal 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
|
@@ -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
|
@@ -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
|
@@ -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
|
119
libraries/FastLED-3.2.0/platforms/arm/nrf51/fastpin_arm_nrf51.h
Normal file
119
libraries/FastLED-3.2.0/platforms/arm/nrf51/fastpin_arm_nrf51.h
Normal 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
|
150
libraries/FastLED-3.2.0/platforms/arm/nrf51/fastspi_arm_nrf51.h
Normal file
150
libraries/FastLED-3.2.0/platforms/arm/nrf51/fastspi_arm_nrf51.h
Normal 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
|
@@ -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
|
120
libraries/FastLED-3.2.0/platforms/arm/sam/clockless_arm_sam.h
Normal file
120
libraries/FastLED-3.2.0/platforms/arm/sam/clockless_arm_sam.h
Normal 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
|
@@ -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
|
10
libraries/FastLED-3.2.0/platforms/arm/sam/fastled_arm_sam.h
Normal file
10
libraries/FastLED-3.2.0/platforms/arm/sam/fastled_arm_sam.h
Normal 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
|
137
libraries/FastLED-3.2.0/platforms/arm/sam/fastpin_arm_sam.h
Normal file
137
libraries/FastLED-3.2.0/platforms/arm/sam/fastpin_arm_sam.h
Normal 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
|
163
libraries/FastLED-3.2.0/platforms/arm/sam/fastspi_arm_sam.h
Normal file
163
libraries/FastLED-3.2.0/platforms/arm/sam/fastspi_arm_sam.h
Normal 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
|
@@ -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
|
@@ -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
|
@@ -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
|
105
libraries/FastLED-3.2.0/platforms/arm/stm32/fastpin_arm_stm32.h
Normal file
105
libraries/FastLED-3.2.0/platforms/arm/stm32/fastpin_arm_stm32.h
Normal 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
|
@@ -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
|
Reference in New Issue
Block a user