diff --git a/wled00/FX.h b/wled00/FX.h index c49f9acb5..4bdec48f9 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -682,6 +682,8 @@ class WS2812FX { ablMilliampsMax, currentMilliamps, triwave16(uint16_t), + getLengthTotal(void), + getLengthPhysical(void), getFps(); uint32_t @@ -841,9 +843,6 @@ class WS2812FX { uint16_t _cumulativeFps = 2; - void load_gradient_palette(uint8_t); - void handle_palette(void); - bool _triggered; @@ -877,7 +876,10 @@ class WS2812FX { void blendPixelColor(uint16_t n, uint32_t color, uint8_t blend), - startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot); + startTransition(uint8_t oldBri, uint32_t oldCol, uint16_t dur, uint8_t segn, uint8_t slot), + estimateCurrentAndLimitBri(void), + load_gradient_palette(uint8_t), + handle_palette(void); uint16_t* customMappingTable = nullptr; uint16_t customMappingSize = 0; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 74404e997..f89df5ed1 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -259,12 +259,7 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) #define MA_FOR_ESP 100 //how much mA does the ESP use (Wemos D1 about 80mA, ESP32 about 120mA) //you can set it to 0 if the ESP is powered by USB and the LEDs by external -void WS2812FX::show(void) { - - // avoid race condition, caputre _callback value - show_callback callback = _callback; - if (callback) callback(); - +void WS2812FX::estimateCurrentAndLimitBri() { //power limit calculation //each LED can draw up 195075 "power units" (approx. 53mA) //one PU is the power it takes to have 1 channel 1 step brighter per brightness step @@ -277,65 +272,72 @@ void WS2812FX::show(void) { actualMilliampsPerLed = 12; // from testing an actual strip } - if (ablMilliampsMax > 149 && actualMilliampsPerLed > 0) //0 mA per LED and too low numbers turn off calculation - { - uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed; - uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power - if (powerBudget > puPerMilliamp * _length) //each LED uses about 1mA in standby, exclude that from power budget - { - powerBudget -= puPerMilliamp * _length; - } else - { - powerBudget = 0; - } - - uint32_t powerSum = 0; - - for (uint16_t i = 0; i < _length; i++) //sum up the usage of each LED - { - uint32_t c = busses.getPixelColor(i); - byte r = c >> 16, g = c >> 8, b = c, w = c >> 24; - - if(useWackyWS2815PowerModel) - { - // ignore white component on WS2815 power calculation - powerSum += (MAX(MAX(r,g),b)) * 3; - } - else - { - powerSum += (r + g + b + w); - } - } - - - if (isRgbw) //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less - { - powerSum *= 3; - powerSum = powerSum >> 2; //same as /= 4 - } - - uint32_t powerSum0 = powerSum; - powerSum *= _brightness; - - if (powerSum > powerBudget) //scale brightness down to stay in current limit - { - float scale = (float)powerBudget / (float)powerSum; - uint16_t scaleI = scale * 255; - uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; - uint8_t newBri = scale8(_brightness, scaleB); - busses.setBrightness(newBri); - currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; - } else - { - currentMilliamps = powerSum / puPerMilliamp; - busses.setBrightness(_brightness); - } - currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate - currentMilliamps += _length; //add standby power back to estimate - } else { + if (ablMilliampsMax < 150 || actualMilliampsPerLed == 0) { //0 mA per LED and too low numbers turn off calculation currentMilliamps = 0; busses.setBrightness(_brightness); + return; } + + uint16_t pLen = getLengthPhysical(); + uint32_t puPerMilliamp = 195075 / actualMilliampsPerLed; + uint32_t powerBudget = (ablMilliampsMax - MA_FOR_ESP) * puPerMilliamp; //100mA for ESP power + if (powerBudget > puPerMilliamp * pLen) { //each LED uses about 1mA in standby, exclude that from power budget + powerBudget -= puPerMilliamp * pLen; + } else { + powerBudget = 0; + } + + uint32_t powerSum = 0; + + for (uint8_t b = 0; b < busses.getNumBusses(); b++) { + Bus *bus = busses.getBus(b); + if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses + uint16_t len = bus->getLength(); + uint32_t busPowerSum = 0; + for (uint16_t i = 0; i < len; i++) { //sum up the usage of each LED + uint32_t c = bus->getPixelColor(i); + byte r = c >> 16, g = c >> 8, b = c, w = c >> 24; + + if(useWackyWS2815PowerModel) { //ignore white component on WS2815 power calculation + busPowerSum += (MAX(MAX(r,g),b)) * 3; + } else { + busPowerSum += (r + g + b + w); + } + } + + if (bus->isRgbw()) { //RGBW led total output with white LEDs enabled is still 50mA, so each channel uses less + busPowerSum *= 3; + busPowerSum = busPowerSum >> 2; //same as /= 4 + } + powerSum += busPowerSum; + } + + uint32_t powerSum0 = powerSum; + powerSum *= _brightness; + + if (powerSum > powerBudget) //scale brightness down to stay in current limit + { + float scale = (float)powerBudget / (float)powerSum; + uint16_t scaleI = scale * 255; + uint8_t scaleB = (scaleI > 255) ? 255 : scaleI; + uint8_t newBri = scale8(_brightness, scaleB); + busses.setBrightness(newBri); //to keep brightness uniform, sets virtual busses too + currentMilliamps = (powerSum0 * newBri) / puPerMilliamp; + } else { + currentMilliamps = powerSum / puPerMilliamp; + busses.setBrightness(_brightness); + } + currentMilliamps += MA_FOR_ESP; //add power of ESP back to estimate + currentMilliamps += pLen; //add standby power back to estimate +} + +void WS2812FX::show(void) { + + // avoid race condition, caputre _callback value + show_callback callback = _callback; + if (callback) callback(); + + estimateCurrentAndLimitBri(); // some buses send asynchronously and this method will return before // all of the data has been sent. @@ -553,6 +555,20 @@ uint32_t WS2812FX::getLastShow(void) { return _lastShow; } +uint16_t WS2812FX::getLengthTotal(void) { + return _length; +} + +uint16_t WS2812FX::getLengthPhysical(void) { + uint16_t len = 0; + for (uint8_t b = 0; b < busses.getNumBusses(); b++) { + Bus *bus = busses.getBus(b); + if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses + len += bus->getLength(); + } + return len; +} + void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) { if (n >= MAX_NUM_SEGMENTS) return; Segment& seg = _segments[n];