diff --git a/components/driver/sdmmc/sdmmc_host.c b/components/driver/sdmmc/sdmmc_host.c index 500e55ad73..158e4eded8 100644 --- a/components/driver/sdmmc/sdmmc_host.c +++ b/components/driver/sdmmc/sdmmc_host.c @@ -9,6 +9,7 @@ #include #include "esp_log.h" #include "esp_intr_alloc.h" +#include "esp_timer.h" #include "soc/soc_caps.h" #include "soc/soc_pins.h" #include "soc/gpio_periph.h" @@ -25,9 +26,6 @@ #define SDMMC_EVENT_QUEUE_LENGTH 32 -#define SDMMC_TIMEOUT_MS 1000 - - static void sdmmc_isr(void* arg); static void sdmmc_host_dma_init(void); @@ -78,9 +76,9 @@ esp_err_t sdmmc_host_reset(void) SDMMC.ctrl.fifo_reset = 1; // Wait for the reset bits to be cleared by hardware - int t0 = esp_timer_get_time(); + int64_t t0 = esp_timer_get_time(); while (SDMMC.ctrl.controller_reset || SDMMC.ctrl.fifo_reset || SDMMC.ctrl.dma_reset) { - if (esp_timer_get_time() - t0 > SDMMC_TIMEOUT_MS) { + if (esp_timer_get_time() - t0 > SDMMC_HOST_RESET_TIMEOUT_US) { return ESP_ERR_TIMEOUT; } } @@ -197,10 +195,10 @@ static esp_err_t sdmmc_host_clock_update_command(int slot) return err; } - int t0 = esp_timer_get_time(); + int64_t t0 = esp_timer_get_time(); while (true) { - if (esp_timer_get_time() - t0 > SDMMC_TIMEOUT_MS) { + if (esp_timer_get_time() - t0 > SDMMC_HOST_CLOCK_UPDATE_CMD_TIMEOUT_US) { return ESP_ERR_TIMEOUT; } @@ -349,9 +347,9 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg) { /* Outputs should be synchronized to cclk_out */ cmd.use_hold_reg = 1; - int t0 = esp_timer_get_time(); + int64_t t0 = esp_timer_get_time(); while (SDMMC.cmd.start_command == 1) { - if (esp_timer_get_time() - t0 > SDMMC_TIMEOUT_MS) { + if (esp_timer_get_time() - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) { return ESP_ERR_TIMEOUT; } } diff --git a/components/driver/sdmmc/sdmmc_private.h b/components/driver/sdmmc/sdmmc_private.h index b065847579..529fa6b823 100644 --- a/components/driver/sdmmc/sdmmc_private.h +++ b/components/driver/sdmmc/sdmmc_private.h @@ -18,6 +18,10 @@ typedef struct { uint32_t dma_status; ///< masked DMA interrupt status } sdmmc_event_t; +#define SDMMC_HOST_CLOCK_UPDATE_CMD_TIMEOUT_US 1000 * 1000 +#define SDMMC_HOST_START_CMD_TIMEOUT_US 1000 * 1000 +#define SDMMC_HOST_RESET_TIMEOUT_US 5000 * 1000 + esp_err_t sdmmc_host_reset(void); esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg); diff --git a/components/driver/sdmmc/sdmmc_transaction.c b/components/driver/sdmmc/sdmmc_transaction.c index f79dd7feac..5a71479494 100644 --- a/components/driver/sdmmc/sdmmc_transaction.c +++ b/components/driver/sdmmc/sdmmc_transaction.c @@ -17,6 +17,7 @@ #include "driver/sdmmc_types.h" #include "driver/sdmmc_defs.h" #include "driver/sdmmc_host.h" +#include "esp_timer.h" #include "sdmmc_private.h" diff --git a/components/fatfs/vfs/vfs_fat_sdmmc.c b/components/fatfs/vfs/vfs_fat_sdmmc.c index 674ef3e90e..f3625a2f0e 100644 --- a/components/fatfs/vfs/vfs_fat_sdmmc.c +++ b/components/fatfs/vfs/vfs_fat_sdmmc.c @@ -88,7 +88,6 @@ static esp_err_t mount_prepare_mem(const char *base_path, if (ff_diskio_get_drive(&pdrv) != ESP_OK || pdrv == FF_DRV_NOT_USED) { ESP_LOGD(TAG, "the maximum count of volumes is already mounted"); return ESP_ERR_NO_MEM; - } // not using ff_memalloc here, as allocation in internal RAM is preferred diff --git a/components/sdmmc/CMakeLists.txt b/components/sdmmc/CMakeLists.txt index b6b1ad4f18..5de0232b67 100644 --- a/components/sdmmc/CMakeLists.txt +++ b/components/sdmmc/CMakeLists.txt @@ -6,6 +6,6 @@ idf_component_register(SRCS "sdmmc_cmd.c" "sdmmc_sd.c" INCLUDE_DIRS include REQUIRES driver - PRIV_REQUIRES soc) + PRIV_REQUIRES soc esp_timer) target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format") diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index 450c6e6c8a..9279532104 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "esp_timer.h" #include "sdmmc_common.h" @@ -451,11 +452,16 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, } uint32_t status = 0; size_t count = 0; + int64_t t0 = esp_timer_get_time(); /* 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 + if (esp_timer_get_time() - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) { + ESP_LOGE(TAG, "write sectors dma - timeout"); + return ESP_ERR_TIMEOUT; + } 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 % 10 == 0) { @@ -470,6 +476,7 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, if (host_is_spi(card)) { 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 (status & SD_SPI_R2_CARD_LOCKED) { @@ -551,10 +558,15 @@ esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst, } uint32_t status = 0; size_t count = 0; + int64_t t0 = esp_timer_get_time(); while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) { - // TODO: add some timeout here + if (esp_timer_get_time() - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) { + ESP_LOGE(TAG, "read sectors dma - timeout"); + return ESP_ERR_TIMEOUT; + } 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 % 10 == 0) { @@ -644,6 +656,7 @@ esp_err_t sdmmc_erase_sectors(sdmmc_card_t* card, size_t start_sector, uint32_t status; 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 (status != 0) { diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index 759151e14c..ee8a59cfb0 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/components/sdmmc/sdmmc_common.h @@ -30,6 +30,9 @@ #define SDMMC_GO_IDLE_DELAY_MS 20 #define SDMMC_IO_SEND_OP_COND_DELAY_MS 10 +#define SDMMC_INIT_WAIT_DATA_READY_TIMEOUT_US 5000 * 1000 +#define SDMMC_READY_FOR_DATA_TIMEOUT_US 5000 * 1000 + /* These delay values are mostly useful for cases when CD pin is not used, and * the card is removed. In this case, SDMMC peripheral may not always return * CMD_DONE / DATA_DONE interrupts after signaling the error. These timeouts work diff --git a/components/sdmmc/sdmmc_io.c b/components/sdmmc/sdmmc_io.c index f36528faa0..1e2e069f4d 100644 --- a/components/sdmmc/sdmmc_io.c +++ b/components/sdmmc/sdmmc_io.c @@ -324,6 +324,8 @@ esp_err_t sdmmc_io_read_bytes(sdmmc_card_t* card, uint32_t function, size_t size_aligned = size & (~3); size_t will_transfer = size_aligned > 0 ? size_aligned : size; + // Note: sdmmc_io_rw_extended has an internal timeout, + // typically SDMMC_DEFAULT_CMD_TIMEOUT_MS esp_err_t err = sdmmc_io_rw_extended(card, function, addr, SD_ARG_CMD53_READ | SD_ARG_CMD53_INCREMENT, pc_dst, will_transfer); @@ -347,6 +349,8 @@ esp_err_t sdmmc_io_write_bytes(sdmmc_card_t* card, uint32_t function, size_t size_aligned = size & (~3); size_t will_transfer = size_aligned > 0 ? size_aligned : size; + // Note: sdmmc_io_rw_extended has an internal timeout, + // typically SDMMC_DEFAULT_CMD_TIMEOUT_MS esp_err_t err = sdmmc_io_rw_extended(card, function, addr, SD_ARG_CMD53_WRITE | SD_ARG_CMD53_INCREMENT, (void*) pc_src, will_transfer); diff --git a/components/sdmmc/sdmmc_sd.c b/components/sdmmc/sdmmc_sd.c index 5b33cb7e45..63d6bf2ca5 100644 --- a/components/sdmmc/sdmmc_sd.c +++ b/components/sdmmc/sdmmc_sd.c @@ -14,6 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "esp_timer.h" #include "sdmmc_common.h" @@ -138,8 +139,12 @@ esp_err_t sdmmc_init_sd_wait_data_ready(sdmmc_card_t* card) /* Wait for the card to be ready for data transfers */ uint32_t status = 0; uint32_t count = 0; + int64_t t0 = esp_timer_get_time(); while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) { - // TODO: add some timeout here + if (esp_timer_get_time() - t0 > SDMMC_INIT_WAIT_DATA_READY_TIMEOUT_US) { + ESP_LOGE(TAG, "init wait data ready - timeout"); + return ESP_ERR_TIMEOUT; + } esp_err_t err = sdmmc_send_cmd_send_status(card, &status); if (err != ESP_OK) { return err;