From dceec3fac09a360efc7a06b79080ec985a58f2b0 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 27 Feb 2024 12:19:19 +0100 Subject: [PATCH 1/2] fix(sdmmc): use correct argument for ACMD41 in SPI mode ACMD41 argument is different between SD mode and SPI mode. In SPI mode, the only non-zero bit may be the HCS bit. Unlike the SD mode, the bits reflecting the host's OCR should be zero. Previously, we used to set these bits the same way as for the SD mode. This has caused certain cards to fail initializing, apparently their controllers have checked the ACMD41 argument more strictly and refused to finish initialization, resulting in an error such as sdmmc_common: sdmmc_init_ocr: send_op_cond (1) returned 0x107 (Note that this error may have other causes than the one fixed in this commit. For example, if the card doesn't have a sufficient and stable power supply, it may also fail to complete the internal initialization process, and will never clear the busy flag in R1 response.) Closes https://github.com/espressif/esp-idf/issues/6686 Closes https://github.com/espressif/esp-idf/issues/10542 --- components/sdmmc/sdmmc_common.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/components/sdmmc/sdmmc_common.c b/components/sdmmc/sdmmc_common.c index c28d447581..6ad6f00a34 100644 --- a/components/sdmmc/sdmmc_common.c +++ b/components/sdmmc/sdmmc_common.c @@ -28,17 +28,27 @@ esp_err_t sdmmc_init_ocr(sdmmc_card_t* card) */ uint32_t host_ocr = get_host_ocr(card->host.io_voltage); - if ((card->ocr & SD_OCR_SDHC_CAP) != 0) { - host_ocr |= SD_OCR_SDHC_CAP; + + /* In SPI mode, the only non-zero bit of ACMD41 is HCS (bit 30) + * In SD mode, bits 23:8 contain the supported voltage mask + */ + uint32_t acmd41_arg = 0; + if (!host_is_spi(card)) { + acmd41_arg = host_ocr; } + + if ((card->ocr & SD_OCR_SDHC_CAP) != 0) { + acmd41_arg |= SD_OCR_SDHC_CAP; + } + /* Send SEND_OP_COND (ACMD41) command to the card until it becomes ready. */ - err = sdmmc_send_cmd_send_op_cond(card, host_ocr, &card->ocr); + err = sdmmc_send_cmd_send_op_cond(card, acmd41_arg, &card->ocr); /* If time-out, re-try send_op_cond as MMC */ if (err == ESP_ERR_TIMEOUT && !host_is_spi(card)) { ESP_LOGD(TAG, "send_op_cond timeout, trying MMC"); card->is_mmc = 1; - err = sdmmc_send_cmd_send_op_cond(card, host_ocr, &card->ocr); + err = sdmmc_send_cmd_send_op_cond(card, acmd41_arg, &card->ocr); } if (err != ESP_OK) { From 6383fd550ac23458ef44d11ef6c7eef067aea6c5 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 27 Feb 2024 12:21:09 +0100 Subject: [PATCH 2/2] fix(sdmmc): extend the maximum number of retries of ACMD41 According to the application note in SD Card Physical Specification: > The host shall set ACMD41 timeout more than 1 second to abort repeat of issuing ACMD41 when the card does not indicate ready. The timeout count starts from the first ACMD41 which is set voltage window in the argument. Previously, the timeout was exactly one second, and this caused certain larger-capacity cards to "time out", because they couldn't finish initialization process in time. --- components/sdmmc/sdmmc_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index e07ebd9109..34d584e6b4 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/components/sdmmc/sdmmc_common.h @@ -41,7 +41,7 @@ /* Maximum retry/error count for SEND_OP_COND (CMD1). * These are somewhat arbitrary, values originate from OpenBSD driver. */ -#define SDMMC_SEND_OP_COND_MAX_RETRIES 100 +#define SDMMC_SEND_OP_COND_MAX_RETRIES 300 #define SDMMC_SEND_OP_COND_MAX_ERRORS 3 /* Functions to send individual commands */