Merge pull request #14420 from ML-PA-Consulting-GmbH/fix/20200630__sdcard_spi

modules/sdcard_spi: improve configurability
This commit is contained in:
benpicco 2020-07-02 18:09:58 +02:00 committed by GitHub
commit 2ed76e2d45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 116 additions and 69 deletions

View File

@ -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.

View File

@ -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;
} }

View File

@ -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 }
}; };

View File

@ -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 \