diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index 9be0179148..ae8cb739a6 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -5,7 +5,6 @@ */ #include -#include "esp_timer.h" #include "sdmmc_common.h" static const char* TAG = "sdmmc_cmd"; @@ -517,8 +516,10 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, if (err != ESP_OK) { if (cmd.opcode == MMC_WRITE_BLOCK_MULTIPLE) { - if (!sdmmc_ready_for_data(status)) { - vTaskDelay(1); + if (!host_is_spi(card)) { + sdmmc_wait_for_idle(card, status); // wait for the card to be idle (in transfer state) + } else { + vTaskDelay(1); // when the host is in spi mode } size_t successfully_written_blocks = 0; if (sdmmc_send_cmd_num_of_written_blocks(card, &successfully_written_blocks) == ESP_OK) { @@ -535,30 +536,19 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, return err; } - size_t count = 0; - int64_t yield_delay_us = 100 * 1000; // initially 100ms - int64_t t0 = esp_timer_get_time(); - int64_t t1 = 0; /* SD mode: wait for the card to become idle based on R1 status */ - while (!host_is_spi(card) && !sdmmc_ready_for_data(status)) { - t1 = esp_timer_get_time(); - if (t1 - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) { - ESP_LOGE(TAG, "write sectors dma - timeout"); - return ESP_ERR_TIMEOUT; - } - if (t1 - t0 > yield_delay_us) { - yield_delay_us *= 2; - vTaskDelay(1); - } - err = sdmmc_send_cmd_send_status(card, &status); - if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: sdmmc_send_cmd_send_status returned 0x%x", __func__, err); - return err; - } - if (++count % 16 == 0) { - ESP_LOGV(TAG, "waiting for card to become ready (%" PRIu32 ")", (uint32_t) count); + if (!host_is_spi(card)) { + switch (sdmmc_wait_for_idle(card, status)) { + case ESP_OK: + break; + case ESP_ERR_TIMEOUT: + ESP_LOGE(TAG, "%s: sdmmc_wait_for_idle timeout", __func__); + return ESP_ERR_TIMEOUT; + default: + return err; } } + /* 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 @@ -665,28 +655,16 @@ esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst, return err; } - size_t count = 0; - int64_t yield_delay_us = 100 * 1000; // initially 100ms - int64_t t0 = esp_timer_get_time(); - int64_t t1 = 0; /* SD mode: wait for the card to become idle based on R1 status */ - while (!host_is_spi(card) && !sdmmc_ready_for_data(status)) { - t1 = esp_timer_get_time(); - if (t1 - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) { - ESP_LOGE(TAG, "read sectors dma - timeout"); - return ESP_ERR_TIMEOUT; - } - if (t1 - t0 > yield_delay_us) { - yield_delay_us *= 2; - vTaskDelay(1); - } - err = sdmmc_send_cmd_send_status(card, &status); - if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: sdmmc_send_cmd_send_status returned 0x%x", __func__, err); - return err; - } - if (++count % 16 == 0) { - ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); + if (!host_is_spi(card)) { + switch (sdmmc_wait_for_idle(card, status)) { + case ESP_OK: + break; + case ESP_ERR_TIMEOUT: + ESP_LOGE(TAG, "%s: sdmmc_wait_for_idle timeout", __func__); + return ESP_ERR_TIMEOUT; + default: + return err; } } return ESP_OK; diff --git a/components/sdmmc/sdmmc_common.c b/components/sdmmc/sdmmc_common.c index 68342e41a9..88554ed7d2 100644 --- a/components/sdmmc/sdmmc_common.c +++ b/components/sdmmc/sdmmc_common.c @@ -16,6 +16,8 @@ */ #include +#include "esp_log.h" +#include "esp_timer.h" #include "sdmmc_common.h" static const char* TAG = "sdmmc_common"; @@ -415,3 +417,33 @@ uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t er return sdmmc_sd_get_erase_timeout_ms(card, arg, erase_size_kb); } } + +esp_err_t sdmmc_wait_for_idle(sdmmc_card_t* card, uint32_t status) +{ + assert(!host_is_spi(card)); + esp_err_t err = ESP_OK; + size_t count = 0; + int64_t yield_delay_us = 100 * 1000; // initially 100ms + int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; + /* SD mode: wait for the card to become idle based on R1 status */ + while (!sdmmc_ready_for_data(status)) { + t1 = esp_timer_get_time(); + if (t1 - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) { + return ESP_ERR_TIMEOUT; + } + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + vTaskDelay(1); + } + err = sdmmc_send_cmd_send_status(card, &status); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: sdmmc_send_cmd_send_status returned 0x%x", __func__, err); + return err; + } + if (++count % 16 == 0) { + ESP_LOGV(TAG, "waiting for card to become ready (%" PRIu32 ")", (uint32_t) count); + } + } + return err; +} diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index 350b1fd378..53e0e6e671 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/components/sdmmc/sdmmc_common.h @@ -30,6 +30,10 @@ #include "soc/soc_caps.h" #include "esp_dma_utils.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SDMMC_GO_IDLE_DELAY_MS 20 #define SDMMC_IO_SEND_OP_COND_DELAY_MS 10 @@ -176,6 +180,13 @@ void sdmmc_flip_byte_order(uint32_t* response, size_t size); esp_err_t sdmmc_fix_host_flags(sdmmc_card_t* card); +// Use only with SDMMC mode (not SDSPI) +esp_err_t sdmmc_wait_for_idle(sdmmc_card_t* card, uint32_t status); + //Currently only SDIO support using this buffer. And only 512 block size is supported. #define SDMMC_IO_BLOCK_SIZE 512 esp_err_t sdmmc_allocate_aligned_buf(sdmmc_card_t* card); + +#ifdef __cplusplus +} +#endif