diff --git a/src/main.cpp b/src/main.cpp index 0dd22911..90f2585f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1028,11 +1028,19 @@ void setup() { // edge shows up as a mid-session "sdmmc_host_wait_for_event returned 0x107" // (ESP_ERR_TIMEOUT) that takes prefs, contacts and chat history down with it. The // T-Display P4 hot-insert path already drops to this rate for the same reason. + sdMountDiagBegin(); bool wio_l2_sd_begun = false; - if (WioTrackerL2Io::ready() && WioTrackerL2Io::setSdPower(true) && - SD_MMC.setPins(2, 3, 1) && - (wio_l2_sd_begun = SD_MMC.begin("/sdcard", true, false, SDMMC_FREQ_DEFAULT)) && - SD_MMC.cardType() != CARD_NONE) { + const bool wio_l2_sd_bus_ready = WioTrackerL2Io::ready() && + WioTrackerL2Io::setSdPower(true) && + SD_MMC.setPins(2, 3, 1); + if (wio_l2_sd_bus_ready) + wio_l2_sd_begun = SD_MMC.begin("/sdcard", true, false, SDMMC_FREQ_DEFAULT); + const bool wio_l2_sd_ready = wio_l2_sd_begun && SD_MMC.cardType() != CARD_NONE; + if (wio_l2_sd_bus_ready) + sdMountDiagAttempt((uint32_t)SDMMC_FREQ_DEFAULT * 1000u, wio_l2_sd_begun, wio_l2_sd_ready); + sdMountDiagSetMounted(wio_l2_sd_ready, + wio_l2_sd_ready ? (uint32_t)SDMMC_FREQ_DEFAULT * 1000u : 0); + if (wio_l2_sd_ready) { sd_storage = store.useSdMmcStorage(); g_contacts_on_sd = sd_storage; g_full_data_on_sd = sd_storage; @@ -1087,6 +1095,7 @@ void setup() { #endif bool sd_mounted = false; #if defined(TLORA_PAGER) + sdMountDiagBegin(); if (!_spi) { Serial.println("[BOOT] SD: shared SPI unavailable"); } else if (!board.sdCardPresent()) { @@ -1099,6 +1108,7 @@ void setup() { Serial.println("[BOOT] SD: card detected; mounting at 4 MHz"); const bool sd_begin_ok = SD.begin(PIN_SD_CS, *_spi, 4000000, "/sd", 6); sd_mounted = sd_begin_ok && SD.cardType() != CARD_NONE; + sdMountDiagAttempt(4000000, sd_begin_ok, sd_mounted); if (!sd_mounted) { if (sd_begin_ok) { // Release only the unusable mount created above. SD.end() unregisters @@ -1112,7 +1122,10 @@ void setup() { } Serial.printf("[BOOT] SD mount: %s\n", sd_mounted ? "ok" : "failed"); } + sdMountDiagSetMounted(sd_mounted, sd_mounted ? 4000000 : 0); #else + sdMountDiagBegin(); + uint32_t mounted_hz = 0; if (_spi) { // Try to mount the card on EVERY boot: even a device that keeps identity on SPIFFS // wants its churn-heavy contacts/channels on the card. @@ -1131,11 +1144,13 @@ void setup() { { 300, 1000000 }, { 450, 1000000 }, { 650, 400000 }, { 900, 400000 }, }; int tries = want_full_sd ? 7 : 3; - uint32_t mounted_hz = 0; for (int a = 0; a < tries && !sd_mounted; ++a) { SD.end(); delay(kBootMount[a].settle_ms); - if (SD.begin(PIN_SD_CS, *_spi, kBootMount[a].hz, "/sd", 6) && SD.cardType() != CARD_NONE) { + const bool begin_ok = SD.begin(PIN_SD_CS, *_spi, kBootMount[a].hz, "/sd", 6); + const bool card_ready = begin_ok && SD.cardType() != CARD_NONE; + sdMountDiagAttempt(kBootMount[a].hz, begin_ok, card_ready); + if (card_ready) { sd_mounted = true; mounted_hz = kBootMount[a].hz; } @@ -1151,13 +1166,18 @@ void setup() { if (sd_mounted && mounted_hz < 4000000) { SD.end(); delay(60); - if (SD.begin(PIN_SD_CS, *_spi, 4000000, "/sd", 6) && SD.cardType() != CARD_NONE) { + const bool fast_begin_ok = SD.begin(PIN_SD_CS, *_spi, 4000000, "/sd", 6); + const bool fast_ready = fast_begin_ok && SD.cardType() != CARD_NONE; + sdMountDiagAttempt(4000000, fast_begin_ok, fast_ready); + if (fast_ready) { Serial.printf("[BOOT] SD renegotiated %lu -> 4000000 Hz\n", (unsigned long)mounted_hz); mounted_hz = 4000000; } else { SD.end(); delay(120); - sd_mounted = SD.begin(PIN_SD_CS, *_spi, mounted_hz, "/sd", 6) && SD.cardType() != CARD_NONE; + const bool fallback_begin_ok = SD.begin(PIN_SD_CS, *_spi, mounted_hz, "/sd", 6); + sd_mounted = fallback_begin_ok && SD.cardType() != CARD_NONE; + sdMountDiagAttempt(mounted_hz, fallback_begin_ok, sd_mounted); if (sd_mounted) Serial.printf("[BOOT] SD stays at %lu Hz (4 MHz renegotiation failed)\n", (unsigned long)mounted_hz); } } @@ -1165,6 +1185,7 @@ void setup() { if (sd_mounted) { mounted_hz = sdTryFastClock(PIN_SD_CS, *_spi, mounted_hz, "BOOT"); sd_mounted = mounted_hz != 0; } if (sd_mounted) { extern uint32_t g_sd_operating_hz; g_sd_operating_hz = mounted_hz; } // About-page readout (UITask.cpp) } + sdMountDiagSetMounted(sd_mounted, mounted_hz); #endif if (sd_mounted) { g_contacts_on_sd = true; // every branch below routes contacts/channels to the card diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index e458497e..b2860a8c 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -2484,6 +2484,49 @@ static lv_color_t* g_draw_buffer = nullptr; // every mount/remount site (main.cpp boot adoption + the two UITask mounts) because SD.begin's // clock is the session clock; Settings -> About reports it on the R8 (no serial console there). uint32_t g_sd_operating_hz = 0; +// Most supported boards expose no card-detect GPIO, so a completed filesystem +// mount is the only positive proof that a card is connected. Preserve existing +// mount attempts for the on-device diagnostic instead of issuing extra probes. +struct SdMountDiagState { + bool checked = false; + bool mounted = false; + bool last_begin_ok = false; + uint8_t attempts = 0; + uint32_t last_attempt_hz = 0; + uint32_t mounted_hz = 0; +}; +static volatile SdMountDiagState s_sd_diag; + +void sdMountDiagBegin() { + s_sd_diag.checked = true; + s_sd_diag.mounted = false; + s_sd_diag.last_begin_ok = false; + s_sd_diag.attempts = 0; + s_sd_diag.last_attempt_hz = 0; + s_sd_diag.mounted_hz = 0; +} + +void sdMountDiagAttempt(uint32_t hz, bool begin_ok, bool card_ready) { + s_sd_diag.checked = true; + if (s_sd_diag.attempts < 0xFF) ++s_sd_diag.attempts; + s_sd_diag.last_attempt_hz = hz; + s_sd_diag.last_begin_ok = begin_ok; + s_sd_diag.mounted = card_ready; + if (card_ready) s_sd_diag.mounted_hz = hz; +} + +void sdMountDiagSetMounted(bool mounted, uint32_t hz) { + s_sd_diag.checked = true; + s_sd_diag.mounted = mounted; + if (!mounted) s_sd_diag.mounted_hz = 0; + else if (hz) s_sd_diag.mounted_hz = hz; +} + +static void sdDiagClockText(uint32_t hz, char* out, size_t cap) { + if (hz >= 1000000) snprintf(out, cap, "%lu MHz", (unsigned long)(hz / 1000000)); + else if (hz > 0) snprintf(out, cap, "%lu kHz", (unsigned long)(hz / 1000)); + else snprintf(out, cap, "unknown"); +} static uint32_t g_draw_buf_px = 240 * LV_DRAW_BUF_LINES; // actual buffer size in px; shrinks if the full alloc fails at boot #if CAP_LARGE_SCREEN // UI resolution scaling (Tanmatsu, no touchscreen). LVGL renders at s_lv_pw x s_lv_ph (PHYSICAL @@ -12431,11 +12474,11 @@ static void sysInfoTextRest(char* buf, size_t cap) { (unsigned)(sketch_size / 1024u), (unsigned)(sketch_free / 1024u)); -#if CAP_SD || defined(TLORA_PAGER) - // microSD size + free. The FAT scan (usedBytes()) is done by the core-0 worker — never - // on this UI thread — so the About sheet can't freeze on it. We just read the worker's - // cached result here and request a (re)scan at most every 30 s. +#if CAP_MICROSD { +#if CAP_SD + // SPI-SD size + free. This existing FAT scan stays on the core-0 worker so + // opening About cannot freeze the UI; SD_MMC builds remain fully passive. static uint32_t sd_req_ms = 0; const uint32_t nowm = millis(); // Once armed, only the worker may clear this request (after publishing @@ -12446,16 +12489,56 @@ static void sysInfoTextRest(char* buf, size_t cap) { if (ensureTileFetchTaskRunning()) s_sdinfo_request = true; // worker rescans off-thread } - if (!s_sdinfo_done) - p += snprintf(buf + p, cap - p, "microSD\n \xE2\x80\xA6\n\n"); // … (computing) - else if (s_sdinfo_ok) +#endif + char sd_clock[16]; + sdDiagClockText(s_sd_diag.mounted ? s_sd_diag.mounted_hz + : s_sd_diag.last_attempt_hz, + sd_clock, sizeof sd_clock); + if (!s_sd_diag.checked) { + p += snprintf(buf + p, cap - p, "microSD\n status: not checked\n\n"); + } else if (!s_sd_diag.mounted && s_sd_diag.attempts == 0) { p += snprintf(buf + p, cap - p, - "microSD\n size: %llu MB\n free: %llu MB\n\n", + "microSD\n status: not mounted\n mount was not attempted\n\n"); + } else if (!s_sd_diag.mounted) { + p += snprintf(buf + p, cap - p, + "microSD\n status: not mounted (missing or unreadable)\n" + " last mount: %u attempt%s, %s\n last init: %s\n\n", + (unsigned)s_sd_diag.attempts, + s_sd_diag.attempts == 1 ? "" : "s", + sd_clock, s_sd_diag.last_begin_ok ? "ok" : "failed"); +#if CAP_SD + } else if (!s_sdinfo_done) { + p += snprintf(buf + p, cap - p, + "microSD\n status: connected / mounted\n" + " mount: %u attempt%s @ %s\n size: checking...\n\n", + (unsigned)s_sd_diag.attempts, + s_sd_diag.attempts == 1 ? "" : "s", sd_clock); + } else if (s_sdinfo_ok) { + p += snprintf(buf + p, cap - p, + "microSD\n status: connected / mounted\n" + " mount: %u attempt%s @ %s\n size: %llu MB\n free: %llu MB\n\n", + (unsigned)s_sd_diag.attempts, + s_sd_diag.attempts == 1 ? "" : "s", sd_clock, (unsigned long long)(s_sdinfo_tot / (1024ull * 1024ull)), (unsigned long long)(s_sdinfo_free / (1024ull * 1024ull))); - else - p += snprintf(buf + p, cap - p, "microSD\n not mounted\n\n"); + } else { + p += snprintf(buf + p, cap - p, + "microSD\n status: mounted, capacity read failed\n" + " mount: %u attempt%s @ %s\n\n", + (unsigned)s_sd_diag.attempts, + s_sd_diag.attempts == 1 ? "" : "s", sd_clock); +#else + } else { + p += snprintf(buf + p, cap - p, + "microSD\n status: connected / mounted\n" + " mount: %u attempt%s @ %s\n\n", + (unsigned)s_sd_diag.attempts, + s_sd_diag.attempts == 1 ? "" : "s", sd_clock); +#endif + } } +#else + p += snprintf(buf + p, cap - p, "microSD\n not available on this hardware\n\n"); #endif // NVS usage across the whole 'nvs' partition (shared by Wi-Fi creds, the @@ -12541,7 +12624,7 @@ static void refreshSysInfo(unsigned long now) { if (lv_indev_get_scroll_dir(in) != LV_DIR_NONE) { next = now + 120; return; } } next = now + 1000; - char buf[832]; + char buf[1024]; sysInfoTextLive(buf, sizeof buf); lv_label_set_text(s_sysinfo_lbl, buf); // Slow tier: pushing identical text would still invalidate + repaint the whole @@ -12614,7 +12697,7 @@ static void refreshSleepDiag(unsigned long now) { static void buildSystemInfoSettings() { lv_obj_t* body = createSettingsModal(TR("System Information"), SettingsModalKind::SystemInfo); - char buf[832]; + char buf[1024]; // FLEX COLUMN, deliberately not the manual y cursor the rest of this file uses. // Both labels below are re-texted AFTER build with text whose LINE COUNT @@ -21868,8 +21951,16 @@ static bool sdAdoptLiveMount() { s_sd_mounted = true; s_sd_size = SD.cardSize(); s_sd_retry_after_ms = 0; + sdMountDiagSetMounted(true, g_sd_operating_hz); return true; } +static bool sdBeginTracked(SPIClass* spi, uint32_t hz, bool* begin_ok_out = nullptr) { + const bool begin_ok = spi && SD.begin(PIN_SD_CS, *spi, hz, "/sd", 6); + const bool card_ready = begin_ok && SD.cardType() != CARD_NONE; + if (begin_ok_out) *begin_ok_out = begin_ok; + sdMountDiagAttempt(hz, begin_ok, card_ready); + return card_ready; +} static bool sdRuntimeLifecycleBusy(); static bool fmSdTryMount() { // main.cpp may already have mounted this global SD object for DataStore. @@ -21902,12 +21993,13 @@ static bool fmSdTryMount() { #endif SPIClass* spi = sdSharedSPI(); if (!spi) return false; + sdMountDiagBegin(); #if defined(TLORA_PAGER) // Vendor-compatible Pager sequence: the shared display/radio bus is already // running, all other CS lines are parked HIGH, and the card gets one 4 MHz // mount attempt. Never tear down that live shared bus or add a retry ladder. - const bool begin_ok = SD.begin(PIN_SD_CS, *spi, 4000000, "/sd", 6); - const bool mounted = begin_ok && SD.cardType() != CARD_NONE; + bool begin_ok = false; + const bool mounted = sdBeginTracked(spi, 4000000, &begin_ok); #else // Cold microSD cards — especially the first mount after boot — often fail // the initial SD.begin and historically only recovered after a physical @@ -21950,7 +22042,7 @@ static bool fmSdTryMount() { for (int attempt = 0; attempt < kAttempts; ++attempt) { SD.end(); delay(kMountLadder[attempt].settle_ms); - if (SD.begin(PIN_SD_CS, *spi, kMountLadder[attempt].hz, "/sd", 6) && SD.cardType() != CARD_NONE) { + if (sdBeginTracked(spi, kMountLadder[attempt].hz)) { mounted = true; mounted_hz = kMountLadder[attempt].hz; break; @@ -21963,10 +22055,10 @@ static bool fmSdTryMount() { if (mounted && mounted_hz < 4000000) { SD.end(); delay(60); - if (!(SD.begin(PIN_SD_CS, *spi, 4000000, "/sd", 6) && SD.cardType() != CARD_NONE)) { + if (!sdBeginTracked(spi, 4000000)) { SD.end(); delay(120); - mounted = SD.begin(PIN_SD_CS, *spi, mounted_hz, "/sd", 6) && SD.cardType() != CARD_NONE; + mounted = sdBeginTracked(spi, mounted_hz); } else { mounted_hz = 4000000; } @@ -21986,6 +22078,7 @@ static bool fmSdTryMount() { // later mount only restores the independently SD-backed data consumers. s_sd_data_warn_next_ms = 0; #endif + sdMountDiagSetMounted(true, mounted_hz); return true; } #if defined(TLORA_PAGER) @@ -21998,6 +22091,7 @@ static bool fmSdTryMount() { #else SD.end(); // clean up on failure #endif + sdMountDiagSetMounted(false, 0); s_sd_retry_after_ms = millis() + 10000; // back off so we don't hammer the card return false; } @@ -22009,6 +22103,7 @@ static void fmSdUnmount() { #endif s_sd_mounted = false; s_sd_size = 0; + sdMountDiagSetMounted(false, 0); } s_sd_retry_after_ms = 0; // a reinsert should be able to mount right away } @@ -23365,23 +23460,39 @@ static bool tanSdTryMount() { if (luaAudioStorageBusy()) return false; #endif if (millis() < s_tan_sd_retry_after) return false; + const uint32_t mount_hz = (uint32_t)SDMMC_FREQ_DEFAULT * 1000u; + if (SD_MMC.cardType() != CARD_NONE) { + s_tan_sd_mounted = true; + s_tan_sd_size = SD_MMC.cardSize(); + sdMountDiagSetMounted(true, 0); // preserve the boot-recorded clock when adopting its mount + return true; + } + sdMountDiagBegin(); + bool attempted = false; + bool begin_ok = false; #if defined(HAS_WIO_TRACKER_L2) // 20 MHz to match main.cpp's boot mount — re-begin()ning at Arduino's 40 MHz // default would quietly re-clock a card the boot already brought up at 20. - if (SD_MMC.cardType() != CARD_NONE || - (WioTrackerL2Io::ready() && WioTrackerL2Io::setSdPower(true) && - SD_MMC.setPins(2, 3, 1) && - SD_MMC.begin("/sdcard", true, false, SDMMC_FREQ_DEFAULT) && - SD_MMC.cardType() != CARD_NONE)) { + if (WioTrackerL2Io::ready() && WioTrackerL2Io::setSdPower(true) && + SD_MMC.setPins(2, 3, 1)) { + attempted = true; + begin_ok = SD_MMC.begin("/sdcard", true, false, SDMMC_FREQ_DEFAULT); + } #elif defined(HAS_TDISPLAY_P4) // Hot-insert path (no-op when main.cpp already mounted at boot): 20 MHz like the boot ladder, // not Arduino's 40 MHz HIGHSPEED default. - if (SD_MMC.begin("/sdcard", false /*4-bit*/, false, SDMMC_FREQ_DEFAULT) && SD_MMC.cardType() != CARD_NONE) { + attempted = true; + begin_ok = SD_MMC.begin("/sdcard", false /*4-bit*/, false, SDMMC_FREQ_DEFAULT); #else - if (SD_MMC.begin("/sdcard", false /*4-bit*/) && SD_MMC.cardType() != CARD_NONE) { + attempted = true; + begin_ok = SD_MMC.begin("/sdcard", false /*4-bit*/); #endif + const bool card_ready = begin_ok && SD_MMC.cardType() != CARD_NONE; + if (attempted) sdMountDiagAttempt(mount_hz, begin_ok, card_ready); + if (card_ready) { s_tan_sd_mounted = true; s_tan_sd_size = SD_MMC.cardSize(); + sdMountDiagSetMounted(true, mount_hz); return true; } #if defined(HAS_WIO_TRACKER_L2) @@ -23400,6 +23511,7 @@ static bool tanSdTryMount() { #else SD_MMC.end(); #endif + sdMountDiagSetMounted(false, 0); s_tan_sd_retry_after = millis() + 8000; // don't grind a missing card on every roots render return false; } @@ -25393,6 +25505,7 @@ static void fileTransferStorageIoFailed() { #else s_tan_sd_mounted = false; s_tan_sd_retry_after = millis() + 8000; + sdMountDiagSetMounted(false, 0); #endif } @@ -29638,7 +29751,7 @@ static void tileFetchTaskFn(void* arg) { if (luaNetWorkerPending()) { luaNetWorkerService(&client, &http); continue; } } #endif -#if CAP_SD || defined(TLORA_PAGER) +#if CAP_SD // microSD usage for the About page — the FAT scan runs here, off the UI thread. if (s_sdinfo_request) { // Publish busy before clearing request so the loop task never observes a @@ -57492,21 +57605,22 @@ static void sdHealthTick() { #endif SPIClass* spi = sdSharedSPI(); if (!spi) return; + sdMountDiagBegin(); #if defined(TLORA_PAGER) // The Pager shares this SPIClass with display + radio: one 4 MHz attempt, // with every other CS parked HIGH and no SD.end() of a potentially live bus. - const bool begin_ok = SD.begin(PIN_SD_CS, *spi, 4000000, "/sd", 6); - const bool remounted = begin_ok && SD.cardType() != CARD_NONE; + bool begin_ok = false; + const bool remounted = sdBeginTracked(spi, 4000000, &begin_ok); #else SD.end(); - bool remounted = SD.begin(PIN_SD_CS, *spi, 4000000, "/sd", 6) && - SD.cardType() != CARD_NONE; + bool remounted = sdBeginTracked(spi, 4000000); if (remounted) { const uint32_t hz = sdTryFastClock(PIN_SD_CS, *spi, 4000000, "SD"); // no-op unless SD_SPI_FAST_HZ remounted = hz != 0; if (remounted) g_sd_operating_hz = hz; } #endif + sdMountDiagSetMounted(remounted, remounted ? g_sd_operating_hz : 0); if (remounted) { s_sd_mounted = true; s_sd_size = SD.cardSize(); diff --git a/src/ui-touch/UITask.h b/src/ui-touch/UITask.h index a7fbc611..cb9696b0 100644 --- a/src/ui-touch/UITask.h +++ b/src/ui-touch/UITask.h @@ -27,6 +27,10 @@ struct ContactInfo; /** Maps bottom tabs (Home, Chats, Contacts, Set — no separate Net tab). */ enum class TouchUiScreen : uint8_t { Home = 0, ChatInbox = 1, Contacts = 2, Settings = 3 }; +void sdMountDiagBegin(); +void sdMountDiagAttempt(uint32_t hz, bool begin_ok, bool card_ready); +void sdMountDiagSetMounted(bool mounted, uint32_t hz); + class UITask : public AbstractUITask { public: static const int MAX_UI_MESSAGES = 500; diff --git a/src/ui-touch/device_caps.h b/src/ui-touch/device_caps.h index d684cf4f..7808d6dd 100644 --- a/src/ui-touch/device_caps.h +++ b/src/ui-touch/device_caps.h @@ -161,6 +161,15 @@ #define CAP_LOCK_SCREEN 0 #endif +// Physical removable microSD slot, independent of the filesystem API used to +// drive it. CAP_SD specifically means Arduino SD over SPI; these three boards +// use SD_MMC instead but still need the same user-facing card diagnostics. +#if CAP_SD || defined(HAS_WIO_TRACKER_L2) || defined(HAS_TANMATSU) || defined(HAS_TDISPLAY_P4) + #define CAP_MICROSD 1 +#else + #define CAP_MICROSD 0 +#endif + // Persisted, restart-to-apply UI-size selector. Large-screen boards already // expose it; the Pager adds font-only presets because its 480x222 viewport is // wide enough for larger type but too short for global geometry scaling. diff --git a/tanmatsu/main/main.cpp b/tanmatsu/main/main.cpp index 0b765109..f25b2dd0 100644 --- a/tanmatsu/main/main.cpp +++ b/tanmatsu/main/main.cpp @@ -379,7 +379,11 @@ static void wadameshSetup() { // the build (-Og "worked by luck"; -Os made the exists()-gated identity + prefs loads come up // empty: fresh node identity, default name, profile changes lost every reboot). The card's FAT // metadata is truthful, so the WHOLE store lives there now; FFat remains only the no-card fallback. - g_sd_ok = SD_MMC.begin("/sdcard", false /*1-bit*/) && SD_MMC.cardType() != CARD_NONE; + sdMountDiagBegin(); + const bool sd_begin_ok = SD_MMC.begin("/sdcard", false /*1-bit*/); + g_sd_ok = sd_begin_ok && SD_MMC.cardType() != CARD_NONE; + sdMountDiagAttempt((uint32_t)SDMMC_FREQ_DEFAULT * 1000u, sd_begin_ok, g_sd_ok); + sdMountDiagSetMounted(g_sd_ok, g_sd_ok ? (uint32_t)SDMMC_FREQ_DEFAULT * 1000u : 0); printf("[storage] SD_MMC.begin = %s\n", g_sd_ok ? "OK" : "no card"); if (g_sd_ok) { SD_MMC.mkdir("/meshcomod"); diff --git a/tdisplay_p4/main/main.cpp b/tdisplay_p4/main/main.cpp index 83dbe5f3..157e3f7e 100644 --- a/tdisplay_p4/main/main.cpp +++ b/tdisplay_p4/main/main.cpp @@ -212,13 +212,18 @@ static void wadameshSetup() { { true, SDMMC_FREQ_DEFAULT, "1-bit 20MHz" }, { true, 5000, "1-bit 5MHz" }, }; + sdMountDiagBegin(); + uint32_t mounted_hz = 0; for (auto &t : tries) { - g_sd_ok = SD_MMC.begin("/sdcard", t.onebit, false, t.khz) && SD_MMC.cardType() != CARD_NONE; + const bool begin_ok = SD_MMC.begin("/sdcard", t.onebit, false, t.khz); + g_sd_ok = begin_ok && SD_MMC.cardType() != CARD_NONE; + sdMountDiagAttempt((uint32_t)t.khz * 1000u, begin_ok, g_sd_ok); printf("[storage] SD_MMC try %s -> %s\n", t.tag, g_sd_ok ? "OK" : "fail"); - if (g_sd_ok) break; + if (g_sd_ok) { mounted_hz = (uint32_t)t.khz * 1000u; break; } SD_MMC.end(); delay(120); } + sdMountDiagSetMounted(g_sd_ok, mounted_hz); } printf("[storage] SD_MMC = %s\n", g_sd_ok ? "OK" : "no card"); if (g_sd_ok) {