From 5f37c19d42051f570b801d520c5f59616d01fbd5 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 28 Mar 2024 16:03:06 +0100 Subject: [PATCH] PSRAM fix & CCT IC - prevent PSRAM use on ESP32 rev.1 without compile fix - add runtime selection for CCT IC (Athom 15W bulb) --- platformio.ini | 2 +- tools/WLED_ESP32-wrover_4MB.csv | 6 ++--- wled00/bus_manager.cpp | 39 +++++++++++++++++---------------- wled00/cfg.cpp | 2 ++ wled00/data/settings_leds.htm | 1 + wled00/file.cpp | 2 +- wled00/json.cpp | 2 +- wled00/presets.cpp | 2 +- wled00/set.cpp | 1 + wled00/wled.cpp | 9 +++++--- wled00/wled.h | 18 ++++++++++----- wled00/xml.cpp | 1 + 12 files changed, 51 insertions(+), 34 deletions(-) mode change 100755 => 100644 wled00/set.cpp mode change 100755 => 100644 wled00/xml.cpp diff --git a/platformio.ini b/platformio.ini index c0467c8f32..345d66d91e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -389,7 +389,7 @@ platform = ${esp32.platform} board = ttgo-t7-v14-mini32 board_build.f_flash = 80000000L board_build.flash_mode = qio -board_build.partitions = ${esp32.default_partitions} +board_build.partitions = tools/WLED_ESP32-wrover_4MB.csv build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_WROVER -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html diff --git a/tools/WLED_ESP32-wrover_4MB.csv b/tools/WLED_ESP32-wrover_4MB.csv index a179a89d0e..39c88e5437 100644 --- a/tools/WLED_ESP32-wrover_4MB.csv +++ b/tools/WLED_ESP32-wrover_4MB.csv @@ -1,6 +1,6 @@ # Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, -app0, app, ota_0, 0x10000, 0x180000, -app1, app, ota_1, 0x190000,0x180000, -spiffs, data, spiffs, 0x310000,0xF0000, +app0, app, ota_0, 0x10000, 0x1A0000, +app1, app, ota_1, 0x1B0000,0x1A0000, +spiffs, data, spiffs, 0x350000,0xB0000, diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index eeb9a15e4b..88b4cc32be 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -9,6 +9,8 @@ #include "bus_wrapper.h" #include "bus_manager.h" +extern bool cctICused; + //colors.cpp uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); @@ -210,7 +212,7 @@ void BusDigital::show() { if (_data) { size_t channels = getNumberOfChannels(); - int16_t oldCCT = _cct; // temporarily save bus CCT + int16_t oldCCT = Bus::_cct; // temporarily save bus CCT for (size_t i=0; i<_len; i++) { size_t offset = i * channels; uint8_t co = _colorOrderMap.getPixelColorOrder(i+_start, _colorOrder); @@ -229,7 +231,7 @@ void BusDigital::show() { // unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT // we need to extract and appy CCT value for each pixel individually even though all buses share the same _cct variable // TODO: there is an issue if CCT is calculated from RGB value (_cct==-1), we cannot do that with double buffer - _cct = _data[offset+channels-1]; + Bus::_cct = _data[offset+channels-1]; Bus::calculateCCT(c, cctWW, cctCW); } uint16_t pix = i; @@ -241,7 +243,7 @@ void BusDigital::show() { if (_skip) PolyBus::setPixelColor(_busPtr, _iType, 0, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black #endif for (int i=1; i<_skip; i++) PolyBus::setPixelColor(_busPtr, _iType, i, 0, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); // paint skipped pixels black - _cct = oldCCT; + Bus::_cct = oldCCT; } else { if (newBri < _bri) { uint16_t hwLen = _len; @@ -291,7 +293,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid) return; uint8_t cctWW = 0, cctCW = 0; if (hasWhite()) c = autoWhiteCalc(c); - if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT + if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT if (_data) { size_t offset = pix * getNumberOfChannels(); if (hasRGB()) { @@ -302,7 +304,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) { if (hasWhite()) _data[offset++] = W(c); // unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT // we need to store CCT value for each pixel (if there is a color correction in play, convert K in CCT ratio) - if (hasCCT()) _data[offset] = _cct >= 1900 ? (_cct - 1900) >> 5 : (_cct < 0 ? 127 : _cct); // TODO: if _cct == -1 we simply ignore it + if (hasCCT()) _data[offset] = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it } else { if (_reversed) pix = _len - pix -1; pix += _skip; @@ -428,8 +430,8 @@ BusPwm::BusPwm(BusConfig &bc) void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { if (pix != 0 || !_valid) return; //only react to first pixel if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c); - if (_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) { - c = colorBalanceFromKelvin(_cct, c); //color correction from CCT + if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) { + c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT } uint8_t r = R(c); uint8_t g = G(c); @@ -441,19 +443,18 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) { _data[0] = w; break; case TYPE_ANALOG_2CH: //warm white + cold white - #ifdef WLED_USE_IC_CCT - _data[0] = w; - _data[1] = cct; - #else - Bus::calculateCCT(c, _data[0], _data[1]); - #endif + if (cctICused) { + _data[0] = w; + _data[1] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct; + } else { + Bus::calculateCCT(c, _data[0], _data[1]); + } break; case TYPE_ANALOG_5CH: //RGB + warm white + cold white - #ifdef WLED_USE_IC_CCT - _data[4] = cct; - #else - Bus::calculateCCT(c, w, _data[4]); - #endif + if (cctICused) + _data[4] = Bus::_cct < 0 || Bus::_cct > 255 ? 127 : Bus::_cct; + else + Bus::calculateCCT(c, w, _data[4]); case TYPE_ANALOG_4CH: //RGBW _data[3] = w; case TYPE_ANALOG_3CH: //standard dumb RGB @@ -618,7 +619,7 @@ BusNetwork::BusNetwork(BusConfig &bc) void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; if (_rgbw) c = autoWhiteCalc(c); - if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT + if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT uint16_t offset = pix * _UDPchannels; _data[offset] = R(c); _data[offset+1] = G(c); diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index a1794a755c..4dd1d133a9 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -110,6 +110,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { Bus::setGlobalAWMode(hw_led[F("rgbwm")] | AW_GLOBAL_DISABLED); CJSON(correctWB, hw_led["cct"]); CJSON(cctFromRgb, hw_led[F("cr")]); + CJSON(cctICused, hw_led[F("ic")]); CJSON(strip.cctBlending, hw_led[F("cb")]); Bus::setCCTBlend(strip.cctBlending); strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS @@ -767,6 +768,7 @@ void serializeConfig() { hw_led[F("ledma")] = 0; // no longer used hw_led["cct"] = correctWB; hw_led[F("cr")] = cctFromRgb; + hw_led[F("ic")] = cctICused; hw_led[F("cb")] = strip.cctBlending; hw_led["fps"] = strip.getTargetFps(); hw_led[F("rgbwm")] = Bus::getGlobalAWMode(); // global auto white mode override diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index fee523ffc9..dddedd471d 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -866,6 +866,7 @@

