Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 39 additions & 18 deletions libraries/SD/src/sd_diskio.cpp
Comment thread
me-no-dev marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ typedef enum {
CRC_ON_OFF = 59
} ardu_sdcard_command_t;

// Align with ESP-IDF sdmmc SPI init (ACMD41 timeout must be >1s per SD spec)
static constexpr uint32_t sd_go_idle_delay_ms = 20;
static constexpr uint32_t sd_op_cond_timeout_ms = 3000;

typedef struct {
uint8_t ssPin;
SPIClass *spi;
Expand Down Expand Up @@ -470,12 +474,12 @@ struct AcquireSPI {
* the SD card specification. It performs card detection, type identification,
* and configuration for SPI mode operation.
*
* The initialization sequence follows the SD card protocol:
* The initialization sequence follows the SD card protocol (SPI mode, aligned with IDF):
* 1. Power-up sequence with 74+ clock cycles
* 2. GO_IDLE_STATE command to reset the card
* 3. CRC_ON_OFF to enable/disable CRC checking
* 2. Two GO_IDLE_STATE attempts to enter SPI mode
* 3. CRC_ON_OFF to enable CRC checking (with retry)
* 4. SEND_IF_COND to identify SDHC/SDXC cards
* 5. APP_OP_COND to set operating conditions
* 5. APP_OP_COND / SEND_OP_COND (SPI args; timeout >1s)
* 6. Card type detection (SD/SDHC/MMC)
* 7. Final configuration and sector count retrieval
*
Expand Down Expand Up @@ -507,9 +511,19 @@ DSTATUS ff_sd_initialize(uint8_t pdrv) {
card->spi->transfer(0XFF);
}

// Step 2: Select the card and send GO_IDLE_STATE command
// This command resets the card to idle state and enables SPI mode
// Fix mount issue - sdWait fail ignored before command GO_IDLE_STATE
// Step 2: Perform two GO_IDLE_STATE (CMD0) attempts in SPI mode.
// Per SD Simplified Spec (figure 4-1) / IDF: some cards enter SD mode on the
// first attempt, so the first response may fail; the second must succeed.
// (sdCommand may also retry internally on no-token/CRC errors.)
// Fix mount issue - sdWait fail ignored before each CMD0 attempt
digitalWrite(card->ssPin, LOW);
if (!sdWait(pdrv, 500)) {
log_w("sdWait fail ignored, card initialize continues");
}
(void)sdCommand(pdrv, GO_IDLE_STATE, 0, NULL);
sdDeselectCard(pdrv);
delay(sd_go_idle_delay_ms);

digitalWrite(card->ssPin, LOW);
if (!sdWait(pdrv, 500)) {
log_w("sdWait fail ignored, card initialize continues");
Expand All @@ -520,10 +534,16 @@ DSTATUS ff_sd_initialize(uint8_t pdrv) {
goto unknown_card;
}
sdDeselectCard(pdrv);
delay(sd_go_idle_delay_ms);

// Step 3: Configure CRC checking
// Enable CRC for data transfers in SPI mode (required for reliable communication)
// Enable CRC for data transfers in SPI mode (required for reliable communication).
// Some cards reject the first CRC_ON_OFF; retry once (same as IDF).
token = sdTransaction(pdrv, CRC_ON_OFF, 1, NULL);
if (token != 1 && token != 0x5) {
delay(10);
token = sdTransaction(pdrv, CRC_ON_OFF, 1, NULL);
}
if (token == 0x5) {
// Old card that doesn't support CRC - disable CRC checking
card->supports_crc = false;
Expand All @@ -547,12 +567,13 @@ DSTATUS ff_sd_initialize(uint8_t pdrv) {
goto unknown_card;
}

// Send APP_OP_COND to set operating conditions for SDHC/SDXC
// Wait up to 1 second for the card to become ready
// Send APP_OP_COND to set operating conditions for SDHC/SDXC.
// In SPI mode only HCS (bit 30) is valid; voltage bits must be 0 (same as IDF).
// Timeout must be >1s per SD spec (IDF uses ~3s).
start = millis();
do {
token = sdTransaction(pdrv, APP_OP_COND, 0x40100000, NULL);
} while (token == 1 && (millis() - start) < 1000);
token = sdTransaction(pdrv, APP_OP_COND, 0x40000000, NULL);
} while (token == 1 && (millis() - start) < sd_op_cond_timeout_ms);

if (token) {
log_w("APP_OP_COND failed: %u", token);
Expand All @@ -577,20 +598,20 @@ DSTATUS ff_sd_initialize(uint8_t pdrv) {
goto unknown_card;
}

// Try SD card initialization first
// Try SD card initialization first (SPI mode: ACMD41 arg must be 0)
start = millis();
do {
token = sdTransaction(pdrv, APP_OP_COND, 0x100000, NULL);
} while (token == 0x01 && (millis() - start) < 1000);
token = sdTransaction(pdrv, APP_OP_COND, 0, NULL);
} while (token == 0x01 && (millis() - start) < sd_op_cond_timeout_ms);

if (!token) {
card->type = CARD_SD; // Standard SD card
} else {
// Try MMC card initialization
// Try MMC card initialization (SPI mode: CMD1 arg must be 0)
start = millis();
do {
token = sdTransaction(pdrv, SEND_OP_COND, 0x100000, NULL);
} while (token != 0x00 && (millis() - start) < 1000);
token = sdTransaction(pdrv, SEND_OP_COND, 0, NULL);
} while (token != 0x00 && (millis() - start) < sd_op_cond_timeout_ms);

if (token == 0x00) {
card->type = CARD_MMC; // MMC card
Expand Down
Loading