diff options
author | Daniel Garcia <danielgarcia@gmail.com> | 2015-02-08 08:34:40 +0300 |
---|---|---|
committer | Daniel Garcia <danielgarcia@gmail.com> | 2015-02-08 08:34:40 +0300 |
commit | ad4b7891b28c6bc270f2a03bbd430abeadc555b4 (patch) | |
tree | 7b482846497afd252fb978a8d38e96204293d598 | |
parent | 77d387a63537efb05e24fb67f475ee04e6e07c8a (diff) |
Work on getting the clockless code into a better state for the teensy-lc
-rw-r--r-- | PORTING.md | 4 | ||||
-rw-r--r-- | platforms/arm/k26/clockless_arm_k26.h | 111 | ||||
-rw-r--r-- | platforms/arm/k26/fastspi_arm_k26.h | 4 |
3 files changed, 74 insertions, 45 deletions
@@ -23,3 +23,7 @@ Explaining how the macros work and should be used is currently beyond the scope == Porting fastspi.h == This is where you define the low level interface to the hardware SPI system (including a writePixels method that does a bunch of housekeeping for writing led data). Use the fastspi_nop.h file as a reference for the methods that need to be implemented. There are ofteh other useful methods that can help with the internals of the SPI code, I recommend taking a look at how the various platforms implement their SPI classes. + +== Porting clockless.h == + +This is where you define the code for the clockless controllers. Across ARM platforms this will usually be fairly similar - though different arm platforms will have different clock sources that you can/should use. diff --git a/platforms/arm/k26/clockless_arm_k26.h b/platforms/arm/k26/clockless_arm_k26.h index 4627c83f..93b98a1d 100644 --- a/platforms/arm/k26/clockless_arm_k26.h +++ b/platforms/arm/k26/clockless_arm_k26.h @@ -6,6 +6,9 @@ #if defined(FASTLED_TEENSYLC) #define FASTLED_HAS_CLOCKLESS 1 +#define FASTLED_K26_TIMER_CNT FTM1_CNT +#define FASTLED_K26_TIMER_SC FTM1_SC + 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 CLEDController { typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t; @@ -55,28 +58,30 @@ protected: 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); + while(!(FTM1_STATUS & 0x100)); + FASTLED_K26_TIMER_CNT = 0; + FTM1_STATUS = 0x1FF; FastPin<DATA_PIN>::fastset(port, hi); if(b&0x80) { - while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); + while(!(FTM1_STATUS & 0x02)); FastPin<DATA_PIN>::fastset(port, lo); } else { - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); + while(!(FTM1_STATUS & 0x01)); FastPin<DATA_PIN>::fastset(port, lo); } b <<= 1; } - while(ARM_DWT_CYCCNT < next_mark); - next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + while(!(FTM1_STATUS & 0x100)); + FASTLED_K26_TIMER_CNT = 0; + FTM1_STATUS = 0x1FF; FastPin<DATA_PIN>::fastset(port, hi); if(b&0x80) { - while((next_mark - ARM_DWT_CYCCNT) > (T3+(2*(F_CPU/24000000)))); + while(!(FTM1_STATUS & 0x02)); FastPin<DATA_PIN>::fastset(port, lo); } else { - while((next_mark - ARM_DWT_CYCCNT) > (T2+T3+(2*(F_CPU/24000000)))); + while(!(FTM1_STATUS & 0x01)); FastPin<DATA_PIN>::fastset(port, lo); } } @@ -84,10 +89,6 @@ protected: // 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();; @@ -98,39 +99,63 @@ protected: pixels.preStepFirstByteDithering(); register uint8_t b = pixels.loadAndScale0(); - #if (FASTLED_ALLOW_INTERRUPTS == 1) cli(); - #endif - uint32_t next_mark = ARM_DWT_CYCCNT + (T1+T2+T3); + // Get access to the clock + FASTLED_K26_TIMER_SC = FTM_SC_PS(0) | FTM_SC_CLKS(0); + FTM1_CONF = 0; + + // Clear the channel modes + FTM1_C0SC = 0; + FTM1_C1SC = 0; + + // Set the channel values for T1 + FTM1_C0SC = FTM_CSC_MSA | FTM_CSC_ELSB | FTM_CSC_ELSA; + FTM1_C0V = T1; + + // Set the channel values for T1+T2 + FTM1_C1SC = FTM_CSC_MSA | FTM_CSC_ELSB | FTM_CSC_ELSA; + FTM1_C1V = (T1+T2); + + // Set the overflow for the full pixel + FTM1_MOD = (T1 + T2 + T3); + uint32_t next_mark = 0; // + (T1+T2+T3); + + pixels.stepDithering(); + + FASTLED_K26_TIMER_CNT = 0; + FTM1_STATUS = 0x1FF; while(pixels.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-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return ARM_DWT_CYCCNT; } + // } + // #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 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 ARM_DWT_CYCCNT; } - } - #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 - }; - - return ARM_DWT_CYCCNT; - } - }; - #endif + }; - #endif + FASTLED_K26_TIMER_SC = 0; + sei(); + return ARM_DWT_CYCCNT; + } +}; +#endif + +#endif diff --git a/platforms/arm/k26/fastspi_arm_k26.h b/platforms/arm/k26/fastspi_arm_k26.h index 2caf5d43..eccdb638 100644 --- a/platforms/arm/k26/fastspi_arm_k26.h +++ b/platforms/arm/k26/fastspi_arm_k26.h @@ -163,9 +163,9 @@ public: 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) { wait(); SPIX.DL = b; } + 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) { writeByte(w>>8); writeByte(w & 0xFF); } + 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) { |