mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
Merge branch 'bugfix/sdmmc_vfs_deinit' into 'master'
SDSPI bug fixes See merge request !1647
This commit is contained in:
@@ -25,12 +25,12 @@
|
|||||||
#include "driver/sdspi_host.h"
|
#include "driver/sdspi_host.h"
|
||||||
#include "sdspi_private.h"
|
#include "sdspi_private.h"
|
||||||
#include "sdspi_crc.h"
|
#include "sdspi_crc.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
|
|
||||||
|
|
||||||
/// Max number of transactions in flight (used in start_command_write_blocks)
|
/// Max number of transactions in flight (used in start_command_write_blocks)
|
||||||
#define SDSPI_TRANSACTION_COUNT 4
|
#define SDSPI_TRANSACTION_COUNT 4
|
||||||
#define SDSPI_MOSI_IDLE_VAL 0xff //!< Data value which causes MOSI to stay high
|
#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
|
#define GPIO_UNUSED 0xff //!< Flag indicating that CD/WP is unused
|
||||||
/// Size of the buffer returned by get_block_buf
|
/// Size of the buffer returned by get_block_buf
|
||||||
#define SDSPI_BLOCK_BUF_SIZE (SDSPI_MAX_DATA_LEN + 4)
|
#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
|
// 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;
|
uint8_t t_rx;
|
||||||
*t = (spi_transaction_t) {
|
*t = (spi_transaction_t) {
|
||||||
@@ -436,7 +436,9 @@ static esp_err_t poll_busy(int slot, spi_transaction_t* t)
|
|||||||
};
|
};
|
||||||
esp_err_t ret;
|
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 = SDSPI_MOSI_IDLE_VAL;
|
||||||
t->rx_data[0] = 0;
|
t->rx_data[0] = 0;
|
||||||
ret = spi_device_transmit(spi_handle(slot), t);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
if (t->rx_data[0] != 0) {
|
if (t->rx_data[0] != 0) {
|
||||||
if (i < SDSPI_RETRY_COUNT - 2) {
|
if (++nonzero_count == 2) {
|
||||||
i = SDSPI_RETRY_COUNT - 2;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} while(esp_timer_get_time() < t_end);
|
||||||
return ESP_OK;
|
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||||
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for response token
|
// 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;
|
uint8_t t_rx;
|
||||||
*t = (spi_transaction_t) {
|
*t = (spi_transaction_t) {
|
||||||
@@ -462,8 +465,8 @@ static esp_err_t poll_response_token(int slot, spi_transaction_t* t)
|
|||||||
.length = 8,
|
.length = 8,
|
||||||
};
|
};
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
uint64_t t_end = esp_timer_get_time() + timeout_ms * 1000;
|
||||||
for (int retry = 0; retry < SDSPI_RETRY_COUNT; retry++) {
|
do {
|
||||||
t_rx = SDSPI_MOSI_IDLE_VAL;
|
t_rx = SDSPI_MOSI_IDLE_VAL;
|
||||||
t->rx_data[0] = 0;
|
t->rx_data[0] = 0;
|
||||||
ret = spi_device_transmit(spi_handle(slot), t);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_OK) {
|
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) {
|
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_CRC_ERR) {
|
||||||
return ESP_ERR_INVALID_CRC;
|
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) {
|
if ((t->rx_data[0] & TOKEN_RSP_MASK) == TOKEN_RSP_WRITE_ERR) {
|
||||||
return ESP_ERR_INVALID_RESPONSE;
|
return ESP_ERR_INVALID_RESPONSE;
|
||||||
}
|
}
|
||||||
if (retry == SDSPI_RETRY_COUNT - 1) {
|
} while (esp_timer_get_time() < t_end);
|
||||||
return ESP_ERR_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ESP_OK;
|
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||||
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for data token, reading 8 bytes at a time.
|
// Wait for data token, reading 8 bytes at a time.
|
||||||
// If the token is found, write all subsequent bytes to extra_ptr,
|
// If the token is found, write all subsequent bytes to extra_ptr,
|
||||||
// and store the number of bytes written to extra_size.
|
// and store the number of bytes written to extra_size.
|
||||||
static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
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];
|
uint8_t t_rx[8];
|
||||||
*t = (spi_transaction_t) {
|
*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,
|
.length = sizeof(t_rx) * 8,
|
||||||
};
|
};
|
||||||
esp_err_t ret;
|
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));
|
memset(t_rx, SDSPI_MOSI_IDLE_VAL, sizeof(t_rx));
|
||||||
ret = spi_device_transmit(spi_handle(slot), t);
|
ret = spi_device_transmit(spi_handle(slot), t);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
@@ -522,13 +524,11 @@ static esp_err_t poll_data_token(int slot, spi_transaction_t* t,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found) {
|
if (found) {
|
||||||
break;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
if (retry == SDSPI_RETRY_COUNT - 1) {
|
} while (esp_timer_get_time() < t_end);
|
||||||
return ESP_ERR_TIMEOUT;
|
ESP_LOGD(TAG, "%s: timeout", __func__);
|
||||||
}
|
return ESP_ERR_TIMEOUT;
|
||||||
}
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -608,11 +608,14 @@ static esp_err_t start_command_read_blocks(int slot, sdspi_hw_cmd_t *cmd,
|
|||||||
if (need_poll) {
|
if (need_poll) {
|
||||||
// Wait for data to be ready
|
// Wait for data to be ready
|
||||||
spi_transaction_t* t_poll = get_transaction(slot);
|
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) {
|
if (extra_data_size) {
|
||||||
extra_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;
|
extra_data_ptr = cmd_u8 + SDSPI_CMD_R1_SIZE;
|
||||||
}
|
}
|
||||||
release_transaction(slot);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arrange RX buffer
|
// 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
|
// To end multi block transfer, send stop command and wait for the
|
||||||
// card to process it
|
// card to process it
|
||||||
sdspi_hw_cmd_t stop_cmd;
|
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);
|
ret = start_command_default(slot, SDSPI_CMD_FLAG_RSP_R1, &stop_cmd);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
spi_transaction_t* t_poll = get_transaction(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);
|
release_transaction(slot);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ESP_OK;
|
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
|
// Poll for response
|
||||||
spi_transaction_t* t_poll = get_transaction(slot);
|
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);
|
release_transaction(slot);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
return ret;
|
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
|
// Wait for the card to finish writing data
|
||||||
t_poll = get_transaction(slot);
|
t_poll = get_transaction(slot);
|
||||||
ret = poll_busy(slot, t_poll);
|
ret = poll_busy(slot, t_poll, cmd->timeout_ms);
|
||||||
release_transaction(slot);
|
release_transaction(slot);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
return ret;
|
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);
|
wait_for_transactions(slot);
|
||||||
|
|
||||||
spi_transaction_t* t_poll = get_transaction(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);
|
release_transaction(slot);
|
||||||
if (ret != ESP_OK) {
|
if (ret != ESP_OK) {
|
||||||
return ret;
|
return ret;
|
||||||
|
@@ -73,6 +73,8 @@ typedef struct {
|
|||||||
uint8_t r1;
|
uint8_t r1;
|
||||||
/// Up to 16 bytes of response. Luckily, this is aligned on 4 byte boundary.
|
/// Up to 16 bytes of response. Luckily, this is aligned on 4 byte boundary.
|
||||||
uint32_t response[4];
|
uint32_t response[4];
|
||||||
|
/// response timeout, in milliseconds
|
||||||
|
int timeout_ms;
|
||||||
} sdspi_hw_cmd_t;
|
} sdspi_hw_cmd_t;
|
||||||
|
|
||||||
#define SDSPI_CMD_NORESP_SIZE 6 //!< Size of the command without any response
|
#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
|
#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,
|
esp_err_t sdspi_host_start_command(int slot, sdspi_hw_cmd_t *cmd,
|
||||||
void *data, uint32_t data_size, int flags);
|
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);
|
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->start_bit = 0;
|
||||||
hw_cmd->transmission_bit = 1;
|
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);
|
uint32_t arg_s = __builtin_bswap32(arg);
|
||||||
memcpy(hw_cmd->arguments, &arg_s, sizeof(arg_s));
|
memcpy(hw_cmd->arguments, &arg_s, sizeof(arg_s));
|
||||||
hw_cmd->crc7 = sdspi_msg_crc7(hw_cmd);
|
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)
|
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);
|
_lock_acquire(&s_lock);
|
||||||
// Convert the command to wire format
|
// Convert the command to wire format
|
||||||
sdspi_hw_cmd_t hw_cmd;
|
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
|
// Flags indicate which of the transfer types should be used
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
@@ -128,6 +128,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
free(workbuf);
|
free(workbuf);
|
||||||
|
workbuf = NULL;
|
||||||
ESP_LOGW(TAG, "mounting again");
|
ESP_LOGW(TAG, "mounting again");
|
||||||
res = f_mount(fs, drv, 0);
|
res = f_mount(fs, drv, 0);
|
||||||
if (res != FR_OK) {
|
if (res != FR_OK) {
|
||||||
@@ -139,7 +140,7 @@ esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
sdmmc_host_deinit();
|
host_config->deinit();
|
||||||
free(workbuf);
|
free(workbuf);
|
||||||
if (fs) {
|
if (fs) {
|
||||||
f_mount(NULL, drv, 0);
|
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};
|
char drv[3] = {(char)('0' + s_pdrv), ':', 0};
|
||||||
f_mount(0, drv, 0);
|
f_mount(0, drv, 0);
|
||||||
// release SD driver
|
// release SD driver
|
||||||
|
esp_err_t (*host_deinit)() = s_card->host.deinit;
|
||||||
ff_diskio_unregister(s_pdrv);
|
ff_diskio_unregister(s_pdrv);
|
||||||
free(s_card);
|
free(s_card);
|
||||||
s_card = NULL;
|
s_card = NULL;
|
||||||
sdmmc_host_deinit();
|
(*host_deinit)();
|
||||||
esp_err_t err = esp_vfs_fat_unregister_path(s_base_path);
|
esp_err_t err = esp_vfs_fat_unregister_path(s_base_path);
|
||||||
free(s_base_path);
|
free(s_base_path);
|
||||||
s_base_path = NULL;
|
s_base_path = NULL;
|
||||||
|
Reference in New Issue
Block a user