#ifndef __INC_CHIPSETS_H #define __INC_CHIPSETS_H #include "pixeltypes.h" #include "clockless.h" ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // LPD8806 controller class - takes data/clock/select pin values (N.B. should take an SPI definition?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template class LPD8806Controller : public CLEDController { typedef SPIOutput SPI; 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) + ((data && (data<254)) & 0x01); } __attribute__((always_inline)) inline static void postBlock(int len) { SPI::writeBytesValueRaw(0, ((len*3+63)>>6)); } }; SPI mSPI; int mClearedLeds; void checkClear(int nLeds) { if(nLeds > mClearedLeds) { clearLine(nLeds); mClearedLeds = nLeds; } } void clearLine(int nLeds) { int n = ((nLeds*3 + 63) >> 6); mSPI.writeBytesValue(0, n); } public: LPD8806Controller() {} virtual void init() { mSPI.init(); mClearedLeds = 0; } virtual void clearLeds(int nLeds) { mSPI.select(); mSPI.writeBytesValueRaw(0x80, nLeds * 3); mSPI.writeBytesValueRaw(0, ((nLeds*3+63)>>6)); mSPI.release(); } protected: virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(PixelController(data, nLeds, scale, getDither())); } virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { // TODO rgb-ize scale mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(PixelController(data, nLeds, scale, getDither())); } #ifdef SUPPORT_ARGB virtual void show(const struct CARGB *data, int nLeds, uint8_t scale) { checkClear(nLeds); mSPI.template writePixels<0, LPD8806_ADJUST, RGB_ORDER>(PixelController(data, nLeds, scale, getDither())); } #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; CMinWait<1000> mWaitDelay; public: WS2801Controller() {} virtual void init() { mSPI.init(); mWaitDelay.mark(); } virtual void clearLeds(int nLeds) { mWaitDelay.wait(); mSPI.writeBytesValue(0, nLeds*3); mWaitDelay.mark(); } protected: virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { mWaitDelay.wait(); mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(PixelController(data, nLeds, scale, getDither())); mWaitDelay.mark(); } virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { mWaitDelay.wait(); mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(PixelController(data, nLeds, scale, getDither())); mWaitDelay.mark(); } #ifdef SUPPORT_ARGB virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { mWaitDelay.wait(); mSPI.template writePixels<0, DATA_NOP, RGB_ORDER>(PixelController(data, nLeds, scale, getDither())); mWaitDelay.mark(); } #endif }; template class WS2803Controller : public WS2801Controller {}; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // APA102 definition - takes data/clock/select pin values (N.B. should take an SPI definition?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template class APA102Controller : public CLEDController { typedef SPIOutput SPI; SPI mSPI; void startBoundary() { mSPI.writeWord(0); mSPI.writeWord(0); } void endBoundary() { /*mSPI.writeWord(0xFFFF); mSPI.writeWord(0xFFFF); */} inline void writeLed(uint8_t b0, uint8_t b1, uint8_t b2) __attribute__((always_inline)) { mSPI.writeByte(0xFF); mSPI.writeByte(b0); mSPI.writeByte(b1); mSPI.writeByte(b2); } public: APA102Controller() {} virtual void init() { mSPI.init(); } virtual void clearLeds(int nLeds) { showColor(CRGB(0,0,0), nLeds, CRGB(0,0,0)); } protected: virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { PixelController pixels(data, nLeds, scale, getDither()); mSPI.select(); startBoundary(); while(nLeds--) { writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); pixels.stepDithering(); } endBoundary(); mSPI.waitFully(); mSPI.release(); } virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { PixelController pixels(data, nLeds, scale, getDither()); mSPI.select(); startBoundary(); for(int i = 0; i < nLeds; i++) { writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); pixels.advanceData(); pixels.stepDithering(); } endBoundary(); mSPI.release(); } #ifdef SUPPORT_ARGB virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { PixelController pixels(data, nLeds,, scale, getDither()); mSPI.select(); startBoundary(); for(int i = 0; i < nLeds; i++) { writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); pixels.advanceData(); pixels.stepDithering(); } endBoundary(); mSPI.release(); } #endif }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // P9813 definition - takes data/clock/select pin values (N.B. should take an SPI definition?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template class P9813Controller : public CLEDController { typedef SPIOutput SPI; SPI mSPI; void writeBoundary() { mSPI.writeWord(0); mSPI.writeWord(0); } inline void writeLed(uint8_t r, uint8_t g, uint8_t b) __attribute__((always_inline)) { register uint8_t top = 0xC0 | ((~b & 0xC0) >> 2) | ((~g & 0xC0) >> 4) | ((~r & 0xC0) >> 6); mSPI.writeByte(top); mSPI.writeByte(b); mSPI.writeByte(g); mSPI.writeByte(r); } public: P9813Controller() {} virtual void init() { mSPI.init(); } virtual void clearLeds(int nLeds) { showColor(CRGB(0,0,0), nLeds, CRGB(0,0,0)); } protected: virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { PixelController pixels(data, nLeds, scale, getDither()); mSPI.select(); writeBoundary(); while(nLeds--) { writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); pixels.stepDithering(); } writeBoundary(); mSPI.waitFully(); mSPI.release(); } virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { PixelController pixels(data, nLeds, scale, getDither()); mSPI.select(); writeBoundary(); for(int i = 0; i < nLeds; i++) { writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); pixels.advanceData(); pixels.stepDithering(); } writeBoundary(); mSPI.release(); } #ifdef SUPPORT_ARGB virtual void show(const struct CRGB *data, int nLeds, CRGB scale) { PixelController pixels(data, nLeds,, scale, getDither()); mSPI.select(); writeBoundary(); for(int i = 0; i < nLeds; i++) { writeLed(pixels.loadAndScale0(), pixels.loadAndScale1(), pixels.loadAndScale2()); pixels.advanceData(); pixels.stepDithering(); } writeBoundary(); mSPI.release(); } #endif }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // SM16716 definition - takes data/clock/select pin values (N.B. should take an SPI definition?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template class SM16716Controller : public CLEDController { typedef SPIOutput SPI; SPI mSPI; void writeHeader() { // Write out 50 zeros to the spi line (6 blocks of 8 followed by two single bit writes) mSPI.select(); mSPI.writeBytesValueRaw(0, 6); mSPI.waitFully(); mSPI.template writeBit<0>(0); mSPI.template writeBit<0>(0); mSPI.release(); } public: SM16716Controller() {} virtual void init() { mSPI.init(); } virtual void clearLeds(int nLeds) { mSPI.select(); while(nLeds--) { mSPI.template writeBit<0>(1); mSPI.writeByte(0); mSPI.writeByte(0); mSPI.writeByte(0); } mSPI.waitFully(); mSPI.release(); writeHeader(); } protected: virtual void showColor(const struct CRGB & data, int nLeds, CRGB scale) { mSPI.template writePixels(PixelController(data, nLeds, scale, getDither())); writeHeader(); } virtual void show(const struct CRGB *data, int nLeds, CRGB 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 // writeHeader(); mSPI.template writePixels( PixelController(data, nLeds, scale, getDither())); writeHeader(); } #ifdef SUPPORT_ARGB virtual void show(const struct CARGB *data, int nLeds, CRGB scale) { 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 writePixels(PixelController(data, nLeds, scale, getDither())); } #endif }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Clockless template instantiations - see clockless.h for how the timing values are used // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // We want to force all avr's to use the Trinket controller when running at 8Mhz, because even the 328's at 8Mhz // need the more tightly defined timeframes. #if (F_CPU == 8000000 || F_CPU == 16000000 || F_CPU == 24000000) // || F_CPU == 48000000 || F_CPU == 96000000) // 125ns/clock #define FMUL (F_CPU/8000000) // LPD1886 template class LPD1886Controller1250Khz : public ClocklessController {}; // WS2811@800khz 2 clocks, 5 clocks, 3 clocks template class WS2811Controller800Khz : public ClocklessController {}; //class WS2811Controller800Khz : public ClocklessController {}; template class WS2811Controller400Khz : public ClocklessController {}; template class UCS1903Controller400Khz : public ClocklessController {}; template class UCS1903BController800Khz : public ClocklessController {}; template class TM1809Controller800Khz : public ClocklessController {}; template class TM1803Controller400Khz : public ClocklessController {}; template class TM1829Controller800Khz : public ClocklessController {}; template class GW6205Controller400Khz : public ClocklessController {}; template class GW6205Controller800Khz : public ClocklessController {}; #else // GW6205@400khz - 800ns, 800ns, 800ns template class GW6205Controller400Khz : public ClocklessController {}; #if NO_TIME(800, 800, 800) #warning "Not enough clock cycles available for the GW6205@400khz" #endif // GW6205@400khz - 400ns, 400ns, 400ns template class GW6205Controller800Khz : public ClocklessController {}; #if NO_TIME(400, 400, 400) #warning "Not enough clock cycles available for the GW6205@400khz" #endif // UCS1903 - 500ns, 1500ns, 500ns template class UCS1903Controller400Khz : public ClocklessController {}; #if NO_TIME(500, 1500, 500) #warning "Not enough clock cycles available for the UCS103@400khz" #endif // UCS1903B - 400ns, 450ns, 450ns template class UCS1903BController800Khz : public ClocklessController {}; #if NO_TIME(400, 450, 450) #warning "Not enough clock cycles available for the UCS103B@800khz" #endif // TM1809 - 350ns, 350ns, 550ns template class TM1809Controller800Khz : public ClocklessController {}; #if NO_TIME(350, 350, 550) #warning "Not enough clock cycles available for the TM1809" #endif // WS2811 - 320ns, 320ns, 640ns template class WS2811Controller800Khz : public ClocklessController {}; #if NO_TIME(320, 320, 640) #warning "Not enough clock cycles available for the WS2811 (800khz)" #endif // WS2811@400khz - 800ns, 800ns, 900ns template class WS2811Controller400Khz : public ClocklessController {}; #if NO_TIME(800, 800, 900) #warning "Not enough clock cycles available for the WS2811 (400Khz)" #endif // 750NS, 750NS, 750NS template class TM1803Controller400Khz : public ClocklessController {}; #if NO_TIME(750, 750, 750) #warning "Not enough clock cycles available for the TM1803" #endif template class TM1829Controller800Khz : public ClocklessController {}; template class TM1829Controller1600Khz : public ClocklessController {}; #if NO_TIME(100, 300, 200) #warning "Not enough clock cycles available for TM1829@1.6Mhz" #endif template class LPD1886Controller1250Khz : public ClocklessController {}; #if NO_TIME(200,400,200) #warning "Not enough clock cycles for LPD1886" #endif #endif #endif