sdmmc: allow command timeouts to be configured
Previously the timeout was set to the same value (1000ms) for all kinds of commands. In some cases, such as with slow cards, write commands failed to complete in time. This change makes command timeouts configurable via sdmmc_host_t structure, and also makes default timeouts different for ordinary commands and write commands. Closes https://github.com/espressif/esp-idf/issues/1093 Ref TW15774.
This commit is contained in:
parent
8e47c355fa
commit
3cf23ff77d
3 changed files with 21 additions and 11 deletions
|
@ -102,6 +102,7 @@ typedef struct {
|
||||||
#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
#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)
|
#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX)
|
||||||
esp_err_t error; /*!< error returned from transfer */
|
esp_err_t error; /*!< error returned from transfer */
|
||||||
|
int timeout_ms; /*!< response timeout, in milliseconds */
|
||||||
} sdmmc_command_t;
|
} 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 (*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 (*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 */
|
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;
|
} sdmmc_host_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,13 +33,6 @@
|
||||||
*/
|
*/
|
||||||
#define SDMMC_DMA_DESC_CNT 4
|
#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";
|
static const char* TAG = "sdmmc_req";
|
||||||
|
|
||||||
typedef enum {
|
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)
|
static esp_err_t handle_event(sdmmc_command_t* cmd, sdmmc_req_state_t* state)
|
||||||
{
|
{
|
||||||
sdmmc_event_t evt;
|
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) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "sdmmc_host_wait_for_event returned 0x%x", err);
|
ESP_LOGE(TAG, "sdmmc_host_wait_for_event returned 0x%x", err);
|
||||||
if (err == ESP_ERR_TIMEOUT) {
|
if (err == ESP_ERR_TIMEOUT) {
|
||||||
|
|
|
@ -28,6 +28,14 @@
|
||||||
|
|
||||||
#define SDMMC_GO_IDLE_DELAY_MS 20
|
#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 const char* TAG = "sdmmc_cmd";
|
||||||
|
|
||||||
static esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* 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)
|
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;
|
int slot = card->host.slot;
|
||||||
ESP_LOGV(TAG, "sending cmd slot=%d op=%d arg=%x flags=%x data=%p blklen=%d datalen=%d",
|
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);
|
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);
|
esp_err_t err = (*card->host.do_transaction)(slot, cmd);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
ESP_LOGD(TAG, "sdmmc_req_run returned 0x%x", err);
|
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,
|
.flags = SCF_CMD_ADTC | SCF_RSP_R1,
|
||||||
.blklen = block_size,
|
.blklen = block_size,
|
||||||
.data = (void*) src,
|
.data = (void*) src,
|
||||||
.datalen = block_count * block_size
|
.datalen = block_count * block_size,
|
||||||
|
.timeout_ms = SDMMC_WRITE_CMD_TIMEOUT_MS
|
||||||
};
|
};
|
||||||
if (block_count == 1) {
|
if (block_count == 1) {
|
||||||
cmd.opcode = MMC_WRITE_BLOCK_SINGLE;
|
cmd.opcode = MMC_WRITE_BLOCK_SINGLE;
|
||||||
|
|
Loading…
Reference in a new issue