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
This commit is contained in:
Ivan Grokhotkov 2024-02-27 12:19:19 +01:00
parent 4a7eab3d13
commit 383048b19f
No known key found for this signature in database
GPG Key ID: 1E050E141B280628

View File

@ -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) {