Merge branch 'fix/sdmmc_sdspi_retry_crc_check_v6.0' into 'release/v6.0'

fix(sdspi): 0x106 error during SD card init via SPI related fixes (v6.0)

See merge request espressif/esp-idf!45691
This commit is contained in:
Jiang Jiang Jian
2026-03-20 10:51:38 +08:00
6 changed files with 55 additions and 3 deletions
@@ -1,9 +1,10 @@
/* /*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <stddef.h> #include <stddef.h>
#include <string.h>
#include "unity.h" #include "unity.h"
#include "sdmmc_cmd.h" #include "sdmmc_cmd.h"
#include "sdmmc_test_begin_end_spi.h" #include "sdmmc_test_begin_end_spi.h"
@@ -47,3 +48,38 @@ TEST_CASE("sdspi probe, slot 1, HS", "[sdspi]")
//here freq should be changed to SDMMC_FREQ_HIGHSPEED after fixing IDF-8749 //here freq should be changed to SDMMC_FREQ_HIGHSPEED after fixing IDF-8749
do_one_sdspi_probe(SLOT_1, SDMMC_FREQ_DEFAULT); do_one_sdspi_probe(SLOT_1, SDMMC_FREQ_DEFAULT);
} }
static void do_one_sdspi_probe_ignore_crc(int slot, int freq_khz)
{
sdmmc_card_t card;
sdmmc_test_spi_skip_if_board_incompatible(slot, freq_khz);
sdmmc_host_t config = SDSPI_HOST_DEFAULT();
config.flags |= SDMMC_HOST_FLAG_SPI_IGNORE_DATA_CRC;
sdmmc_test_spi_begin(slot, freq_khz, &card, &config, NULL, NULL);
sdmmc_card_print_info(stdout, &card);
size_t sector_size = card.csd.sector_size;
uint8_t* buffer = heap_caps_calloc(sector_size, 1, MALLOC_CAP_DMA);
TEST_ESP_OK(sdmmc_read_sectors(&card, buffer, 0, 1));
uint8_t* w_buffer = heap_caps_calloc(sector_size, 1, MALLOC_CAP_DMA);
memset(w_buffer, 0xAB, sector_size);
int k = 10; // write every k sectors
for (int i = 0; i < 30; i += sector_size * k) {
memset(buffer, 0, sector_size);
TEST_ESP_OK(sdmmc_write_sectors(&card, w_buffer, i, 1));
TEST_ESP_OK(sdmmc_read_sectors(&card, buffer, i, 1));
TEST_ASSERT_TRUE(memcmp(buffer, w_buffer, sector_size) == 0);
}
free(w_buffer);
free(buffer);
sdmmc_test_spi_end(slot, &card);
}
TEST_CASE("sdspi probe, slot 0, disabled crc check", "[sdspi]")
{
do_one_sdspi_probe_ignore_crc(SLOT_0, SDMMC_FREQ_DEFAULT);
}
TEST_CASE("sdspi probe, slot 1, disabled crc check", "[sdspi]")
{
do_one_sdspi_probe_ignore_crc(SLOT_1, SDMMC_FREQ_DEFAULT);
}
@@ -33,6 +33,7 @@ extern "C" {
#define SDMMC_GO_IDLE_DELAY_MS 20 #define SDMMC_GO_IDLE_DELAY_MS 20
#define SDMMC_IO_SEND_OP_COND_DELAY_MS 10 #define SDMMC_IO_SEND_OP_COND_DELAY_MS 10
#define SDMMC_INIT_SPI_CRC_RETRY_DELAY_MS 10
#define SDMMC_INIT_WAIT_DATA_READY_TIMEOUT_US (5000 * 1000) #define SDMMC_INIT_WAIT_DATA_READY_TIMEOUT_US (5000 * 1000)
#define SDMMC_READY_FOR_DATA_TIMEOUT_US (5000 * 1000) #define SDMMC_READY_FOR_DATA_TIMEOUT_US (5000 * 1000)
@@ -191,6 +191,9 @@ typedef struct {
Currently this is only used by the SDIO driver. Set this flag when Currently this is only used by the SDIO driver. Set this flag when
using SDIO CMD53 byte mode, with user buffer that is behind the cache using SDIO CMD53 byte mode, with user buffer that is behind the cache
or not aligned to 4 byte boundary. */ or not aligned to 4 byte boundary. */
#define SDMMC_HOST_FLAG_SPI_IGNORE_DATA_CRC \
BIT(7) /*!< SPI mode only: Do not enable CRC verification (skip CMD59).
Not recommended as it disables data integrity checking. */
int slot; /*!< slot number, to be passed to host functions */ int slot; /*!< slot number, to be passed to host functions */
int max_freq_khz; /*!< max frequency supported by the host */ int max_freq_khz; /*!< max frequency supported by the host */
#define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */ #define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */
+4
View File
@@ -384,6 +384,10 @@ esp_err_t sdmmc_fix_host_flags(sdmmc_card_t* card)
} }
} }
if (card->host.flags & SDMMC_HOST_FLAG_SPI_IGNORE_DATA_CRC) {
ESP_LOGW(TAG, "SDMMC_HOST_FLAG_SPI_IGNORE_DATA_CRC flag is set on non-SPI host");
}
#if !SOC_SDMMC_UHS_I_SUPPORTED #if !SOC_SDMMC_UHS_I_SUPPORTED
if ((card->host.max_freq_khz == SDMMC_FREQ_SDR50) || if ((card->host.max_freq_khz == SDMMC_FREQ_SDR50) ||
(card->host.max_freq_khz == SDMMC_FREQ_DDR50) || (card->host.max_freq_khz == SDMMC_FREQ_DDR50) ||
+5 -2
View File
@@ -93,9 +93,12 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
const bool is_mem = card->is_mem; const bool is_mem = card->is_mem;
const bool is_sdio = !is_mem; const bool is_sdio = !is_mem;
const bool ignore_data_crc = (config->flags & SDMMC_HOST_FLAG_SPI_IGNORE_DATA_CRC);
/* Enable CRC16 checks for data transfers in SPI mode */ if (!ignore_data_crc) {
SDMMC_INIT_STEP(is_spi, sdmmc_init_spi_crc); /* Enable CRC16 checks for data transfers in SPI mode */
SDMMC_INIT_STEP(is_spi, sdmmc_init_spi_crc);
}
/* Use SEND_OP_COND to set up card OCR */ /* Use SEND_OP_COND to set up card OCR */
SDMMC_INIT_STEP(is_mem, sdmmc_init_ocr); SDMMC_INIT_STEP(is_mem, sdmmc_init_ocr);
+5
View File
@@ -643,6 +643,11 @@ esp_err_t sdmmc_init_spi_crc(sdmmc_card_t* card)
*/ */
assert(host_is_spi(card)); assert(host_is_spi(card));
esp_err_t err = sdmmc_send_cmd_crc_on_off(card, true); esp_err_t err = sdmmc_send_cmd_crc_on_off(card, true);
if (err == ESP_ERR_NOT_SUPPORTED) { // Some cards fail to enable CRC on the first try, trying again
ESP_LOGD(TAG, "%s: enabling CRC failed with 0x%x, trying again", __func__, err);
vTaskDelay(SDMMC_INIT_SPI_CRC_RETRY_DELAY_MS / portTICK_PERIOD_MS);
err = sdmmc_send_cmd_crc_on_off(card, true);
}
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: sdmmc_send_cmd_crc_on_off returned 0x%x", __func__, err); ESP_LOGE(TAG, "%s: sdmmc_send_cmd_crc_on_off returned 0x%x", __func__, err);
return err; return err;