diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 795096c05..9a35059f3 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -427,6 +427,9 @@ BusPwm::BusPwm(BusConfig &bc) #else ledcSetup(_ledcStart + i, _frequency, _depth); ledcAttachPin(_pins[i], _ledcStart + i); + // LEDC timer reset credit @dedehai + uint8_t group = ((_ledcStart + i) / 8), channel = ((_ledcStart + i) % 8); // _ledcStart + i is always less than MAX_LED_CHANNELS/LEDC_CHANNELS + ledc_timer_rst((ledc_mode_t)group, (ledc_channel_t)channel); // reset timer so all timers are almost in sync (for phase shift) #endif } _hasRgb = hasRGB(bc.type); @@ -496,29 +499,30 @@ uint32_t BusPwm::getPixelColor(uint16_t pix) const { void BusPwm::show() { if (!_valid) return; - unsigned numPins = getPins(); - unsigned maxBri = (1<<_depth) - 1; + const unsigned numPins = getPins(); + const unsigned maxBri = (1<<_depth); // use CIE brightness formula unsigned pwmBri = (unsigned)_bri * 100; - if(pwmBri < 2040) pwmBri = ((pwmBri << _depth) + 115043) / 230087; //adding '0.5' before division for correct rounding + if (pwmBri < 2040) + pwmBri = ((pwmBri << _depth) + 115043) / 230087; //adding '0.5' before division for correct rounding else { pwmBri += 4080; float temp = (float)pwmBri / 29580; - temp = temp * temp * temp * (1<<_depth) - 1; + temp = temp * temp * temp * maxBri; pwmBri = (unsigned)temp; } // determine phase shift POC (credit @dedehai) - [[maybe_unused]] uint32_t phaseOffset = maxBri / numPins; for (unsigned i = 0; i < numPins; i++) { unsigned scaled = (_data[i] * pwmBri) / 255; if (_reversed) scaled = maxBri - scaled; #ifdef ESP8266 analogWrite(_pins[i], scaled); #else - if (_needsRefresh) { // hacked to determine if phase shifted PWM is requested + // CCT blending has to be 0 for phse shift to work (WW & CW must not overlap) + if (_type == TYPE_ANALOG_2CH && _needsRefresh && Bus::getCCTBlend() == 0) { // hacked to determine if phase shifted PWM is requested + if (scaled >= maxBri/2) scaled = maxBri/2 - 1; // safety check & add dead time of 1 pulse uint8_t group = ((_ledcStart + i) / 8), channel = ((_ledcStart + i) % 8); // _ledcStart + i is always less than MAX_LED_CHANNELS/LEDC_CHANNELS - ledc_set_duty_with_hpoint((ledc_mode_t)group, (ledc_channel_t)channel, scaled, phaseOffset*i); - ledc_update_duty((ledc_mode_t)group, (ledc_channel_t)channel); + ledc_set_duty_and_update((ledc_mode_t)group, (ledc_channel_t)channel, scaled, (maxBri / numPins)*i); } else ledcWrite(_ledcStart + i, scaled); #endif @@ -719,8 +723,8 @@ String BusManager::getLEDTypesJSONString(void) { {TYPE_WS2805, "D", PSTR("WS2805 RGBCW")}, {TYPE_SM16825, "D", PSTR("SM16825 RGBCW")}, {TYPE_WS2812_1CH_X3, "D", PSTR("WS2811 White")}, - //{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, - //{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, + //{TYPE_WS2812_2CH_X3, "D", PSTR("WS2811 CCT")}, // not implemented + //{TYPE_WS2812_WWA, "D", PSTR("WS2811 WWA")}, // not implemented {TYPE_WS2801, "2P", PSTR("WS2801")}, {TYPE_APA102, "2P", PSTR("APA102")}, {TYPE_LPD8806, "2P", PSTR("LPD8806")}, @@ -732,11 +736,15 @@ String BusManager::getLEDTypesJSONString(void) { {TYPE_ANALOG_3CH, "AAA", PSTR("PWM RGB")}, {TYPE_ANALOG_4CH, "AAAA", PSTR("PWM RGBW")}, {TYPE_ANALOG_5CH, "AAAAA", PSTR("PWM RGB+CCT")}, - //{TYPE_ANALOG_6CH, "AAAAAA", PSTR("PWM RGB+DCCT")}, - {TYPE_NET_DDP_RGB, "V", PSTR("DDP RGB (network)")}, - {TYPE_NET_ARTNET_RGB, "V", PSTR("Art-Net RGB (network)")}, - {TYPE_NET_DDP_RGBW, "V", PSTR("DDP RGBW (network)")}, - {TYPE_NET_ARTNET_RGBW, "V", PSTR("Art-Net RGBW (network)")} + //{TYPE_ANALOG_6CH, "AAAAAA", PSTR("PWM RGB+DCCT")}, // unimplementable ATM + {TYPE_NET_DDP_RGB, "N", PSTR("DDP RGB (network)")}, + {TYPE_NET_ARTNET_RGB, "N", PSTR("Art-Net RGB (network)")}, + {TYPE_NET_DDP_RGBW, "N", PSTR("DDP RGBW (network)")}, + {TYPE_NET_ARTNET_RGBW, "N", PSTR("Art-Net RGBW (network)")}, + // hypothetical extensions + //{TYPE_VIRTUAL_I2C_W, "V", PSTR("I2C White (virtual)")}, // allows setting I2C address in _pin[0] + //{TYPE_VIRTUAL_I2C_CCT, "V", PSTR("I2C CCT (virtual)")}, // allows setting I2C address in _pin[0] + //{TYPE_VIRTUAL_I2C_RGB, "V", PSTR("I2C RGB (virtual)")}, // allows setting I2C address in _pin[0] }; String json = "["; for (const auto &type : types) { diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 57d94f31a..30709e12d 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -24,7 +24,8 @@ function isAna(t) { return gT(t).t === "" || isPWM(t); } // is analog type function isDig(t) { return gT(t).t === "D" || isD2P(t); } // is digital type function isD2P(t) { return gT(t).t === "2P"; } // is digital 2 pin type - function isVir(t) { return gT(t).t === "V"; } // is virtual type + function isNet(t) { return gT(t).t === "N"; } // is network type + function isVir(t) { return gT(t).t === "V" || isNet(t); } // is virtual type function hasRGB(t) { return !!(gT(t).c & 0x01); } // has RGB function hasW(t) { return !!(gT(t).c & 0x02); } // has white channel function hasCCT(t) { return !!(gT(t).c & 0x04); } // is white CCT enabled @@ -202,12 +203,10 @@ let len = parseInt(d.getElementsByName("LC"+n)[0].value); len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too let dbl = 0; - let ch = 3; + let ch = 3*hasRGB(t) + hasW(t) + hasCCT(t); let mul = 1; if (isDig(t)) { if (is16b(t)) len *= 2; // 16 bit LEDs - if (t > 28 && t < 40) ch = 4; //RGBW - if (t == 28) ch = 5; //GRBCW if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem mul = 5; } @@ -216,7 +215,6 @@ } if (d.Sf.LD.checked) dbl = len * ch; // double buffering } - if (isVir(t) && t == 88) ch = 4; return len * ch * mul + dbl; } @@ -232,27 +230,36 @@ let p1d = ""; let off = "Off Refresh"; switch (gT(t).t.charAt(0)) { - case '2': + case '2': // 2 pin digital p1d = "Clock "+p0d; - case 'D': + // fallthrough + case 'D': // digital p0d = "Data "+p0d; break; - case 'A': - if (gT(t).t.length > 1) { - p0d = "GPIOs:"; - off = "Phase shift"; - } else gId(`dig${n}f`).style.display = "none"; + case 'A': // PWM analog + switch (gT(t).t.length) { // type length determines number of GPIO used + case 1: break; + case 2: off = "Phase shift"; + if (d.Sf["CB"].value != 0) gId(`rf${n}`).checked = 0; // disable phase shifting + gId(`rf${n}`).disabled = (d.Sf["CB"].value != 0); // prevent changes + // fallthrough + default: p0d = "GPIOs:"; break; + } + // PWM CCT allows phase shifting + gId(`dig${n}f`).style.display = (gT(t).t.length != 2) ? "none" : "inline"; break; - case 'V': + case 'N': // network p0d = "IP address:"; break; + case 'V': // virtual/non-GPIO based + p0d = "Config:" + break; } gId("p0d"+n).innerText = p0d; gId("p1d"+n).innerText = p1d; gId("off"+n).innerText = off; - // secondary pins show/hide (type string length is equivalent to number of pins used; except for virtual and on/off) - let pins = gT(t).t.length + 3*isVir(t); // fixes virtual pins to 4 - if (pins == 0) pins = 1; // fixes on/off pin + // secondary pins show/hide (type string length is equivalent to number of pins used; except for network and on/off) + let pins = Math.min(gT(t).t.length,1) + 3*isNet(t); // fixes network pins to 4 for (let p=1; p<5; p++) { var LK = d.Sf["L"+p+n]; if (!LK) continue; @@ -909,7 +916,7 @@ Swap:
CCT IC used (Athom 15W):
- CCT additive blending: % + CCT additive blending: %

Advanced

Palette blending: