diff options
author | Daniel Garcia <dgarcia@dgarcia.net> | 2019-08-12 06:53:44 +0300 |
---|---|---|
committer | Daniel Garcia <dgarcia@dgarcia.net> | 2019-08-12 06:53:44 +0300 |
commit | 3f2f9121d591751ecb20b8725dbdcf79d2bd833b (patch) | |
tree | 4fa1f471b03868b6f0c90bd3017dca728672f64d | |
parent | 0b337fb865a26dfa350b5220b0c54a3819edd82a (diff) |
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
-rw-r--r-- | fastspi.h | 15 | ||||
-rw-r--r-- | fastspi_bitbang.h | 16 | ||||
-rw-r--r-- | led_sysdefs.h | 3 | ||||
-rw-r--r-- | platforms.h | 3 | ||||
-rw-r--r-- | platforms/arm/mxrt1062/clockless_arm_mxrt1062.h | 115 | ||||
-rw-r--r-- | platforms/arm/mxrt1062/fastled_arm_mxrt1062.h | 7 | ||||
-rw-r--r-- | platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h | 90 | ||||
-rw-r--r-- | platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h | 140 | ||||
-rw-r--r-- | platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h | 43 | ||||
-rw-r--r-- | release_notes.md | 4 |
10 files changed, 431 insertions, 5 deletions
@@ -13,6 +13,10 @@ FASTLED_NAMESPACE_BEGIN #if defined(FASTLED_TEENSY3) && (F_CPU > 48000000) #define DATA_RATE_MHZ(X) (((48000000L / 1000000L) / 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 #define DATA_RATE_MHZ(X) ((F_CPU / 1000000L) / X) #define DATA_RATE_KHZ(X) ((F_CPU / 1000L) / X) @@ -64,6 +68,17 @@ template<uint32_t SPI_SPEED> class SPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED> : public ARMHardwareSPIOutput<SPI2_DATA, SPI_CLOCK, SPI_SPEED, 0x4002C000> {}; #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) #define DECLARE_SPI0(__DATA,__CLOCK) template<uint32_t SPI_SPEED>\ diff --git a/fastspi_bitbang.h b/fastspi_bitbang.h index 292c8ecd..70795e8b 100644 --- a/fastspi_bitbang.h +++ b/fastspi_bitbang.h @@ -113,10 +113,16 @@ private: public: // 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 CLOCK_HI_DELAY delaycycles<MIN_DELAY>(); delaycycles<(((SPI_SPEED-6) / 2) - MIN_DELAY)>(); - #define CLOCK_LO_DELAY delaycycles<(((SPI_SPEED-6) / 4))>(); + #define CLOCK_HI_DELAY do { delaycycles<MIN_DELAY>(); delaycycles<(((SPI_SPEED-6) / 2) - MIN_DELAY)>(); } while(0); + #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 template <uint8_t BIT> __attribute__((always_inline, hot)) inline static void writeBit(uint8_t b) { @@ -126,8 +132,8 @@ public: #ifdef ESP32 // try to ensure we never have adjacent write opcodes to the same register FastPin<CLOCK_PIN>::lo(); - FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY; - FastPin<CLOCK_PIN>::toggle(); CLOCK_LO_DELAY; + FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY; + FastPin<CLOCK_PIN>::toggle(); CLOCK_LO_DELAY; #else FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY; FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY; @@ -137,7 +143,7 @@ public: FastPin<CLOCK_PIN>::hi(); CLOCK_HI_DELAY; #ifdef ESP32 // 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 FastPin<CLOCK_PIN>::lo(); CLOCK_LO_DELAY; #endif diff --git a/led_sysdefs.h b/led_sysdefs.h index 7abcd15e..27da24a0 100644 --- a/led_sysdefs.h +++ b/led_sysdefs.h @@ -18,6 +18,9 @@ #elif defined(__MKL26Z64__) // Include kl26/T-LC headers #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__) // Include sam/due headers #include "platforms/arm/sam/led_sysdefs_arm_sam.h" diff --git a/platforms.h b/platforms.h index 82d7d993..f66599fd 100644 --- a/platforms.h +++ b/platforms.h @@ -18,6 +18,9 @@ #elif defined(__MKL26Z64__) // Include kl26/T-LC headers #include "platforms/arm/kl26/fastled_arm_kl26.h" +#elif defined(__IMXRT1062__) +// teensy4 +#include "platforms/arm/mxrt1062/fastled_arm_mxrt1062.h" #elif defined(__SAM3X8E__) // Include sam/due headers #include "platforms/arm/sam/fastled_arm_sam.h" diff --git a/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h b/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h new file mode 100644 index 00000000..ce0d972e --- /dev/null +++ b/platforms/arm/mxrt1062/clockless_arm_mxrt1062.h @@ -0,0 +1,115 @@ +#ifndef __INC_CLOCKLESS_ARM_MXRT1062_H +#define __INC_CLOCKLESS_ARM_MXRT1062_H + +FASTLED_NAMESPACE_BEGIN + +// Definition for a single channel clockless controller for the teensy4 +// See clockless.h for detailed info on how the template parameters are used. +#if defined(FASTLED_TEENSY4) + +#define FASTLED_HAS_CLOCKLESS 1 + +#define _FASTLED_NS_TO_DWT(_NS) (((F_CPU_ACTUAL>>16)*(_NS)) / (1000000000UL>>16)) + +template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50> +class ClocklessController : public CPixelLEDController<RGB_ORDER> { + typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t; + typedef typename FastPin<DATA_PIN>::port_t data_t; + + data_t mPinMask; + data_ptr_t mPort; + CMinWait<WAIT_TIME> mWait; +public: + virtual void init() { + FastPin<DATA_PIN>::setOutput(); + mPinMask = FastPin<DATA_PIN>::mask(); + mPort = FastPin<DATA_PIN>::port(); + FastPin<DATA_PIN>::lo(); + } + +protected: + + virtual void showPixels(PixelController<RGB_ORDER> & pixels) { + mWait.wait(); + if(!showRGBInternal(pixels)) { + sei(); delayMicroseconds(WAIT_TIME); cli(); + showRGBInternal(pixels); + } + mWait.mark(); + } + + template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register uint32_t off1, register uint32_t off2, register uint32_t off3, register uint32_t & b) { + for(register uint32_t i = BITS-1; i > 0; i--) { + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + off1; + FastPin<DATA_PIN>::hi(); + if(b&0x80) { + while((next_mark - ARM_DWT_CYCCNT) > off2); + FastPin<DATA_PIN>::lo(); + } else { + while((next_mark - ARM_DWT_CYCCNT) > off3); + FastPin<DATA_PIN>::lo(); + } + b <<= 1; + } + + while(ARM_DWT_CYCCNT < next_mark); + next_mark = ARM_DWT_CYCCNT + off1; + FastPin<DATA_PIN>::hi(); + + if(b&0x80) { + while((next_mark - ARM_DWT_CYCCNT) > off2); + FastPin<DATA_PIN>::lo(); + } else { + while((next_mark - ARM_DWT_CYCCNT) > off3); + FastPin<DATA_PIN>::lo(); + } + } + + uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) { + // Setup the pixel controller and load/scale the first byte + pixels.preStepFirstByteDithering(); + register uint32_t b = pixels.loadAndScale0(); + + cli(); + uint32_t off1 = _FASTLED_NS_TO_DWT(T1+T2+T3); + uint32_t off2 = _FASTLED_NS_TO_DWT(T3); + uint32_t off3 = _FASTLED_NS_TO_DWT(T2+T3); + uint32_t wait_off = _FASTLED_NS_TO_DWT((WAIT_TIME-INTERRUPT_THRESHOLD)); + + uint32_t next_mark = ARM_DWT_CYCCNT + off1; + + while(pixels.has(1)) { + pixels.stepDithering(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) + cli(); + // if interrupts took longer than 45µs, punt on the current frame + if(ARM_DWT_CYCCNT > next_mark) { + if((ARM_DWT_CYCCNT-next_mark) > wait_off) { sei(); return 0; } + } + #endif + // Write first byte, read next byte + writeBits<8+XTRA0>(next_mark, off1, off2, off3, b); + b = pixels.loadAndScale1(); + + // Write second byte, read 3rd byte + writeBits<8+XTRA0>(next_mark, off1, off2, off3, b); + b = pixels.loadAndScale2(); + + // Write third byte, read 1st byte of next pixel + writeBits<8+XTRA0>(next_mark, off1, off2, off3, b); + b = pixels.advanceAndLoadAndScale0(); + #if (FASTLED_ALLOW_INTERRUPTS == 1) + sei(); + #endif + }; + + sei(); + return ARM_DWT_CYCCNT; + } +}; +#endif + +FASTLED_NAMESPACE_END + +#endif diff --git a/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h b/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h new file mode 100644 index 00000000..313ab0d3 --- /dev/null +++ b/platforms/arm/mxrt1062/fastled_arm_mxrt1062.h @@ -0,0 +1,7 @@ +#ifndef __INC_FASTLED_ARM_MXRT1062_H +#define __INC_FASTLED_ARM_MXRT1062_H + +#include "fastpin_arm_mxrt1062.h" +#include "fastspi_arm_mxrt1062.h" +#include "clockless_arm_mxrt1062.h" +#endif diff --git a/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h b/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h new file mode 100644 index 00000000..bfb1cb47 --- /dev/null +++ b/platforms/arm/mxrt1062/fastpin_arm_mxrt1062.h @@ -0,0 +1,90 @@ +#ifndef __FASTPIN_ARM_MXRT1062_H +#define __FASTPIN_ARM_MXRT1062_H + +FASTLED_NAMESPACE_BEGIN + +#if defined(FASTLED_FORCE_SOFTWARE_PINS) +#warning "Software pin support forced, pin access will be slightly slower." +#define NO_HARDWARE_PIN_SUPPORT +#undef HAS_HARDWARE_PIN_SUPPORT + +#else + +/// Template definition for teensy 4.0 style ARM pins, providing direct access to the various GPIO registers. Note that this +/// uses the full port GPIO registers. It calls through to pinMode for setting input/output on pins +/// The registers are data output, set output, clear output, toggle output, input, and direction +template<uint8_t PIN, uint32_t _MASK, typename _GPIO_DR, typename _GPIO_DR_SET, typename _GPIO_DR_CLEAR, typename _GPIO_DR_TOGGLE> class _ARMPIN { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } + inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { _GPIO_DR_SET::r() = _MASK; } + inline static void lo() __attribute__ ((always_inline)) { _GPIO_DR_CLEAR::r() = _MASK; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { _GPIO_DR::r() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { _GPIO_DR_TOGGLE::r() = _MASK; } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } + inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + inline static port_t hival() __attribute__ ((always_inline)) { return _GPIO_DR::r() | _MASK; } + inline static port_t loval() __attribute__ ((always_inline)) { return _GPIO_DR::r() & ~_MASK; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_GPIO_DR::r(); } + inline static port_ptr_t sport() __attribute__ ((always_inline)) { return &_GPIO_DR_SET::r(); } + inline static port_ptr_t cport() __attribute__ ((always_inline)) { return &_GPIO_DR_CLEAR::r(); } + inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } +}; + + +#define _R(T) struct __gen_struct_ ## T +#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } }; +#define _IO32(L) _RD32(GPIO ## L ## _DR); _RD32(GPIO ## L ## _DR_SET); _RD32(GPIO ## L ## _DR_CLEAR); _RD32(GPIO ## L ## _DR_TOGGLE); + +// From the teensy core - it looks like there's the "default set" of port registers at GPIO1-5 - but then there +// are a mirrored set for GPIO1-4 at GPIO6-9, which in the teensy core is referred to as "fast" - while the pin definitiosn +// at https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=193716&viewfull=1#post193716 +// refer to GPIO1-4, we're going to use GPIO6-9 in the definitions below because the fast registers are what +// the teensy core is using internally +#define _DEFPIN_T4(PIN, L, BIT) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << BIT, _R(GPIO ## L ## _DR), _R(GPIO ## L ## _DR_SET), _R(GPIO ## L ## _DR_CLEAR), _R(GPIO ## L ## _DR_TOGGLE)> {}; + +#if defined(FASTLED_TEENSY4) && defined(CORE_TEENSY) +_IO32(1); _IO32(2); _IO32(3); _IO32(4); _IO32(5); +_IO32(6); _IO32(7); _IO32(8); _IO32(9); + +#define MAX_PIN 39 +_DEFPIN_T4( 0,6, 3); _DEFPIN_T4( 1,6, 2); _DEFPIN_T4( 2,9, 4); _DEFPIN_T4( 3,9, 5); +_DEFPIN_T4( 4,9, 6); _DEFPIN_T4( 5,9, 8); _DEFPIN_T4( 6,7,10); _DEFPIN_T4( 7,7,17); +_DEFPIN_T4( 8,7,16); _DEFPIN_T4( 9,7,11); _DEFPIN_T4(10,7, 0); _DEFPIN_T4(11,7, 2); +_DEFPIN_T4(12,7, 1); _DEFPIN_T4(13,7, 3); _DEFPIN_T4(14,6,18); _DEFPIN_T4(15,6,19); +_DEFPIN_T4(16,6,23); _DEFPIN_T4(17,6,22); _DEFPIN_T4(18,6,17); _DEFPIN_T4(19,6,16); +_DEFPIN_T4(20,6,26); _DEFPIN_T4(21,6,27); _DEFPIN_T4(22,6,24); _DEFPIN_T4(23,6,25); +_DEFPIN_T4(24,6,12); _DEFPIN_T4(25,6,13); _DEFPIN_T4(26,6,30); _DEFPIN_T4(27,6,31); +_DEFPIN_T4(28,8,18); _DEFPIN_T4(29,9,31); _DEFPIN_T4(30,8,23); _DEFPIN_T4(31,8,22); +_DEFPIN_T4(32,7,12); _DEFPIN_T4(33,9, 7); _DEFPIN_T4(34,8,15); _DEFPIN_T4(35,8,14); +_DEFPIN_T4(36,8,13); _DEFPIN_T4(37,8,12); _DEFPIN_T4(38,8,17); _DEFPIN_T4(39,8,16); + +#define HAS_HARDWARE_PIN_SUPPORT + +#define ARM_HARDWARE_SPI +#define SPI_DATA 11 +#define SPI_CLOCK 13 + +#define SPI1_DATA 26 +#define SPI1_CLOCK 27 + +#define SPI2_DATA 35 +#define SPI2_CLOCK 37 + +#endif // defined FASTLED_TEENSY4 + +#endif // FASTLED_FORCE_SOFTWARE_PINSs + +FASTLED_NAMESPACE_END + +#endif diff --git a/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h b/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h new file mode 100644 index 00000000..fa6b81ff --- /dev/null +++ b/platforms/arm/mxrt1062/fastspi_arm_mxrt1062.h @@ -0,0 +1,140 @@ +#ifndef __INC_FASTSPI_ARM_MXRT1062_H +#define __INC_FASTSPI_ARM_MXRT1062_H + +FASTLED_NAMESPACE_BEGIN + +#if defined (FASTLED_TEENSY4) && defined(ARM_HARDWARE_SPI) +#include <SPI.h> + +template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint32_t _SPI_CLOCK_RATE, SPIClass & _SPIObject, int _SPI_INDEX> +class Teesy4HardwareSPIOutput { + Selectable *m_pSelect; + uint32_t m_bitCount; + uint32_t m_bitData; + inline IMXRT_LPSPI_t & port() __attribute__((always_inline)) { + switch(_SPI_INDEX) { + case 0: + return IMXRT_LPSPI4_S; + case 1: + return IMXRT_LPSPI3_S; + case 2: + return IMXRT_LPSPI1_S; + } + } + +public: + Teesy4HardwareSPIOutput() { m_pSelect = NULL; m_bitCount = 0;} + Teesy4HardwareSPIOutput(Selectable *pSelect) { m_pSelect = pSelect; m_bitCount = 0;} + + // set the object representing the selectable -- ignore for now + void setSelect(Selectable *pSelect) { /* TODO */ } + + // initialize the SPI subssytem + void init() { _SPIObject.begin(); } + + // latch the CS select + void inline select() __attribute__((always_inline)) { + // begin the SPI transaction + _SPIObject.beginTransaction(SPISettings(_SPI_CLOCK_RATE, MSBFIRST, SPI_MODE0)); + if(m_pSelect != NULL) { m_pSelect->select(); } + } + + // release the CS select + void inline release() __attribute__((always_inline)) { + if(m_pSelect != NULL) { m_pSelect->release(); } + _SPIObject.endTransaction(); + } + + // wait until all queued up data has been written + static void waitFully() { /* TODO */ } + + // write a byte out via SPI (returns immediately on writing register) - + void inline writeByte(uint8_t b) __attribute__((always_inline)) { + if(m_bitCount == 0) { + _SPIObject.transfer(b); + } else { + // There's been a bit of data written, add that to the output as well + uint32_t outData = (m_bitData << 8) | b; + uint32_t tcr = port().TCR; + port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ((8+m_bitCount) - 1); // turn on 9 bit mode + port().TDR = outData; // output 9 bit data. + while ((port().RSR & LPSPI_RSR_RXEMPTY)) ; // wait while the RSR fifo is empty... + port().TCR = (tcr & 0xfffff000) | LPSPI_TCR_FRAMESZ((8) - 1); // turn back on 8 bit mode + port().RDR; + m_bitCount = 0; + } + } + + // write a word out via SPI (returns immediately on writing register) + void inline writeWord(uint16_t w) __attribute__((always_inline)) { + writeByte(((w>>8) & 0xFF)); + _SPIObject.transfer(w & 0xFF); + } + + // A raw set of writing byte values, assumes setup/init/waiting done elsewhere + static void writeBytesValueRaw(uint8_t value, int len) { + while(len--) { _SPIObject.transfer(value); } + } + + // A full cycle of writing a value for len bytes, including select, release, and waiting + void writeBytesValue(uint8_t value, int len) { + select(); writeBytesValueRaw(value, len); release(); + } + + // A full cycle of writing a value for len bytes, including select, release, and waiting + template <class D> void writeBytes(register uint8_t *data, int len) { + uint8_t *end = data + len; + select(); + // could be optimized to write 16bit words out instead of 8bit bytes + while(data != end) { + writeByte(D::adjust(*data++)); + } + D::postBlock(len); + waitFully(); + release(); + } + + // A full cycle of writing a value for len bytes, including select, release, and waiting + void writeBytes(register uint8_t *data, int len) { writeBytes<DATA_NOP>(data, len); } + + // write a single bit out, which bit from the passed in byte is determined by template parameter + template <uint8_t BIT> inline void writeBit(uint8_t b) { + m_bitData = (m_bitData<<1) | ((b&(1<<BIT)) != 0); + // If this is the 8th bit we've collected, just write it out raw + register uint32_t bc = m_bitCount; + bc = (bc + 1) & 0x07; + if (!bc) { + m_bitCount = 0; + _SPIObject.transfer(m_bitData); + } + m_bitCount = bc; + } + + // write a block of uint8_ts out in groups of three. len is the total number of uint8_ts to write out. The template + // parameters indicate how many uint8_ts to skip at the beginning and/or end of each grouping + template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) { + select(); + int len = pixels.mLen; + + while(pixels.has(1)) { + if(FLAGS & FLAG_START_BIT) { + writeBit<0>(1); + } + writeByte(D::adjust(pixels.loadAndScale0())); + writeByte(D::adjust(pixels.loadAndScale1())); + writeByte(D::adjust(pixels.loadAndScale2())); + + pixels.advanceData(); + pixels.stepDithering(); + } + D::postBlock(len); + release(); + } + +}; + + +#endif + +FASTLED_NAMESPACE_END +#endif diff --git a/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h b/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h new file mode 100644 index 00000000..ac490825 --- /dev/null +++ b/platforms/arm/mxrt1062/led_sysdefs_arm_mxrt1062.h @@ -0,0 +1,43 @@ +#ifndef __INC_LED_SYSDEFS_ARM_MXRT1062_H +#define __INC_LED_SYSDEFS_ARM_MXRT1062_H + +#define FASTLED_TEENSY4 +#define FASTLED_ARM + +#ifndef INTERRUPT_THRESHOLD +#define INTERRUPT_THRESHOLD 1 +#endif + +// Default to allowing interrupts +#ifndef FASTLED_ALLOW_INTERRUPTS +#define FASTLED_ALLOW_INTERRUPTS 1 +#endif + +#if FASTLED_ALLOW_INTERRUPTS == 1 +#define FASTLED_ACCURATE_CLOCK +#endif + +#if (F_CPU == 96000000) +#define CLK_DBL 1 +#endif + +// Get some system include files +#include <avr/io.h> +#include <avr/interrupt.h> // for cli/se definitions + +// Define the register types +#if defined(ARDUINO) // && ARDUINO < 150 +typedef volatile uint32_t RoReg; /**< Read only 8-bit register (volatile const unsigned int) */ +typedef volatile uint32_t RwReg; /**< Read-Write 8-bit register (volatile unsigned int) */ +#endif + +// extern volatile uint32_t systick_millis_count; +// # define MS_COUNTER systick_millis_count + +// Teensy4 provides progmem +#ifndef FASTLED_USE_PROGMEM +#define FASTLED_USE_PROGMEM 1 +#endif + + +#endif diff --git a/release_notes.md b/release_notes.md index 81d16f33..925f054a 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,3 +1,7 @@ +FastLED 3.2.11 +============== +* Preliminary Teensy 4 support + FastLED 3.2.10 ============== * Adafruit Metro M4 Airlift support |