Permalink
Browse files

Add global brightness support for ADA102 and SK9822 (#653)

* Add global brightness support for ADA102 and SK9822

* Move brightness computation outside of the loop
  • Loading branch information...
extesy authored and focalintent committed Sep 20, 2018
1 parent 1463ed5 commit 38105c61de097066946f2df4d2bb2c36ddc78d7c
Showing with 68 additions and 31 deletions.
  1. +51 −29 chipsets.h
  2. +13 −2 controller.h
  3. +4 −0 fastled_config.h
View
@@ -162,8 +162,19 @@ class APA102Controller : public CPixelLEDController<RGB_ORDER> {
void startBoundary() { mSPI.writeWord(0); mSPI.writeWord(0); }
void endBoundary(int nLeds) { int nDWords = (nLeds/32); do { mSPI.writeByte(0xFF); mSPI.writeByte(0x00); mSPI.writeByte(0x00); mSPI.writeByte(0x00); } while(nDWords--); }
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);
inline void writeLed(uint8_t brightness, uint8_t b0, uint8_t b1, uint8_t b2) __attribute__((always_inline)) {
#ifdef FASTLED_SPI_BYTE_ONLY
mSPI.writeByte(0xE0 | brightness);
mSPI.writeByte(b0);
mSPI.writeByte(b1);
mSPI.writeByte(b2);
#else
uint16_t b = 0xE000 | (brightness << 8) | (uint16_t)b0;
mSPI.writeWord(b);
uint16_t w = b1 << 8;
w |= b2;
mSPI.writeWord(w);
#endif
}
public:
@@ -178,24 +189,25 @@ class APA102Controller : public CPixelLEDController<RGB_ORDER> {
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
startBoundary();
while(pixels.has(1)) {
#ifdef FASTLED_SPI_BYTE_ONLY
mSPI.writeByte(0xFF);
mSPI.writeByte(pixels.loadAndScale0());
mSPI.writeByte(pixels.loadAndScale1());
mSPI.writeByte(pixels.loadAndScale2());
uint8_t s0 = pixels.getScale0(), s1 = pixels.getScale1(), s2 = pixels.getScale2();
#if FASTLED_USE_GLOBAL_BRIGHTNESS == 1
const uint16_t maxBrightness = 0x1F;
uint16_t brightness = (max(max(s0, s1), s2) * maxBrightness >> 8) + 1;
s0 = ((uint16_t)s0 + 1) * maxBrightness / brightness - 1;
s1 = ((uint16_t)s1 + 1) * maxBrightness / brightness - 1;
s2 = ((uint16_t)s2 + 1) * maxBrightness / brightness - 1;
#else
uint16_t b = 0xFF00 | (uint16_t)pixels.loadAndScale0();
mSPI.writeWord(b);
uint16_t w = pixels.loadAndScale1() << 8;
w |= pixels.loadAndScale2();
mSPI.writeWord(w);
const uint8_t brightness = 0x1F;
#endif
startBoundary();
while (pixels.has(1)) {
writeLed(brightness, pixels.loadAndScale0(0, s0), pixels.loadAndScale1(0, s1), pixels.loadAndScale2(0, s2));
pixels.stepDithering();
pixels.advanceData();
}
endBoundary(pixels.size());
mSPI.waitFully();
mSPI.release();
}
@@ -215,8 +227,19 @@ class SK9822Controller : public CPixelLEDController<RGB_ORDER> {
void startBoundary() { mSPI.writeWord(0); mSPI.writeWord(0); }
void endBoundary(int nLeds) { int nLongWords = (nLeds/32); do { mSPI.writeByte(0x00); mSPI.writeByte(0x00); mSPI.writeByte(0x00); mSPI.writeByte(0x00); } while(nLongWords--); }
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);
inline void writeLed(uint8_t brightness, uint8_t b0, uint8_t b1, uint8_t b2) __attribute__((always_inline)) {
#ifdef FASTLED_SPI_BYTE_ONLY
mSPI.writeByte(0xE0 | brightness);
mSPI.writeByte(b0);
mSPI.writeByte(b1);
mSPI.writeByte(b2);
#else
uint16_t b = 0xE000 | (brightness << 8) | (uint16_t)b0;
mSPI.writeWord(b);
uint16_t w = b1 << 8;
w |= b2;
mSPI.writeWord(w);
#endif
}
public:
@@ -231,24 +254,23 @@ class SK9822Controller : public CPixelLEDController<RGB_ORDER> {
virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
mSPI.select();
startBoundary();
while(pixels.has(1)) {
#ifdef FASTLED_SPI_BYTE_ONLY
mSPI.writeByte(0xFF);
mSPI.writeByte(pixels.loadAndScale0());
mSPI.writeByte(pixels.loadAndScale1());
mSPI.writeByte(pixels.loadAndScale2());
uint8_t s0 = pixels.getScale0(), s1 = pixels.getScale1(), s2 = pixels.getScale2();
#if FASTLED_USE_GLOBAL_BRIGHTNESS == 1
const uint16_t maxBrightness = 0x1F;
uint16_t brightness = (max(max(s0, s1), s2) * maxBrightness >> 8) + 1;
s0 = ((uint16_t)s0 + 1) * maxBrightness / brightness - 1;
s1 = ((uint16_t)s1 + 1) * maxBrightness / brightness - 1;
s2 = ((uint16_t)s2 + 1) * maxBrightness / brightness - 1;
#else
uint16_t b = 0xFF00 | (uint16_t)pixels.loadAndScale0();
mSPI.writeWord(b);
uint16_t w = pixels.loadAndScale1() << 8;
w |= pixels.loadAndScale2();
mSPI.writeWord(w);
const uint8_t brightness = 0x1F;
#endif
startBoundary();
while (pixels.has(1)) {
writeLed(brightness, pixels.loadAndScale0(0, s0), pixels.loadAndScale1(0, s1), pixels.loadAndScale2(0, s2));
pixels.stepDithering();
pixels.advanceData();
}
endBoundary(pixels.size());
mSPI.waitFully();
View
@@ -357,11 +357,18 @@ struct PixelController {
template<int SLOT> __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(PixelController & pc) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc); }
template<int SLOT> __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(PixelController & pc, int lane) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc, lane); }
template<int SLOT> __attribute__((always_inline)) inline static uint8_t advanceAndLoadAndScale(PixelController & pc, int lane, uint8_t scale) { pc.advanceData(); return pc.loadAndScale<SLOT>(pc, lane, scale); }
template<int SLOT> __attribute__((always_inline)) inline static uint8_t getd(PixelController & pc) { return pc.d[RO(SLOT)]; }
template<int SLOT> __attribute__((always_inline)) inline static uint8_t getscale(PixelController & pc) { return pc.mScale.raw[RO(SLOT)]; }
template<int SLOT> __attribute__((always_inline)) inline static uint8_t getd(PixelController & pc) { return pc.d[RO(SLOT)]; }
template<int SLOT> __attribute__((always_inline)) inline static uint8_t getscale(PixelController & pc) { return pc.mScale.raw[RO(SLOT)]; }
// Helper functions to get around gcc stupidities
__attribute__((always_inline)) inline uint8_t loadAndScale0(int lane, uint8_t scale) { return loadAndScale<0>(*this, lane, scale); }
__attribute__((always_inline)) inline uint8_t loadAndScale1(int lane, uint8_t scale) { return loadAndScale<1>(*this, lane, scale); }
__attribute__((always_inline)) inline uint8_t loadAndScale2(int lane, uint8_t scale) { return loadAndScale<2>(*this, lane, scale); }
__attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0(int lane, uint8_t scale) { return advanceAndLoadAndScale<0>(*this, lane, scale); }
__attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0(int lane, uint8_t scale) { stepDithering(); return advanceAndLoadAndScale<0>(*this, lane, scale); }
__attribute__((always_inline)) inline uint8_t loadAndScale0(int lane) { return loadAndScale<0>(*this, lane); }
__attribute__((always_inline)) inline uint8_t loadAndScale1(int lane) { return loadAndScale<1>(*this, lane); }
__attribute__((always_inline)) inline uint8_t loadAndScale2(int lane) { return loadAndScale<2>(*this, lane); }
@@ -373,6 +380,10 @@ struct PixelController {
__attribute__((always_inline)) inline uint8_t loadAndScale2() { return loadAndScale<2>(*this); }
__attribute__((always_inline)) inline uint8_t advanceAndLoadAndScale0() { return advanceAndLoadAndScale<0>(*this); }
__attribute__((always_inline)) inline uint8_t stepAdvanceAndLoadAndScale0() { stepDithering(); return advanceAndLoadAndScale<0>(*this); }
__attribute__((always_inline)) inline uint8_t getScale0() { return getscale<0>(*this); }
__attribute__((always_inline)) inline uint8_t getScale1() { return getscale<1>(*this); }
__attribute__((always_inline)) inline uint8_t getScale2() { return getscale<2>(*this); }
};
template<EOrder RGB_ORDER, int LANES=1, uint32_t MASK=0xFFFFFFFF> class CPixelLEDController : public CLEDController {
View
@@ -61,5 +61,9 @@
#define FASTLED_INTERRUPT_RETRY_COUNT 2
#endif
// Use this toggle to enable global brightness in contollers that support is (ADA102 and SK9822).
// It changes how color scaling works and uses global brightness before scaling down color values.
// This enable much more accurate color control on low brightness settings.
//#define FASTLED_USE_GLOBAL_BRIGHTNESS 1
#endif

0 comments on commit 38105c6

Please sign in to comment.