First commit.
This commit is contained in:
120
.pio/libdeps/local/FastLED/platforms/arm/sam/clockless_arm_sam.h
Normal file
120
.pio/libdeps/local/FastLED/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
|
@ -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
|
138
.pio/libdeps/local/FastLED/platforms/arm/sam/fastpin_arm_sam.h
Normal file
138
.pio/libdeps/local/FastLED/platforms/arm/sam/fastpin_arm_sam.h
Normal file
@ -0,0 +1,138 @@
|
||||
#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 _FL_IO(L,C) _RD32(REG_PIO ## L ## _ODSR); _RD32(REG_PIO ## L ## _SODR); _RD32(REG_PIO ## L ## _CODR); _RD32(REG_PIO ## L ## _OER); _FL_DEFINE_PORT3(L, C, _R(REG_PIO ## L ## _ODSR));
|
||||
|
||||
#define _FL_DEFPIN(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)> {};
|
||||
|
||||
_FL_IO(A,0);
|
||||
_FL_IO(B,1);
|
||||
_FL_IO(C,2);
|
||||
_FL_IO(D,3);
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
|
||||
|
||||
#define MAX_PIN 78
|
||||
_FL_DEFPIN(0, 8, A); _FL_DEFPIN(1, 9, A); _FL_DEFPIN(2, 25, B); _FL_DEFPIN(3, 28, C);
|
||||
_FL_DEFPIN(4, 26, C); _FL_DEFPIN(5, 25, C); _FL_DEFPIN(6, 24, C); _FL_DEFPIN(7, 23, C);
|
||||
_FL_DEFPIN(8, 22, C); _FL_DEFPIN(9, 21, C); _FL_DEFPIN(10, 29, C); _FL_DEFPIN(11, 7, D);
|
||||
_FL_DEFPIN(12, 8, D); _FL_DEFPIN(13, 27, B); _FL_DEFPIN(14, 4, D); _FL_DEFPIN(15, 5, D);
|
||||
_FL_DEFPIN(16, 13, A); _FL_DEFPIN(17, 12, A); _FL_DEFPIN(18, 11, A); _FL_DEFPIN(19, 10, A);
|
||||
_FL_DEFPIN(20, 12, B); _FL_DEFPIN(21, 13, B); _FL_DEFPIN(22, 26, B); _FL_DEFPIN(23, 14, A);
|
||||
_FL_DEFPIN(24, 15, A); _FL_DEFPIN(25, 0, D); _FL_DEFPIN(26, 1, D); _FL_DEFPIN(27, 2, D);
|
||||
_FL_DEFPIN(28, 3, D); _FL_DEFPIN(29, 6, D); _FL_DEFPIN(30, 9, D); _FL_DEFPIN(31, 7, A);
|
||||
_FL_DEFPIN(32, 10, D); _FL_DEFPIN(33, 1, C); _FL_DEFPIN(34, 2, C); _FL_DEFPIN(35, 3, C);
|
||||
_FL_DEFPIN(36, 4, C); _FL_DEFPIN(37, 5, C); _FL_DEFPIN(38, 6, C); _FL_DEFPIN(39, 7, C);
|
||||
_FL_DEFPIN(40, 8, C); _FL_DEFPIN(41, 9, C); _FL_DEFPIN(42, 19, A); _FL_DEFPIN(43, 20, A);
|
||||
_FL_DEFPIN(44, 19, C); _FL_DEFPIN(45, 18, C); _FL_DEFPIN(46, 17, C); _FL_DEFPIN(47, 16, C);
|
||||
_FL_DEFPIN(48, 15, C); _FL_DEFPIN(49, 14, C); _FL_DEFPIN(50, 13, C); _FL_DEFPIN(51, 12, C);
|
||||
_FL_DEFPIN(52, 21, B); _FL_DEFPIN(53, 14, B); _FL_DEFPIN(54, 16, A); _FL_DEFPIN(55, 24, A);
|
||||
_FL_DEFPIN(56, 23, A); _FL_DEFPIN(57, 22, A); _FL_DEFPIN(58, 6, A); _FL_DEFPIN(59, 4, A);
|
||||
_FL_DEFPIN(60, 3, A); _FL_DEFPIN(61, 2, A); _FL_DEFPIN(62, 17, B); _FL_DEFPIN(63, 18, B);
|
||||
_FL_DEFPIN(64, 19, B); _FL_DEFPIN(65, 20, B); _FL_DEFPIN(66, 15, B); _FL_DEFPIN(67, 16, B);
|
||||
_FL_DEFPIN(68, 1, A); _FL_DEFPIN(69, 0, A); _FL_DEFPIN(70, 17, A); _FL_DEFPIN(71, 18, A);
|
||||
_FL_DEFPIN(72, 30, C); _FL_DEFPIN(73, 21, A); _FL_DEFPIN(74, 25, A); _FL_DEFPIN(75, 26, A);
|
||||
_FL_DEFPIN(76, 27, A); _FL_DEFPIN(77, 28, A); _FL_DEFPIN(78, 23, B);
|
||||
|
||||
// digix pins
|
||||
_FL_DEFPIN(90, 0, B); _FL_DEFPIN(91, 1, B); _FL_DEFPIN(92, 2, B); _FL_DEFPIN(93, 3, B);
|
||||
_FL_DEFPIN(94, 4, B); _FL_DEFPIN(95, 5, B); _FL_DEFPIN(96, 6, B); _FL_DEFPIN(97, 7, B);
|
||||
_FL_DEFPIN(98, 8, B); _FL_DEFPIN(99, 9, B); _FL_DEFPIN(100, 5, A); _FL_DEFPIN(101, 22, B);
|
||||
_FL_DEFPIN(102, 23, B); _FL_DEFPIN(103, 24, B); _FL_DEFPIN(104, 27, C); _FL_DEFPIN(105, 20, C);
|
||||
_FL_DEFPIN(106, 11, C); _FL_DEFPIN(107, 10, C); _FL_DEFPIN(108, 21, A); _FL_DEFPIN(109, 30, C);
|
||||
_FL_DEFPIN(110, 29, B); _FL_DEFPIN(111, 30, B); _FL_DEFPIN(112, 31, B); _FL_DEFPIN(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
.pio/libdeps/local/FastLED/platforms/arm/sam/fastspi_arm_sam.h
Normal file
163
.pio/libdeps/local/FastLED/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, uint32_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
|
Reference in New Issue
Block a user