From a4cec4355a88ddc2abb156ef4daaeb48c8cb50a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Tue, 16 Dec 2025 12:35:07 +0100 Subject: [PATCH] fix(sdspi): 0x106 error during SD card init via SPI related fixes Try to turn on CRC16 again if first failed, allow disabling of CRC check altogether Releated https://github.com/espressif/esp-idf/issues/15450 --- .../sdspi_tests/sdmmc_test_probe_spi.c | 38 ++++++++++++++++++- .../sdmmc/include/esp_private/sdmmc_common.h | 1 + components/sdmmc/include/sd_protocol_types.h | 3 ++ components/sdmmc/sdmmc_common.c | 4 ++ components/sdmmc/sdmmc_init.c | 7 +++- components/sdmmc/sdmmc_sd.c | 5 +++ 6 files changed, 55 insertions(+), 3 deletions(-) diff --git a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c index c64d721bca..ea1dbd9ac5 100644 --- a/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c +++ b/components/esp_driver_sdspi/test_apps/sdspi/components/sdspi_tests/sdmmc_test_probe_spi.c @@ -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 */ #include +#include #include "unity.h" #include "sdmmc_cmd.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 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); +} diff --git a/components/sdmmc/include/esp_private/sdmmc_common.h b/components/sdmmc/include/esp_private/sdmmc_common.h index c3979ac30e..83dc1df664 100644 --- a/components/sdmmc/include/esp_private/sdmmc_common.h +++ b/components/sdmmc/include/esp_private/sdmmc_common.h @@ -33,6 +33,7 @@ extern "C" { #define SDMMC_GO_IDLE_DELAY_MS 20 #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_READY_FOR_DATA_TIMEOUT_US (5000 * 1000) diff --git a/components/sdmmc/include/sd_protocol_types.h b/components/sdmmc/include/sd_protocol_types.h index c882ce7eee..cf56ee5e06 100644 --- a/components/sdmmc/include/sd_protocol_types.h +++ b/components/sdmmc/include/sd_protocol_types.h @@ -191,6 +191,9 @@ typedef struct { 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 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 max_freq_khz; /*!< max frequency supported by the host */ #define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */ diff --git a/components/sdmmc/sdmmc_common.c b/components/sdmmc/sdmmc_common.c index e35c72f400..498aac2206 100644 --- a/components/sdmmc/sdmmc_common.c +++ b/components/sdmmc/sdmmc_common.c @@ -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 ((card->host.max_freq_khz == SDMMC_FREQ_SDR50) || (card->host.max_freq_khz == SDMMC_FREQ_DDR50) || diff --git a/components/sdmmc/sdmmc_init.c b/components/sdmmc/sdmmc_init.c index 290971fd94..428e9d2974 100644 --- a/components/sdmmc/sdmmc_init.c +++ b/components/sdmmc/sdmmc_init.c @@ -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_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 */ - SDMMC_INIT_STEP(is_spi, sdmmc_init_spi_crc); + if (!ignore_data_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 */ SDMMC_INIT_STEP(is_mem, sdmmc_init_ocr); diff --git a/components/sdmmc/sdmmc_sd.c b/components/sdmmc/sdmmc_sd.c index 4d2c1872b0..156e396643 100644 --- a/components/sdmmc/sdmmc_sd.c +++ b/components/sdmmc/sdmmc_sd.c @@ -643,6 +643,11 @@ esp_err_t sdmmc_init_spi_crc(sdmmc_card_t* card) */ assert(host_is_spi(card)); 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) { ESP_LOGE(TAG, "%s: sdmmc_send_cmd_crc_on_off returned 0x%x", __func__, err); return err;