@@ -1194,8 +1194,9 @@ void WS2812FX::finalizeInit() {
1194
1194
if (busEnd > _length) _length = busEnd;
1195
1195
// This must be done after all buses have been created, as some kinds (parallel I2S) interact
1196
1196
bus->begin ();
1197
- bus->setBrightness (bri);
1197
+ bus->setBrightness (scaledBri ( bri) );
1198
1198
}
1199
+ BusManager::initializeABL (); // init brightness limiter
1199
1200
DEBUG_PRINTF_P (PSTR (" Heap after buses: %d\n " ), ESP.getFreeHeap ());
1200
1201
1201
1202
Segment::maxWidth = _length;
@@ -1297,7 +1298,7 @@ static uint8_t _add (uint8_t a, uint8_t b) { unsigned t = a + b; return t
1297
1298
static uint8_t _subtract (uint8_t a, uint8_t b) { return b > a ? (b - a) : 0 ; }
1298
1299
static uint8_t _difference (uint8_t a, uint8_t b) { return b > a ? (b - a) : (a - b); }
1299
1300
static uint8_t _average (uint8_t a, uint8_t b) { return (a + b) >> 1 ; }
1300
- #ifdef CONFIG_IDF_TARGET_ESP32C3
1301
+ #if defined(ESP8266) || defined( CONFIG_IDF_TARGET_ESP32C3)
1301
1302
static uint8_t _multiply (uint8_t a, uint8_t b) { return ((a * b) + 255 ) >> 8 ; } // faster than division on C3 but slightly less accurate
1302
1303
#else
1303
1304
static uint8_t _multiply (uint8_t a, uint8_t b) { return (a * b) / 255 ; } // origianl uses a & b in range [0,1]
@@ -1308,10 +1309,10 @@ static uint8_t _darken (uint8_t a, uint8_t b) { return a < b ? a : b; }
1308
1309
static uint8_t _screen (uint8_t a, uint8_t b) { return 255 - _multiply (~a,~b); } // 255 - (255-a)*(255-b)/255
1309
1310
static uint8_t _overlay (uint8_t a, uint8_t b) { return b < 128 ? 2 * _multiply (a,b) : (255 - 2 * _multiply (~a,~b)); }
1310
1311
static uint8_t _hardlight (uint8_t a, uint8_t b) { return a < 128 ? 2 * _multiply (a,b) : (255 - 2 * _multiply (~a,~b)); }
1311
- #ifdef CONFIG_IDF_TARGET_ESP32C3
1312
- static uint8_t _softlight (uint8_t a, uint8_t b) { return (((b * b * (255 - 2 * a) + 255 ) >> 8 ) + 2 * a * b + 255 ) >> 8 ; } // Pegtop's formula (1 - 2a)b^2 + 2ab
1312
+ #if defined(ESP8266) || defined( CONFIG_IDF_TARGET_ESP32C3)
1313
+ static uint8_t _softlight (uint8_t a, uint8_t b) { return (((b * b * (255 - 2 * a)) ) + (( 2 * a * b + 256 ) << 8 )) >> 16 ; } // Pegtop's formula (1 - 2a)b^2
1313
1314
#else
1314
- static uint8_t _softlight (uint8_t a, uint8_t b) { return (b * b * (255 - 2 * a) / 255 + 2 * a * b) / 255 ; } // Pegtop's formula (1 - 2a)b^2 + 2ab
1315
+ static uint8_t _softlight (uint8_t a, uint8_t b) { return (b * b * (255 - 2 * a) + 255 * 2 * a * b) / ( 255 * 255 ) ; } // Pegtop's formula (1 - 2a)b^2 + 2ab
1315
1316
#endif
1316
1317
static uint8_t _dodge (uint8_t a, uint8_t b) { return _divide (~a,b); }
1317
1318
static uint8_t _burn (uint8_t a, uint8_t b) { return ~_divide (a,~b); }
@@ -1550,66 +1551,6 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
1550
1551
Segment::setClippingRect (0 , 0 ); // disable clipping for overlays
1551
1552
}
1552
1553
1553
- // To disable brightness limiter we either set output max current to 0 or single LED current to 0
1554
- static uint8_t estimateCurrentAndLimitBri (uint8_t brightness, uint32_t *pixels) {
1555
- unsigned milliAmpsMax = BusManager::ablMilliampsMax ();
1556
- if (milliAmpsMax > 0 ) {
1557
- unsigned milliAmpsTotal = 0 ;
1558
- unsigned avgMilliAmpsPerLED = 0 ;
1559
- unsigned lengthDigital = 0 ;
1560
- bool useWackyWS2815PowerModel = false ;
1561
-
1562
- for (size_t i = 0 ; i < BusManager::getNumBusses (); i++) {
1563
- const Bus *bus = BusManager::getBus (i);
1564
- if (!(bus && bus->isDigital () && bus->isOk ())) continue ;
1565
- unsigned maPL = bus->getLEDCurrent ();
1566
- if (maPL == 0 || bus->getMaxCurrent () > 0 ) continue ; // skip buses with 0 mA per LED or max current per bus defined (PP-ABL)
1567
- if (maPL == 255 ) {
1568
- useWackyWS2815PowerModel = true ;
1569
- maPL = 12 ; // WS2815 uses 12mA per channel
1570
- }
1571
- avgMilliAmpsPerLED += maPL * bus->getLength ();
1572
- lengthDigital += bus->getLength ();
1573
- // sum up the usage of each LED on digital bus
1574
- uint32_t busPowerSum = 0 ;
1575
- for (unsigned j = 0 ; j < bus->getLength (); j++) {
1576
- uint32_t c = pixels[j + bus->getStart ()];
1577
- byte r = R (c), g = G (c), b = B (c), w = W (c);
1578
- if (useWackyWS2815PowerModel) { // ignore white component on WS2815 power calculation
1579
- busPowerSum += (max (max (r,g),b)) * 3 ;
1580
- } else {
1581
- busPowerSum += (r + g + b + w);
1582
- }
1583
- }
1584
- // RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less
1585
- if (bus->hasWhite ()) {
1586
- busPowerSum *= 3 ;
1587
- busPowerSum >>= 2 ; // same as /= 4
1588
- }
1589
- // powerSum has all the values of channels summed (max would be getLength()*765 as white is excluded) so convert to milliAmps
1590
- milliAmpsTotal += (busPowerSum * maPL * brightness) / (765 *255 );
1591
- }
1592
- if (lengthDigital > 0 ) {
1593
- avgMilliAmpsPerLED /= lengthDigital;
1594
-
1595
- if (milliAmpsMax > MA_FOR_ESP && avgMilliAmpsPerLED > 0 ) { // 0 mA per LED and too low numbers turn off calculation
1596
- unsigned powerBudget = (milliAmpsMax - MA_FOR_ESP); // 80/120mA for ESP power
1597
- if (powerBudget > lengthDigital) { // each LED uses about 1mA in standby, exclude that from power budget
1598
- powerBudget -= lengthDigital;
1599
- } else {
1600
- powerBudget = 0 ;
1601
- }
1602
- if (milliAmpsTotal > powerBudget) {
1603
- // scale brightness down to stay in current limit
1604
- unsigned scaleB = powerBudget * 255 / milliAmpsTotal;
1605
- brightness = ((brightness * scaleB) >> 8 ) + 1 ;
1606
- }
1607
- }
1608
- }
1609
- }
1610
- return brightness;
1611
- }
1612
-
1613
1554
void WS2812FX::show () {
1614
1555
if (!_pixels) return ; // no pixels allocated, nothing to show
1615
1556
@@ -1637,10 +1578,6 @@ void WS2812FX::show() {
1637
1578
show_callback callback = _callback;
1638
1579
if (callback) callback (); // will call setPixelColor or setRealtimePixelColor
1639
1580
1640
- // determine ABL brightness
1641
- uint8_t newBri = estimateCurrentAndLimitBri (_brightness, _pixels);
1642
- if (newBri != _brightness) BusManager::setBrightness (newBri);
1643
-
1644
1581
// paint actual pixels
1645
1582
int oldCCT = Bus::getCCT (); // store original CCT value (since it is global)
1646
1583
// when cctFromRgb is true we implicitly calculate WW and CW from RGB values (cct==-1)
@@ -1651,7 +1588,11 @@ void WS2812FX::show() {
1651
1588
if (_pixelCCT) { // cctFromRgb already exluded at allocation
1652
1589
if (i == 0 || _pixelCCT[i-1 ] != _pixelCCT[i]) BusManager::setSegmentCCT (_pixelCCT[i], correctWB);
1653
1590
}
1654
- BusManager::setPixelColor (getMappedPixelIndex (i), realtimeMode && arlsDisableGammaCorrection ? _pixels[i] : gamma32 (_pixels[i]));
1591
+
1592
+ uint32_t c = _pixels[i]; // need a copy, do not modify _pixels directly (no byte access allowed on ESP32)
1593
+ if (c > 0 && !(realtimeMode && arlsDisableGammaCorrection))
1594
+ c = gamma32 (c); // apply gamma correction if enabled note: applying gamma after brightness has too much color loss
1595
+ BusManager::setPixelColor (getMappedPixelIndex (i), c);
1655
1596
}
1656
1597
Bus::setCCT (oldCCT); // restore old CCT for ABL adjustments
1657
1598
@@ -1663,9 +1604,6 @@ void WS2812FX::show() {
1663
1604
// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods
1664
1605
BusManager::show ();
1665
1606
1666
- // restore brightness for next frame
1667
- if (newBri != _brightness) BusManager::setBrightness (_brightness);
1668
-
1669
1607
if (diff > 0 ) { // skip calculation if no time has passed
1670
1608
size_t fpsCurr = (1000 << FPS_CALC_SHIFT) / diff; // fixed point math
1671
1609
_cumulativeFps = (FPS_CALC_AVG * _cumulativeFps + fpsCurr + FPS_CALC_AVG / 2 ) / (FPS_CALC_AVG + 1 ); // "+FPS_CALC_AVG/2" for proper rounding
@@ -1730,7 +1668,7 @@ void WS2812FX::setBrightness(uint8_t b, bool direct) {
1730
1668
if (_brightness == 0 ) { // unfreeze all segments on power off
1731
1669
for (const Segment &seg : _segments) seg.freeze = false ; // freeze is mutable
1732
1670
}
1733
- BusManager::setBrightness (b );
1671
+ BusManager::setBrightness (scaledBri (b) );
1734
1672
if (!direct) {
1735
1673
unsigned long t = millis ();
1736
1674
if (_segments[0 ].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) trigger (); // apply brightness change immediately if no refresh soon
0 commit comments