diff --git a/wled00/file.cpp b/wled00/file.cpp index d3727d16..e2ae00bb 100644 --- a/wled00/file.cpp +++ b/wled00/file.cpp @@ -8,6 +8,7 @@ #if WLED_FS != LITTLEFS && ESP_IDF_VERSION_MAJOR < 4 #include "esp_spiffs.h" #endif +//#define yield() {delay(0);} // WLEDMM yield() is completely unnecessary on esp32, but delay(0) can reduce task contention #endif //WLEDMM seems that 256 is indeed the optimal buffer length @@ -37,7 +38,20 @@ static File f; // don't export to other cpp files void closeFile() { #ifdef ARDUINO_ARCH_ESP32 // WLEDMM: file.close() triggers flash writing. While flash is writing, the NPB RMT driver cannot fill its buffer which may create glitches. + // WLEDMM more precisely (thanks to a web research done by AI): + // the RMT peripheral itself doesn’t stall, but the refill path often does. In Arduino-ESP32/WLED + // typical builds, close() that commits flash writes frequently causes enough blocking that the LED pipeline under-runs, resulting in visible glitches. + // So the assumption is practically correct for this project context. + // --> with neopixelBus 2.7.5, the practical ISR stall budget is about 0.08–0.12 ms — far less than LittleFS flash commit times. + // typical flash write "commit" times are between 0.5ms and 10ms, but they can be a few 100ms in worst case + // --> file reads rarely cause refill stalls compared to writes, but large/fragmented reads can still exceed the ~0.08–0.12 ms budget. + // esp32 recommendations: use f.setBufferSize() (512–1024 for reads is reasonable); use delay(0) after file reads, to reduce task contention + + if (!f) {doCloseFile = false; return;} // WLEDMM only do all this hick-hack when f is an open file + unsigned long t_wait = millis(); + bool oldLock = suspendStripService; + if (strip.isUpdating()) suspendStripService = true; // WLEDMM schedule short pause to prevent LEDs glitching during flash write while(strip.isUpdating() && (millis() - t_wait < 72)) delay(1); // WLEDMM try to catch a moment when strip is idle while(strip.isUpdating() && (millis() - t_wait < 96)) delay(0); // try harder //if (strip.isUpdating()) USER_PRINTLN("closeFile: strip still updating."); @@ -47,7 +61,12 @@ void closeFile() { DEBUGFS_PRINT(F("Close -> ")); uint32_t s = millis(); #endif + if ((suspendStripService == false) && (oldLock == true)) oldLock = false; // update in case of parallel lock release by another task f.close(); + #ifdef ARDUINO_ARCH_ESP32 + delay(1); // might help + #endif + suspendStripService = oldLock; // restore previous lock DEBUGFS_PRINTF("took %d ms\n", millis() - s); doCloseFile = false; } @@ -61,7 +80,7 @@ static bool bufferedFind(const char *target, bool fromStart = true) { uint32_t s = millis(); #endif - if (!f || !f.size()) return false; + if (!f || !f.size()) return false; // fast return when current file closed, or file size is zero size_t targetLen = strlen(target); size_t index = 0; @@ -466,11 +485,11 @@ static const uint8_t *getPresetCache(size_t &size) { #endif // WLEDMM -static bool haveLedmapFile = true; -static bool haveIndexFile = true; -static bool haveSkinFile = true; -static bool haveICOFile = true; -static bool haveCpalFile = true; +static volatile bool haveLedmapFile = true; +static volatile bool haveIndexFile = true; +static volatile bool haveSkinFile = true; +static volatile bool haveICOFile = true; +static volatile bool haveCpalFile = true; void invalidateFileNameCache() { // reset "file not found" cache haveLedmapFile = true; haveIndexFile = true; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index d778251b..a91280e5 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -99,7 +99,11 @@ void WLED::reset() #endif long dly = millis(); while (millis() - dly < 450) { +#ifdef ARDUINO_ARCH_ESP32 + delay(2); // yield => BS +#else yield(); // enough time to send response to client +#endif } applyBri(); USER_PRINTLN(F("\nWLED RESTART\n")); @@ -191,6 +195,9 @@ void WLED::loop() reset(); if (doCloseFile) { +#ifdef ARDUINO_ARCH_ESP32 + delay(0); // yield => BS +#endif closeFile(); yield(); } @@ -203,7 +210,11 @@ void WLED::loop() #endif handleNightlight(); handlePlaylist(); +#ifdef ARDUINO_ARCH_ESP32 + delay(0); // yield => BS +#else yield(); +#endif #ifndef WLED_DISABLE_HUESYNC handleHue(); @@ -211,7 +222,11 @@ void WLED::loop() #endif handlePresets(); +#ifdef ARDUINO_ARCH_ESP32 + delay(0); // yield => BS +#else yield(); +#endif #if defined(_MoonModules_WLED_) && defined(WLEDMM_FASTPATH) #ifdef WLED_DEBUG diff --git a/wled00/wled.h b/wled00/wled.h index dd1ba6da..2778ed21 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -714,9 +714,9 @@ WLED_GLOBAL uint16_t olen _INIT(0); // General filesystem WLED_GLOBAL size_t fsBytesUsed _INIT(0); WLED_GLOBAL size_t fsBytesTotal _INIT(0); -WLED_GLOBAL unsigned long presetsModifiedTime _INIT(0L); +WLED_GLOBAL volatile unsigned long presetsModifiedTime _INIT(0L); WLED_GLOBAL JsonDocument* fileDoc; -WLED_GLOBAL bool doCloseFile _INIT(false); +WLED_GLOBAL volatile bool doCloseFile _INIT(false); // presets WLED_GLOBAL byte currentPreset _INIT(0);