diff --git a/components/driver/include/driver/sdmmc_types.h b/components/driver/include/driver/sdmmc_types.h index 4bc1e05e5..835eaa3fb 100644 --- a/components/driver/include/driver/sdmmc_types.h +++ b/components/driver/include/driver/sdmmc_types.h @@ -102,6 +102,7 @@ typedef struct { #define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) #define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) esp_err_t error; /*!< error returned from transfer */ + int timeout_ms; /*!< response timeout, in milliseconds */ } sdmmc_command_t; /** @@ -127,6 +128,7 @@ typedef struct { esp_err_t (*set_card_clk)(int slot, uint32_t freq_khz); /*!< host function to set card clock frequency */ esp_err_t (*do_transaction)(int slot, sdmmc_command_t* cmdinfo); /*!< host function to do a transaction */ esp_err_t (*deinit)(void); /*!< host function to deinitialize the driver */ + int command_timeout_ms; /*!< timeout, in milliseconds, of a single command. Set to 0 to use the default value. */ } sdmmc_host_t; /** diff --git a/components/driver/sdmmc_transaction.c b/components/driver/sdmmc_transaction.c index 8f06be88e..a0ff102db 100644 --- a/components/driver/sdmmc_transaction.c +++ b/components/driver/sdmmc_transaction.c @@ -33,13 +33,6 @@ */ #define SDMMC_DMA_DESC_CNT 4 -/* Max delay value is 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. This delay works - * as a safety net in such cases. - */ -#define SDMMC_MAX_EVT_WAIT_DELAY_MS 1000 - static const char* TAG = "sdmmc_req"; typedef enum { @@ -206,7 +199,7 @@ static esp_err_t handle_idle_state_events() static esp_err_t handle_event(sdmmc_command_t* cmd, sdmmc_req_state_t* state) { sdmmc_event_t evt; - esp_err_t err = sdmmc_host_wait_for_event(SDMMC_MAX_EVT_WAIT_DELAY_MS / portTICK_PERIOD_MS, &evt); + esp_err_t err = sdmmc_host_wait_for_event(cmd->timeout_ms / portTICK_PERIOD_MS, &evt); if (err != ESP_OK) { ESP_LOGE(TAG, "sdmmc_host_wait_for_event returned 0x%x", err); if (err == ESP_ERR_TIMEOUT) { diff --git a/components/sdmmc/sdmmc_cmd.c b/components/sdmmc/sdmmc_cmd.c index 3b962d432..a55440225 100644 --- a/components/sdmmc/sdmmc_cmd.c +++ b/components/sdmmc/sdmmc_cmd.c @@ -28,6 +28,14 @@ #define SDMMC_GO_IDLE_DELAY_MS 20 +/* 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 + * as a safety net in such cases. + */ +#define SDMMC_DEFAULT_CMD_TIMEOUT_MS 1000 // Max timeout of ordinary commands +#define SDMMC_WRITE_CMD_TIMEOUT_MS 5000 // Max timeout of write commands + static const char* TAG = "sdmmc_cmd"; static esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd); @@ -344,9 +352,15 @@ void sdmmc_card_print_info(FILE* stream, const sdmmc_card_t* card) static esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd) { + if (card->host.command_timeout_ms != 0) { + cmd->timeout_ms = card->host.command_timeout_ms; + } else if (cmd->timeout_ms == 0) { + cmd->timeout_ms = SDMMC_DEFAULT_CMD_TIMEOUT_MS; + } + int slot = card->host.slot; - ESP_LOGV(TAG, "sending cmd slot=%d op=%d arg=%x flags=%x data=%p blklen=%d datalen=%d", - slot, cmd->opcode, cmd->arg, cmd->flags, cmd->data, cmd->blklen, cmd->datalen); + ESP_LOGV(TAG, "sending cmd slot=%d op=%d arg=%x flags=%x data=%p blklen=%d datalen=%d timeout=%d", + slot, cmd->opcode, cmd->arg, cmd->flags, cmd->data, cmd->blklen, cmd->datalen, cmd->timeout_ms); esp_err_t err = (*card->host.do_transaction)(slot, cmd); if (err != 0) { ESP_LOGD(TAG, "sdmmc_req_run returned 0x%x", err); @@ -758,7 +772,8 @@ static esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, .flags = SCF_CMD_ADTC | SCF_RSP_R1, .blklen = block_size, .data = (void*) src, - .datalen = block_count * block_size + .datalen = block_count * block_size, + .timeout_ms = SDMMC_WRITE_CMD_TIMEOUT_MS }; if (block_count == 1) { cmd.opcode = MMC_WRITE_BLOCK_SINGLE;