Skip to content

Fix SPI SD single-sector write busy wait and sdWait idle check - #3092

Open
pingequalab wants to merge 1 commit into
BruceDevices:devfrom
pingequalab:fix/sd-spi-remount-zombie
Open

pingequalab wants to merge 1 commit into
BruceDevices:devfrom
pingequalab:fix/sd-spi-remount-zombie

Conversation

@pingequalab

Copy link
Copy Markdown

Summary

Follow-up to #3082 (fefc13b). Fixes silent single-sector / tail-sector write drops (CMD24 / sdWriteSector()) and premature sdWait() return on shared-SPI / pulled-up MISO buses in lib/HAL/sd_card/sd_diskio.cpp.

(#3082 was merged into dev shortly before our 20-round byte-level MD5 single-sector hardware stress test finished; this PR submits the companion busy-wait fix 6beb4ae caught and verified by that stress suite.)

Hardware Tested

  • Board: m5stack-sticks3 with external shared-SPI module (CC1101 + NRF24 + 32GB MicroSD sharing SCK=5, MISO=4, MOSI=6), verified under both USB power and standalone internal battery power.
  • Applies to all SPI SD targets using lib/HAL/sd_card/sd_diskio.cpp.

Root Cause

  • After Fix SPI SD card remount zombie state, MISO release clock, and USBSerial vprintf #3082 added the trailing 0xFF clock in sdDeselectCard() so the SD card properly releases DAT0/MISO to pulled-up 0xFF (1 kOhm pull-up on the shared SPI bus), sdWriteSector() (CMD24) still deasserted CS immediately after reading the data-response token (0x05) without waiting for internal NAND programming to finish.
  • Immediately afterward (~1 us), sdTransaction(SEND_STATUS) (CMD13) re-asserted CS and called sdWait(pdrv, 500). Because sdWait() previously exited as soon as a single byte was non-zero (while (resp == 0x00) with signed char resp, returning resp > 0x00), the initial non-zero N_CS transition byte sampled on the pulled-up MISO line before the card drove DO low (0x00 busy) caused sdWait() to return true prematurely.
  • Subsequent CMD13 / CMD24 commands collided with active NAND programming, silently dropping <512 B files, tail sectors, and directory-entry updates without logging an error.

Changes (lib/HAL/sd_card/sd_diskio.cpp)

  • sdWait(): Use uint8_t resp and require two 0xFF idle bytes (resp == 0xFF && ++ff_count == 2) before returning true, so an initial N_CS transition byte after CS assertion cannot prematurely pass a busy check.
  • sdSelectCard(): Call sdDeselectCard(pdrv) instead of raw digitalWrite(card->ssPin, HIGH) on sdWait() timeout so MISO is cleanly clocked to Hi-Z.
  • sdWriteSector() (CMD24): Check uint8_t token == 0x05 (deselecting and retrying on 0x0A / 0x0B CRC error), call sdWait(pdrv, 500) while CS is still held LOW before sdDeselectCard(pdrv) (matching multi-sector sdWriteSectors() / CMD25), and initialize unsigned int resp = 0.

Verification

  • Build: pio run -e m5stack-sticks3 -> SUCCESS (RAM: 40.2% / 131,748 B, Flash: 56.5% / 4,736,991 B).
  • 20-round automated hardware stress suite (OVERALL=PASS | S0=True | S1_PureSD=5/5 | S2_Stress=15/15 | Clean=True):
    • S0 + S1 (5 rounds): Multi-sector (CMD25) + tail single-sector (CMD24) writes (2,880 B & 1,920 B), byte-level MD5 verification, 12-sector golden reference CRC32 readback, and directory-entry remove -> 5/5 PASS, 0 SPI/SD errors.
    • S2 (15 rounds): Continuous shared-SPI switching across CC1101 RSSI Spectrum -> NRF24 80-ch 10MHz Spectrum -> UI Files -> SD Card directory browse -> dynamic multi/single-sector SD write + MD5 + 12-sector CRC32 + remove -> 15/15 PASS, 0 Card Failed / Select Failed / Wait Failed, stable heap (113,219 B -> 111,123 B) and PSRAM (8,370,212 B -> 8,370,212 B).
  • Standalone battery stress test: Verified under internal battery operation with concurrent RF + MicroSD stress load -> PASS.

After clocking MISO release in sdDeselectCard(), re-selecting CS during internal NAND programming can return an initial non-zero transition byte before the card drives DO low. Require two 0xFF samples in sdWait(), release MISO via sdDeselectCard() on sdSelectCard() timeout, and wait for programming completion while CS is held low in sdWriteSector().

Verified: pio run -e m5stack-sticks3 (exit 0); 20/20 shared-SPI + multi/single-sector MD5/CRC32 hardware stress rounds (exit 0).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant