From 85e2f7eb34458aeda38e02e8bcf9a10e12260d9f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 2 Sep 2024 17:53:15 +0200 Subject: [PATCH 1/6] fixed offsets and inverted signal plus dead time --- wled00/bus_manager.cpp | 63 ++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 4d12c93b6..8428e1266 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -410,6 +410,7 @@ BusPwm::BusPwm(BusConfig &bc) { if (!isPWM(bc.type)) return; unsigned numPins = numPWMPins(bc.type); + unsigned dithering = 0; _frequency = bc.frequency ? bc.frequency : WLED_PWM_FREQ; // duty cycle resolution (_depth) can be extracted from this formula: CLOCK_FREQUENCY > _frequency * 2^_depth for (_depth = MAX_BIT_WIDTH; _depth > 8; _depth--) if (((CLOCK_FREQUENCY/_frequency) >> _depth) > 0) break; @@ -428,7 +429,10 @@ BusPwm::BusPwm(BusConfig &bc) pinManager.deallocateMultiplePins(pins, numPins, PinOwner::BusPwm); return; } - if (_needsRefresh) _depth = 8; // fixed 8 bit depth with 4 bit dithering (ESP8266 has no hardware to support dithering) + if (_needsRefresh) { + _depth = 12; // fixed 8 bit depth PWM with 4 bit dithering (ESP8266 has no hardware to support dithering) + dithering = 4; + } #endif for (unsigned i = 0; i < numPins; i++) { @@ -437,7 +441,7 @@ BusPwm::BusPwm(BusConfig &bc) pinMode(_pins[i], OUTPUT); #else unsigned channel = _ledcStart + i; - ledcSetup(channel, _frequency, _depth); + ledcSetup(channel, _frequency, _depth - dithering); ledcAttachPin(_pins[i], channel); // LEDC timer reset credit @dedehai uint8_t group = (channel / 8), timer = ((channel / 2) % 4); // same fromula as in ledcSetup() @@ -511,8 +515,11 @@ uint32_t BusPwm::getPixelColor(uint16_t pix) const { void BusPwm::show() { if (!_valid) return; + bool dithering = _needsRefresh; // avoid working with bitfield const unsigned numPins = getPins(); - const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) + const unsigned maxBri = (1<<_depth) + 1; // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) note: +1 ensures 'full on' (else there is one low pulse period at 100% dutycycle) + const unsigned bithsift = dithering * 4; + //const unsigned maxBri = (1<<_depth) << (dithering*4); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) // use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness // the formula is based on 12 bit resolution as there is no need for greater precision @@ -525,41 +532,37 @@ void BusPwm::show() { // cubic response for values [21-255] pwmBri += 4080; float temp = (float)pwmBri / 29580.0f; - temp = temp * temp * temp * 4095.0f; + temp = temp * temp * temp * (float)maxBri; pwmBri = (unsigned)temp; } // pwmBri is in range [0-4095] // determine phase shift [[maybe_unused]] unsigned phaseOffset = maxBri / numPins; // (maxBri is at _depth resolution) - // we will be phase shifting every channel by fixed amount (i times /2 or /3 or /4 or /5) - // phase shifting is only mandatory when using H-bridge to drive reverse-polarity PWM CCT (2 wire) LED type (with 180° phase) + + unsigned phaseOffset = 0; + // we will be phase shifting every channel by previous pulse length (plus dead time if required) + // phase shifting is only mandatory when using H-bridge to drive reverse-polarity PWM CCT (2 wire) LED type // CCT additive blending must be 0 (WW & CW must not overlap) in such case // for all other cases it will just try to "spread" the load on PSU - [[maybe_unused]] bool cctOverlap = (_type == TYPE_ANALOG_2CH) && (_data[0]+_data[1] >= 254); // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) - bool dithering = _needsRefresh; // avoid working with bitfield for (unsigned i = 0; i < numPins; i++) { - unsigned scaled = (_data[i] * pwmBri) / 255; // scaled is at 12 bit depth (same as pwmBri) - // adjust "scaled" value (to fit resolution bounds) - if (_depth < 12 && !dithering) scaled >>= 12 - _depth; // normalize scaled value (if not using dithering) - else if (_depth > 12) scaled <<= _depth - 12; // scale to _depth if using >12 bit - if (_reversed) scaled = maxBri - scaled; + unsigned scaled = (_data[i] * pwmBri) / 255; + if (_reversed) scaled = maxBri - scaled; // scaled is now at _depth resolution (8-14 bits) except when using dithering, 12 bit in such case #ifdef ESP8266 analogWrite(_pins[i], scaled); #else unsigned channel = _ledcStart + i; - // prevent overlapping PWM signals for H-bridge - // pinManager will make sure both LEDC channels are in the same speed group and sharing the same timer - // so we only need to take care of shortening the signal at 50% distribution for 1 pulse - if (cctOverlap && Bus::getCCTBlend() == 0) { - unsigned shift = (dithering*4); - unsigned briLimit = phaseOffset << shift; // expand limit if using dithering - if (scaled >= briLimit) scaled = briLimit - (1<> bithsift) + 1; // fixed 180°, add 1 pulse for dead time (min pulse with dithering is 8bit) + phaseOffset += 2 + (scaled >> bithsift); // offset to cascade the signals, dithering requires two pulses and in non-dithering the extra pulse does not hurt + if(phaseOffset >= maxBri >> bithsift) phaseOffset = 0; // offset it out of bounds, reset + + Serial.print(" maxbri = "); + Serial.print(maxBri); + Serial.print(" offset = "); + Serial.print(phaseOffset); + Serial.print(" bit depth = "); + Serial.print(_depth); + Serial.print(" freq = "); + Serial.print(_frequency); + Serial.print(" scaled= "); + Serial.println(scaled); + Serial.print(" duty = "); + Serial.println(LEDC.channel_group[gr].channel[ch].duty.duty); + #endif } + Serial.println("*********"); } uint8_t BusPwm::getPins(uint8_t* pinArray) const { From be7475fe669def0a0ad4b25080de59f18dd50bf7 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 2 Sep 2024 22:06:46 +0200 Subject: [PATCH 2/6] bugfixes, removed debug printout --- wled00/bus_manager.cpp | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 8428e1266..ba36eb12b 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -533,13 +533,8 @@ void BusPwm::show() { pwmBri += 4080; float temp = (float)pwmBri / 29580.0f; temp = temp * temp * temp * (float)maxBri; - pwmBri = (unsigned)temp; + pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri] } - // pwmBri is in range [0-4095] - - // determine phase shift - [[maybe_unused]] unsigned phaseOffset = maxBri / numPins; // (maxBri is at _depth resolution) - unsigned phaseOffset = 0; // we will be phase shifting every channel by previous pulse length (plus dead time if required) // phase shifting is only mandatory when using H-bridge to drive reverse-polarity PWM CCT (2 wire) LED type @@ -575,27 +570,10 @@ void BusPwm::show() { LEDC_MUTEX_UNLOCK(); ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch); - - phaseOffset += ((scaled + (maxBri - scaled) / 2) >> bithsift) + 1; // fixed 180°, add 1 pulse for dead time (min pulse with dithering is 8bit) phaseOffset += 2 + (scaled >> bithsift); // offset to cascade the signals, dithering requires two pulses and in non-dithering the extra pulse does not hurt - if(phaseOffset >= maxBri >> bithsift) phaseOffset = 0; // offset it out of bounds, reset - - Serial.print(" maxbri = "); - Serial.print(maxBri); - Serial.print(" offset = "); - Serial.print(phaseOffset); - Serial.print(" bit depth = "); - Serial.print(_depth); - Serial.print(" freq = "); - Serial.print(_frequency); - Serial.print(" scaled= "); - Serial.println(scaled); - Serial.print(" duty = "); - Serial.println(LEDC.channel_group[gr].channel[ch].duty.duty); - + if(phaseOffset >= maxBri >> bithsift) phaseOffset = 0; // offset it out of bounds, reset TODO: maybe this should be (maxBri-1), need to test #endif } - Serial.println("*********"); } uint8_t BusPwm::getPins(uint8_t* pinArray) const { From 2cc0aceac7ad08d45cbb1e981c9ae203cf349470 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 3 Sep 2024 19:14:50 +0200 Subject: [PATCH 3/6] Bugfixes - fixed maxBri value - fixed overflow in dead time subtraction - deadtime and offset now also work if signals are inverted (_reversed) --- wled00/bus_manager.cpp | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index ba36eb12b..2756cc946 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -517,10 +517,8 @@ void BusPwm::show() { if (!_valid) return; bool dithering = _needsRefresh; // avoid working with bitfield const unsigned numPins = getPins(); - const unsigned maxBri = (1<<_depth) + 1; // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) note: +1 ensures 'full on' (else there is one low pulse period at 100% dutycycle) + const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) const unsigned bithsift = dithering * 4; - //const unsigned maxBri = (1<<_depth) << (dithering*4); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) - // use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness // the formula is based on 12 bit resolution as there is no need for greater precision // see: https://en.wikipedia.org/wiki/Lightness @@ -540,38 +538,37 @@ void BusPwm::show() { // phase shifting is only mandatory when using H-bridge to drive reverse-polarity PWM CCT (2 wire) LED type // CCT additive blending must be 0 (WW & CW must not overlap) in such case // for all other cases it will just try to "spread" the load on PSU - // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) - for (unsigned i = 0; i < numPins; i++) { unsigned scaled = (_data[i] * pwmBri) / 255; - if (_reversed) scaled = maxBri - scaled; + // prevent overlapping PWM signals (required for H-bridge driven CCT strips) + // pinManager will make sure both LEDC channels are in the same speed group and sharing the same timer (i.e. they are in sync) + // we only need to take care of shortening the signal at full brightness, otherwise the pulses overlap with CCTBlend() == 0 + signed deadtime = 0; // add dead time when brightness is 100% (when using dithering, two full 8bit pulses are required, in non-dithering one extra pulse does not hurt at all note: actually could add dead time only if global brightness is also at 255 + if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { + deadtime = 2 << bithsift; + if (_bri == 255 && scaled >= deadtime) scaled -= deadtime; + //another way (maybe more elegant?) of doing this would be to limit bus brightness to 254 if CCT is enabled with zero blending + if(_reversed) deadtime = -deadtime; // need to invert dead time at this point: phaseshift needs to go the opposite way so low signals dont overlap + } + if (_reversed) scaled = maxBri - scaled; // scaled is now at _depth resolution (8-14 bits) except when using dithering, 12 bit in such case #ifdef ESP8266 analogWrite(_pins[i], scaled); #else - unsigned channel = _ledcStart + i; - // prevent overlapping PWM signals (required for H-bridge driven CCT strips) - // pinManager will make sure both LEDC channels are in the same speed group and sharing the same timer (i.e. they are in sync) - // we only need to take care of shortening the signal at full brightness, otherwise the pulses cannot overlap with CCTBlend() == 0 - if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { - if (_bri==255) scaled -= 2 << bithsift; // add dead time when brightness is 100% (when using dithering, two full 8bit pulses are required, in non-dithering one extra pulse does not hurt at all note: actually could add dead time only if global brightness is also at 255 - //another way (maybe more elegant?) of doing this would be to limit bus brightness to 254 if CCT is enabled with zero blending ( - } + unsigned channel = _ledcStart + i; unsigned gr = channel/8; // high/low speed group unsigned ch = channel%8; // group channel // directly write to LEDC struct as there is no HAL exposed function for dithering // duty has 20 bit resolution with 4 fractional bits (24 bits in total) - // _depth is 8 bit in this case (and maxBri==256), scaled is still at 12 bit LEDC_MUTEX_LOCK(); - LEDC.channel_group[gr].channel[ch].duty.duty = scaled << ((!dithering)*4); // write full 12 bit value (4 dithering bits) - LEDC.channel_group[gr].channel[ch].hpoint.hpoint = phaseOffset*i; // phaseOffset is at _depth resolution (8 bit) + LEDC.channel_group[gr].channel[ch].duty.duty = scaled << ((!dithering)*4); // lowest 4 bits are used for dithering, shift by 4 bits if not using dithering + LEDC.channel_group[gr].channel[ch].hpoint.hpoint = phaseOffset; LEDC_MUTEX_UNLOCK(); ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch); - - phaseOffset += 2 + (scaled >> bithsift); // offset to cascade the signals, dithering requires two pulses and in non-dithering the extra pulse does not hurt - if(phaseOffset >= maxBri >> bithsift) phaseOffset = 0; // offset it out of bounds, reset TODO: maybe this should be (maxBri-1), need to test + phaseOffset += ((scaled + deadtime) >> bithsift); // offset to cascade the signals, add dead time if required (to ensure pulses do not overlap) + if(phaseOffset >= maxBri >> bithsift) phaseOffset = 0; // offset it out of bounds, reset #endif } } From b1e58dd10dd326f619b3c983174d4cf8e50aa3b9 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 3 Sep 2024 22:28:21 +0200 Subject: [PATCH 4/6] Optimisations - renamed variables - some tuning --- wled00/bus_manager.cpp | 55 +++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 2756cc946..f9dd847d7 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -429,6 +429,7 @@ BusPwm::BusPwm(BusConfig &bc) pinManager.deallocateMultiplePins(pins, numPins, PinOwner::BusPwm); return; } + // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) if (_needsRefresh) { _depth = 12; // fixed 8 bit depth PWM with 4 bit dithering (ESP8266 has no hardware to support dithering) dithering = 4; @@ -515,10 +516,13 @@ uint32_t BusPwm::getPixelColor(uint16_t pix) const { void BusPwm::show() { if (!_valid) return; - bool dithering = _needsRefresh; // avoid working with bitfield + // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) + // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) + const bool dithering = _needsRefresh; // avoid working with bitfield const unsigned numPins = getPins(); - const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) - const unsigned bithsift = dithering * 4; + const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8) + const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits) + // use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness // the formula is based on 12 bit resolution as there is no need for greater precision // see: https://en.wikipedia.org/wiki/Lightness @@ -533,42 +537,37 @@ void BusPwm::show() { temp = temp * temp * temp * (float)maxBri; pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri] } - unsigned phaseOffset = 0; + + [[maybe_unused]] unsigned hPoint = 0; // phase shift (0 - maxBri) // we will be phase shifting every channel by previous pulse length (plus dead time if required) // phase shifting is only mandatory when using H-bridge to drive reverse-polarity PWM CCT (2 wire) LED type - // CCT additive blending must be 0 (WW & CW must not overlap) in such case + // CCT additive blending must be 0 (WW & CW will not overlap) otherwise signals *will* overlap // for all other cases it will just try to "spread" the load on PSU - // if _needsRefresh is true (UI hack) we are using dithering (credit @dedehai & @zalatnaicsongor) - // https://github.com/Aircoookie/WLED/pull/4115 and https://github.com/zalatnaicsongor/WLED/pull/1) + // Phase shifting requires that LEDC timers are synchronised (see setup()). For PWM CCT (and H-bridge) it is + // also mandatory that both channels use the same timer (pinManager takes care of that). for (unsigned i = 0; i < numPins; i++) { - unsigned scaled = (_data[i] * pwmBri) / 255; - // prevent overlapping PWM signals (required for H-bridge driven CCT strips) - // pinManager will make sure both LEDC channels are in the same speed group and sharing the same timer (i.e. they are in sync) - // we only need to take care of shortening the signal at full brightness, otherwise the pulses overlap with CCTBlend() == 0 - signed deadtime = 0; // add dead time when brightness is 100% (when using dithering, two full 8bit pulses are required, in non-dithering one extra pulse does not hurt at all note: actually could add dead time only if global brightness is also at 255 - if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { - deadtime = 2 << bithsift; - if (_bri == 255 && scaled >= deadtime) scaled -= deadtime; - //another way (maybe more elegant?) of doing this would be to limit bus brightness to 254 if CCT is enabled with zero blending - if(_reversed) deadtime = -deadtime; // need to invert dead time at this point: phaseshift needs to go the opposite way so low signals dont overlap - } - if (_reversed) scaled = maxBri - scaled; - // scaled is now at _depth resolution (8-14 bits) except when using dithering, 12 bit in such case + unsigned duty = (_data[i] * pwmBri) / 255; + if (_reversed) duty = maxBri - duty; #ifdef ESP8266 - analogWrite(_pins[i], scaled); + analogWrite(_pins[i], duty); #else - unsigned channel = _ledcStart + i; + unsigned deadTime = 0; + if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { + // add dead time between signals (when using dithering, two full 8bit pulses are required) + deadTime = (1+dithering) << bitShift; + // we only need to take care of shortening the signal at (almost) full brightness otherwise pulses may overflow hPoint + if (_bri >= 254 && duty + deadTime + hPoint >= maxBri) duty = maxBri - hPoint - deadTime; // shorten duty if overflowing + } + unsigned channel = _ledcStart + i; unsigned gr = channel/8; // high/low speed group unsigned ch = channel%8; // group channel // directly write to LEDC struct as there is no HAL exposed function for dithering // duty has 20 bit resolution with 4 fractional bits (24 bits in total) - LEDC_MUTEX_LOCK(); - LEDC.channel_group[gr].channel[ch].duty.duty = scaled << ((!dithering)*4); // lowest 4 bits are used for dithering, shift by 4 bits if not using dithering - LEDC.channel_group[gr].channel[ch].hpoint.hpoint = phaseOffset; - LEDC_MUTEX_UNLOCK(); + LEDC.channel_group[gr].channel[ch].duty.duty = duty << ((!dithering)*4); // lowest 4 bits are used for dithering, shift by 4 bits if not using dithering + LEDC.channel_group[gr].channel[ch].hpoint.hpoint = hPoint >> bitShift; // hPoint is at _depth resolution (needs shifting if dithering) ledc_update_duty((ledc_mode_t)gr, (ledc_channel_t)ch); - phaseOffset += ((scaled + deadtime) >> bithsift); // offset to cascade the signals, add dead time if required (to ensure pulses do not overlap) - if(phaseOffset >= maxBri >> bithsift) phaseOffset = 0; // offset it out of bounds, reset + hPoint += duty + deadTime; // offset to cascade the signals + if (hPoint >= maxBri) hPoint = 0; // offset it out of bounds, reset #endif } } From d3c31c52a27faaefb6bd1aca5bdc3b76ea4431fd Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 4 Sep 2024 18:03:52 +0200 Subject: [PATCH 5/6] found a better way of deadTime subtraction, fixed inverted signals --- wled00/bus_manager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index f9dd847d7..e18d1023c 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -546,18 +546,20 @@ void BusPwm::show() { // Phase shifting requires that LEDC timers are synchronised (see setup()). For PWM CCT (and H-bridge) it is // also mandatory that both channels use the same timer (pinManager takes care of that). for (unsigned i = 0; i < numPins; i++) { - unsigned duty = (_data[i] * pwmBri) / 255; - if (_reversed) duty = maxBri - duty; + unsigned duty = (_data[i] * pwmBri) / 255; #ifdef ESP8266 + if (_reversed) duty = maxBri - duty; analogWrite(_pins[i], duty); #else unsigned deadTime = 0; if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { // add dead time between signals (when using dithering, two full 8bit pulses are required) deadTime = (1+dithering) << bitShift; - // we only need to take care of shortening the signal at (almost) full brightness otherwise pulses may overflow hPoint - if (_bri >= 254 && duty + deadTime + hPoint >= maxBri) duty = maxBri - hPoint - deadTime; // shorten duty if overflowing + // we only need to take care of shortening the signal at (almost) full brightness otherwise pulses may overlap + if (_bri >= 254 && duty >= maxBri / 2 && duty < maxBri) duty -= deadTime << 1; // shorten duty of larger signal except if full on + if(_reversed) deadTime = -deadTime; // need to invert dead time to make phaseshift go the opposite way so low signals dont overlap } + if (_reversed) duty = maxBri - duty; unsigned channel = _ledcStart + i; unsigned gr = channel/8; // high/low speed group unsigned ch = channel%8; // group channel From 092a5a1ca34c2c17c353c6c0c87550cf831a9e80 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 4 Sep 2024 20:54:44 +0200 Subject: [PATCH 6/6] Unsigned fix --- wled00/bus_manager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index e18d1023c..ef7df007d 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -551,13 +551,13 @@ void BusPwm::show() { if (_reversed) duty = maxBri - duty; analogWrite(_pins[i], duty); #else - unsigned deadTime = 0; + int deadTime = 0; if (_type == TYPE_ANALOG_2CH && Bus::getCCTBlend() == 0) { // add dead time between signals (when using dithering, two full 8bit pulses are required) deadTime = (1+dithering) << bitShift; // we only need to take care of shortening the signal at (almost) full brightness otherwise pulses may overlap if (_bri >= 254 && duty >= maxBri / 2 && duty < maxBri) duty -= deadTime << 1; // shorten duty of larger signal except if full on - if(_reversed) deadTime = -deadTime; // need to invert dead time to make phaseshift go the opposite way so low signals dont overlap + if (_reversed) deadTime = -deadTime; // need to invert dead time to make phaseshift go the opposite way so low signals dont overlap } if (_reversed) duty = maxBri - duty; unsigned channel = _ledcStart + i;