Merge pull request #14420 from ML-PA-Consulting-GmbH/fix/20200630__sdcard_spi
modules/sdcard_spi: improve configurability
This commit is contained in:
commit
2ed76e2d45
@ -125,33 +125,83 @@ extern "C" {
|
|||||||
#define SD_CSD_V2 1
|
#define SD_CSD_V2 1
|
||||||
#define SD_CSD_VUNSUPPORTED -1
|
#define SD_CSD_VUNSUPPORTED -1
|
||||||
|
|
||||||
/* the retry counters below are used as timeouts for specific actions.
|
/**
|
||||||
The values may need some adjustments to either give the card more time to respond
|
* @name Set retry parameters for specific actions
|
||||||
to commands or to achieve a lower delay / avoid infinite blocking. */
|
*
|
||||||
#define R1_POLLING_RETRY_CNT 1000000
|
* Retry timeouts in microseconds for specific actions.
|
||||||
#define SD_DATA_TOKEN_RETRY_CNT 1000000
|
* The value interpretation is uint32_t.
|
||||||
#define INIT_CMD_RETRY_CNT 1000000
|
* A value of 0 disables retries.
|
||||||
#define INIT_CMD0_RETRY_CNT 3
|
*
|
||||||
#define SD_WAIT_FOR_NOT_BUSY_CNT 1000000 /* use -1 for full blocking till the card isn't busy */
|
* @{
|
||||||
#define SD_BLOCK_READ_CMD_RETRIES 10 /* only affects sending of cmd not whole transaction! */
|
*/
|
||||||
#define SD_BLOCK_WRITE_CMD_RETRIES 10 /* only affects sending of cmd not whole transaction! */
|
#ifndef INIT_CMD_RETRY_US
|
||||||
|
#define INIT_CMD_RETRY_US (250 * US_PER_MS) /**< initialization command retry */
|
||||||
|
#endif
|
||||||
|
#ifndef INIT_CMD0_RETRY_US
|
||||||
|
#define INIT_CMD0_RETRY_US (100UL) /**< initialization command 0 retry */
|
||||||
|
#endif
|
||||||
|
#ifndef R1_POLLING_RETRY_US
|
||||||
|
#define R1_POLLING_RETRY_US (100 * US_PER_MS) /**< initialization first response */
|
||||||
|
#endif
|
||||||
|
#ifndef SD_DATA_TOKEN_RETRY_US
|
||||||
|
#define SD_DATA_TOKEN_RETRY_US (100 * US_PER_MS) /**< data packet token read retry */
|
||||||
|
#endif
|
||||||
|
#ifndef SD_WAIT_FOR_NOT_BUSY_US
|
||||||
|
#define SD_WAIT_FOR_NOT_BUSY_US (250 * US_PER_MS) /**< wait for SD card */
|
||||||
|
#endif
|
||||||
|
#ifndef SD_BLOCK_READ_CMD_RETRY_US
|
||||||
|
#define SD_BLOCK_READ_CMD_RETRY_US (100UL) /**< only affects sending of cmd not whole transaction! */
|
||||||
|
#endif
|
||||||
|
#ifndef SD_BLOCK_WRITE_CMD_RETRY_US
|
||||||
|
#define SD_BLOCK_WRITE_CMD_RETRY_US (100UL) /**< only affects sending of cmd not whole transaction! */
|
||||||
|
#endif
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/* memory capacity in bytes = (C_SIZE+1) * SD_CSD_V2_C_SIZE_BLOCK_MULT * BLOCK_LEN */
|
/**
|
||||||
|
* @brief memory capacity in bytes = (C_SIZE+1) * SD_CSD_V2_C_SIZE_BLOCK_MULT * BLOCK_LEN
|
||||||
|
*/
|
||||||
#define SD_CSD_V2_C_SIZE_BLOCK_MULT 1024
|
#define SD_CSD_V2_C_SIZE_BLOCK_MULT 1024
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SPI mode used for SD card
|
||||||
|
*/
|
||||||
|
#ifndef SD_CARD_SPI_MODE
|
||||||
#define SD_CARD_SPI_MODE SPI_MODE_0
|
#define SD_CARD_SPI_MODE SPI_MODE_0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* this speed setting is only used while the init procedure is performed */
|
/**
|
||||||
|
* @brief this speed setting is only used while the init procedure is performed
|
||||||
|
*/
|
||||||
|
#ifndef SD_CARD_SPI_SPEED_PREINIT
|
||||||
#define SD_CARD_SPI_SPEED_PREINIT SPI_CLK_400KHZ
|
#define SD_CARD_SPI_SPEED_PREINIT SPI_CLK_400KHZ
|
||||||
|
#endif
|
||||||
|
|
||||||
/* after init procedure is finished the driver auto sets the card to this speed */
|
/**
|
||||||
|
* @brief after init procedure is finished the driver auto sets the card to this speed
|
||||||
|
*/
|
||||||
|
#ifndef SD_CARD_SPI_SPEED_POSTINIT
|
||||||
#define SD_CARD_SPI_SPEED_POSTINIT SPI_CLK_10MHZ
|
#define SD_CARD_SPI_SPEED_POSTINIT SPI_CLK_10MHZ
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SD_CARD_DUMMY_BYTE 0xFF
|
/**
|
||||||
|
* @brief Dummy Byte
|
||||||
|
*/
|
||||||
|
#define SD_CARD_DUMMY_BYTE (0xFF)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 1 kiB in Bytes
|
||||||
|
*/
|
||||||
#define SDCARD_SPI_IEC_KIBI (1024L)
|
#define SDCARD_SPI_IEC_KIBI (1024L)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 1 kB in Bytes
|
||||||
|
*/
|
||||||
#define SDCARD_SPI_SI_KILO (1000L)
|
#define SDCARD_SPI_SI_KILO (1000L)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SD card driver internal states
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SD_INIT_START,
|
SD_INIT_START,
|
||||||
SD_INIT_SPI_POWER_SEQ,
|
SD_INIT_SPI_POWER_SEQ,
|
||||||
@ -169,6 +219,7 @@ typedef enum {
|
|||||||
SD_INIT_SET_MAX_SPI_SPEED,
|
SD_INIT_SET_MAX_SPI_SPEED,
|
||||||
SD_INIT_FINISH
|
SD_INIT_FINISH
|
||||||
} sd_init_fsm_state_t;
|
} sd_init_fsm_state_t;
|
||||||
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a cmd to the sd card.
|
* @brief Sends a cmd to the sd card.
|
||||||
@ -179,14 +230,14 @@ typedef enum {
|
|||||||
* (for CMDX this parameter is simply the integer value X).
|
* (for CMDX this parameter is simply the integer value X).
|
||||||
* @param[in] argument The argument for the given cmd. As described by "7.3.1.1 Command Format".
|
* @param[in] argument The argument for the given cmd. As described by "7.3.1.1 Command Format".
|
||||||
* This argument is transmitted byte wise with most significant byte first.
|
* This argument is transmitted byte wise with most significant byte first.
|
||||||
* @param[in] max_retry Specifies how often the command should be retried if an error occurs.
|
* @param[in] retry_us Specifies microsecond timeout for retries in case of command errors.
|
||||||
* Use 0 to try only once, -1 to try forever, or n to retry n times.
|
* Use 0 to try exactly once.
|
||||||
*
|
*
|
||||||
* @return R1 response of the command if no (low-level) communication error occurred
|
* @return R1 response of the command if no (low-level) communication error occurred
|
||||||
* @return SD_INVALID_R1_RESPONSE if either waiting for the card to enter
|
* @return SD_INVALID_R1_RESPONSE if either waiting for the card to enter
|
||||||
* not-busy-state timed out or spi communication failed
|
* not-busy-state timed out or spi communication failed
|
||||||
*/
|
*/
|
||||||
uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, int32_t max_retry);
|
uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, uint32_t retry_us);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends an acmd to the sd card. ACMD<n> consists of sending CMD55 + CMD<n>
|
* @brief Sends an acmd to the sd card. ACMD<n> consists of sending CMD55 + CMD<n>
|
||||||
@ -197,14 +248,14 @@ uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t arg
|
|||||||
* (for ACMDX this parameter is simply the integer value X).
|
* (for ACMDX this parameter is simply the integer value X).
|
||||||
* @param[in] argument The argument for the given cmd. As described by "7.3.1.1 Command Format".
|
* @param[in] argument The argument for the given cmd. As described by "7.3.1.1 Command Format".
|
||||||
* This argument is transmitted byte wise with most significant byte first.
|
* This argument is transmitted byte wise with most significant byte first.
|
||||||
* @param[in] max_retry Specifies how often the command should be retried if an error occurs.
|
* @param[in] retry_us Specifies microsecond timeout for retries in case of command errors.
|
||||||
* Use 0 to try only once, -1 to try forever, or n to retry n times.
|
* Use 0 to try exactly once.
|
||||||
*
|
*
|
||||||
* @return R1 response of the command if no (low-level) communication error occurred
|
* @return R1 response of the command if no (low-level) communication error occurred
|
||||||
* @return SD_INVALID_R1_RESPONSE if either waiting for the card to enter
|
* @return SD_INVALID_R1_RESPONSE if either waiting for the card to enter
|
||||||
* not-busy-state timed out or spi communication failed
|
* not-busy-state timed out or spi communication failed
|
||||||
*/
|
*/
|
||||||
uint8_t sdcard_spi_send_acmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, int32_t max_retry);
|
uint8_t sdcard_spi_send_acmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, uint32_t retry_us);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the sector count of the card.
|
* @brief Gets the sector count of the card.
|
||||||
|
|||||||
@ -33,10 +33,10 @@
|
|||||||
|
|
||||||
static inline void _select_card_spi(sdcard_spi_t *card);
|
static inline void _select_card_spi(sdcard_spi_t *card);
|
||||||
static inline void _unselect_card_spi(sdcard_spi_t *card);
|
static inline void _unselect_card_spi(sdcard_spi_t *card);
|
||||||
static inline uint8_t _wait_for_r1(sdcard_spi_t *card, int32_t max_retries);
|
static inline uint8_t _wait_for_r1(sdcard_spi_t *card, uint32_t retry_us);
|
||||||
static inline void _send_dummy_byte(sdcard_spi_t *card);
|
static inline void _send_dummy_byte(sdcard_spi_t *card);
|
||||||
static inline bool _wait_for_not_busy(sdcard_spi_t *card, int32_t max_retries);
|
static inline bool _wait_for_not_busy(sdcard_spi_t *card, uint32_t retry_us);
|
||||||
static inline bool _wait_for_token(sdcard_spi_t *card, uint8_t token, int32_t max_retries);
|
static inline bool _wait_for_token(sdcard_spi_t *card, uint8_t token, uint32_t retry_us);
|
||||||
static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_state_t state);
|
static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_state_t state);
|
||||||
static sd_rw_response_t _read_cid(sdcard_spi_t *card);
|
static sd_rw_response_t _read_cid(sdcard_spi_t *card);
|
||||||
static sd_rw_response_t _read_csd(sdcard_spi_t *card);
|
static sd_rw_response_t _read_csd(sdcard_spi_t *card);
|
||||||
@ -132,7 +132,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
|
|
||||||
/* select sdcard for cmd0 */
|
/* select sdcard for cmd0 */
|
||||||
gpio_clear(card->params.cs);
|
gpio_clear(card->params.cs);
|
||||||
uint8_t cmd0_r1 = sdcard_spi_send_cmd(card, SD_CMD_0, SD_CMD_NO_ARG, INIT_CMD0_RETRY_CNT);
|
uint8_t cmd0_r1 = sdcard_spi_send_cmd(card, SD_CMD_0, SD_CMD_NO_ARG, INIT_CMD0_RETRY_US);
|
||||||
gpio_set(card->params.cs);
|
gpio_set(card->params.cs);
|
||||||
|
|
||||||
if (R1_VALID(cmd0_r1) && !R1_ERROR(cmd0_r1) && R1_IDLE_BIT_SET(cmd0_r1)) {
|
if (R1_VALID(cmd0_r1) && !R1_ERROR(cmd0_r1) && R1_IDLE_BIT_SET(cmd0_r1)) {
|
||||||
@ -150,7 +150,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
case SD_INIT_ENABLE_CRC:
|
case SD_INIT_ENABLE_CRC:
|
||||||
DEBUG("SD_INIT_ENABLE_CRC\n");
|
DEBUG("SD_INIT_ENABLE_CRC\n");
|
||||||
_select_card_spi(card);
|
_select_card_spi(card);
|
||||||
uint8_t r1 = sdcard_spi_send_cmd(card, SD_CMD_59, SD_CMD_59_ARG_EN, INIT_CMD_RETRY_CNT);
|
uint8_t r1 = sdcard_spi_send_cmd(card, SD_CMD_59, SD_CMD_59_ARG_EN, INIT_CMD_RETRY_US);
|
||||||
_unselect_card_spi(card);
|
_unselect_card_spi(card);
|
||||||
|
|
||||||
if (R1_VALID(r1) && !R1_ERROR(r1)) {
|
if (R1_VALID(r1) && !R1_ERROR(r1)) {
|
||||||
@ -163,7 +163,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
DEBUG("SD_INIT_SEND_CMD8\n");
|
DEBUG("SD_INIT_SEND_CMD8\n");
|
||||||
_select_card_spi(card);
|
_select_card_spi(card);
|
||||||
int cmd8_arg = (SD_CMD_8_VHS_2_7_V_TO_3_6_V << 8) | SD_CMD_8_CHECK_PATTERN;
|
int cmd8_arg = (SD_CMD_8_VHS_2_7_V_TO_3_6_V << 8) | SD_CMD_8_CHECK_PATTERN;
|
||||||
uint8_t cmd8_r1 = sdcard_spi_send_cmd(card, SD_CMD_8, cmd8_arg, INIT_CMD_RETRY_CNT);
|
uint8_t cmd8_r1 = sdcard_spi_send_cmd(card, SD_CMD_8, cmd8_arg, INIT_CMD_RETRY_US);
|
||||||
|
|
||||||
if (R1_VALID(cmd8_r1) && !R1_ERROR(cmd8_r1)) {
|
if (R1_VALID(cmd8_r1) && !R1_ERROR(cmd8_r1)) {
|
||||||
DEBUG("CMD8: [OK] --> reading remaining bytes for R7\n");
|
DEBUG("CMD8: [OK] --> reading remaining bytes for R7\n");
|
||||||
@ -199,7 +199,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
|
|
||||||
case SD_INIT_SEND_ACMD41_HCS:
|
case SD_INIT_SEND_ACMD41_HCS:
|
||||||
DEBUG("SD_INIT_SEND_ACMD41_HCS\n");
|
DEBUG("SD_INIT_SEND_ACMD41_HCS\n");
|
||||||
int acmd41_hcs_retries = 0;
|
const uint32_t acmd41_hcs_retry_timeout = xtimer_now_usec() + INIT_CMD_RETRY_US;
|
||||||
do {
|
do {
|
||||||
uint8_t acmd41hcs_r1 = sdcard_spi_send_acmd(card, SD_CMD_41, SD_ACMD_41_ARG_HC, 0);
|
uint8_t acmd41hcs_r1 = sdcard_spi_send_acmd(card, SD_CMD_41, SD_ACMD_41_ARG_HC, 0);
|
||||||
if (R1_VALID(acmd41hcs_r1) && !R1_ERROR(acmd41hcs_r1) &&
|
if (R1_VALID(acmd41hcs_r1) && !R1_ERROR(acmd41hcs_r1) &&
|
||||||
@ -207,14 +207,13 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
DEBUG("ACMD41: [OK]\n");
|
DEBUG("ACMD41: [OK]\n");
|
||||||
return SD_INIT_SEND_CMD58;
|
return SD_INIT_SEND_CMD58;
|
||||||
}
|
}
|
||||||
acmd41_hcs_retries++;
|
} while (((uint32_t)INIT_CMD_RETRY_US > 0) && (xtimer_now_usec() < acmd41_hcs_retry_timeout));
|
||||||
} while ((INIT_CMD_RETRY_CNT < 0) || (acmd41_hcs_retries <= (int)INIT_CMD_RETRY_CNT));
|
|
||||||
_unselect_card_spi(card);
|
_unselect_card_spi(card);
|
||||||
return SD_INIT_CARD_UNKNOWN;
|
return SD_INIT_CARD_UNKNOWN;
|
||||||
|
|
||||||
case SD_INIT_SEND_ACMD41:
|
case SD_INIT_SEND_ACMD41:
|
||||||
DEBUG("SD_INIT_SEND_ACMD41\n");
|
DEBUG("SD_INIT_SEND_ACMD41\n");
|
||||||
int acmd41_retries = 0;
|
const uint32_t acmd41_retry_timeout = xtimer_now_usec() + INIT_CMD_RETRY_US;
|
||||||
do {
|
do {
|
||||||
uint8_t acmd41_r1 = sdcard_spi_send_acmd(card, SD_CMD_41, SD_CMD_NO_ARG, 0);
|
uint8_t acmd41_r1 = sdcard_spi_send_acmd(card, SD_CMD_41, SD_CMD_NO_ARG, 0);
|
||||||
if (R1_VALID(acmd41_r1) && !R1_ERROR(acmd41_r1) && !R1_IDLE_BIT_SET(acmd41_r1)) {
|
if (R1_VALID(acmd41_r1) && !R1_ERROR(acmd41_r1) && !R1_IDLE_BIT_SET(acmd41_r1)) {
|
||||||
@ -223,8 +222,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
card->card_type = SD_V1;
|
card->card_type = SD_V1;
|
||||||
return SD_INIT_SEND_CMD16;
|
return SD_INIT_SEND_CMD16;
|
||||||
}
|
}
|
||||||
acmd41_retries++;
|
} while (((uint32_t)INIT_CMD_RETRY_US > 0) && (xtimer_now_usec() < acmd41_retry_timeout));
|
||||||
} while ((INIT_CMD_RETRY_CNT < 0) || (acmd41_retries <= (int)INIT_CMD_RETRY_CNT));
|
|
||||||
|
|
||||||
DEBUG("ACMD41: [ERROR]\n");
|
DEBUG("ACMD41: [ERROR]\n");
|
||||||
return SD_INIT_SEND_CMD1;
|
return SD_INIT_SEND_CMD1;
|
||||||
@ -237,7 +235,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
|
|
||||||
case SD_INIT_SEND_CMD58:
|
case SD_INIT_SEND_CMD58:
|
||||||
DEBUG("SD_INIT_SEND_CMD58\n");
|
DEBUG("SD_INIT_SEND_CMD58\n");
|
||||||
uint8_t cmd58_r1 = sdcard_spi_send_cmd(card, SD_CMD_58, SD_CMD_NO_ARG, INIT_CMD_RETRY_CNT);
|
uint8_t cmd58_r1 = sdcard_spi_send_cmd(card, SD_CMD_58, SD_CMD_NO_ARG, INIT_CMD_RETRY_US);
|
||||||
if (R1_VALID(cmd58_r1) && !R1_ERROR(cmd58_r1)) {
|
if (R1_VALID(cmd58_r1) && !R1_ERROR(cmd58_r1)) {
|
||||||
DEBUG("CMD58: [OK]\n");
|
DEBUG("CMD58: [OK]\n");
|
||||||
card->card_type = SD_V2;
|
card->card_type = SD_V2;
|
||||||
@ -285,7 +283,7 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
|
|
||||||
case SD_INIT_SEND_CMD16:
|
case SD_INIT_SEND_CMD16:
|
||||||
DEBUG("SD_INIT_SEND_CMD16\n");
|
DEBUG("SD_INIT_SEND_CMD16\n");
|
||||||
uint8_t r1_16 = sdcard_spi_send_cmd(card, SD_CMD_16, SD_HC_BLOCK_SIZE, INIT_CMD_RETRY_CNT);
|
uint8_t r1_16 = sdcard_spi_send_cmd(card, SD_CMD_16, SD_HC_BLOCK_SIZE, INIT_CMD_RETRY_US);
|
||||||
if (R1_VALID(r1_16) && !R1_ERROR(r1_16)) {
|
if (R1_VALID(r1_16) && !R1_ERROR(r1_16)) {
|
||||||
DEBUG("CARD TYPE IS SDSC (SD_V1 with byte addressing)\n");
|
DEBUG("CARD TYPE IS SDSC (SD_V1 with byte addressing)\n");
|
||||||
_unselect_card_spi(card);
|
_unselect_card_spi(card);
|
||||||
@ -335,9 +333,9 @@ static sd_init_fsm_state_t _init_sd_fsm_step(sdcard_spi_t *card, sd_init_fsm_sta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _wait_for_token(sdcard_spi_t *card, uint8_t token, int32_t max_retries)
|
static inline bool _wait_for_token(sdcard_spi_t *card, uint8_t token, uint32_t retry_us)
|
||||||
{
|
{
|
||||||
int tried = 0;
|
const uint32_t retry_timeout = xtimer_now_usec() + retry_us;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint8_t read_byte = 0;
|
uint8_t read_byte = 0;
|
||||||
@ -351,8 +349,7 @@ static inline bool _wait_for_token(sdcard_spi_t *card, uint8_t token, int32_t ma
|
|||||||
DEBUG("_wait_for_token: [NO MATCH] (0x%02x)\n", read_byte);
|
DEBUG("_wait_for_token: [NO MATCH] (0x%02x)\n", read_byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
tried++;
|
} while ((retry_us > 0) && (xtimer_now_usec() < retry_timeout));
|
||||||
} while ((max_retries < 0) || (tried <= max_retries));
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -369,12 +366,12 @@ static inline void _send_dummy_byte(sdcard_spi_t *card)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool _wait_for_not_busy(sdcard_spi_t *card, int32_t max_retries)
|
static inline bool _wait_for_not_busy(sdcard_spi_t *card, uint32_t retry_us)
|
||||||
{
|
{
|
||||||
uint8_t read_byte;
|
const uint32_t retry_timeout = xtimer_now_usec() + retry_us;
|
||||||
int tried = 0;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
uint8_t read_byte;
|
||||||
if (_dyn_spi_rxtx_byte(card, SD_CARD_DUMMY_BYTE, &read_byte) == 1) {
|
if (_dyn_spi_rxtx_byte(card, SD_CARD_DUMMY_BYTE, &read_byte) == 1) {
|
||||||
if (read_byte == 0xFF) {
|
if (read_byte == 0xFF) {
|
||||||
DEBUG("_wait_for_not_busy: [OK]\n");
|
DEBUG("_wait_for_not_busy: [OK]\n");
|
||||||
@ -389,8 +386,7 @@ static inline bool _wait_for_not_busy(sdcard_spi_t *card, int32_t max_retries)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tried++;
|
} while ((retry_us > 0) && (xtimer_now_usec() < retry_timeout));
|
||||||
} while ((max_retries < 0) || (tried <= max_retries));
|
|
||||||
|
|
||||||
DEBUG("_wait_for_not_busy: [FAILED]\n");
|
DEBUG("_wait_for_not_busy: [FAILED]\n");
|
||||||
return false;
|
return false;
|
||||||
@ -413,9 +409,10 @@ static uint8_t _crc_7(const uint8_t *data, int n)
|
|||||||
return (crc << 1) | 1;
|
return (crc << 1) | 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, int32_t max_retry)
|
uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, uint32_t retry_us)
|
||||||
{
|
{
|
||||||
int try_cnt = 0;
|
const uint32_t retry_timeout = xtimer_now_usec() + retry_us;
|
||||||
|
|
||||||
uint8_t r1_resu;
|
uint8_t r1_resu;
|
||||||
uint8_t cmd_data[6];
|
uint8_t cmd_data[6];
|
||||||
|
|
||||||
@ -429,19 +426,18 @@ uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t arg
|
|||||||
uint8_t echo[sizeof(cmd_data)];
|
uint8_t echo[sizeof(cmd_data)];
|
||||||
|
|
||||||
do {
|
do {
|
||||||
DEBUG("sdcard_spi_send_cmd: CMD%02d (0x%08" PRIx32 ") (retry %d)\n", sd_cmd_idx, argument, try_cnt);
|
DEBUG("sdcard_spi_send_cmd: CMD%02d (0x%08" PRIx32 ") (remaining retry time %"PRIu32" usec)\n", sd_cmd_idx, argument,
|
||||||
|
(retry_timeout > xtimer_now_usec()) ? (retry_timeout - xtimer_now_usec()) : 0);
|
||||||
|
|
||||||
if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_CNT)) {
|
if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_US)) {
|
||||||
DEBUG("sdcard_spi_send_cmd: timeout while waiting for bus to be not busy!\n");
|
DEBUG("sdcard_spi_send_cmd: timeout while waiting for bus to be not busy!\n");
|
||||||
r1_resu = SD_INVALID_R1_RESPONSE;
|
r1_resu = SD_INVALID_R1_RESPONSE;
|
||||||
try_cnt++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_transfer_bytes(card, cmd_data, echo, sizeof(cmd_data)) != sizeof(cmd_data)) {
|
if (_transfer_bytes(card, cmd_data, echo, sizeof(cmd_data)) != sizeof(cmd_data)) {
|
||||||
DEBUG("sdcard_spi_send_cmd: _transfer_bytes: send cmd [%d]: [ERROR]\n", sd_cmd_idx);
|
DEBUG("sdcard_spi_send_cmd: _transfer_bytes: send cmd [%d]: [ERROR]\n", sd_cmd_idx);
|
||||||
r1_resu = SD_INVALID_R1_RESPONSE;
|
r1_resu = SD_INVALID_R1_RESPONSE;
|
||||||
try_cnt++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +452,7 @@ uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t arg
|
|||||||
_send_dummy_byte(card);
|
_send_dummy_byte(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
r1_resu = _wait_for_r1(card, R1_POLLING_RETRY_CNT);
|
r1_resu = _wait_for_r1(card, R1_POLLING_RETRY_US);
|
||||||
|
|
||||||
if (R1_VALID(r1_resu)) {
|
if (R1_VALID(r1_resu)) {
|
||||||
break;
|
break;
|
||||||
@ -465,20 +461,21 @@ uint8_t sdcard_spi_send_cmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t arg
|
|||||||
DEBUG("sdcard_spi_send_cmd: R1_TIMEOUT (0x%02x)\n", r1_resu);
|
DEBUG("sdcard_spi_send_cmd: R1_TIMEOUT (0x%02x)\n", r1_resu);
|
||||||
r1_resu = SD_INVALID_R1_RESPONSE;
|
r1_resu = SD_INVALID_R1_RESPONSE;
|
||||||
}
|
}
|
||||||
try_cnt++;
|
|
||||||
|
|
||||||
} while ((max_retry < 0) || (try_cnt <= max_retry));
|
} while ((retry_us > 0) && (xtimer_now_usec() < retry_timeout));
|
||||||
|
|
||||||
return r1_resu;
|
return r1_resu;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t sdcard_spi_send_acmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, int32_t max_retry)
|
uint8_t sdcard_spi_send_acmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t argument, uint32_t retry_us)
|
||||||
{
|
{
|
||||||
int err_cnt = 0;
|
const uint32_t retry_timeout = xtimer_now_usec() + retry_us;
|
||||||
|
|
||||||
uint8_t r1_resu;
|
uint8_t r1_resu;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
DEBUG("sdcard_spi_send_acmd: CMD%02d (0x%08" PRIx32 ")(retry %d)\n", sd_cmd_idx, argument, err_cnt);
|
DEBUG("sdcard_spi_send_acmd: CMD%02d (0x%08" PRIx32 ") (remaining retry time %"PRIu32" usec)\n", sd_cmd_idx, argument,
|
||||||
|
(retry_timeout > xtimer_now_usec()) ? (retry_timeout - xtimer_now_usec()) : 0);
|
||||||
r1_resu = sdcard_spi_send_cmd(card, SD_CMD_55, SD_CMD_NO_ARG, 0);
|
r1_resu = sdcard_spi_send_cmd(card, SD_CMD_55, SD_CMD_NO_ARG, 0);
|
||||||
if (R1_VALID(r1_resu) && !R1_ERROR(r1_resu)) {
|
if (R1_VALID(r1_resu) && !R1_ERROR(r1_resu)) {
|
||||||
r1_resu = sdcard_spi_send_cmd(card, sd_cmd_idx, argument, 0);
|
r1_resu = sdcard_spi_send_cmd(card, sd_cmd_idx, argument, 0);
|
||||||
@ -488,29 +485,27 @@ uint8_t sdcard_spi_send_acmd(sdcard_spi_t *card, uint8_t sd_cmd_idx, uint32_t ar
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DEBUG("ACMD%02d: [ERROR / NO RESPONSE]\n", sd_cmd_idx);
|
DEBUG("ACMD%02d: [ERROR / NO RESPONSE]\n", sd_cmd_idx);
|
||||||
err_cnt++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DEBUG("CMD55: [ERROR / NO RESPONSE]\n");
|
DEBUG("CMD55: [ERROR / NO RESPONSE]\n");
|
||||||
err_cnt++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} while ((max_retry < 0) || (err_cnt <= max_retry));
|
} while ((retry_us > 0) && (xtimer_now_usec() < retry_timeout));
|
||||||
|
|
||||||
DEBUG("sdcard_spi_send_acmd: [TIMEOUT]\n");
|
DEBUG("sdcard_spi_send_acmd: [TIMEOUT]\n");
|
||||||
return r1_resu;
|
return r1_resu;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint8_t _wait_for_r1(sdcard_spi_t *card, int32_t max_retries)
|
static inline uint8_t _wait_for_r1(sdcard_spi_t *card, uint32_t retry_us)
|
||||||
{
|
{
|
||||||
int tried = 0;
|
const uint32_t retry_timeout = xtimer_now_usec() + retry_us;
|
||||||
|
|
||||||
uint8_t r1;
|
uint8_t r1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (_dyn_spi_rxtx_byte(card, SD_CARD_DUMMY_BYTE, &r1) != 1) {
|
if (_dyn_spi_rxtx_byte(card, SD_CARD_DUMMY_BYTE, &r1) != 1) {
|
||||||
DEBUG("_wait_for_r1: _dyn_spi_rxtx_byte:[ERROR]\n");
|
DEBUG("_wait_for_r1: _dyn_spi_rxtx_byte:[ERROR]\n");
|
||||||
tried++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -521,8 +516,8 @@ static inline uint8_t _wait_for_r1(sdcard_spi_t *card, int32_t max_retries)
|
|||||||
DEBUG("_wait_for_r1: R1_VALID\n");
|
DEBUG("_wait_for_r1: R1_VALID\n");
|
||||||
return r1;
|
return r1;
|
||||||
}
|
}
|
||||||
tried++;
|
|
||||||
} while ((max_retries < 0) || (tried <= max_retries));
|
} while ((retry_us > 0) && (xtimer_now_usec() < retry_timeout));
|
||||||
|
|
||||||
DEBUG("_wait_for_r1: [TIMEOUT]\n");
|
DEBUG("_wait_for_r1: [TIMEOUT]\n");
|
||||||
return r1;
|
return r1;
|
||||||
@ -591,7 +586,7 @@ static inline int _transfer_bytes(sdcard_spi_t *card, const uint8_t *out, uint8_
|
|||||||
static sd_rw_response_t _read_data_packet(sdcard_spi_t *card, uint8_t token, uint8_t *data, int size)
|
static sd_rw_response_t _read_data_packet(sdcard_spi_t *card, uint8_t token, uint8_t *data, int size)
|
||||||
{
|
{
|
||||||
DEBUG("_read_data_packet: size: %d\n", size);
|
DEBUG("_read_data_packet: size: %d\n", size);
|
||||||
if (_wait_for_token(card, token, SD_DATA_TOKEN_RETRY_CNT) == true) {
|
if (_wait_for_token(card, token, SD_DATA_TOKEN_RETRY_US) == true) {
|
||||||
DEBUG("_read_data_packet: [GOT TOKEN]\n");
|
DEBUG("_read_data_packet: [GOT TOKEN]\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -636,7 +631,7 @@ static inline int _read_blocks(sdcard_spi_t *card, int cmd_idx, int bladdr, uint
|
|||||||
int reads = 0;
|
int reads = 0;
|
||||||
|
|
||||||
uint32_t addr = card->use_block_addr ? bladdr : (bladdr * SD_HC_BLOCK_SIZE);
|
uint32_t addr = card->use_block_addr ? bladdr : (bladdr * SD_HC_BLOCK_SIZE);
|
||||||
uint8_t cmd_r1_resu = sdcard_spi_send_cmd(card, cmd_idx, addr, SD_BLOCK_READ_CMD_RETRIES);
|
uint8_t cmd_r1_resu = sdcard_spi_send_cmd(card, cmd_idx, addr, SD_BLOCK_READ_CMD_RETRY_US);
|
||||||
|
|
||||||
if (R1_VALID(cmd_r1_resu) && !R1_ERROR(cmd_r1_resu)) {
|
if (R1_VALID(cmd_r1_resu) && !R1_ERROR(cmd_r1_resu)) {
|
||||||
DEBUG("_read_blocks: send CMD%d: [OK]\n", cmd_idx);
|
DEBUG("_read_blocks: send CMD%d: [OK]\n", cmd_idx);
|
||||||
@ -752,7 +747,7 @@ static inline int _write_blocks(sdcard_spi_t *card, uint8_t cmd_idx, int bladdr,
|
|||||||
int written = 0;
|
int written = 0;
|
||||||
|
|
||||||
uint32_t addr = card->use_block_addr ? bladdr : (bladdr * SD_HC_BLOCK_SIZE);
|
uint32_t addr = card->use_block_addr ? bladdr : (bladdr * SD_HC_BLOCK_SIZE);
|
||||||
uint8_t cmd_r1_resu = sdcard_spi_send_cmd(card, cmd_idx, addr, SD_BLOCK_WRITE_CMD_RETRIES);
|
uint8_t cmd_r1_resu = sdcard_spi_send_cmd(card, cmd_idx, addr, SD_BLOCK_WRITE_CMD_RETRY_US);
|
||||||
|
|
||||||
if (R1_VALID(cmd_r1_resu) && !R1_ERROR(cmd_r1_resu)) {
|
if (R1_VALID(cmd_r1_resu) && !R1_ERROR(cmd_r1_resu)) {
|
||||||
DEBUG("_write_blocks: send CMD%d: [OK]\n", cmd_idx);
|
DEBUG("_write_blocks: send CMD%d: [OK]\n", cmd_idx);
|
||||||
@ -773,7 +768,7 @@ static inline int _write_blocks(sdcard_spi_t *card, uint8_t cmd_idx, int bladdr,
|
|||||||
*state = write_resu;
|
*state = write_resu;
|
||||||
return written;
|
return written;
|
||||||
}
|
}
|
||||||
if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_CNT)) {
|
if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_US)) {
|
||||||
DEBUG("_write_blocks: _wait_for_not_busy: [FAILED]\n");
|
DEBUG("_write_blocks: _wait_for_not_busy: [FAILED]\n");
|
||||||
_unselect_card_spi(card);
|
_unselect_card_spi(card);
|
||||||
*state = SD_RW_TIMEOUT;
|
*state = SD_RW_TIMEOUT;
|
||||||
@ -792,7 +787,7 @@ static inline int _write_blocks(sdcard_spi_t *card, uint8_t cmd_idx, int bladdr,
|
|||||||
/* sd card needs dummy byte before we can wait for not-busy
|
/* sd card needs dummy byte before we can wait for not-busy
|
||||||
state */
|
state */
|
||||||
_send_dummy_byte(card);
|
_send_dummy_byte(card);
|
||||||
if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_CNT)) {
|
if (!_wait_for_not_busy(card, SD_WAIT_FOR_NOT_BUSY_US)) {
|
||||||
_unselect_card_spi(card);
|
_unselect_card_spi(card);
|
||||||
*state = SD_RW_TIMEOUT;
|
*state = SD_RW_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -369,7 +369,7 @@ static const shell_command_t shell_commands[] = {
|
|||||||
{ "read", "'read n m' reads m blocks beginning at block address n and prints the result. "
|
{ "read", "'read n m' reads m blocks beginning at block address n and prints the result. "
|
||||||
"Append -c option to print data readable chars", _read },
|
"Append -c option to print data readable chars", _read },
|
||||||
{ "write", "'write n data' writes data to block n. Append -r option to "
|
{ "write", "'write n data' writes data to block n. Append -r option to "
|
||||||
"repeatedly write data to coplete block", _write },
|
"repeatedly write data to complete block", _write },
|
||||||
{ "copy", "'copy src dst' copies block src to block dst", _copy },
|
{ "copy", "'copy src dst' copies block src to block dst", _copy },
|
||||||
{ NULL, NULL, NULL }
|
{ NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,6 +7,7 @@ BOARD_INSUFFICIENT_MEMORY := \
|
|||||||
msb-430 \
|
msb-430 \
|
||||||
msb-430h \
|
msb-430h \
|
||||||
nucleo-f031k6 \
|
nucleo-f031k6 \
|
||||||
|
nucleo-f042k6 \
|
||||||
stm32f030f4-demo \
|
stm32f030f4-demo \
|
||||||
telosb \
|
telosb \
|
||||||
wsn430-v1_3b \
|
wsn430-v1_3b \
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user