kopia lustrzana https://github.com/espressif/esp-idf
Merge branch 'bugfix/sdmmc_vfs_deinit' into 'master'
SDSPI bug fixes See merge request !1647pull/1387/head
commit
68bba96911
|
@ -25,12 +25,12 @@
|
|||
#include "driver/sdspi_host.h"
|
||||
#include "sdspi_private.h"
|
||||
#include "sdspi_crc.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
|
||||
/// Max number of transactions in flight (used in start_command_write_blocks)
|
||||
#define SDSPI_TRANSACTION_COUNT 4
|
||||
#define SDSPI_MOSI_IDLE_VAL 0xff //!< Data value which causes MOSI to stay high
|
||||
/// FIXME: this has to be replaced with a timeout expressed in ms, rather in retries
|
||||
#define SDSPI_RETRY_COUNT 1000
|
||||
#define GPIO_UNUSED 0xff //!< Flag indicating that CD/WP is unused
|
||||
/// Size of the buffer returned by get_block_buf
|
||||
#define SDSPI_BLOCK_BUF_SIZE (SDSPI_MAX_DATA_LEN + 4)
|
||||
|
@ -426,7 +426,7 @@ static esp_err_t start_command_default(int slot, int flags, sdspi_hw_cmd_t *cmd)
|
|||
}
|
||||
|
||||
// Wait until MISO goes high
|
||||
static esp_err_t poll_busy(int slot, spi_transaction_t* t)
|
||||
static esp_err_t poll_busy(int slot, spi_transaction_t* t, int timeout_ms)
|
||||
{
|
||||
uint8_t t_rx;
|
||||
*t = (spi_transaction_t) {
|
||||
|
@ -436,7 +436,9 @@ static esp_err_t poll_busy(int slot, spi_transaction_t* t)
|
|||
};
|
||||
esp_err_t ret;
|
||||
|
||||
for (int i = 0; i < SDSPI_RETRY_COUNT; i++) {
|
||||
uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
|
||||
int nonzero_count = 0;
|
||||
do {
|
||||
t_rx = SDSPI_MOSI_IDLE_VAL;
|
||||
t->rx_data[0] = 0;
|
||||
ret = spi_device_transmit(spi_handle(slot), t);
|
||||
|
@ -444,16 +446,17 @@ static esp_err_t poll_busy(int slot, spi_transaction_t* t)
|
|||
return ret;
|
||||
}
|
||||
if (t->rx_data[0] != 0) {
|
||||
if (i < SDSPI_RETRY_COUNT - 2) {
|
||||
i = SDSPI_RETRY_COUNT - 2;
|
||||
if (++nonzero_count == 2) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
} while(esp_timer_get_time() < t_end);
|
||||
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
// Wait for response token
|
||||
static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
||||
static esp_err_t poll_response_token(int slot, spi_transaction_t* t, int timeout_ms)
|
||||
{
|
||||
uint8_t t_rx;
|
||||
*t = (spi_transaction_t) {
|
||||
|
@ -462,8 +465,8 @@ static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
|||
.length = 8,
|
||||
};
|
||||
esp_err_t ret;
|
||||
|
||||
for (int retry = 0; retry < SDSPI_RETRY_COUNT; retry++) {
|
||||
uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
|
||||
do {
|
||||
t_rx = SDSPI_MOSI_IDLE_VAL;
|
||||
t->rx_data[0] = 0;
|
||||
ret = spi_device_transmit(spi_handle(slot), t);
|
||||
|
@ -471,7 +474,7 @@ static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
|||
return ret;
|
||||
}
|
||||
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_OK) {
|
||||
break;
|
||||
return ESP_OK;
|
||||
}
|
||||
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_CRC_ERR) {
|
||||
return ESP_ERR_INVALID_CRC;
|
||||
|
@ -479,19 +482,17 @@ static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
|||
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_WRITE_ERR) {
|
||||
return ESP_ERR_INVALID_RESPONSE;
|
||||
}
|
||||
if (retry == SDSPI_RETRY_COUNT - 1) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
} while (esp_timer_get_time() < t_end);
|
||||
|
||||
return ESP_OK;
|
||||
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
// Wait for data token, reading 8 bytes at a time.
|
||||
// If the token is found, write all subsequent bytes to extra_ptr,
|
||||
// and store the number of bytes written to extra_size.
|
||||
static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
||||
uint8_t* extra_ptr, size_t* extra_size)
|
||||
uint8_t* extra_ptr, size_t* extra_size, int timeout_ms)
|
||||
{
|
||||
uint8_t t_rx[8];
|
||||
*t = (spi_transaction_t) {
|
||||
|
@ -500,7 +501,8 @@ static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
|||
.length = sizeof(t_rx) * 8,
|
||||
};
|
||||
esp_err_t ret;
|
||||
for (int retry = 0; retry < SDSPI_RETRY_COUNT; retry++) {
|
||||
uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
|
||||
do {
|
||||
memset(t_rx, SDSPI_MOSI_IDLE_VAL, sizeof(t_rx));
|
||||
ret = spi_device_transmit(spi_handle(slot), t);
|
||||
if (ret != ESP_OK) {
|
||||
|
@ -522,13 +524,11 @@ static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
|||
}
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
return ESP_OK;
|
||||
}
|
||||
if (retry == SDSPI_RETRY_COUNT - 1) {
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
} while (esp_timer_get_time() < t_end);
|
||||
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||
return ESP_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
|
@ -608,11 +608,14 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
|||
if (need_poll) {
|
||||
// Wait for data to be ready
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
poll_data_token(slot, t_poll, cmd_u8 + SDSPI_CMD_R1_SIZE, &extra_data_size);
|
||||
ret = poll_data_token(slot, t_poll, cmd_u8 + SDSPI_CMD_R1_SIZE, &extra_data_size, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
if (extra_data_size) {
|
||||
extra_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;
|
||||
}
|
||||
release_transaction(slot);
|
||||
}
|
||||
|
||||
// Arrange RX buffer
|
||||
|
@ -674,14 +677,17 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
|||
// To end multi block transfer, send stop command and wait for the
|
||||
// card to process it
|
||||
sdspi_hw_cmd_t stop_cmd;
|
||||
make_hw_cmd(MMC_STOP_TRANSMISSION, 0, &stop_cmd);
|
||||
make_hw_cmd(MMC_STOP_TRANSMISSION, 0, cmd->timeout_ms, &stop_cmd);
|
||||
ret = start_command_default(slot, SDSPI_CMD_FLAG_RSP_R1, &stop_cmd);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
ret = poll_busy(slot, t_poll);
|
||||
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -768,7 +774,7 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
|||
|
||||
// Poll for response
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
ret = poll_response_token(slot, t_poll);
|
||||
ret = poll_response_token(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
|
@ -776,7 +782,7 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
|||
|
||||
// Wait for the card to finish writing data
|
||||
t_poll = get_transaction(slot);
|
||||
ret = poll_busy(slot, t_poll);
|
||||
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
|
@ -803,7 +809,7 @@ static esp_err_t start_command_write_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
|||
wait_for_transactions(slot);
|
||||
|
||||
spi_transaction_t* t_poll = get_transaction(slot);
|
||||
ret = poll_busy(slot, t_poll);
|
||||
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
|
||||
release_transaction(slot);
|
||||
if (ret != ESP_OK) {
|
||||
return ret;
|
||||
|
|
|
@ -73,6 +73,8 @@ typedef struct {
|
|||
uint8_t r1;
|
||||
/// Up to 16 bytes of response. Luckily, this is aligned on 4 byte boundary.
|
||||
uint32_t response[4];
|
||||
/// response timeout, in milliseconds
|
||||
int timeout_ms;
|
||||
} sdspi_hw_cmd_t;
|
||||
|
||||
#define SDSPI_CMD_NORESP_SIZE 6 //!< Size of the command without any response
|
||||
|
@ -90,7 +92,7 @@ typedef struct {
|
|||
|
||||
#define SDSPI_MAX_DATA_LEN 512 //!< Max size of single block transfer
|
||||
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, sdspi_hw_cmd_t *hw_cmd);
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, int timeout_ms, sdspi_hw_cmd_t *hw_cmd);
|
||||
|
||||
esp_err_t sdspi_host_start_command(int slot, sdspi_hw_cmd_t *cmd,
|
||||
void *data, uint32_t data_size, int flags);
|
||||
|
|
|
@ -36,7 +36,7 @@ static uint8_t sdspi_msg_crc7(sdspi_hw_cmd_t* hw_cmd)
|
|||
return sdspi_crc7((const uint8_t *)hw_cmd, bytes_to_crc);
|
||||
}
|
||||
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, sdspi_hw_cmd_t *hw_cmd)
|
||||
void make_hw_cmd(uint32_t opcode, uint32_t arg, int timeout_ms, sdspi_hw_cmd_t *hw_cmd)
|
||||
{
|
||||
hw_cmd->start_bit = 0;
|
||||
hw_cmd->transmission_bit = 1;
|
||||
|
@ -48,6 +48,7 @@ void make_hw_cmd(uint32_t opcode, uint32_t arg, sdspi_hw_cmd_t *hw_cmd)
|
|||
uint32_t arg_s = __builtin_bswap32(arg);
|
||||
memcpy(hw_cmd->arguments, &arg_s, sizeof(arg_s));
|
||||
hw_cmd->crc7 = sdspi_msg_crc7(hw_cmd);
|
||||
hw_cmd->timeout_ms = timeout_ms;
|
||||
}
|
||||
|
||||
esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
|
||||
|
@ -55,7 +56,7 @@ esp_err_t sdspi_host_do_transaction(int slot, sdmmc_command_t *cmdinfo)
|
|||
_lock_acquire(&s_lock);
|
||||
// Convert the command to wire format
|
||||
sdspi_hw_cmd_t hw_cmd;
|
||||
make_hw_cmd(cmdinfo->opcode, cmdinfo->arg, &hw_cmd);
|
||||
make_hw_cmd(cmdinfo->opcode, cmdinfo->arg, cmdinfo->timeout_ms, &hw_cmd);
|
||||
|
||||
// Flags indicate which of the transfer types should be used
|
||||
int flags = 0;
|
||||
|
|
|
@ -128,6 +128,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
|
|||
goto fail;
|
||||
}
|
||||
free(workbuf);
|
||||
workbuf = NULL;
|
||||
ESP_LOGW(TAG, "mounting again");
|
||||
res = f_mount(fs, drv, 0);
|
||||
if (res != FR_OK) {
|
||||
|
@ -139,7 +140,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
|
|||
return ESP_OK;
|
||||
|
||||
fail:
|
||||
sdmmc_host_deinit();
|
||||
host_config->deinit();
|
||||
free(workbuf);
|
||||
if (fs) {
|
||||
f_mount(NULL, drv, 0);
|
||||
|
@ -160,10 +161,11 @@ esp_err_t esp_vfs_fat_sdmmc_unmount()
|
|||
char drv[3] = {(char)('0' + s_pdrv), ':', 0};
|
||||
f_mount(0, drv, 0);
|
||||
// release SD driver
|
||||
esp_err_t (*host_deinit)() = s_card->host.deinit;
|
||||
ff_diskio_unregister(s_pdrv);
|
||||
free(s_card);
|
||||
s_card = NULL;
|
||||
sdmmc_host_deinit();
|
||||
(*host_deinit)();
|
||||
esp_err_t err = esp_vfs_fat_unregister_path(s_base_path);
|
||||
free(s_base_path);
|
||||
s_base_path = NULL;
|
||||
|
|
Ładowanie…
Reference in New Issue