Skip to content

Commit

Permalink
Teensy 4 support! (#864)
Browse files Browse the repository at this point in the history
* Pre-teensy4 work - with a 600Mhz clock, a 1Mhz clock was giving us a clock divider that overflowed a uint8_t - whoops...

* Some tweaks to chipset definitions to help out the Teensy 4 implementation

* Updating the pintest program w/Teensy 4 defs

* Preliminary Teensy 4 support, including hardware SPI and clockless chipsets - no support for parallel output or DMA'd output yet - also not fully tested for all chipsets on all pins, but smoke tested with some chipsets and pin combinations and logic analyzer in the meantime

* Checking in initial block clockless output - it compiles, but no testing yet, so it shouldn't be hooked up anywhere yet.

* Tweak and fix parallel output - still need  to hook it up to the default addLeds setup

* more kicking
  • Loading branch information
focalintent committed Aug 13, 2019
1 parent e68b185 commit 032ae7c
Show file tree
Hide file tree
Showing 22 changed files with 746 additions and 59 deletions.
31 changes: 21 additions & 10 deletions chipsets.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class PixieController : public CPixelLEDController<RGB_ORDER> {
/// @tparam CLOCK_PIN the clock pin for these leds /// @tparam CLOCK_PIN the clock pin for these leds
/// @tparam RGB_ORDER the RGB ordering for these leds /// @tparam RGB_ORDER the RGB ordering for these leds
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12) /// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12)
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(12) > template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(12) >
class LPD8806Controller : public CPixelLEDController<RGB_ORDER> { class LPD8806Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI; typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;


Expand Down Expand Up @@ -118,7 +118,7 @@ class LPD8806Controller : public CPixelLEDController<RGB_ORDER> {
/// @tparam CLOCK_PIN the clock pin for these leds /// @tparam CLOCK_PIN the clock pin for these leds
/// @tparam RGB_ORDER the RGB ordering for these leds /// @tparam RGB_ORDER the RGB ordering for these leds
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(1) /// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(1)
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(1)> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(1)>
class WS2801Controller : public CPixelLEDController<RGB_ORDER> { class WS2801Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI; typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI; SPI mSPI;
Expand All @@ -140,7 +140,7 @@ class WS2801Controller : public CPixelLEDController<RGB_ORDER> {
} }
}; };


template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(25)> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(25)>
class WS2803Controller : public WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_SPEED> {}; class WS2803Controller : public WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER, SPI_SPEED> {};


/// LPD6803 controller class (LPD1101). /// LPD6803 controller class (LPD1101).
Expand All @@ -151,7 +151,7 @@ class WS2803Controller : public WS2801Controller<DATA_PIN, CLOCK_PIN, RGB_ORDER,
/// @tparam CLOCK_PIN the clock pin for these leds /// @tparam CLOCK_PIN the clock pin for these leds
/// @tparam RGB_ORDER the RGB ordering for these leds /// @tparam RGB_ORDER the RGB ordering for these leds
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12) /// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12)
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(12)> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(12)>
class LPD6803Controller : public CPixelLEDController<RGB_ORDER> { class LPD6803Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI; typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI; SPI mSPI;
Expand Down Expand Up @@ -201,7 +201,7 @@ class LPD6803Controller : public CPixelLEDController<RGB_ORDER> {
/// @tparam CLOCK_PIN the clock pin for these leds /// @tparam CLOCK_PIN the clock pin for these leds
/// @tparam RGB_ORDER the RGB ordering for these leds /// @tparam RGB_ORDER the RGB ordering for these leds
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12) /// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(12)
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(12)> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(12)>
class APA102Controller : public CPixelLEDController<RGB_ORDER> { class APA102Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI; typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI; SPI mSPI;
Expand Down Expand Up @@ -266,7 +266,7 @@ class APA102Controller : public CPixelLEDController<RGB_ORDER> {
/// @tparam CLOCK_PIN the clock pin for these leds /// @tparam CLOCK_PIN the clock pin for these leds
/// @tparam RGB_ORDER the RGB ordering for these leds /// @tparam RGB_ORDER the RGB ordering for these leds
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(24) /// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(24)
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(24)> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(24)>
class SK9822Controller : public CPixelLEDController<RGB_ORDER> { class SK9822Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI; typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI; SPI mSPI;
Expand Down Expand Up @@ -340,7 +340,7 @@ class SK9822Controller : public CPixelLEDController<RGB_ORDER> {
/// @tparam CLOCK_PIN the clock pin for these leds /// @tparam CLOCK_PIN the clock pin for these leds
/// @tparam RGB_ORDER the RGB ordering for these leds /// @tparam RGB_ORDER the RGB ordering for these leds
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(10) /// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(10)
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(10)> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(10)>
class P9813Controller : public CPixelLEDController<RGB_ORDER> { class P9813Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI; typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI; SPI mSPI;
Expand Down Expand Up @@ -390,18 +390,23 @@ class P9813Controller : public CPixelLEDController<RGB_ORDER> {
/// @tparam CLOCK_PIN the clock pin for these leds /// @tparam CLOCK_PIN the clock pin for these leds
/// @tparam RGB_ORDER the RGB ordering for these leds /// @tparam RGB_ORDER the RGB ordering for these leds
/// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(16) /// @tparam SPI_SPEED the clock divider used for these leds. Set using the DATA_RATE_MHZ/DATA_RATE_KHZ macros. Defaults to DATA_RATE_MHZ(16)
template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint8_t SPI_SPEED = DATA_RATE_MHZ(16)> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, EOrder RGB_ORDER = RGB, uint32_t SPI_SPEED = DATA_RATE_MHZ(16)>
class SM16716Controller : public CPixelLEDController<RGB_ORDER> { class SM16716Controller : public CPixelLEDController<RGB_ORDER> {
typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI; typedef SPIOutput<DATA_PIN, CLOCK_PIN, SPI_SPEED> SPI;
SPI mSPI; SPI mSPI;


void writeHeader() { void writeHeader() {
// Write out 50 zeros to the spi line (6 blocks of 8 followed by two single bit writes) // Write out 50 zeros to the spi line (6 blocks of 8 followed by two single bit writes)
mSPI.select(); mSPI.select();
mSPI.writeBytesValueRaw(0, 6);
mSPI.waitFully();
mSPI.template writeBit<0>(0); mSPI.template writeBit<0>(0);
mSPI.writeByte(0);
mSPI.writeByte(0);
mSPI.writeByte(0);
mSPI.template writeBit<0>(0); mSPI.template writeBit<0>(0);
mSPI.writeByte(0);
mSPI.writeByte(0);
mSPI.writeByte(0);
mSPI.waitFully();
mSPI.release(); mSPI.release();
} }


Expand Down Expand Up @@ -524,7 +529,13 @@ class PL9823Controller : public ClocklessController<DATA_PIN, 3 * FMUL, 8 * FMUL


// Similar to NS() macro, this calculates the number of cycles for // Similar to NS() macro, this calculates the number of cycles for
// the clockless chipset (which may differ from CPU cycles) // the clockless chipset (which may differ from CPU cycles)

#ifdef FASTLED_TEENSY4
// just use raw nanosecond values for the teensy4
#define C_NS(_NS) _NS
#else
#define C_NS(_NS) (((_NS * ((CLOCKLESS_FREQUENCY / 1000000L)) + 999)) / 1000) #define C_NS(_NS) (((_NS * ((CLOCKLESS_FREQUENCY / 1000000L)) + 999)) / 1000)
#endif


// GE8822 - 350ns 660ns 350ns // GE8822 - 350ns 660ns 350ns
template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB> template <uint8_t DATA_PIN, EOrder RGB_ORDER = RGB>
Expand Down
49 changes: 37 additions & 12 deletions examples/Pintest/Pintest.ino
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,10 @@


#include <FastSPI_LED.h> #include <FastLED.h>

char fullstrBuffer[64];


const char *getPort(void *portPtr) { const char *getPort(void *portPtr) {
// AVR port checks
#ifdef PORTA #ifdef PORTA
if(portPtr == (void*)&PORTA) { return "PORTA"; } if(portPtr == (void*)&PORTA) { return "PORTA"; }
#endif #endif
Expand Down Expand Up @@ -38,6 +41,8 @@ const char *getPort(void *portPtr) {
#ifdef PORTL #ifdef PORTL
if(portPtr == (void*)&PORTL) { return "PORTL"; } if(portPtr == (void*)&PORTL) { return "PORTL"; }
#endif #endif

// Teensy 3.x port checks
#ifdef GPIO_A_PDOR #ifdef GPIO_A_PDOR
if(portPtr == (void*)&GPIO_A_PDOR) { return "GPIO_A_PDOR"; } if(portPtr == (void*)&GPIO_A_PDOR) { return "GPIO_A_PDOR"; }
#endif #endif
Expand Down Expand Up @@ -65,7 +70,24 @@ const char *getPort(void *portPtr) {
#ifdef REG_PIO_D_ODSR #ifdef REG_PIO_D_ODSR
if(portPtr == (void*)&REG_PIO_D_ODSR) { return "REG_PIO_D_ODSR"; } if(portPtr == (void*)&REG_PIO_D_ODSR) { return "REG_PIO_D_ODSR"; }
#endif #endif
return "unknown";
// Teensy 4 port checks
#ifdef GPIO1_DR
if(portPtr == (void*)&GPIO1_DR) { return "GPIO1_DR"; }
#endif
#ifdef GPIO2_DR
if(portPtr == (void*)&GPIO2_DR) { return "GPIO21_DR"; }
#endif
#ifdef GPIO3_DR
if(portPtr == (void*)&GPIO3_DR) { return "GPIO3_DR"; }
#endif
#ifdef GPIO4_DR
if(portPtr == (void*)&GPIO4_DR) { return "GPIO4_DR"; }
#endif
String unknown_str = "Unknown: " + String((size_t)portPtr, HEX);
strncpy(fullstrBuffer, unknown_str.c_str(), unknown_str.length());
fullstrBuffer[sizeof(fullstrBuffer)-1] = '\0';
return fullstrBuffer;
} }


template<uint8_t PIN> void CheckPin() template<uint8_t PIN> void CheckPin()
Expand All @@ -74,32 +96,35 @@ template<uint8_t PIN> void CheckPin()


RwReg *systemThinksPortIs = portOutputRegister(digitalPinToPort(PIN)); RwReg *systemThinksPortIs = portOutputRegister(digitalPinToPort(PIN));
RwReg systemThinksMaskIs = digitalPinToBitMask(PIN); RwReg systemThinksMaskIs = digitalPinToBitMask(PIN);

Serial.print("Pin "); Serial.print(PIN); Serial.print(": Port "); Serial.print("Pin "); Serial.print(PIN); Serial.print(": Port ");

if(systemThinksPortIs == FastPin<PIN>::port()) { if(systemThinksPortIs == FastPin<PIN>::port()) {
Serial.print("valid & mask "); Serial.print("valid & mask ");
} else { } else {
Serial.print("invalid, is "); Serial.print(getPort((void*)FastPin<PIN>::port())); Serial.print(" should be "); Serial.print("invalid, is "); Serial.print(getPort((void*)FastPin<PIN>::port())); Serial.print(" should be ");
Serial.print(getPort((void*)systemThinksPortIs)); Serial.print(getPort((void*)systemThinksPortIs));
Serial.print(" & mask "); Serial.print(" & mask ");
} }


if(systemThinksMaskIs == FastPin<PIN>::mask()) { if(systemThinksMaskIs == FastPin<PIN>::mask()) {
Serial.println("valid."); Serial.println("valid.");
} else { } else {
Serial.print("invalid, is "); Serial.print(FastPin<PIN>::mask()); Serial.print(" should be "); Serial.println(systemThinksMaskIs); Serial.print("invalid, is "); Serial.print(FastPin<PIN>::mask()); Serial.print(" should be "); Serial.println(systemThinksMaskIs);
} }
} }


template<> void CheckPin<-1> () {} template<> void CheckPin<-1> () {}


void setup() { void setup() {
delay(5000);
Serial.begin(38400); Serial.begin(38400);
Serial.println("resetting!"); Serial.println("resetting!");
} }


void loop() { void loop() {
CheckPin<MAX_PIN>(); CheckPin<MAX_PIN>();
delay(10000); delay(100000);

Serial.print("GPIO_1_DR is: "); Serial.print(getPort((void*)&(GPIO1_DR)));
} }
45 changes: 30 additions & 15 deletions fastspi.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ FASTLED_NAMESPACE_BEGIN
#if defined(FASTLED_TEENSY3) && (F_CPU > 48000000) #if defined(FASTLED_TEENSY3) && (F_CPU > 48000000)
#define DATA_RATE_MHZ(X) (((48000000L / 1000000L) / X)) #define DATA_RATE_MHZ(X) (((48000000L / 1000000L) / X))
#define DATA_RATE_KHZ(X) (((48000000L / 1000L) / X)) #define DATA_RATE_KHZ(X) (((48000000L / 1000L) / X))
#elif defined(FASTLED_TEENSY4) // && (ARM_HARDWARE_SPI)
// just use clocks
#define DATA_RATE_MHZ(X) (1000000 * (X))
#define DATA_RATE_KHZ(X) (1000 * (X))
#else #else
#define DATA_RATE_MHZ(X) ((F_CPU / 1000000L) / X) #define DATA_RATE_MHZ(X) ((F_CPU / 1000000L) / X)
#define DATA_RATE_KHZ(X) ((F_CPU / 1000L) / X) #define DATA_RATE_KHZ(X) ((F_CPU / 1000L) / X)
Expand All @@ -26,49 +30,60 @@ FASTLED_NAMESPACE_BEGIN
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


#if !defined(FASTLED_ALL_PINS_HARDWARE_SPI) #if !defined(FASTLED_ALL_PINS_HARDWARE_SPI)
template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class SPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; class SPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {};
#endif #endif


template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class SoftwareSPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; class SoftwareSPIOutput : public AVRSoftwareSPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {};


#ifndef FASTLED_FORCE_SOFTWARE_SPI #ifndef FASTLED_FORCE_SOFTWARE_SPI


#if defined(NRF51) && defined(FASTLED_ALL_PINS_HARDWARE_SPI) #if defined(NRF51) && defined(FASTLED_ALL_PINS_HARDWARE_SPI)
template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class SPIOutput : public NRF51SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; class SPIOutput : public NRF51SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {};
#endif #endif


#if defined(NRF52_SERIES) && defined(FASTLED_ALL_PINS_HARDWARE_SPI) #if defined(NRF52_SERIES) && defined(FASTLED_ALL_PINS_HARDWARE_SPI)
template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> template<uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class SPIOutput : public NRF52SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {}; class SPIOutput : public NRF52SPIOutput<_DATA_PIN, _CLOCK_PIN, _SPI_CLOCK_DIVIDER> {};
#endif #endif


#if defined(SPI_DATA) && defined(SPI_CLOCK) #if defined(SPI_DATA) && defined(SPI_CLOCK)


#if defined(FASTLED_TEENSY3) && defined(ARM_HARDWARE_SPI) #if defined(FASTLED_TEENSY3) && defined(ARM_HARDWARE_SPI)


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED, 0x4002C000> {}; class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED, 0x4002C000> {};


#if defined(SPI2_DATA) #if defined(SPI2_DATA)


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED, 0x4002C000> {}; class SPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED, 0x4002C000> {};


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI_DATA, SPI2_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI_DATA, SPI2_CLOCK, SPI_SPEED, 0x4002C000> {}; class SPIOutput<SPI_DATA, SPI2_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI_DATA, SPI2_CLOCK, SPI_SPEED, 0x4002C000> {};


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED, 0x4002C000> {}; class SPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED, 0x4002C000> {};
#endif #endif


#elif defined(FASTLED_TEENSY4) && defined(ARM_HARDWARE_SPI)

template<uint32_t SPI_SPEED>
class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public Teesy4HardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED, SPI, 0> {};

template<uint32_t SPI_SPEED>
class SPIOutput<SPI1_DATA, SPI_CLOCK, SPI_SPEED> : public Teesy4HardwareSPIOutput<SPI1_DATA, SPI1_CLOCK, SPI_SPEED, SPI1, 1> {};

template<uint32_t SPI_SPEED>
class SPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED> : public Teesy4HardwareSPIOutput<SPI2_DATA, SPI2_CLOCK, SPI_SPEED, SPI2, 2> {};

#elif defined(FASTLED_TEENSYLC) && defined(ARM_HARDWARE_SPI) #elif defined(FASTLED_TEENSYLC) && defined(ARM_HARDWARE_SPI)


#define DECLARE_SPI0(__DATA,__CLOCK) template<uint8_t SPI_SPEED>\ #define DECLARE_SPI0(__DATA,__CLOCK) template<uint32_t SPI_SPEED>\
class SPIOutput<__DATA, __CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<__DATA, __CLOCK, SPI_SPEED, 0x40076000> {}; class SPIOutput<__DATA, __CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<__DATA, __CLOCK, SPI_SPEED, 0x40076000> {};
#define DECLARE_SPI1(__DATA,__CLOCK) template<uint8_t SPI_SPEED>\ #define DECLARE_SPI1(__DATA,__CLOCK) template<uint32_t SPI_SPEED>\
class SPIOutput<__DATA, __CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<__DATA, __CLOCK, SPI_SPEED, 0x40077000> {}; class SPIOutput<__DATA, __CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<__DATA, __CLOCK, SPI_SPEED, 0x40077000> {};


DECLARE_SPI0(7,13); DECLARE_SPI0(7,13);
Expand All @@ -85,24 +100,24 @@ DECLARE_SPI1(21,20);


#elif defined(__SAM3X8E__) #elif defined(__SAM3X8E__)


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public SAMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {}; class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public SAMHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {};


#elif defined(AVR_HARDWARE_SPI) #elif defined(AVR_HARDWARE_SPI)


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public AVRHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {}; class SPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> : public AVRHardwareSPIOutput<SPI_DATA, SPI_CLOCK, SPI_SPEED> {};


#if defined(SPI_UART0_DATA) #if defined(SPI_UART0_DATA)


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> : public AVRUSART0SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> {}; class SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> : public AVRUSART0SPIOutput<SPI_UART0_DATA, SPI_UART0_CLOCK, SPI_SPEED> {};


#endif #endif


#if defined(SPI_UART1_DATA) #if defined(SPI_UART1_DATA)


template<uint8_t SPI_SPEED> template<uint32_t SPI_SPEED>
class SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> : public AVRUSART1SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> {}; class SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> : public AVRUSART1SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> {};


#endif #endif
Expand All @@ -120,7 +135,7 @@ class SPIOutput<SPI_UART1_DATA, SPI_UART1_CLOCK, SPI_SPEED> : public AVRUSART1SP
#endif #endif


// #if defined(USART_DATA) && defined(USART_CLOCK) // #if defined(USART_DATA) && defined(USART_CLOCK)
// template<uint8_t SPI_SPEED> // template<uint32_t SPI_SPEED>
// class AVRSPIOutput<USART_DATA, USART_CLOCK, SPI_SPEED> : public AVRUSARTSPIOutput<USART_DATA, USART_CLOCK, SPI_SPEED> {}; // class AVRSPIOutput<USART_DATA, USART_CLOCK, SPI_SPEED> : public AVRUSARTSPIOutput<USART_DATA, USART_CLOCK, SPI_SPEED> {};
// #endif // #endif


Expand Down
18 changes: 12 additions & 6 deletions fastspi_bitbang.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ FASTLED_NAMESPACE_BEGIN
// //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, uint8_t SPI_SPEED> template <uint8_t DATA_PIN, uint8_t CLOCK_PIN, uint32_t SPI_SPEED>
class AVRSoftwareSPIOutput { class AVRSoftwareSPIOutput {
// The data types for pointers to the pin port - typedef'd here from the Pin definition because on avr these // The data types for pointers to the pin port - typedef'd here from the Pin definition because on avr these
// are pointers to 8 bit values, while on arm they are 32 bit // are pointers to 8 bit values, while on arm they are 32 bit
Expand Down Expand Up @@ -113,10 +113,16 @@ class AVRSoftwareSPIOutput {
public: public:


// We want to make sure that the clock pulse is held high for a nininum of 35ns. // We want to make sure that the clock pulse is held high for a nininum of 35ns.
#if defined(FASTLED_TEENSY4)
#define DELAY_NS (1000 / (SPI_SPEED/1000000))
#define CLOCK_HI_DELAY do { delayNanoseconds((DELAY_NS/4)); } while(0);
#define CLOCK_LO_DELAY do { delayNanoseconds((DELAY_NS/4)); } while(0);
#else
#define MIN_DELAY (NS(35) - 3) #define MIN_DELAY (NS(35) - 3)


#define CLOCK_HI_DELAY delaycycles<MIN_DELAY>(); delaycycles<(((SPI_SPEED-6) / 2) - MIN_DELAY)>(); #define CLOCK_HI_DELAY do { delaycycles<MIN_DELAY>(); delaycycles<(((SPI_SPEED-6) / 2) - MIN_DELAY)>(); } while(0);
#define CLOCK_LO_DELAY delaycycles<(((SPI_SPEED-6) / 4))>(); #define CLOCK_LO_DELAY do { delaycycles<(((SPI_SPEED-6) / 4))>(); } while(0);
#endif


// write the BIT'th bit out via spi, setting the data pin then strobing the clcok // write the BIT'th bit out via spi, setting the data pin then strobing the clcok
template <uint8_t BIT> __attribute__((always_inline, hot)) inline static void writeBit(uint8_t b) { template <uint8_t BIT> __attribute__((always_inline, hot)) inline static void writeBit(uint8_t b) {
Expand All @@ -126,8 +132,8 @@ class AVRSoftwareSPIOutput {
#ifdef ESP32 #ifdef ESP32
// try to ensure we never have adjacent write opcodes to the same register // try to ensure we never have adjacent write opcodes to the same register
FastPin<CLOCK_PIN>::lo(); FastPin<CLOCK_PIN>::lo();
FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY; FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
FastPin<CLOCK_PIN>::toggle(); CLOCK_LO_DELAY; FastPin<CLOCK_PIN>::toggle(); CLOCK_LO_DELAY;
#else #else
FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY; FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY; FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY;
Expand All @@ -137,7 +143,7 @@ class AVRSoftwareSPIOutput {
FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY; FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY;
#ifdef ESP32 #ifdef ESP32
// try to ensure we never have adjacent write opcodes to the same register // try to ensure we never have adjacent write opcodes to the same register
FastPin<CLOCK_PIN>::toggle(); CLOCK_HI_DELAY; FastPin<CLOCK_PIN>::toggle(); CLOCK_HI_DELAY;
#else #else
FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY; FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY;
#endif #endif
Expand Down
2 changes: 1 addition & 1 deletion fastspi_nop.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ FASTLED_NAMESPACE_BEGIN
/// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations. Should /// 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 /// 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) /// 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> template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class NOPSPIOutput { class NOPSPIOutput {
Selectable *m_pSelect; Selectable *m_pSelect;


Expand Down
2 changes: 1 addition & 1 deletion fastspi_ref.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ FASTLED_NAMESPACE_BEGIN


// A skeletal implementation of hardware SPI support. Fill in the necessary code for init, waiting, and writing. The rest of // A skeletal implementation of hardware SPI support. Fill in the necessary code for init, waiting, and writing. The rest of
// the method implementations should provide a starting point, even if not hte most efficient to start with // the method implementations should provide a starting point, even if not hte most efficient to start with
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER> template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_DIVIDER>
class REFHardwareSPIOutput { class REFHardwareSPIOutput {
Selectable *m_pSelect; Selectable *m_pSelect;
public: public:
Expand Down
3 changes: 3 additions & 0 deletions led_sysdefs.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
#elif defined(__MKL26Z64__) #elif defined(__MKL26Z64__)
// Include kl26/T-LC headers // Include kl26/T-LC headers
#include "platforms/arm/kl26/led_sysdefs_arm_kl26.h" #include "platforms/arm/kl26/led_sysdefs_arm_kl26.h"
#elif defined(__IMXRT1062__)
// teensy4
#include "platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h"
#elif defined(__SAM3X8E__) #elif defined(__SAM3X8E__)
// Include sam/due headers // Include sam/due headers
#include "platforms/arm/sam/led_sysdefs_arm_sam.h" #include "platforms/arm/sam/led_sysdefs_arm_sam.h"
Expand Down
Loading

0 comments on commit 032ae7c

Please sign in to comment.