diff --git a/src/main.cpp b/src/main.cpp index 97760fc4..d844b5e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -519,11 +519,34 @@ 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) + if (SD.begin(PIN_SD_CS, *_spi, kBootMount[a].hz, "/sd", 6) && SD.cardType() != CARD_NONE) { sd_mounted = true; + mounted_hz = kBootMount[a].hz; + } + } + // RENEGOTIATE UPWARD after a slow-rung success (GH #194). Standard SD bring-up is + // "initialise at a conservative clock, then raise it" — but SD.begin's clock is the + // operating clock for the whole session, so a card that only WOKE at 400 kHz then ran + // its entire life at 400 kHz (~25 KB/s). With the card as the primary store that was a + // ~3-minute boot (contacts + history at modem speed), runtime f_getfree timeouts (the + // file manager showing an inserted card as 0 KB/empty), and wedged backups. An + // initialised card almost always sustains 4 MHz even when its power-up handshake needed + // 400 kHz; if the fast re-begin fails, fall back to the clock that just worked. + if (sd_mounted && mounted_hz < 4000000) { + SD.end(); + delay(60); + if (SD.begin(PIN_SD_CS, *_spi, 4000000, "/sd", 6) && SD.cardType() != CARD_NONE) { + Serial.printf("[BOOT] SD renegotiated %lu -> 4000000 Hz\n", (unsigned long)mounted_hz); + } else { + SD.end(); + delay(120); + sd_mounted = SD.begin(PIN_SD_CS, *_spi, mounted_hz, "/sd", 6) && SD.cardType() != CARD_NONE; + if (sd_mounted) Serial.printf("[BOOT] SD stays at %lu Hz (4 MHz renegotiation failed)\n", (unsigned long)mounted_hz); + } } } if (sd_mounted) { diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index 2c44a75d..55fd08fb 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -18698,15 +18698,30 @@ static bool fmSdTryMount() { }; const int kAttempts = (int)(sizeof(kMountLadder) / sizeof(kMountLadder[0])); bool mounted = false; + uint32_t mounted_hz = 0; disableLoopWDT(); 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) { mounted = true; + mounted_hz = kMountLadder[attempt].hz; break; } } + // Renegotiate upward after a slow-rung success (GH #194): the succeeding rung's clock used + // to become the SESSION clock, so a card whose wake-up needed 400 kHz served contacts, + // history and tiles at ~25 KB/s forever after ("slower is fine" above predates the SD being + // the primary store). Init slow, then raise — fall back to the proven clock if 4 MHz fails. + if (mounted && mounted_hz < 4000000) { + SD.end(); + delay(60); + if (!(SD.begin(PIN_SD_CS, *spi, 4000000, "/sd", 6) && SD.cardType() != CARD_NONE)) { + SD.end(); + delay(120); + mounted = SD.begin(PIN_SD_CS, *spi, mounted_hz, "/sd", 6) && SD.cardType() != CARD_NONE; + } + } enableLoopWDT(); if (mounted) { s_sd_mounted = true;