#include "driver/sdspi_host.h"\r
#include "sdspi_private.h"\r
#include "sdspi_crc.h"\r
+#include "esp_timer.h"\r
+\r
\r
/// Max number of transactions in flight (used in start_command_write_blocks)\r
#define SDSPI_TRANSACTION_COUNT 4\r
#define SDSPI_MOSI_IDLE_VAL 0xff //!< Data value which causes MOSI to stay high\r
-/// FIXME: this has to be replaced with a timeout expressed in ms, rather in retries\r
-#define SDSPI_RETRY_COUNT 1000\r
#define GPIO_UNUSED 0xff //!< Flag indicating that CD/WP is unused\r
/// Size of the buffer returned by get_block_buf\r
#define SDSPI_BLOCK_BUF_SIZE (SDSPI_MAX_DATA_LEN + 4)\r
}\r
\r
// Wait until MISO goes high\r
-static esp_err_t poll_busy(int slot, spi_transaction_t* t)\r
+static esp_err_t poll_busy(int slot, spi_transaction_t* t, int timeout_ms)\r
{\r
uint8_t t_rx;\r
*t = (spi_transaction_t) {\r
};\r
esp_err_t ret;\r
\r
- for (int i = 0; i < SDSPI_RETRY_COUNT; i++) {\r
+ uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;\r
+ int nonzero_count = 0;\r
+ do {\r
t_rx = SDSPI_MOSI_IDLE_VAL;\r
t->rx_data[0] = 0;\r
ret = spi_device_transmit(spi_handle(slot), t);\r
return ret;\r
}\r
if (t->rx_data[0] != 0) {\r
- if (i < SDSPI_RETRY_COUNT - 2) {\r
- i = SDSPI_RETRY_COUNT - 2;\r
+ if (++nonzero_count == 2) {\r
+ return ESP_OK;\r
}\r
}\r
- }\r
- return ESP_OK;\r
+ } while(esp_timer_get_time() < t_end);\r
+ ESP_LOGD(TAG, "%s: timeout", __func__);\r
+ return ESP_ERR_TIMEOUT;\r
}\r
\r
// Wait for response token\r
-static esp_err_t poll_response_token(int slot, spi_transaction_t* t)\r
+static esp_err_t poll_response_token(int slot, spi_transaction_t* t, int timeout_ms)\r
{\r
uint8_t t_rx;\r
*t = (spi_transaction_t) {\r
.length = 8,\r
};\r
esp_err_t ret;\r
-\r
- for (int retry = 0; retry < SDSPI_RETRY_COUNT; retry++) {\r
+ uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;\r
+ do {\r
t_rx = SDSPI_MOSI_IDLE_VAL;\r
t->rx_data[0] = 0;\r
ret = spi_device_transmit(spi_handle(slot), t);\r
return ret;\r
}\r
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_OK) {\r
- break;\r
+ return ESP_OK;\r
}\r
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_CRC_ERR) {\r
return ESP_ERR_INVALID_CRC;\r
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_WRITE_ERR) {\r
return ESP_ERR_INVALID_RESPONSE;\r
}\r
- if (retry == SDSPI_RETRY_COUNT - 1) {\r
- return ESP_ERR_TIMEOUT;\r
- }\r
- }\r
+ } while (esp_timer_get_time() < t_end);\r
\r
- return ESP_OK;\r
+ ESP_LOGD(TAG, "%s: timeout", __func__);\r
+ return ESP_ERR_TIMEOUT;\r
}\r
\r
// Wait for data token, reading 8 bytes at a time.\r
// If the token is found, write all subsequent bytes to extra_ptr,\r
// and store the number of bytes written to extra_size.\r
static esp_err_t poll_data_token(int slot, spi_transaction_t* t,\r
- uint8_t* extra_ptr, size_t* extra_size)\r
+ uint8_t* extra_ptr, size_t* extra_size, int timeout_ms)\r
{\r
uint8_t t_rx[8];\r
*t = (spi_transaction_t) {\r
.length = sizeof(t_rx) * 8,\r
};\r
esp_err_t ret;\r
- for (int retry = 0; retry < SDSPI_RETRY_COUNT; retry++) {\r
+ uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;\r
+ do {\r
memset(t_rx, SDSPI_MOSI_IDLE_VAL, sizeof(t_rx));\r
ret = spi_device_transmit(spi_handle(slot), t);\r
if (ret != ESP_OK) {\r
}\r
}\r
if (found) {\r
- break;\r
+ return ESP_OK;\r
}\r
- if (retry == SDSPI_RETRY_COUNT - 1) {\r
- return ESP_ERR_TIMEOUT;\r
- }\r
- }\r
- return ESP_OK;\r
+ } while (esp_timer_get_time() < t_end);\r
+ ESP_LOGD(TAG, "%s: timeout", __func__);\r
+ return ESP_ERR_TIMEOUT;\r
}\r
\r
\r
if (need_poll) {\r
// Wait for data to be ready\r
spi_transaction_t* t_poll = get_transaction(slot);\r
- poll_data_token(slot, t_poll, cmd_u8 + SDSPI_CMD_R1_SIZE, &extra_data_size);\r
+ ret = poll_data_token(slot, t_poll, cmd_u8 + SDSPI_CMD_R1_SIZE, &extra_data_size, cmd->timeout_ms);\r
+ release_transaction(slot);\r
+ if (ret != ESP_OK) {\r
+ return ret;\r
+ }\r
if (extra_data_size) {\r
extra_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;\r
}\r
- release_transaction(slot);\r
}\r
\r
// Arrange RX buffer\r
// To end multi block transfer, send stop command and wait for the\r
// card to process it\r
sdspi_hw_cmd_t stop_cmd;\r
- make_hw_cmd(MMC_STOP_TRANSMISSION, 0, &stop_cmd);\r
+ make_hw_cmd(MMC_STOP_TRANSMISSION, 0, cmd->timeout_ms, &stop_cmd);\r
ret = start_command_default(slot, SDSPI_CMD_FLAG_RSP_R1, &stop_cmd);\r
if (ret != ESP_OK) {\r
return ret;\r
}\r
spi_transaction_t* t_poll = get_transaction(slot);\r
- ret = poll_busy(slot, t_poll);\r
+ ret = poll_busy(slot, t_poll, cmd->timeout_ms);\r
release_transaction(slot);\r
+ if (ret != ESP_OK) {\r
+ return ret;\r
+ }\r
}\r
return ESP_OK;\r
}\r
\r
// Poll for response\r
spi_transaction_t* t_poll = get_transaction(slot);\r
- ret = poll_response_token(slot, t_poll);\r
+ ret = poll_response_token(slot, t_poll, cmd->timeout_ms);\r
release_transaction(slot);\r
if (ret != ESP_OK) {\r
return ret;\r
\r
// Wait for the card to finish writing data\r
t_poll = get_transaction(slot);\r
- ret = poll_busy(slot, t_poll);\r
+ ret = poll_busy(slot, t_poll, cmd->timeout_ms);\r
release_transaction(slot);\r
if (ret != ESP_OK) {\r
return ret;\r
wait_for_transactions(slot);\r
\r
spi_transaction_t* t_poll = get_transaction(slot);\r
- ret = poll_busy(slot, t_poll);\r
+ ret = poll_busy(slot, t_poll, cmd->timeout_ms);\r
release_transaction(slot);\r
if (ret != ESP_OK) {\r
return ret;\r