diff --git a/components/driver/include/driver/sdmmc_defs.h b/components/driver/include/driver/sdmmc_defs.h index 1e336c2d72..04ba136d21 100644 --- a/components/driver/include/driver/sdmmc_defs.h +++ b/components/driver/include/driver/sdmmc_defs.h @@ -119,6 +119,20 @@ #define SDIO_R1_FUNC_NUM_ERR (1<<4) +/* SPI mode R2 response type bits. + * The first byte is the same as for R1. + * The bits below belong to the second byte. + * Bits 10, 11, 12, 15 can also be reported in data error token of a read command response. + */ +#define SD_SPI_R2_CARD_LOCKED (1<<8) /* Set when the card is locked by the user */ +#define SD_SPI_R2_UNLOCK_FAILED (1<<9) /* Host attempts to erase a write-protected sector or makes an error during card lock/unlock operation */ +#define SD_SPI_R2_ERROR (1<<10) /* A general or an unknown error occurred during the operation */ +#define SD_SPI_R2_CC_ERROR (1<<11) /* Internal card controller error */ +#define SD_SPI_R2_ECC_FAILED (1<<12) /* Card internal ECC was applied but failed to correct the data */ +#define SD_SPI_R2_WP_VIOLATION (1<<13) /* The command tried to write a write-protected block */ +#define SD_SPI_R2_ERASE_PARAM (1<<14) /* An invalid selection for erase, sectors or groups */ +#define SD_SPI_R2_OUT_OF_RANGE (1<<15) /* The command argument was out of the allowed range for this card */ + /* 48-bit response decoding (32 bits w/o CRC) */ #define MMC_R1(resp) ((resp)[0]) #define MMC_R3(resp) ((resp)[0]) @@ -358,6 +372,9 @@ /* SSR (SD Status Register) */ #define SSR_DAT_BUS_WIDTH(ssr) MMC_RSP_BITS((ssr), 510, 2) #define SSR_AU_SIZE(ssr) MMC_RSP_BITS((ssr), 428, 4) +#define SSR_ERASE_SIZE(ssr) MMC_RSP_BITS((ssr), 408, 16) +#define SSR_ERASE_TIMEOUT(ssr) MMC_RSP_BITS((ssr), 402, 6) +#define SSR_ERASE_OFFSET(ssr) MMC_RSP_BITS((ssr), 400, 2) #define SSR_DISCARD_SUPPORT(ssr) MMC_RSP_BITS((ssr), 313, 1) #define SSR_FULE_SUPPORT(ssr) MMC_RSP_BITS((ssr), 312, 1) diff --git a/components/driver/include/driver/sdmmc_types.h b/components/driver/include/driver/sdmmc_types.h index 58ccfd4468..374790ef4a 100644 --- a/components/driver/include/driver/sdmmc_types.h +++ b/components/driver/include/driver/sdmmc_types.h @@ -71,10 +71,14 @@ typedef struct { * Note: When new member is added, update reserved bits accordingly */ typedef struct { + uint32_t alloc_unit_kb: 16; /*!< Allocation unit of the card, in multiples of kB (1024 bytes) */ + uint32_t erase_size_au: 16; /*!< Erase size for the purpose of timeout calculation, in multiples of allocation unit */ uint32_t cur_bus_width: 2; /*!< SD current bus width */ uint32_t discard_support: 1; /*!< SD discard feature support */ uint32_t fule_support: 1; /*!< SD FULE (Full User Area Logical Erase) feature support */ - uint32_t reserved: 28; /*!< reserved for future expansion */ + uint32_t erase_timeout: 6; /*!< Timeout (in seconds) for erase of a single allocation unit */ + uint32_t erase_offset: 2; /*!< Constant timeout offset (in seconds) for any erase operation */ + uint32_t reserved: 20; /*!< reserved for future expansion */ } sdmmc_ssr_t; /** diff --git a/components/driver/sdspi_host.c b/components/driver/sdspi_host.c index 5a4424b0bd..fd9749a33d 100644 --- a/components/driver/sdspi_host.c +++ b/components/driver/sdspi_host.c @@ -482,7 +482,8 @@ static esp_err_t start_command_default(slot_info_t *slot, int flags, sdspi_hw_cm { size_t cmd_size = SDSPI_CMD_R1_SIZE; if ((flags & SDSPI_CMD_FLAG_RSP_R1) || - (flags & SDSPI_CMD_FLAG_NORSP)) { + (flags & SDSPI_CMD_FLAG_NORSP) || + (flags & SDSPI_CMD_FLAG_RSP_R1B )) { cmd_size = SDSPI_CMD_R1_SIZE; } else if (flags & SDSPI_CMD_FLAG_RSP_R2) { cmd_size = SDSPI_CMD_R2_SIZE; @@ -522,6 +523,13 @@ static esp_err_t start_command_default(slot_info_t *slot, int flags, sdspi_hw_cm ret = shift_cmd_response(cmd, cmd_size); if (ret != ESP_OK) return ESP_ERR_TIMEOUT; + if (flags & SDSPI_CMD_FLAG_RSP_R1B) { + ret = poll_busy(slot, cmd->timeout_ms, no_use_polling); + if (ret != ESP_OK) { + return ret; + } + } + return ESP_OK; } @@ -777,7 +785,7 @@ static esp_err_t start_command_read_blocks(slot_info_t *slot, sdspi_hw_cmd_t *cm // card to process it sdspi_hw_cmd_t stop_cmd; make_hw_cmd(MMC_STOP_TRANSMISSION, 0, cmd->timeout_ms, &stop_cmd); - ret = start_command_default(slot, SDSPI_CMD_FLAG_RSP_R1, &stop_cmd); + ret = start_command_default(slot, SDSPI_CMD_FLAG_RSP_R1B, &stop_cmd); if (ret != ESP_OK) { return ret; } diff --git a/components/driver/sdspi_private.h b/components/driver/sdspi_private.h index 2acf853bd1..e78756b4c2 100644 --- a/components/driver/sdspi_private.h +++ b/components/driver/sdspi_private.h @@ -85,13 +85,14 @@ typedef struct { #define SDSPI_CMD_FLAG_DATA BIT(0) //!< Command has data transfer #define SDSPI_CMD_FLAG_WRITE BIT(1) //!< Data is written to the card #define SDSPI_CMD_FLAG_RSP_R1 BIT(2) //!< Response format R1 (1 byte) -#define SDSPI_CMD_FLAG_RSP_R2 BIT(3) //!< Response format R2 (2 bytes) -#define SDSPI_CMD_FLAG_RSP_R3 BIT(4) //!< Response format R3 (5 bytes) -#define SDSPI_CMD_FLAG_RSP_R4 BIT(5) //!< Response format R4 (5 bytes) -#define SDSPI_CMD_FLAG_RSP_R5 BIT(6) //!< Response format R5 (2 bytes) -#define SDSPI_CMD_FLAG_RSP_R7 BIT(7) //!< Response format R7 (5 bytes) -#define SDSPI_CMD_FLAG_NORSP BIT(8) //!< Don't expect response (used when sending CMD0 first time). -#define SDSPI_CMD_FLAG_MULTI_BLK BIT(9) //!< For the write multiblock commands, the start token should be different +#define SDSPI_CMD_FLAG_RSP_R1B BIT(3) //!< Response format R1 (1 byte), with busy polling +#define SDSPI_CMD_FLAG_RSP_R2 BIT(4) //!< Response format R2 (2 bytes) +#define SDSPI_CMD_FLAG_RSP_R3 BIT(5) //!< Response format R3 (5 bytes) +#define SDSPI_CMD_FLAG_RSP_R4 BIT(6) //!< Response format R4 (5 bytes) +#define SDSPI_CMD_FLAG_RSP_R5 BIT(7) //!< Response format R5 (2 bytes) +#define SDSPI_CMD_FLAG_RSP_R7 BIT(8) //!< Response format R7 (5 bytes) +#define SDSPI_CMD_FLAG_NORSP BIT(9) //!< Don't expect response (used when sending CMD0 first time). +#define SDSPI_CMD_FLAG_MULTI_BLK BIT(10) //!< For the write multiblock commands, the start token should be different #define SDSPI_MAX_DATA_LEN 512 //!< Max size of single block transfer diff --git a/components/driver/sdspi_transaction.c b/components/driver/sdspi_transaction.c index 0d969dae13..583c6cfc35 100644 --- a/components/driver/sdspi_transaction.c +++ b/components/driver/sdspi_transaction.c @@ -140,6 +140,8 @@ esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo) if (cmdinfo->arg & SD_ARG_CMD53_WRITE) flags |= SDSPI_CMD_FLAG_WRITE; // The CMD53 can assign block mode in the arg when the length is exactly 512 bytes if (cmdinfo->arg & SD_ARG_CMD53_BLOCK_MODE) flags |= SDSPI_CMD_FLAG_MULTI_BLK; + } else if (!s_app_cmd && (cmdinfo->opcode == MMC_ERASE || cmdinfo->opcode == MMC_STOP_TRANSMISSION)) { + flags |= SDSPI_CMD_FLAG_RSP_R1B; } else { flags |= SDSPI_CMD_FLAG_RSP_R1; } @@ -152,11 +154,11 @@ esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo) if (ret == ESP_OK) { ESP_LOGV(TAG, "r1 = 0x%02x hw_cmd.r[0]=0x%08x", hw_cmd.r1, hw_cmd.response[0]); // Some errors should be reported using return code - if (flags & SDSPI_CMD_FLAG_RSP_R1) { + if (flags & (SDSPI_CMD_FLAG_RSP_R1 | SDSPI_CMD_FLAG_RSP_R1B)) { cmdinfo->response[0] = hw_cmd.r1; r1_response_to_err(hw_cmd.r1, cmdinfo->opcode, &ret); } else if (flags & SDSPI_CMD_FLAG_RSP_R2) { - cmdinfo->response[0] = (((uint32_t)hw_cmd.r1) << 8) | (hw_cmd.response[0] >> 24); + cmdinfo->response[0] = ((uint32_t)hw_cmd.r1) | ((hw_cmd.response[0] & 0xff) << 8); } else if (flags & (SDSPI_CMD_FLAG_RSP_R3 | SDSPI_CMD_FLAG_RSP_R7)) { r1_response_to_err(hw_cmd.r1, cmdinfo->opcode, &ret); cmdinfo->response[0] = __builtin_bswap32(hw_cmd.response[0]); diff --git a/components/fatfs/diskio/diskio_sdmmc.c b/components/fatfs/diskio/diskio_sdmmc.c index 19f6d5698c..97578c9f0e 100644 --- a/components/fatfs/diskio/diskio_sdmmc.c +++ b/components/fatfs/diskio/diskio_sdmmc.c @@ -101,13 +101,6 @@ DRESULT ff_sdmmc_ioctl (BYTE pdrv, BYTE cmd, void* buff) return RES_ERROR; #if FF_USE_TRIM case CTRL_TRIM: - /* - * limitation with sector erase when used in SDSPI mode - * hence return if host is SPI. - */ - if ((card->host.flags & SDMMC_HOST_FLAG_SPI) != 0) { - return RES_ERROR; - } return ff_sdmmc_trim (pdrv, *((DWORD*)buff), //start_sector (*((DWORD*)buff + 1) - *((DWORD*)buff) + 1)); //sector_count #endif //FF_USE_TRIM diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index 706badb1ae..139d0ed0cd 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -347,7 +347,11 @@ esp_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status) return err; } if (out_status) { - *out_status = MMC_R1(cmd.response); + if (host_is_spi(card)) { + *out_status = SD_SPI_R2(cmd.response); + } else { + *out_status = MMC_R1(cmd.response); + } } return ESP_OK; } @@ -414,6 +418,7 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, } uint32_t status = 0; size_t count = 0; + /* SD mode: wait for the card to become idle based on R1 status */ while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) { // TODO: add some timeout here err = sdmmc_send_cmd_send_status(card, &status); @@ -424,6 +429,27 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); } } + /* SPI mode: although card busy indication is based on the busy token, + * SD spec recommends that the host checks the results of programming by sending + * SEND_STATUS command. Some of the conditions reported in SEND_STATUS are not + * reported via a data error token. + */ + if (host_is_spi(card)) { + err = sdmmc_send_cmd_send_status(card, &status); + if (err != ESP_OK) { + return err; + } + if (status & SD_SPI_R2_CARD_LOCKED) { + ESP_LOGE(TAG, "%s: write failed, card is locked: r2=0x%04x", + __func__, status); + return ESP_ERR_INVALID_STATE; + } + if (status != 0) { + ESP_LOGE(TAG, "%s: card status indicates an error after write operation: r2=0x%04x", + __func__, status); + return ESP_ERR_INVALID_RESPONSE; + } + } return ESP_OK; } @@ -546,7 +572,7 @@ esp_err_t sdmmc_erase_sectors(sdmmc_card_t* card, size_t start_sector, esp_err_t err = sdmmc_send_cmd(card, &cmd); if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + ESP_LOGE(TAG, "%s: sdmmc_send_cmd (ERASE_GROUP_START) returned 0x%x", __func__, err); return err; } @@ -556,7 +582,7 @@ esp_err_t sdmmc_erase_sectors(sdmmc_card_t* card, size_t start_sector, err = sdmmc_send_cmd(card, &cmd); if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + ESP_LOGE(TAG, "%s: sdmmc_send_cmd (ERASE_GROUP_END) returned 0x%x", __func__, err); return err; } @@ -565,15 +591,27 @@ esp_err_t sdmmc_erase_sectors(sdmmc_card_t* card, size_t start_sector, cmd.flags = SCF_CMD_AC | SCF_RSP_R1B | SCF_WAIT_BUSY; cmd.opcode = MMC_ERASE; cmd.arg = cmd38_arg; - // TODO: best way, application to compute timeout value. For this card - // structure should have a place holder for erase_timeout. - cmd.timeout_ms = (SDMMC_ERASE_BLOCK_TIMEOUT_MS + sector_count); + cmd.timeout_ms = sdmmc_get_erase_timeout_ms(card, cmd38_arg, sector_count * card->csd.sector_size / 1024); err = sdmmc_send_cmd(card, &cmd); if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, err); + ESP_LOGE(TAG, "%s: sdmmc_send_cmd (ERASE) returned 0x%x", __func__, err); return err; } + + if (host_is_spi(card)) { + uint32_t status; + err = sdmmc_send_cmd_send_status(card, &status); + if (err != ESP_OK) { + return err; + } + if (status != 0) { + ESP_LOGE(TAG, "%s: card status indicates an error after erase operation: r2=0x%04x", + __func__, status); + return ESP_ERR_INVALID_RESPONSE; + } + } + return ESP_OK; } @@ -644,9 +682,10 @@ esp_err_t sdmmc_full_erase(sdmmc_card_t* card) if (card->is_mmc) { arg = sdmmc_mmc_can_sanitize(card) == ESP_OK ? SDMMC_MMC_DISCARD_ARG: SDMMC_MMC_TRIM_ARG; } - err = sdmmc_erase_sectors(card, 0, card->csd.capacity, arg); + err = sdmmc_erase_sectors(card, 0, card->csd.capacity, arg); if ((err == ESP_OK) && (arg == SDMMC_MMC_DISCARD_ARG)) { - return sdmmc_mmc_sanitize(card, SDMMC_ERASE_BLOCK_TIMEOUT_MS + card->csd.capacity); + uint32_t timeout_ms = sdmmc_get_erase_timeout_ms(card, SDMMC_MMC_DISCARD_ARG, card->csd.capacity * ((uint64_t) card->csd.sector_size) / 1024); + return sdmmc_mmc_sanitize(card, timeout_ms); } return err; } diff --git a/components/sdmmc/sdmmc_common.c b/components/sdmmc/sdmmc_common.c index 0d04ddbb26..341a0f4a9c 100644 --- a/components/sdmmc/sdmmc_common.c +++ b/components/sdmmc/sdmmc_common.c @@ -318,3 +318,12 @@ esp_err_t sdmmc_fix_host_flags(sdmmc_card_t* card) } return ESP_OK; } + +uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb) +{ + if (card->is_mmc) { + return sdmmc_mmc_get_erase_timeout_ms(card, arg, erase_size_kb); + } else { + return sdmmc_sd_get_erase_timeout_ms(card, arg, erase_size_kb); + } +} diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index a6d7dbbf29..759151e14c 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/components/sdmmc/sdmmc_common.h @@ -37,7 +37,9 @@ */ #define SDMMC_DEFAULT_CMD_TIMEOUT_MS 1000 // Max timeout of ordinary commands #define SDMMC_WRITE_CMD_TIMEOUT_MS 5000 // Max timeout of write commands -#define SDMMC_ERASE_BLOCK_TIMEOUT_MS 500 // Max timeout of erase per block + + +#define SDMMC_SD_DISCARD_TIMEOUT 250 // SD erase (discard) timeout /* Maximum retry/error count for SEND_OP_COND (CMD1). * These are somewhat arbitrary, values originate from OpenBSD driver. @@ -79,6 +81,7 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, size_t start_block, size_t block_count); esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst, size_t start_block, size_t block_count); +uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb); /* SD specific */ esp_err_t sdmmc_check_scr(sdmmc_card_t* card); @@ -86,6 +89,7 @@ esp_err_t sdmmc_decode_cid(sdmmc_response_t resp, sdmmc_cid_t* out_cid); esp_err_t sdmmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd); esp_err_t sdmmc_decode_scr(uint32_t *raw_scr, sdmmc_scr_t* out_scr); esp_err_t sdmmc_decode_ssr(uint32_t *raw_ssr, sdmmc_ssr_t* out_ssr); +uint32_t sdmmc_sd_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb); /* SDIO specific */ esp_err_t sdmmc_io_reset(sdmmc_card_t* card); @@ -103,6 +107,7 @@ esp_err_t sdmmc_mmc_switch(sdmmc_card_t* card, uint8_t set, uint8_t index, uint8 esp_err_t sdmmc_mmc_decode_cid(int mmc_ver, sdmmc_response_t resp, sdmmc_cid_t* out_cid); esp_err_t sdmmc_mmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd); esp_err_t sdmmc_mmc_enable_hs_mode(sdmmc_card_t* card); +uint32_t sdmmc_mmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb); /* Parts of card initialization flow */ esp_err_t sdmmc_init_sd_if_cond(sdmmc_card_t* card); diff --git a/components/sdmmc/sdmmc_mmc.c b/components/sdmmc/sdmmc_mmc.c index 82c978aea6..4f726ea90a 100644 --- a/components/sdmmc/sdmmc_mmc.c +++ b/components/sdmmc/sdmmc_mmc.c @@ -288,3 +288,13 @@ out: free(ext_csd); return err; } + +uint32_t sdmmc_mmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb) +{ + /* TODO: calculate erase timeout based on ext_csd (trim_timeout) */ + uint32_t timeout_ms = SDMMC_SD_DISCARD_TIMEOUT * erase_size_kb / card->csd.sector_size; + timeout_ms = MAX(1000, timeout_ms); + ESP_LOGD(TAG, "%s: erase timeout %u s (erasing %u kB, %ums per sector)", + __func__, timeout_ms / 1000, erase_size_kb, SDMMC_SD_DISCARD_TIMEOUT); + return timeout_ms; +} diff --git a/components/sdmmc/sdmmc_sd.c b/components/sdmmc/sdmmc_sd.c index 03037e5c26..15bc866357 100644 --- a/components/sdmmc/sdmmc_sd.c +++ b/components/sdmmc/sdmmc_sd.c @@ -96,7 +96,7 @@ esp_err_t sdmmc_init_sd_ssr(sdmmc_card_t* card) .data = sd_ssr, .datalen = SD_SSR_SIZE, .blklen = SD_SSR_SIZE, - .opcode = MMC_SEND_STATUS, + .opcode = SD_APP_SD_STATUS, .arg = 0, .flags = SCF_CMD_ADTC | SCF_RSP_R1 | SCF_CMD_READ }; @@ -387,6 +387,16 @@ esp_err_t sdmmc_decode_scr(uint32_t *raw_scr, sdmmc_scr_t* out_scr) return ESP_OK; } +static const uint32_t s_au_to_size_kb[] = { + 0, 16, 32, 64, + 128, 256, 512, 1024, + 2 * 1024, 4 * 1024, + 8 * 1024, 12 * 1024, + 16 * 1024, 24 * 1024, + 32 * 1024, 64 * 1024 +}; +_Static_assert(sizeof(s_au_to_size_kb)/sizeof(s_au_to_size_kb[0]) == 16, "invalid number of elements in s_au_to_size_kb"); + esp_err_t sdmmc_decode_ssr(uint32_t *raw_ssr, sdmmc_ssr_t* out_ssr) { uint32_t ssr[(SD_SSR_SIZE/sizeof(uint32_t))] = { 0 }; @@ -399,6 +409,41 @@ esp_err_t sdmmc_decode_ssr(uint32_t *raw_ssr, sdmmc_ssr_t* out_ssr) out_ssr->cur_bus_width = SSR_DAT_BUS_WIDTH(ssr); out_ssr->discard_support = SSR_DISCARD_SUPPORT(ssr); out_ssr->fule_support = SSR_FULE_SUPPORT(ssr); + uint32_t au = SSR_AU_SIZE(ssr); + out_ssr->alloc_unit_kb = s_au_to_size_kb[au]; + out_ssr->erase_timeout = SSR_ERASE_TIMEOUT(ssr); + out_ssr->erase_size_au = SSR_ERASE_SIZE(ssr); + out_ssr->erase_offset = SSR_ERASE_OFFSET(ssr); return ESP_OK; } + +uint32_t sdmmc_sd_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb) +{ + if (arg == SDMMC_SD_DISCARD_ARG) { + return SDMMC_SD_DISCARD_TIMEOUT; + } else if (arg == SDMMC_SD_ERASE_ARG) { + if (card->ssr.alloc_unit_kb != 0 && + card->ssr.erase_size_au != 0 && + card->ssr.erase_timeout != 0 && + card->ssr.erase_offset != 0) { + /* Card supports erase timeout estimation. See the erase timeout equation in SD spec. */ + uint32_t timeout_sec = card->ssr.erase_offset + + card->ssr.erase_timeout * (erase_size_kb + card->ssr.alloc_unit_kb - 1) / + (card->ssr.erase_size_au * card->ssr.alloc_unit_kb); + ESP_LOGD(TAG, "%s: erase timeout %u s (erasing %u kB, ES=%u, ET=%u, EO=%u, AU=%u kB)", + __func__, timeout_sec, erase_size_kb, card->ssr.erase_size_au, + card->ssr.erase_timeout, card->ssr.erase_offset, card->ssr.alloc_unit_kb); + return timeout_sec * 1000; + } else { + uint32_t timeout_ms = SDMMC_SD_DISCARD_TIMEOUT * erase_size_kb / card->csd.sector_size; + timeout_ms = MAX(1000, timeout_ms); + ESP_LOGD(TAG, "%s: erase timeout %u s (erasing %u kB, %ums per sector)", + __func__, timeout_ms / 1000, erase_size_kb, SDMMC_SD_DISCARD_TIMEOUT); + return timeout_ms; + } + } else { + assert(false && "unexpected SD erase argument"); + return 0; + } +} diff --git a/components/sdmmc/test/test_sd.c b/components/sdmmc/test/test_sd.c index 5fcfc7fe11..0a04d3166a 100644 --- a/components/sdmmc/test/test_sd.c +++ b/components/sdmmc/test/test_sd.c @@ -869,10 +869,6 @@ static void test_sdspi_erase_blocks(size_t start_block, size_t block_count) float time_er = 1e3f * (t_stop_wr.tv_sec - t_start_er.tv_sec) + 1e-3f * (t_stop_wr.tv_usec - t_start_er.tv_usec); printf("Erase duration: %.2fms\n", time_er); - // nominal delay before re-init card - vTaskDelay(pdMS_TO_TICKS(1000)); - // has to re-init card, after erase operation. - TEST_ESP_OK(sdmmc_card_init(&config, card)); printf("Verifying erase state...\n"); uint8_t erase_mem_byte = 0xFF; // ensure all the blocks are erased and are up to after erase state.