#ifndef __INC_CHIPSETS_H #define __INC_CHIPSETS_H #include "pixeltypes.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; } __attribute__((always_inline)) inline static uint8_t adjust(register uint8_t data, register uint8_t scale) { return (scale8(data, scale)>>1) | 0x80; } __attribute__((always_inline)) inline static void postBlock(int len) { SPI::writeBytesValueRaw(0, ((len+63)>>6)); } }; SPI mSPI; 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() {} 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(); } virtual void showColor(const struct CRGB & data, int nLeds, uint8_t scale = 255) { mSPI.select(); uint8_t a = 0x80 | (scale8(data[RGB_BYTE0(RGB_ORDER)], scale) >> 1); uint8_t b = 0x80 | (scale8(data[RGB_BYTE1(RGB_ORDER)], scale) >> 1); uint8_t c = 0x80 | (scale8(data[RGB_BYTE2(RGB_ORDER)], scale) >> 1); int iLeds = 0; while(iLeds++ < nLeds) { mSPI.writeByte(a); mSPI.writeByte(b); mSPI.writeByte(c); } // latch in the world mSPI.writeBytesValueRaw(0, ((nLeds*3+63)>>6)); mSPI.release(); } virtual void show(const struct CRGB *data, int nLeds, uint8_t scale = 255) { mSPI.template writeBytes3((byte*)data, nLeds * 3, scale); } #ifdef SUPPORT_ARGB virtual void show(const struct CARGB *data, int nLeds, uint8_t scale) { checkClear(nLeds); mSPI.template writeBytes3<1, LPD8806_ADJUST, RGB_ORDER>((byte*)data, nLeds * 4, scale); } #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<24> mWaitDelay; public: WS2801Controller() {} virtual void init() { mSPI.init(); mWaitDelay.mark(); } virtual void clearLeds(int nLeds) { mWaitDelay.wait(); mSPI.writeBytesValue(0, nLeds*3); mWaitDelay.mark(); } virtual void showColor(const struct CRGB & data, int nLeds, uint8_t scale = 255) { mWaitDelay.wait(); mSPI.select(); uint8_t a = scale8(data[RGB_BYTE0(RGB_ORDER)], scale); uint8_t b = scale8(data[RGB_BYTE1(RGB_ORDER)], scale); uint8_t c = scale8(data[RGB_BYTE2(RGB_ORDER)], scale); while(nLeds--) { mSPI.writeByte(a); mSPI.writeByte(b); mSPI.writeByte(c); } mSPI.waitFully(); mSPI.release(); mWaitDelay.mark(); } virtual void show(const 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 show(const struct CRGB *data, int nLeds, uint8_t scale) { mWaitDelay.wait(); mSPI.template writeBytes3<1, RGB_ORDER>((byte*)data, nLeds * 4, scale); mWaitDelay.mark(); } #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(const struct CRGB & data, uint8_t scale) __attribute__((always_inline)) { // prep the byte register uint8_t r = scale8(data[RGB_BYTE0(RGB_ORDER)], scale); register uint8_t g = scale8(data[RGB_BYTE1(RGB_ORDER)], scale); register uint8_t b = scale8(data[RGB_BYTE2(RGB_ORDER)], scale); register uint8_t top = 0xC0 | (~b & 0xC0) >> 2 | (~g & 0xC0) >> 4 | (~r & 0xC0); 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); } virtual void showColor(const struct CRGB & data, int nLeds, uint8_t scale = 255) { mSPI.select(); writeBoundary(); while(nLeds--) { writeLed(data, scale); } writeBoundary(); mSPI.waitFully(); mSPI.release(); } virtual void show(const struct CRGB *data, int nLeds, uint8_t scale) { mSPI.select(); writeBoundary(); for(int i = 0; i < nLeds; i++) { writeLed(data[i], scale); } writeBoundary(); mSPI.release(); } #ifdef SUPPORT_ARGB virtual void show(const struct CRGB *data, int nLeds, uint8_t scale) { mSPI.template writeBytes3<1, RGB_ORDER>((byte*)data, nLeds * 4, scale); } #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(); } virtual void showColor(const struct CRGB & data, int nLeds, uint8_t scale = 255) { mSPI.select(); uint8_t a = scale8(data[RGB_BYTE0(RGB_ORDER)], scale); uint8_t b = scale8(data[RGB_BYTE1(RGB_ORDER)], scale); uint8_t c = scale8(data[RGB_BYTE2(RGB_ORDER)], scale); while(nLeds--) { mSPI.template writeBit<0>(1); mSPI.writeByte(a); mSPI.writeByte(b); mSPI.writeByte(c); } writeHeader(); mSPI.release(); } virtual void show(const struct CRGB *data, int nLeds, uint8_t scale = 255) { // 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 writeBytes3((byte*)data, nLeds * 3, scale); writeHeader(); } #ifdef SUPPORT_ARGB virtual void show(const struct CARGB *data, int nLeds, uint8_t scale = 255) { 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, scale); } #endif }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Clockless template instantiations // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // UCS1903 - 500ns, 1500ns, 500ns template class UCS1903Controller400Khz : public ClocklessController {}; #if NO_TIME(500, 1500, 500) #warning "Not enough clock cycles available for the UCS103" #endif // TM1809 - 312.5ns, 312.5ns, 325ns template class TM1809Controller800Khz : public ClocklessController {}; #if NO_TIME(320, 320, 550) #warning "Not enough clock cycles available for the TM1809" #endif // WS2811 - 350n, 350ns, 550ns template class WS2811Controller800Khz : public ClocklessController {}; template class WS2811Controller2800Khz : public ClocklessController2 {}; #if NO_TIME(320, 320, 550) #warning "Not enough clock cycles available for the WS2811" #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 { public: // virtual void show(const struct CRGB *data, int nLeds, uint8_t scale = 255) { // ClocklessController::show(data, nLeds, scale8(scale, 254)); // } // virtual void showColor(const struct CRGB &data, int nLeds, uint8_t scale = 255) { // ClocklessController::showColor(data, nLeds, scale8(scale, 254)); // } }; template class TM1829Controller1600Khz : public ClocklessController { public: virtual void show(const struct CRGB *data, int nLeds, uint8_t scale = 255) { ClocklessController::show(data, nLeds, scale8(scale, 254)); } virtual void showColor(const struct CRGB &data, int nLeds, uint8_t scale = 255) { ClocklessController::showColor(data, nLeds, scale8(scale, 254)); } }; #if NO_TIME(100, 300, 200) #warning "Not enough clock cycles available for TM1829@1.6Mhz" #endif #endif