From 0cb8d71e9da98423ea75f0c77b05d4a441d57af8 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Tue, 10 May 2011 18:33:49 +0000 Subject: SDC improvements. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2946 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/dox/sdc.dox | 24 +++++---- os/hal/include/sdc.h | 109 +++++++++++++++++++++++++++++---------- os/hal/platforms/STM32/sdc_lld.c | 24 ++++----- os/hal/src/sdc.c | 103 +++++++++++++++++++++++++++--------- readme.txt | 2 + 5 files changed, 190 insertions(+), 72 deletions(-) diff --git a/os/hal/dox/sdc.dox b/os/hal/dox/sdc.dox index 925b1af8a..2a18977ff 100644 --- a/os/hal/dox/sdc.dox +++ b/os/hal/dox/sdc.dox @@ -42,7 +42,8 @@ stop [label="SDC_STOP\nLow Power"]; uninit [label="SDC_UNINIT", style="bold"]; ready [label="SDC_READY\nClock Enabled"]; - connect [label="SDC_CONNECT\nConnecting"]; + connecting [label="SDC_CONN.ING\nConnecting"]; + disconnecting [label="SDC_DISC.ING\nDisconnecting"]; active [label="SDC_ACTIVE\nCard Ready"]; reading [label="SDC_READING\nReading"]; writing [label="SDC_WRITING\nWriting"]; @@ -52,10 +53,11 @@ stop -> ready [label="\nsdcStart()"]; ready -> stop [label="\nsdcStop()"]; ready -> ready [label="\nsdcStart()"]; - ready -> connect [label="\nsdcConnect()"]; - connect -> active [label="\nconnection\nsuccessful"]; - connect -> ready [label="\nconnection\nfailed"]; - active -> ready [label="\nsdcDisconnect()"]; + ready -> connecting [label="\nsdcConnect()"]; + connecting -> active [label="\nconnection\nsuccessful"]; + connecting -> ready [label="\nconnection\nfailed"]; + disconnecting -> active [label="\nsdcDisconnect()", dir="back"]; + ready -> disconnecting [label="\ndisconnection\nfinished", dir="back"]; active -> reading [label="\nsdcRead()"]; reading -> active [label="\nread finished\nread error"]; active -> writing [label="\nsdcWrite()"]; @@ -73,7 +75,8 @@ stop [label="SDC_STOP\nLow Power"]; uninit [label="SDC_UNINIT", style="bold"]; ready [label="SDC_READY\nClock Enabled"]; - connect [label="SDC_CONNECT\nConnecting"]; + connecting [label="SDC_CONN.ING\nConnecting"]; + disconnecting [label="SDC_DISC.ING\nDisconnecting"]; active [label="SDC_ACTIVE\nCard Ready"]; reading [label="SDC_READING\nReading"]; writing [label="SDC_WRITING\nWriting"]; @@ -83,10 +86,11 @@ stop -> ready [label="\nsdcStart()"]; ready -> stop [label="\nsdcStop()"]; ready -> ready [label="\nsdcStart()"]; - ready -> connect [label="\nsdcConnect()"]; - connect -> active [label="\nconnection\nsuccessful"]; - connect -> ready [label="\nconnection\nfailed"]; - active -> ready [label="\nsdcDisconnect()"]; + ready -> connecting [label="\nsdcConnect()"]; + connecting -> active [label="\nconnection\nsuccessful"]; + connecting -> ready [label="\nconnection\nfailed"]; + disconnecting -> active [label="\nsdcDisconnect()", dir="back"]; + ready -> disconnecting [label="\ndisconnection\nfinished", dir="back"]; active -> reading [label="\nsdcRead()"]; reading -> active [label="\nread finished\nread error"]; active -> writing [label="\nsdcWrite()"]; diff --git a/os/hal/include/sdc.h b/os/hal/include/sdc.h index 7c505a170..1c095221b 100644 --- a/os/hal/include/sdc.h +++ b/os/hal/include/sdc.h @@ -37,7 +37,34 @@ #define SDC_BLOCK_SIZE 512 /**< Fixed block size. */ +/** + * @brief Fixed pattern for CMD8. + */ +#define SDC_CMD8_PATTERN 0x000001AA + +#define SDC_MODE_CARDTYPE_MASK 0xF /**< @brief Card type mask. */ +#define SDC_MODE_CARDTYPE_SDV11 0 /**< @brief Card is SD V1.1.*/ +#define SDC_MODE_CARDTYPE_SDV20 1 /**< @brief Card is SD V2.0.*/ +#define SDC_MODE_CARDTYPE_MMC 2 /**< @brief Card is MMC. */ +#define SDC_MODE_HIGH_CAPACITY 0x10 /**< @brief High cap.card. */ + +/** + * @brief Mask of error bits in R1 responses. + */ +#define SDC_R1_ERROR_MASK 0xFDFFE008 + +#define SDC_STS_IDLE 0 +#define SDC_STS_READY 1 +#define SDC_STS_IDENT 2 +#define SDC_STS_STBY 3 +#define SDC_STS_TRAN 4 +#define SDC_STS_DATA 5 +#define SDC_STS_RCV 6 +#define SDC_STS_PRG 7 +#define SDC_STS_DIS 8 + #define SDC_CMD_GO_IDLE_STATE 0 +#define SDC_CMD_INIT 1 #define SDC_CMD_ALL_SEND_CID 2 #define SDC_CMD_SEND_RELATIVE_ADDR 3 #define SDC_CMD_SET_BUS_WIDTH 6 @@ -51,35 +78,40 @@ #define SDC_CMD_SET_BLOCK_COUNT 23 #define SDC_CMD_WRITE_MULTIPLE_BLOCK 25 #define SDC_CMD_APP_OP_COND 41 +#define SDC_CMD_LOCK_UNLOCK 42 #define SDC_CMD_APP_CMD 55 -#define SDC_MODE_CARDTYPE_MASK 0xF -#define SDC_MODE_CARDTYPE_SDV11 0 /**< Card is V1.1 compliant.*/ -#define SDC_MODE_CARDTYPE_SDV20 1 /**< Card is V2.0 compliant.*/ -#define SDC_MODE_CARDTYPE_MMC 2 /**< Card is MMC compliant. */ -#define SDC_MODE_HIGH_CAPACITY 0x10 /**< High capacity card. */ - -#define SDC_STS(r1) (((r1) >> 9) & 15) -#define SDC_STS_IDLE 0 -#define SDC_STS_READY 1 -#define SDC_STS_IDENT 2 -#define SDC_STS_STBY 3 -#define SDC_STS_TRAN 4 -#define SDC_STS_DATA 5 -#define SDC_STS_RCV 6 -#define SDC_STS_PRG 7 -#define SDC_STS_DIS 8 - -#define SDC_CMD8_PATTERN 0x000001AA - -#define SDC_ACMD41_RETRY 100 - -#define SDC_R1_ERROR_MASK 0xFDFFE008 - /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intevals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ @@ -95,10 +127,11 @@ typedef enum { SDC_UNINIT = 0, /**< Not initialized. */ SDC_STOP = 1, /**< Stopped. */ SDC_READY = 2, /**< Ready. */ - SDC_INITNG = 3, /**< Card initialization in progress. */ - SDC_ACTIVE = 4, /**< Cart initialized. */ - SDC_READING = 5, /**< Read operation in progress. */ - SDC_WRITING = 6, /**< Write operation in progress. */ + SDC_CONNECTING = 3, /**< Card connection in progress. */ + SDC_DISCONNECTING = 4, /**< Card disconnection in progress. */ + SDC_ACTIVE = 5, /**< Cart initialized. */ + SDC_READING = 6, /**< Read operation in progress. */ + SDC_WRITING = 7, /**< Write operation in progress. */ } sdcstate_t; #include "sdc_lld.h" @@ -107,6 +140,27 @@ typedef enum { /* Driver macros. */ /*===========================================================================*/ +/** + * @brief Evaluates to @p TRUE if the R1 response contains error flags. + * + * @param[in] r1 the r1 response + */ +#define SDC_R1_ERROR(r1) (((r1) & SDC_R1_ERROR_MASK) != 0) + +/** + * @brief Returns the status field of an R1 response. + * + * @param[in] r1 the r1 response + */ +#define SDC_R1_STS(r1) (((r1) >> 9) & 15) + +/** + * @brief Evaluates to @p TRUE if the R1 response indicates a locked card. + * + * @param[in] r1 the r1 response + */ +#define SDC_R1_IS_CARD_LOCKED(r1) (((r1) >> 21) & 1) + /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ @@ -124,6 +178,7 @@ extern "C" { uint8_t *buffer, uint32_t n); bool_t sdcWrite(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buffer, uint32_t n); + bool_t sdc_wait_for_transfer_state(SDCDriver *sdcp); #ifdef __cplusplus } #endif diff --git a/os/hal/platforms/STM32/sdc_lld.c b/os/hal/platforms/STM32/sdc_lld.c index a0d5965fc..6f2ea95ba 100644 --- a/os/hal/platforms/STM32/sdc_lld.c +++ b/os/hal/platforms/STM32/sdc_lld.c @@ -332,6 +332,10 @@ bool_t sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) { uint32_t resp[1]; + /* Checks for errors and waits for the card to be ready for reading.*/ + if (sdc_wait_for_transfer_state(sdcp)) + return TRUE; + /* Prepares the DMA channel for reading.*/ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4], (n * SDC_BLOCK_SIZE) / sizeof (uint32_t), buf, @@ -355,7 +359,7 @@ bool_t sdc_lld_read(SDCDriver *sdcp, uint32_t startblk, if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_READ_MULTIPLE_BLOCK, startblk, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) goto error; chSysLock(); @@ -399,8 +403,11 @@ error: */ bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t n) { - uint32_t sts, resp[1]; - bool_t err; + uint32_t resp[1]; + + /* Checks for errors and waits for the card to be ready for writing.*/ + if (sdc_wait_for_transfer_state(sdcp)) + return TRUE; /* Prepares the DMA channel for writing.*/ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4], @@ -412,7 +419,7 @@ bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, /* Write multiple blocks command.*/ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_WRITE_MULTIPLE_BLOCK, startblk, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) return TRUE; /* Setting up data transfer. @@ -447,14 +454,7 @@ bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk, SDIO->DCTRL = 0; chSysUnlock(); - err = sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp); - do { - if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SEND_STATUS,sdcp->rca, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) - return TRUE; - sts = SDC_STS(resp[0]); - } while ((sts == SDC_STS_RCV) || (sts == SDC_STS_PRG)); - return err; + return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp); error: dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4); SDIO->ICR = 0xFFFFFFFF; diff --git a/os/hal/src/sdc.c b/os/hal/src/sdc.c index 5e1bede8f..7eaa8e631 100644 --- a/os/hal/src/sdc.c +++ b/os/hal/src/sdc.c @@ -43,6 +43,43 @@ /* Driver local functions. */ /*===========================================================================*/ +/** + * @brief Wait for the card to complete pending operations. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @return The operation status. + * @retval FALSE the card is now in transfer state. + * @retval TRUE an error occurred while waiting or the card is in an + * unexpected state. + * + * @notapi + */ +bool_t sdc_wait_for_transfer_state(SDCDriver *sdcp) { + uint32_t resp[1]; + + while (TRUE) { + if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SEND_STATUS, + sdcp->rca, resp) || + SDC_R1_ERROR(resp[0])) + return TRUE; + switch (SDC_R1_STS(resp[0])) { + case SDC_STS_TRAN: + return FALSE; + case SDC_STS_DATA: + case SDC_STS_RCV: + case SDC_STS_PRG: +#if SDC_NICE_WAITING + chThdSleepMilliseconds(1); +#endif + continue; + default: + /* The card should have been initialized so any other state is not + valid and is reported as an error.*/ + return TRUE; + } + } +} + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -133,7 +170,7 @@ bool_t sdcConnect(SDCDriver *sdcp) { chSysLock(); chDbgAssert(sdcp->state == SDC_READY, "mmcConnect(), #1", "invalid state"); - sdcp->state = SDC_INITNG; + sdcp->state = SDC_CONNECTING; chSysUnlock(); /* Card clock initialization.*/ @@ -150,32 +187,41 @@ bool_t sdcConnect(SDCDriver *sdcp) { if (((resp[0] >> 8) & 0xF) != 1) goto failed; if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_APP_CMD, 0, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) goto failed; else { - /* MMC or SD detection.*/ +#if SDC_MMC_SUPPORT + /* MMC or SD V1.1 detection.*/ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_APP_CMD, 0, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) sdcp->cardmode = SDC_MODE_CARDTYPE_MMC; else +#endif /* SDC_MMC_SUPPORT */ sdcp->cardmode = SDC_MODE_CARDTYPE_SDV11; } - if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) { +#if SDC_MMC_SUPPORT + if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) { + /* TODO: MMC initialization.*/ + return TRUE; } - else { - uint32_t ocr = 0x80100000; + else +#endif /* SDC_MMC_SUPPORT */ + { unsigned i; + uint32_t ocr; + /* SD initialization.*/ if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_SDV20) - ocr |= 0x40000000; + ocr = 0xC0100000; + else + ocr = 0x80100000; /* SD-type initialization. */ i = 0; while (TRUE) { - chThdSleepMilliseconds(10); if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_APP_CMD, 0, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) goto failed; if (sdc_lld_send_cmd_short(sdcp, SDC_CMD_APP_OP_COND, ocr, resp)) goto failed; @@ -184,8 +230,9 @@ bool_t sdcConnect(SDCDriver *sdcp) { sdcp->cardmode |= SDC_MODE_HIGH_CAPACITY; break; } - if (++i >= SDC_ACMD41_RETRY) + if (++i >= SDC_INIT_RETRY) goto failed; + chThdSleepMilliseconds(10); } } @@ -194,7 +241,8 @@ bool_t sdcConnect(SDCDriver *sdcp) { goto failed; /* Asks for the RCA.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SEND_RELATIVE_ADDR, 0, &sdcp->rca)) + if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SEND_RELATIVE_ADDR, + 0, &sdcp->rca)) goto failed; /* Reads CSD.*/ @@ -205,13 +253,14 @@ bool_t sdcConnect(SDCDriver *sdcp) { sdc_lld_set_data_clk(sdcp); /* Selects the card for operations.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SEL_DESEL_CARD, sdcp->rca, resp)) + if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SEL_DESEL_CARD, + sdcp->rca, resp)) goto failed; /* Block length fixed at 512 bytes.*/ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SET_BLOCKLEN, SDC_BLOCK_SIZE, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) goto failed; /* Switches to wide bus mode.*/ @@ -220,10 +269,10 @@ bool_t sdcConnect(SDCDriver *sdcp) { case SDC_MODE_CARDTYPE_SDV20: sdc_lld_set_bus_mode(sdcp, SDC_MODE_4BIT); if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_APP_CMD, sdcp->rca, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) goto failed; if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_SET_BUS_WIDTH, 2, resp) || - (resp[0] & SDC_R1_ERROR_MASK)) + SDC_R1_ERROR(resp[0])) goto failed; } @@ -253,9 +302,17 @@ bool_t sdcDisconnect(SDCDriver *sdcp) { chSysLock(); chDbgAssert(sdcp->state == SDC_ACTIVE, "sdcDisconnect(), #1", "invalid state"); + sdcp->state = SDC_DISCONNECTING; + chSysUnlock(); + + /* Waits for eventual pending operations completion.*/ + if (sdc_wait_for_transfer_state(sdcp)) + return TRUE; + + /* Card clock stopped.*/ sdc_lld_stop_clk(sdcp); + sdcp->state = SDC_READY; - chSysUnlock(); return FALSE; } @@ -277,7 +334,7 @@ bool_t sdcDisconnect(SDCDriver *sdcp) { */ bool_t sdcRead(SDCDriver *sdcp, uint32_t startblk, uint8_t *buf, uint32_t n) { - bool_t sts; + bool_t err; chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcRead"); @@ -289,9 +346,9 @@ bool_t sdcRead(SDCDriver *sdcp, uint32_t startblk, if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0) startblk *= SDC_BLOCK_SIZE; - sts = sdc_lld_read(sdcp, startblk, buf, n); + err = sdc_lld_read(sdcp, startblk, buf, n); sdcp->state = SDC_ACTIVE; - return sts; + return err; } /** @@ -312,7 +369,7 @@ bool_t sdcRead(SDCDriver *sdcp, uint32_t startblk, */ bool_t sdcWrite(SDCDriver *sdcp, uint32_t startblk, const uint8_t *buf, uint32_t n) { - bool_t sts; + bool_t err; chDbgCheck((sdcp != NULL) && (buf != NULL) && (n > 0), "sdcRead"); @@ -324,9 +381,9 @@ bool_t sdcWrite(SDCDriver *sdcp, uint32_t startblk, if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0) startblk *= SDC_BLOCK_SIZE; - sts = sdc_lld_write(sdcp, startblk, buf, n); + err = sdc_lld_write(sdcp, startblk, buf, n); sdcp->state = SDC_ACTIVE; - return sts; + return err; } #endif /* HAL_USE_SDC */ diff --git a/readme.txt b/readme.txt index 215a6e166..bedf49b1f 100644 --- a/readme.txt +++ b/readme.txt @@ -85,6 +85,8 @@ to 2.2.4). - FIX: Fixed spurious characters generated by Serial over USB driver (bug 3276379). +- NEW: Added new SDC driver model, Secure Digital Card. +- NEW: SDC driver implementation for STM32. - NEW: Updated the STM32 header file to the latest version 3.4.0, had to fix a bug regarding the STM32 XL sub-family. - NEW: New unified GCC startup file for Cortex-Mx processors, it is written -- cgit v1.2.3