diff --git a/os/hal/include/sdc.h b/os/hal/include/sdc.h index 860bbbbda..027eee2c0 100644 --- a/os/hal/include/sdc.h +++ b/os/hal/include/sdc.h @@ -36,6 +36,18 @@ /*===========================================================================*/ #define SDC_CMD_GO_IDLE_STATE 0 +#define SDC_CMD_SEND_IF_COND 8 +#define SDC_CMD_APP_OP_COND 41 +#define SDC_CMD_APP_CMD 55 + +#define SDC_MODE_CARDTYPE_MASK 0xF +#define SDC_MODE_CARDTYPE_SD 0 /**< Old SD card. */ +#define SDC_MODE_CARDTYPE_SDV20 1 /**< Card is V2.0 compliant. */ +#define SDC_MODE_CARDTYPE_MMC 2 /**< Card is MMC. */ + +#define SDC_CMD8_PATTERN 0x000001AA + +#define SDC_ACMD41_RETRY 100 /*===========================================================================*/ /* Driver pre-compile time settings. */ diff --git a/os/hal/platforms/STM32/sdc_lld.c b/os/hal/platforms/STM32/sdc_lld.c index 8517a040d..626702084 100644 --- a/os/hal/platforms/STM32/sdc_lld.c +++ b/os/hal/platforms/STM32/sdc_lld.c @@ -189,6 +189,8 @@ void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) { * @brief Sends an SDIO command with no response expected. * * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in[ cmd card command + * @param[in] arg command argument * * @notapi */ @@ -206,6 +208,9 @@ void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { * @brief Sends an SDIO command with a short response expected. * * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in[ cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (one word) * @return The operation status. * @retval FALSE the operation succeeded. * @retval TRUE the operation failed because timeout, CRC check or @@ -215,13 +220,28 @@ void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) { */ bool_t sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, uint32_t *resp) { + uint32_t sta; + (void)sdcp; + SDIO->ARG = arg; + SDIO->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN; + while (((sta = SDIO->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + SDIO->ICR = 0xFFFFFFFF; + if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0) + return TRUE; + *resp = SDIO->RESP1; + return FALSE; } /** * @brief Sends an SDIO command with a long response expected. * * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in[ cmd card command + * @param[in] arg command argument + * @param[out] resp pointer to the response buffer (four words) * @return The operation status. * @retval FALSE the operation succeeded. * @retval TRUE the operation failed because timeout, CRC check or @@ -232,6 +252,20 @@ bool_t sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, bool_t sdc_lld_send_cmd_long(SDCDriver *sdcp, uint8_t cmd, uint32_t arg, uint32_t *resp) { + uint32_t sta; + + (void)sdcp; + SDIO->ARG = arg; + SDIO->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_WAITRESP_1 | + SDIO_CMD_CPSMEN; + while (((sta = SDIO->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT | + SDIO_STA_CCRCFAIL)) == 0) + ; + SDIO->ICR = 0xFFFFFFFF; + if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0) + return TRUE; + *resp = SDIO->RESP1; + return FALSE; } #endif /* HAL_USE_SDC */ diff --git a/os/hal/platforms/STM32/sdc_lld.h b/os/hal/platforms/STM32/sdc_lld.h index 729244e91..fff6133b2 100644 --- a/os/hal/platforms/STM32/sdc_lld.h +++ b/os/hal/platforms/STM32/sdc_lld.h @@ -98,6 +98,11 @@ typedef enum { SDC_MODE_8BIT } sdcbusmode_t; +/** + * @brief Type of card flags. + */ +typedef uint32_t sdcmode_t; + /** * @brief Type of a structure representing an SDC driver. */ @@ -123,6 +128,10 @@ struct SDCDriver { * @brief Current configuration data. */ const SDCConfig *config; + /** + * @brief Various flags regarding the mounted card. + */ + sdcmode_t cardmode; /* End of the mandatory fields.*/ }; @@ -144,7 +153,7 @@ extern "C" { void sdc_lld_init(void); void sdc_lld_start(SDCDriver *sdcp); void sdc_lld_stop(SDCDriver *sdcp); - void sdc_lld_set_init_clk(SDCDriver *sdcp); + void sdc_lld_start_clk(SDCDriver *sdcp); void sdc_lld_set_data_clk(SDCDriver *sdcp); void sdc_lld_stop_clk(SDCDriver *sdcp); void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode); diff --git a/os/hal/src/sdc.c b/os/hal/src/sdc.c index b64dcf9c5..07f25aa65 100644 --- a/os/hal/src/sdc.c +++ b/os/hal/src/sdc.c @@ -127,6 +127,7 @@ void sdcStop(SDCDriver *sdcp) { * @api */ bool_t sdcConnect(SDCDriver *sdcp) { + uint32_t resp; chDbgCheck(sdcp != NULL, "sdcConnect"); @@ -135,12 +136,60 @@ bool_t sdcConnect(SDCDriver *sdcp) { sdcp->state = SDC_INITNG; chSysUnlock(); + /* Resets card attributes.*/ + sdcp->cardmode = 0; + + /* Card clock initialization.*/ sdc_lld_start_clk(sdcp); + /* Enforces the initial card state.*/ sdc_lld_send_cmd_none(sdcp, SDC_CMD_GO_IDLE_STATE, 0); + /* V2.0 cards detection.*/ + if (!sdc_lld_send_cmd_short(sdcp, SDC_CMD_SEND_IF_COND, + SDC_CMD8_PATTERN, &resp)) + sdcp->cardmode |= SDC_MODE_CARDTYPE_SDV20; + /* Voltage verification.*/ + if (((resp >> 8) & 0xF) != 1) + goto failed; + if (sdc_lld_send_cmd_short(sdcp, SDC_CMD_APP_CMD, 0, &resp)) + goto failed; + else { + /* MMC or SD detection.*/ + if (sdc_lld_send_cmd_short(sdcp, SDC_CMD_APP_CMD, 0, &resp)) + sdcp->cardmode |= SDC_MODE_CARDTYPE_MMC; + } + + if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_MMC) { + } + else { + uint32_t ocr = 0x80100000; + unsigned i; + + if ((sdcp->cardmode & SDC_MODE_CARDTYPE_MASK) == SDC_MODE_CARDTYPE_SDV20) + ocr |= 0x40000000; + + /* SD-type initialization. */ + i = 0; + while (TRUE) { + chThdSleepMilliseconds(10); + if (sdc_lld_send_cmd_short(sdcp, SDC_CMD_APP_CMD, 0, &resp)) + goto failed; + if (sdc_lld_send_cmd_short(sdcp, SDC_CMD_APP_OP_COND, ocr, &resp)) + goto failed; + if ((resp & 0x80000000) != 0) + break; + if (++i >= SDC_ACMD41_RETRY) + goto failed; + } + } + sdcp->state = SDC_ACTIVE; return FALSE; +failed: + sdc_lld_stop_clk(sdcp); + sdcp->state = SDC_READY; + return TRUE; } /**