From 1bc0c7ab39e82fc0a20b1946530af394f3b689ce Mon Sep 17 00:00:00 2001 From: Kaj Schittecat Date: Fri, 31 Jul 2026 11:28:57 +0200 Subject: [PATCH] p4: route prefs off internal-flash NVS onto the SD card (#167) The T-Display P4 never called SdNvsPrefs::useFile, so although contacts and chat history correctly moved to the SD card, every settings/thread-state write still landed in internal-flash NVS. On this board that is not just wear: the DSI panel streams its framebuffer continuously out of PSRAM, and an internal-flash write visibly disturbs it -- the whole-screen flash reported as #167. The trigger list matches exactly: a message arriving, opening a chat with unread messages, and deleting a contact (which writes repeatedly, hence flickering for the whole operation). Map panning writes tiles to SD continuously and never flickers, which is what pinned it down. Only when a card is mounted. With no card there is nowhere better to put prefs, and moving them from NVS to the internal FAT partition would trade one flash write for another while needlessly relocating existing users' settings. Old NVS values still load and migrate on their next save, so this is transparent. Fixing it also required an include-path fix. The vendored core component publishes core/src publicly and still carries OLD copies of the headers whose .cpp files it deliberately excludes because our src/ ships them. main.cpp's angle includes therefore resolved to the stale core headers while the linker bound the new objects, so anything added since the core tag looked like it did not exist (SdNvsPrefs::useFile, touchPrefsReload). Putting the repo's src/ ahead of the core dir in main's INCLUDE_DIRS makes main.cpp and the app layer agree. Verified on device: "[PREFS] backend = FILE /meshcomod". Co-Authored-By: Claude Opus 4.8 (1M context) --- tdisplay_p4/main/CMakeLists.txt | 8 ++++++++ tdisplay_p4/main/main.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/tdisplay_p4/main/CMakeLists.txt b/tdisplay_p4/main/CMakeLists.txt index 2d4ccde..2b47f75 100644 --- a/tdisplay_p4/main/CMakeLists.txt +++ b/tdisplay_p4/main/CMakeLists.txt @@ -19,6 +19,14 @@ idf_component_register( c6_at # AT-over-SDIO Wi-Fi/BLE driver for the on-board ESP32-C6 (P4-only) INCLUDE_DIRS "." + # The repo's own src/ MUST come before the meshcore component's include dir. The vendored + # core publishes core/src publicly and still carries OLD copies of the headers whose .cpp + # files it deliberately excludes (SdNvsPrefs, TouchPrefsStore, ...) because our src/ ships + # them. Without this line an angle include here resolves to the stale core header while the + # linker binds the new object -- so anything added to those headers since the core tag looks + # like it does not exist (SdNvsPrefs::useFile, touchPrefsReload). Same headers the app + # component compiles against, so main.cpp and the app layer now agree. + "${CMAKE_CURRENT_LIST_DIR}/../../src" ) # The vendored MeshCore core + Arduino libs trip IDF's blanket -Werror=all. A bare diff --git a/tdisplay_p4/main/main.cpp b/tdisplay_p4/main/main.cpp index 8a7f393..4bb78d1 100644 --- a/tdisplay_p4/main/main.cpp +++ b/tdisplay_p4/main/main.cpp @@ -21,6 +21,7 @@ #include #include // wifiConfig* (runtime Wi-Fi state the loop drives) #include // touchPrefsBuildLocalTz + WIFI_CONFIG_* sizes +#include // route prefs off internal-flash NVS onto the SD card #include "esp_hosted.h" #include "esp_netif.h" #include "esp_event.h" @@ -212,6 +213,30 @@ static void wadameshSetup() { } store.useSdMmcStorage(); } + + // Route the touch settings + Wi-Fi creds off internal-flash NVS onto the SD card, the same way + // every S3 board does (src/main.cpp). This board never did it, so although contacts and chat + // history correctly moved to SD above, EVERY pref write still hit NVS in internal flash. + // + // That matters here beyond wear: this panel is a DSI video one whose framebuffer is streamed + // continuously out of PSRAM, and an internal-flash write visibly disturbs it -- a whole-screen + // flash, reported as #167. The trigger list is exactly the pref/thread-state writes: a message + // arriving, opening a chat that has unread messages, and deleting a contact (which writes + // repeatedly and so flickers for the whole operation). Writes that go to the SD card instead + // never do it -- panning the map downloads and writes tiles continuously with no flicker at all, + // which is what pinned this down. + // + // Only when a card is actually mounted: with no card there is nowhere better to put prefs, and + // moving them from NVS to the internal FAT partition would trade one flash write for another + // while needlessly changing where existing users' settings live. Old NVS values still load and + // migrate on their next save, so this is transparent. touchPrefsReload() is required because + // boot already read prefs (UI rotation) through the old backend and cached the blob. + if (g_sd_ok) { + SdNvsPrefs::useFile((fs::FS*)&SD_MMC, "/meshcomod"); + touchPrefsReload(); + printf("[storage] prefs -> SD /meshcomod (off internal-flash NVS)\n"); + } + store.begin(); the_mesh.begin(disp != NULL);