sdspi: handle delayed responses for data write commands

Command response tokens can be delayed from the original command by 1
to 8 bytes. In 4a2489b9, handling for delayed tokens was added for
normal (no data) commands, and data read commands. This adds handling
for delayed commands for data write commands.
This commit is contained in:
Ivan Grokhotkov 2018-04-23 20:10:38 +08:00
parent e3d404bb8f
commit 2699bb49ae

View file

@ -67,6 +67,8 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
static esp_err_t start_command_default(int slot, int flags, sdspi_hw_cmd_t *cmd);
static esp_err_t poll_cmd_response(int slot, sdspi_hw_cmd_t *cmd);
/// A few helper functions
/// Set CS high for given slot
@ -429,32 +431,21 @@ static esp_err_t start_command_default(int slot, int flags, sdspi_hw_cmd_t *cmd)
/* response is a stuff byte from previous transfer, ignore it */
cmd->r1 = 0xff;
}
if (ret != ESP_OK) {
ESP_LOGD(TAG, "%s: spi_device_transmit returned 0x%x", __func__, ret);
return ret;
}
if (flags & SDSPI_CMD_FLAG_NORSP) {
/* no (correct) response expected from the card, so skip polling loop */
ESP_LOGV(TAG, "%s: ignoring response byte", __func__);
cmd->r1 = 0x00;
}
int response_delay_bytes = SDSPI_RESPONSE_MAX_DELAY;
while ((cmd->r1 & SD_SPI_R1_NO_RESPONSE) != 0 && response_delay_bytes-- > 0) {
spi_transaction_t* t = get_transaction(slot);
*t = (spi_transaction_t) {
.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA,
.length = 8,
};
t->tx_data[0] = 0xff;
ret = spi_device_transmit(spi_handle(slot), t);
uint8_t r1 = t->rx_data[0];
release_transaction(slot);
if (ret != ESP_OK) {
return ret;
}
cmd->r1 = r1;
ret = poll_cmd_response(slot, cmd);
if (ret != ESP_OK) {
ESP_LOGD(TAG, "%s: poll_cmd_response returned 0x%x", __func__, ret);
return ret;
}
if (cmd->r1 & SD_SPI_R1_NO_RESPONSE) {
ESP_LOGD(TAG, "%s: no response token found", __func__);
return ESP_ERR_TIMEOUT;
}
return ret;
return ESP_OK;
}
// Wait until MISO goes high
@ -563,6 +554,30 @@ static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
return ESP_ERR_TIMEOUT;
}
static esp_err_t poll_cmd_response(int slot, sdspi_hw_cmd_t *cmd)
{
int response_delay_bytes = SDSPI_RESPONSE_MAX_DELAY;
while ((cmd->r1 & SD_SPI_R1_NO_RESPONSE) != 0 && response_delay_bytes-- > 0) {
spi_transaction_t* t = get_transaction(slot);
*t = (spi_transaction_t) {
.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA,
.length = 8,
};
t->tx_data[0] = 0xff;
esp_err_t ret = spi_device_transmit(spi_handle(slot), t);
uint8_t r1 = t->rx_data[0];
release_transaction(slot);
if (ret != ESP_OK) {
return ret;
}
cmd->r1 = r1;
}
if (cmd->r1 & SD_SPI_R1_NO_RESPONSE) {
return ESP_ERR_TIMEOUT;
}
return ESP_OK;
}
/**
* Receiving one or more blocks of data happens as follows:
@ -759,9 +774,17 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
if (ret != ESP_OK) {
return ret;
}
wait_for_transactions(slot);
// Poll for command response which may be delayed up to 8 bytes
ret = poll_cmd_response(slot, cmd);
if (ret != ESP_OK) {
ESP_LOGD(TAG, "%s: poll_cmd_response returned 0x%x", __func__, ret);
return ret;
}
uint8_t start_token = tx_length <= SDSPI_MAX_DATA_LEN ?
TOKEN_BLOCK_START : TOKEN_BLOCK_START_WRITE_MULTI;
wait_for_transactions(slot);
while (tx_length > 0) {
@ -771,7 +794,7 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
.length = sizeof(start_token) * 8,
.tx_buffer = &start_token
};
esp_err_t ret = spi_device_queue_trans(spi_handle(slot), t_start_token, 0);
ret = spi_device_queue_trans(spi_handle(slot), t_start_token, 0);
if (ret != ESP_OK) {
return ret;
}
@ -816,12 +839,6 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
// Wait for data to be sent
wait_for_transactions(slot);
// Check if R1 response for the command was correct
if (cmd->r1 != 0) {
ESP_LOGD(TAG, "%s: invalid R1 response: 0x%02x", __func__, cmd->r1);
return ESP_ERR_INVALID_RESPONSE;
}
// Poll for response
spi_transaction_t* t_poll = get_transaction(slot);
ret = poll_response_token(slot, t_poll, cmd->timeout_ms);