White management


Calculate CCT from RGB:
+ CCT IC used (Athom 15W):
CCT additive blending: %

Advanced

diff --git a/wled00/file.cpp b/wled00/file.cpp index dc41c6f12b..eae50ff1df 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -417,7 +417,7 @@ bool handleFileRead(AsyncWebServerRequest* request, String path){ if(path.endsWith("/")) path += "index.htm"; if(path.indexOf(F("sec")) > -1) return false; #ifdef ARDUINO_ARCH_ESP32 - if (psramFound() && path.endsWith(FPSTR(getPresetsFileName()))) { + if (psramSafe && psramFound() && path.endsWith(FPSTR(getPresetsFileName()))) { size_t psize; const uint8_t *presets = getPresetCache(psize); if (presets) { diff --git a/wled00/json.cpp b/wled00/json.cpp index 76cb4667f2..02eb22ba49 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -753,7 +753,7 @@ void serializeInfo(JsonObject root) root[F("freeheap")] = ESP.getFreeHeap(); #if defined(ARDUINO_ARCH_ESP32) - if (psramFound()) root[F("psram")] = ESP.getFreePsram(); + if (psramSafe && psramFound()) root[F("psram")] = ESP.getFreePsram(); #endif root[F("uptime")] = millis()/1000 + rolloverMillis*4294967; diff --git a/wled00/presets.cpp b/wled00/presets.cpp index 857b2fbb38..2916d337a5 100644 --- a/wled00/presets.cpp +++ b/wled00/presets.cpp @@ -56,7 +56,7 @@ static void doSaveState() { size_t len = measureJson(*pDoc) + 1; DEBUG_PRINTLN(len); // if possible use SPI RAM on ESP32 - if (psramFound()) + if (psramSafe && psramFound()) tmpRAMbuffer = (char*) ps_malloc(len); else tmpRAMbuffer = (char*) malloc(len); diff --git a/wled00/set.cpp b/wled00/set.cpp old mode 100755 new mode 100644 index 6e7064bb30..9b3b6bea79 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -123,6 +123,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) autoSegments = request->hasArg(F("MS")); correctWB = request->hasArg(F("CCT")); cctFromRgb = request->hasArg(F("CR")); + cctICused = request->hasArg(F("IC")); strip.cctBlending = request->arg(F("CB")).toInt(); Bus::setCCTBlend(strip.cctBlending); Bus::setGlobalAWMode(request->arg(F("AW")).toInt()); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 878eb26a4b..7b753da3b4 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -241,7 +241,7 @@ void WLED::loop() DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime()); DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap()); #if defined(ARDUINO_ARCH_ESP32) - if (psramFound()) { + if (psramSafe && psramFound()) { DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); } @@ -367,9 +367,12 @@ void WLED::setup() DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); #if defined(ARDUINO_ARCH_ESP32) - pDoc = new PSRAMDynamicJsonDocument((psramFound() ? 2 : 1)*JSON_BUFFER_SIZE); + #ifndef BOARD_HAS_PSRAM + if (psramFound() && ESP.getChipRevision() < 3) psramSafe = false; + #endif + pDoc = new PSRAMDynamicJsonDocument((psramSafe && psramFound() ? 2 : 1)*JSON_BUFFER_SIZE); // if the above fails requestJsonBufferLock() will always return false preventing crashes - if (psramFound()) { + if (psramSafe && psramFound()) { DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); } diff --git a/wled00/wled.h b/wled00/wled.h index 1361f9f7eb..35b99260a0 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2403260 +#define VERSION 2403280 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -159,14 +159,15 @@ // There is a code that will still not use PSRAM though: // AsyncJsonResponse is a derived class that implements DynamicJsonDocument (AsyncJson-v6.h) #if defined(ARDUINO_ARCH_ESP32) +extern bool psramSafe; struct PSRAM_Allocator { void* allocate(size_t size) { - if (psramFound()) return ps_malloc(size); // use PSRAM if it exists - else return malloc(size); // fallback + if (psramSafe && psramFound()) return ps_malloc(size); // use PSRAM if it exists + else return malloc(size); // fallback } void* reallocate(void* ptr, size_t new_size) { - if (psramFound()) return ps_realloc(ptr, new_size); // use PSRAM if it exists - else return realloc(ptr, new_size); // fallback + if (psramSafe && psramFound()) return ps_realloc(ptr, new_size); // use PSRAM if it exists + else return realloc(ptr, new_size); // fallback } void deallocate(void* pointer) { free(pointer); @@ -348,6 +349,11 @@ WLED_GLOBAL bool useGlobalLedBuffer _INIT(true); // double buffering enabled on #endif WLED_GLOBAL bool correctWB _INIT(false); // CCT color correction of RGB color WLED_GLOBAL bool cctFromRgb _INIT(false); // CCT is calculated from RGB instead of using seg.cct +#ifdef WLED_USE_IC_CCT +WLED_GLOBAL bool cctICused _INIT(true); // CCT IC used (Athom 15W bulbs) +#else +WLED_GLOBAL bool cctICused _INIT(false); // CCT IC used (Athom 15W bulbs) +#endif WLED_GLOBAL bool gammaCorrectCol _INIT(true); // use gamma correction on colors WLED_GLOBAL bool gammaCorrectBri _INIT(false); // use gamma correction on brightness WLED_GLOBAL float gammaCorrectVal _INIT(2.8f); // gamma correction value @@ -705,6 +711,8 @@ WLED_GLOBAL byte optionType; WLED_GLOBAL bool doSerializeConfig _INIT(false); // flag to initiate saving of config WLED_GLOBAL bool doReboot _INIT(false); // flag to initiate reboot from async handlers +WLED_GLOBAL bool psramSafe _INIT(true); // is it safe to use PSRAM (on ESP32 rev.1; compiler fix used "-mfix-esp32-psram-cache-issue") + // status led #if defined(STATUSLED) WLED_GLOBAL unsigned long ledStatusLastMillis _INIT(0); diff --git a/wled00/xml.cpp b/wled00/xml.cpp old mode 100755 new mode 100644 index fc754c4a24..c91f0dd7e8 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -360,6 +360,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('c',SET_F("MS"),autoSegments); sappend('c',SET_F("CCT"),correctWB); + sappend('c',SET_F("IC"),cctICused); sappend('c',SET_F("CR"),cctFromRgb); sappend('v',SET_F("CB"),strip.cctBlending); sappend('v',SET_F("FR"),strip.getTargetFps());