#ifndef __INC_FASTSPI_LED2_H #define __INC_FASTSPI_LED2_H #include "controller.h" #include "fastpin.h" #include "fastspi.h" #include "clockless.h" #include "lib8tion.h" #include "hsv2rgb.h" ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // LPD8806 controller class - takes data/clock/select pin values (N.B. should take an SPI definition?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class LPD8806_ADJUST { public: // LPD8806 spec wants the high bit of every rgb data byte sent out to be set. __attribute__((always_inline)) inline static uint8_t adjust(register uint8_t data) { return (data>>1) | 0x80; } __attribute__((always_inline)) inline static uint8_t adjust(register uint8_t data, register uint8_t scale) { return (scale8(data, scale)>>1) | 0x80; } }; template class LPD8806Controller : public CLEDController { typedef SPIOutput SPI; SPI mSPI; OutputPin selectPin; int mClearedLeds; void checkClear(int nLeds) { if(nLeds > mClearedLeds) { clearLine(nLeds); mClearedLeds = nLeds; } } void clearLine(int nLeds) { int n = ((nLeds + 63) >> 6); mSPI.writeBytesValue(0, n); } public: LPD8806Controller() : selectPin(SELECT_PIN) {} virtual void init() { mSPI.setSelect(&selectPin); mSPI.init(); mClearedLeds = 0; } virtual void clearLeds(int nLeds) { checkClear(nLeds); mSPI.writeBytesValue(0x80, nLeds * 3); } virtual void showRGB(register struct CRGB *rgbdata, register int nLeds) { showRGB(rgbdata, nLeds, 255); } virtual void showRGB(struct CRGB *data, int nLeds, uint8_t scale) { checkClear(nLeds); mSPI.template writeBytes3((byte*)data, nLeds * 3, scale); clearLine(nLeds); } #ifdef SUPPORT_ARGB virtual void showARGB(struct CARGB *data, int nLeds) { checkClear(nLeds); mSPI.template writeBytes3<1, LPD8806_ADJUST, RGB_ORDER>((byte*)data, nLeds * 4, 255); clearLine(nLeds); } #endif }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // WS2801 definition - takes data/clock/select pin values (N.B. should take an SPI definition?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template class WS2801Controller : public CLEDController { typedef SPIOutput SPI; SPI mSPI; OutputPin selectPin; CMinWait<24> mWaitDelay; public: WS2801Controller() : selectPin(SELECT_PIN) {} virtual void init() { mSPI.setSelect(&selectPin); mSPI.init(); // 0 out as much as we can on the line mSPI.writeBytesValue(0, 1000); mWaitDelay.mark(); } virtual void clearLeds(int nLeds) { mWaitDelay.wait(); mSPI.writeBytesValue(0, nLeds*3); mWaitDelay.mark(); } virtual void showRGB(register struct CRGB *rgbdata, register int nLeds) { showRGB(rgbdata, nLeds, 255); } virtual void showRGB(struct CRGB *data, int nLeds, uint8_t scale) { mWaitDelay.wait(); mSPI.template writeBytes3<0, RGB_ORDER>((byte*)data, nLeds * 3, scale); mWaitDelay.mark(); } #ifdef SUPPORT_ARGB virtual void showARGB(struct CRGB *data, int nLeds) { mWaitDelay.wait(); mSPI.template writeBytes3<1, RGB_ORDER>((byte*)data, nLeds * 4, 255); mWaitDelay.mark(); } #endif }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // SM16716 definition - takes data/clock/select pin values (N.B. should take an SPI definition?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template class SM16716Controller : public CLEDController { #if defined(__MK20DX128__) // for Teensy 3.0 // Have to force software SPI for the teensy 3.0 right now because it doesn't deal well // with flipping in and out of hardware SPI typedef SPIOutput SPI; #else typedef SPIOutput SPI; #endif SPI mSPI; OutputPin selectPin; void writeHeader() { // Write out 50 zeros to the spi line (6 blocks of 8 followed by two single bit writes) mSPI.writeBytesValue(0, 6); mSPI.template writeBit<0>(0); mSPI.template writeBit<0>(0); } public: SM16716Controller() : selectPin(SELECT_PIN) {} virtual void init() { mSPI.setSelect(&selectPin); mSPI.init(); } virtual void clearLeds(int nLeds) { writeHeader(); mSPI.select(); while(nLeds--) { mSPI.template writeBit<0>(1); mSPI.writeByte(0); mSPI.writeByte(0); mSPI.writeByte(0); } mSPI.waitFully(); mSPI.release(); } virtual void showRGB(register struct CRGB *rgbdata, register int nLeds) { showRGB(rgbdata, nLeds, 255); } virtual void showRGB(struct CRGB *data, int nLeds, uint8_t scale) { // Make sure the FLAG_START_BIT flag is set to ensure that an extra 1 bit is sent at the start // of each triplet of bytes for rgb data mSPI.template writeBytes3((byte*)data, nLeds * 3, scale); } #ifdef SUPPORT_ARGB virtual void showARGB(struct CARGB *data, int nLeds) { mSPI.writeBytesValue(0, 6); mSPI.template writeBit<0>(0); mSPI.template writeBit<0>(0); // Make sure the FLAG_START_BIT flag is set to ensure that an extra 1 bit is sent at the start // of each triplet of bytes for rgb data mSPI.template writeBytes3<1 | FLAG_START_BIT, RGB_ORDER>((byte*)data, nLeds * 4, 255); } #endif }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Clockless template instantiations // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 500ns, 1500ns, 500ns template class UCS1903Controller400Mhz : public ClocklessController {}; template class UCS1903Controller400Khz : public ClocklessController {}; #if NO_TIME(500, 1500, 500) #warning "No enough clock cycles available for the UCS103" #endif // 312.5ns, 312.5ns, 325ns template class TM1809Controller800Mhz : public ClocklessController {}; template class TM1809Controller800Khz : public ClocklessController {}; #if NO_TIME(350, 350, 550) #warning "No enough clock cycles available for the UCS103" #endif // 350n, 350ns, 550ns template class WS2811Controller800Mhz : public ClocklessController {}; template class WS2811Controller800Khz : public ClocklessController {}; #if NO_TIME(320, 320, 550) #warning "No enough clock cycles available for the UCS103" #endif // 750NS, 750NS, 750NS template class TM1803Controller400Mhz : public ClocklessController {}; template class TM1803Controller400Khz : public ClocklessController {}; #if NO_TIME(750, 750, 750) #warning "No enough clock cycles available for the UCS103" #endif #endif