From 7e9dc56209ac095328e67f823057760bad18751d Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 23 Mar 2026 21:17:26 +0100 Subject: [PATCH 1/4] Add H-bridge compatible mode for TYPE_ANALOG_2CH_HBRIDGE (mutually exclusive PWM outputs) --- wled00/bus_manager.cpp | 17 ++++++++++++++++- wled00/bus_manager.h | 3 ++- wled00/const.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 96df2d5ac1..450afc1017 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -454,6 +454,19 @@ void BusPwm::setPixelColor(unsigned pix, uint32_t c) { Bus::calculateCCT(c, _data[0], _data[1]); } break; + case TYPE_ANALOG_2CH_HBRIDGE: //warm white + cold white, relies on auto white calculation, uses H-bridge for better dimming performance at low brightness + { + uint8_t level = (Bus::_cct < 0 || Bus::_cct > 255) ? 127 : Bus::_cct; + uint8_t brightness = w; + + if (level <= 127) { + _data[0] = (map(level, 0, 127, 255, 0) * brightness) / 255; + _data[1] = 0; + } else { + _data[0] = 0; + _data[1] = (map(level, 128, 255, 0, 255) * brightness) / 255; + } + } case TYPE_ANALOG_5CH: //RGB + warm white + cold white if (cctICused) _data[4] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct; @@ -475,6 +488,7 @@ uint32_t BusPwm::getPixelColor(unsigned pix) const { case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation return RGBW32(0, 0, 0, _data[0]); case TYPE_ANALOG_2CH: //warm white + cold white + case TYPE_ANALOG_2CH_HBRIDGE: //warm white + cold white, relies on auto white calculation, uses H-bridge for better dimming performance at low brightness if (cctICused) return RGBW32(0, 0, 0, _data[0]); else return RGBW32(0, 0, 0, _data[0] + _data[1]); case TYPE_ANALOG_5CH: //RGB + warm white + cold white @@ -525,7 +539,7 @@ void BusPwm::show() { unsigned duty = (_data[i] * pwmBri) / 255; unsigned deadTime = 0; - if (_type == TYPE_ANALOG_2CH && Bus::_cctBlend == 0) { + if ((_type == TYPE_ANALOG_2CH || _type == TYPE_ANALOG_2CH_HBRIDGE) && Bus::_cctBlend == 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 @@ -579,6 +593,7 @@ std::vector BusPwm::getLEDTypes() { return { {TYPE_ANALOG_1CH, "A", PSTR("PWM White")}, {TYPE_ANALOG_2CH, "AA", PSTR("PWM CCT")}, + {TYPE_ANALOG_2CH_HBRIDGE, "AA", PSTR("PWM CCT (H-bridge)")}, {TYPE_ANALOG_3CH, "AAA", PSTR("PWM RGB")}, {TYPE_ANALOG_4CH, "AAAA", PSTR("PWM RGBW")}, {TYPE_ANALOG_5CH, "AAAAA", PSTR("PWM RGB+CCT")}, diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index a4cd370c90..f5b320870f 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -181,7 +181,8 @@ class Bus { } static constexpr bool hasCCT(uint8_t type) { return type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA || - type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_5CH || + type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_2CH_HBRIDGE || + type == TYPE_ANALOG_5CH || type == TYPE_FW1906 || type == TYPE_WS2805 || type == TYPE_SM16825; } diff --git a/wled00/const.h b/wled00/const.h index 3ffa8814c1..268e2756b1 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -325,6 +325,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define TYPE_ANALOG_MIN 41 // first usable analog type #define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel #define TYPE_ANALOG_2CH 42 //analog WW + CW +#define TYPE_ANALOG_2CH_HBRIDGE 96 //analog WW + CW, relies on auto white calculation, uses H-bridge for better dimming performance at low brightness #define TYPE_ANALOG_3CH 43 //analog RGB #define TYPE_ANALOG_4CH 44 //analog RGBW #define TYPE_ANALOG_5CH 45 //analog RGB + WW + CW From 83116980a346e592becc9bd3f158e39eaddce997 Mon Sep 17 00:00:00 2001 From: adam Date: Tue, 24 Mar 2026 22:01:01 +0100 Subject: [PATCH 2/4] break fix --- wled00/bus_manager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 450afc1017..a71de4f9c3 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -455,7 +455,6 @@ void BusPwm::setPixelColor(unsigned pix, uint32_t c) { } break; case TYPE_ANALOG_2CH_HBRIDGE: //warm white + cold white, relies on auto white calculation, uses H-bridge for better dimming performance at low brightness - { uint8_t level = (Bus::_cct < 0 || Bus::_cct > 255) ? 127 : Bus::_cct; uint8_t brightness = w; @@ -466,7 +465,7 @@ void BusPwm::setPixelColor(unsigned pix, uint32_t c) { _data[0] = 0; _data[1] = (map(level, 128, 255, 0, 255) * brightness) / 255; } - } + break; case TYPE_ANALOG_5CH: //RGB + warm white + cold white if (cctICused) _data[4] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct; From e9adf1911b2526999ca5f0f6546982b9d37cb32a Mon Sep 17 00:00:00 2001 From: adam Date: Fri, 27 Mar 2026 04:00:12 +0100 Subject: [PATCH 3/4] fix animations: use brightness instead of white balance remove TYPE_ANALOG_2CH_HBRIDGE --- wled00/bus_manager.cpp | 27 ++++++++++----------------- wled00/bus_manager.h | 3 +-- wled00/const.h | 1 - 3 files changed, 11 insertions(+), 20 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index a71de4f9c3..b37d489287 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -448,24 +448,19 @@ void BusPwm::setPixelColor(unsigned pix, uint32_t c) { break; case TYPE_ANALOG_2CH: //warm white + cold white if (cctICused) { - _data[0] = w; - _data[1] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct; + // _data[0] = w; + // _data[1] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct; + if (w < 128) { + _data[0] = map(w, 0, 127, 255, 0); + _data[1] = 0; + } else { + _data[0] = 0; + _data[1] = map(w, 128, 255, 0, 255); + } } else { Bus::calculateCCT(c, _data[0], _data[1]); } break; - case TYPE_ANALOG_2CH_HBRIDGE: //warm white + cold white, relies on auto white calculation, uses H-bridge for better dimming performance at low brightness - uint8_t level = (Bus::_cct < 0 || Bus::_cct > 255) ? 127 : Bus::_cct; - uint8_t brightness = w; - - if (level <= 127) { - _data[0] = (map(level, 0, 127, 255, 0) * brightness) / 255; - _data[1] = 0; - } else { - _data[0] = 0; - _data[1] = (map(level, 128, 255, 0, 255) * brightness) / 255; - } - break; case TYPE_ANALOG_5CH: //RGB + warm white + cold white if (cctICused) _data[4] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct; @@ -487,7 +482,6 @@ uint32_t BusPwm::getPixelColor(unsigned pix) const { case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation return RGBW32(0, 0, 0, _data[0]); case TYPE_ANALOG_2CH: //warm white + cold white - case TYPE_ANALOG_2CH_HBRIDGE: //warm white + cold white, relies on auto white calculation, uses H-bridge for better dimming performance at low brightness if (cctICused) return RGBW32(0, 0, 0, _data[0]); else return RGBW32(0, 0, 0, _data[0] + _data[1]); case TYPE_ANALOG_5CH: //RGB + warm white + cold white @@ -538,7 +532,7 @@ void BusPwm::show() { unsigned duty = (_data[i] * pwmBri) / 255; unsigned deadTime = 0; - if ((_type == TYPE_ANALOG_2CH || _type == TYPE_ANALOG_2CH_HBRIDGE) && Bus::_cctBlend == 0) { + if ((_type == TYPE_ANALOG_2CH) && Bus::_cctBlend == 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 @@ -592,7 +586,6 @@ std::vector BusPwm::getLEDTypes() { return { {TYPE_ANALOG_1CH, "A", PSTR("PWM White")}, {TYPE_ANALOG_2CH, "AA", PSTR("PWM CCT")}, - {TYPE_ANALOG_2CH_HBRIDGE, "AA", PSTR("PWM CCT (H-bridge)")}, {TYPE_ANALOG_3CH, "AAA", PSTR("PWM RGB")}, {TYPE_ANALOG_4CH, "AAAA", PSTR("PWM RGBW")}, {TYPE_ANALOG_5CH, "AAAAA", PSTR("PWM RGB+CCT")}, diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index f5b320870f..a4cd370c90 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -181,8 +181,7 @@ class Bus { } static constexpr bool hasCCT(uint8_t type) { return type == TYPE_WS2812_2CH_X3 || type == TYPE_WS2812_WWA || - type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_2CH_HBRIDGE || - type == TYPE_ANALOG_5CH || + type == TYPE_ANALOG_2CH || type == TYPE_ANALOG_5CH || type == TYPE_FW1906 || type == TYPE_WS2805 || type == TYPE_SM16825; } diff --git a/wled00/const.h b/wled00/const.h index 268e2756b1..3ffa8814c1 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -325,7 +325,6 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit"); #define TYPE_ANALOG_MIN 41 // first usable analog type #define TYPE_ANALOG_1CH 41 //single channel PWM. Uses value of brightest RGBW channel #define TYPE_ANALOG_2CH 42 //analog WW + CW -#define TYPE_ANALOG_2CH_HBRIDGE 96 //analog WW + CW, relies on auto white calculation, uses H-bridge for better dimming performance at low brightness #define TYPE_ANALOG_3CH 43 //analog RGB #define TYPE_ANALOG_4CH 44 //analog RGBW #define TYPE_ANALOG_5CH 45 //analog RGB + WW + CW From 63dd66f352eb970af0b04d847aea7221ab61185b Mon Sep 17 00:00:00 2001 From: adam Date: Fri, 27 Mar 2026 04:02:30 +0100 Subject: [PATCH 4/4] revert parenthesis --- wled00/bus_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index b37d489287..d0bebeda9d 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -532,7 +532,7 @@ void BusPwm::show() { unsigned duty = (_data[i] * pwmBri) / 255; unsigned deadTime = 0; - if ((_type == TYPE_ANALOG_2CH) && Bus::_cctBlend == 0) { + if (_type == TYPE_ANALOG_2CH && Bus::_cctBlend == 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