From 6d46eed8e408fdb2cb25f5a7cc5efab24eb2e1c8 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 5 Jul 2018 16:50:16 +0800 Subject: [PATCH] sdmmc: enable host auto_stop only for certain commands Perviously host send_auto_stop flag would be set for every data transfer over 1 block long. This caused stop commands to be sent after CMD53, which shouldn't be done. Fix by adding an explicit list of commands for which send_auto_stop should be set. --- components/driver/include/driver/sdmmc_defs.h | 2 ++ components/driver/sdmmc_transaction.c | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/components/driver/include/driver/sdmmc_defs.h b/components/driver/include/driver/sdmmc_defs.h index b9b13680d..c3a63bd8d 100644 --- a/components/driver/include/driver/sdmmc_defs.h +++ b/components/driver/include/driver/sdmmc_defs.h @@ -31,11 +31,13 @@ #define MMC_SEND_EXT_CSD 8 /* R1 */ #define MMC_SEND_CSD 9 /* R2 */ #define MMC_SEND_CID 10 /* R1 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* R1 */ #define MMC_STOP_TRANSMISSION 12 /* R1B */ #define MMC_SEND_STATUS 13 /* R1 */ #define MMC_SET_BLOCKLEN 16 /* R1 */ #define MMC_READ_BLOCK_SINGLE 17 /* R1 */ #define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* R1 */ #define MMC_SET_BLOCK_COUNT 23 /* R1 */ #define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */ #define MMC_WRITE_BLOCK_MULTIPLE 25 /* R1 */ diff --git a/components/driver/sdmmc_transaction.c b/components/driver/sdmmc_transaction.c index 495d3d4a1..43f74c086 100644 --- a/components/driver/sdmmc_transaction.c +++ b/components/driver/sdmmc_transaction.c @@ -271,6 +271,16 @@ static esp_err_t handle_event(sdmmc_command_t* cmd, sdmmc_req_state_t* state, return ESP_OK; } +static bool cmd_needs_auto_stop(const sdmmc_command_t* cmd) +{ + /* SDMMC host needs an "auto stop" flag for the following commands: */ + return cmd->datalen > 0 && + (cmd->opcode == MMC_WRITE_BLOCK_MULTIPLE || + cmd->opcode == MMC_READ_BLOCK_MULTIPLE || + cmd->opcode == MMC_WRITE_DAT_UNTIL_STOP || + cmd->opcode == MMC_READ_DAT_UNTIL_STOP); +} + static sdmmc_hw_cmd_t make_hw_cmd(sdmmc_command_t* cmd) { sdmmc_hw_cmd_t res = { 0 }; @@ -302,12 +312,11 @@ static sdmmc_hw_cmd_t make_hw_cmd(sdmmc_command_t* cmd) res.rw = 1; } assert(cmd->datalen % cmd->blklen == 0); - if ((cmd->datalen / cmd->blklen) > 1) { - res.send_auto_stop = 1; - } + res.send_auto_stop = cmd_needs_auto_stop(cmd) ? 1 : 0; } - ESP_LOGV(TAG, "%s: opcode=%d, rexp=%d, crc=%d", __func__, - res.cmd_index, res.response_expect, res.check_response_crc); + ESP_LOGV(TAG, "%s: opcode=%d, rexp=%d, crc=%d, auto_stop=%d", __func__, + res.cmd_index, res.response_expect, res.check_response_crc, + res.send_auto_stop); return res; }