From f13c9f746fb97dd46f989ce1a41191942e108d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Tue, 16 May 2023 00:16:52 +0200 Subject: [PATCH] sdmmc: incrementally increase delay of vTaskDelay Prevents unnecessary slowdown in polling functions --- components/driver/sdmmc/sdmmc_host.c | 37 +++++++++++++++++++--------- components/sdmmc/sdmmc_cmd.c | 25 ++++++++++++++----- components/sdmmc/sdmmc_common.h | 4 +-- components/sdmmc/sdmmc_sd.c | 10 ++++++-- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/components/driver/sdmmc/sdmmc_host.c b/components/driver/sdmmc/sdmmc_host.c index 0596d863ce..d2d3d02eb9 100644 --- a/components/driver/sdmmc/sdmmc_host.c +++ b/components/driver/sdmmc/sdmmc_host.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -79,12 +79,18 @@ esp_err_t sdmmc_host_reset(void) SDMMC.ctrl.fifo_reset = 1; // Wait for the reset bits to be cleared by hardware + int64_t yield_delay_us = 100 * 1000; // initially 100ms int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; while (SDMMC.ctrl.controller_reset || SDMMC.ctrl.fifo_reset || SDMMC.ctrl.dma_reset) { - if (esp_timer_get_time() - t0 > SDMMC_HOST_RESET_TIMEOUT_US) { + t1 = esp_timer_get_time(); + if (t1 - t0 > SDMMC_HOST_RESET_TIMEOUT_US) { return ESP_ERR_TIMEOUT; } - vTaskDelay(1); + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + vTaskDelay(1); + } } return ESP_OK; @@ -195,13 +201,14 @@ static esp_err_t sdmmc_host_clock_update_command(int slot) ESP_RETURN_ON_ERROR(sdmmc_host_start_command(slot, cmd_val, 0), TAG, "sdmmc_host_start_command returned 0x%x", err_rc_); + int64_t yield_delay_us = 100 * 1000; // initially 100ms int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; while (true) { - - if (esp_timer_get_time() - t0 > SDMMC_HOST_CLOCK_UPDATE_CMD_TIMEOUT_US) { + t1 = esp_timer_get_time(); + if (t1 - t0 > SDMMC_HOST_CLOCK_UPDATE_CMD_TIMEOUT_US) { return ESP_ERR_TIMEOUT; } - // Sending clock update command to the CIU can generate HLE error. // According to the manual, this is okay and we must retry the command. if (SDMMC.rintsts.hle) { @@ -215,8 +222,10 @@ static esp_err_t sdmmc_host_clock_update_command(int slot) repeat = false; break; } - - vTaskDelay(1); + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + vTaskDelay(1); + } } } @@ -401,12 +410,18 @@ 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; + int64_t yield_delay_us = 100 * 1000; // initially 100ms int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; while (SDMMC.cmd.start_command == 1) { - if (esp_timer_get_time() - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) { + t1 = esp_timer_get_time(); + if (t1 - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) { return ESP_ERR_TIMEOUT; } - vTaskDelay(1); + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + vTaskDelay(1); + } } SDMMC.cmdarg = arg; cmd.card_num = slot; @@ -866,7 +881,7 @@ static void sdmmc_isr(void* arg) { uint32_t sdio_pending = SDMMC.mintsts.sdio; if (sdio_pending) { - // disable the interrupt (no need to clear here, this is done in sdmmc_host_io_wait_int) + // disable the interrupt (no need to clear here, this is done in sdmmc_host_io_int_wait) SDMMC.intmask.sdio &= ~sdio_pending; xSemaphoreGiveFromISR(s_io_intr_event, &higher_priority_task_awoken); } diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index 1851a8ca94..71302cccae 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -452,22 +452,28 @@ esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, } uint32_t status = 0; 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) && !(status & MMC_R1_READY_FOR_DATA)) { - if (esp_timer_get_time() - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) { + 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 % 10 == 0) { + if (++count % 16 == 0) { ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); } - vTaskDelay(1); } /* 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 @@ -559,21 +565,28 @@ esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst, } uint32_t status = 0; 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) && !(status & MMC_R1_READY_FOR_DATA)) { - if (esp_timer_get_time() - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) { + 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 % 10 == 0) { + if (++count % 16 == 0) { ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); } - vTaskDelay(1); } return ESP_OK; } diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index ee8a59cfb0..e28ef3d0ec 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/components/sdmmc/sdmmc_common.h @@ -30,8 +30,8 @@ #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 +#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 diff --git a/components/sdmmc/sdmmc_sd.c b/components/sdmmc/sdmmc_sd.c index 50147fef6d..6c71f41e4d 100644 --- a/components/sdmmc/sdmmc_sd.c +++ b/components/sdmmc/sdmmc_sd.c @@ -139,12 +139,19 @@ 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 yield_delay_us = 100 * 1000; // initially 100ms int64_t t0 = esp_timer_get_time(); + int64_t t1 = 0; while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) { - if (esp_timer_get_time() - t0 > SDMMC_INIT_WAIT_DATA_READY_TIMEOUT_US) { + t1 = esp_timer_get_time(); + if (t1 - t0 > SDMMC_INIT_WAIT_DATA_READY_TIMEOUT_US) { ESP_LOGE(TAG, "init wait data ready - timeout"); return ESP_ERR_TIMEOUT; } + if (t1 - t0 > yield_delay_us) { + yield_delay_us *= 2; + vTaskDelay(1); + } esp_err_t err = sdmmc_send_cmd_send_status(card, &status); if (err != ESP_OK) { return err; @@ -152,7 +159,6 @@ esp_err_t sdmmc_init_sd_wait_data_ready(sdmmc_card_t* card) if (++count % 16 == 0) { ESP_LOGV(TAG, "waiting for card to become ready (%d)", count); } - vTaskDelay(1); } return ESP_OK; }