/******************************************************************************* * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved. * * This software component is licensed by HDSC under BSD 3-Clause license * (the "License"); You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause */ /******************************************************************************/ /** \file sdmmc_cmd.c ** ** A detailed description is available at ** @link SdiocGroup SDIOC description @endlink ** ** - 2018-11-15 CDT First version for Device Driver Library of SDIOC. ** ******************************************************************************/ /******************************************************************************* * Include files ******************************************************************************/ #include "sdmmc_cmd.h" /** ******************************************************************************* ** \addtogroup SdiocGroup ******************************************************************************/ //@{ /******************************************************************************* * Local type definitions ('typedef') ******************************************************************************/ /******************************************************************************* * Local pre-processor symbols/macros ('#define') ******************************************************************************/ /*!< Parameter valid check for SDIOC Instances. */ #define IS_VALID_SDIOC(__SDIOCx__) \ ( (M4_SDIOC1 == (__SDIOCx__)) || \ (M4_SDIOC2 == (__SDIOCx__))) /*!< Parameter valid check for SDIOC Instances. */ #define IS_VALID_SD_TYPE(x) \ ( (SdmmcHighCapacity == (x)) || \ (SdmmcStanderdCapacity == (x))) /*!< CMDBSY bit loop count */ #define SDIOC_FLAG_CMDBUSY_LOOPS (200000ul) /*!< Command send and response timeout */ #define SDMMC_CMD_TIMEOUT (10000ul) /*!< OCR register bit */ #define SDMMC_SD_OCR_HCS (0x40000000ul) /* High Capacity Support */ #define SDMMC_SD_OCR_BUSY (0x80000000ul) /* Card power up status bit (busy) */ #define SDMMC_BUS_WIDTH_1BIT (0x00000000ul) #define SDMMC_BUS_WIDTH_4BIT (0x00000002ul) #define SDMMC_CMD8_CHECK_PATTERN (0x000000AAul) #define SDMMC_CMD8_VOLTAGE_SUPPLIED (0x00000100ul) /* 2.7 - 3.6v*/ #define SDMMC_CMD8_ARGUEMENT (SDMMC_CMD8_VOLTAGE_SUPPLIED | SDMMC_CMD8_CHECK_PATTERN) #define SDMMC_ACMD41_VOLTAGE (SDMMC_SD_VOLT_3_3) #define SDMMC_ACMD41_HCS (1ul << 30u) /*!< Masks for R1 Response (SD Card Status Register) */ #define SDMMC_R1_AKE_SEQ_ERROR (0x1ul << 3u ) #define SDMMC_R1_ERASE_RESET (0x1ul << 13u) #define SDMMC_R1_CARD_ECC_DISABLED (0x1ul << 14u) #define SDMMC_R1_WP_ERASE_SKIP (0x1ul << 15u) #define SDMMC_R1_CID_CSD_OVERWRITE (0x1ul << 16u) #define SDMMC_R1_STREAM_WRITE_OVERRUN (0x1ul << 17u) #define SDMMC_R1_STREAM_READ_UNDERRUN (0x1ul << 18u) #define SDMMC_R1_GENERAL_UNKNOWN_ERROR (0x1ul << 19u) #define SDMMC_R1_CC_ERROR (0x1ul << 20u) #define SDMMC_R1_CARD_ECC_FAILED (0x1ul << 21u) #define SDMMC_R1_ILLEGAL_COMMAND (0x1ul << 22u) #define SDMMC_R1_COM_CRC_ERROR (0x1ul << 23u) #define SDMMC_R1_LOCK_UNLOCK_FAILED (0x1ul << 24u) #define SDMMC_R1_WP_VIOLATION (0x1ul << 26u) #define SDMMC_R1_ERASE_PARAM_ERROR (0x1ul << 27u) #define SDMMC_R1_ERASE_SEQ_ERROR (0x1ul << 28u) #define SDMMC_R1_BLOCK_LEN_ERROR (0x1ul << 29u) #define SDMMC_R1_ADDRESS_ERROR (0x1ul << 30u) #define SDMMC_R1_OUT_OF_RANGE (0x1ul << 31u) #define SDMMC_R1_ERRORS (0xFDFFE008ul) /*!< Masks for R6 Response. */ #define SDMMC_R6_GENERAL_UNKNOWN_ERROR (0x1ul << 13u) #define SDMMC_R6_ILLEGAL_CMD (0x1ul << 14u) #define SDMMC_R6_COM_CRC_ERROR (0x1ul << 15u) /******************************************************************************* * Global variable definitions (declared in header file with 'extern') ******************************************************************************/ /******************************************************************************* * Local function prototypes ('static') ******************************************************************************/ static en_result_t SDMMC_GetCmdResp1(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32CmdResp1, uint32_t u32Timeout); static en_result_t SDMMC_GetCmdResp1b(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32CmdResp1, uint32_t u32Timeout); static en_result_t SDMMC_GetCmdResp2(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32CID_CSD[4]); static en_result_t SDMMC_GetCmdResp3(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32OCR); static en_result_t SDMMC_GetCmdResp6(M4_SDIOC_TypeDef *SDIOx, uint32_t *pu32RCA); static en_result_t SDMMC_GetCmdResp7(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32IfCond); static en_result_t SDMMC_WaitBusIdle(M4_SDIOC_TypeDef *SDIOCx); static en_result_t SDMMC_WaitResponse(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Timeout); static bool SDMMC_GetCardDetection(M4_SDIOC_TypeDef *SDIOCx); /******************************************************************************* * Local variable definitions ('static') ******************************************************************************/ /******************************************************************************* * Function implementation - global ('extern') and local ('static') ******************************************************************************/ /** ******************************************************************************* ** \brief Send the GO_IDLE_STATE command which will reset all cards to idle state ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd0_GoIdleState(M4_SDIOC_TypeDef *SDIOCx) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { stcCmdCfg.u8CmdIndex = CMD0_GO_IDLE_STATE; stcCmdCfg.u32Argument = 0u; stcCmdCfg.enRspIndex = SdiocCmdNoRsp; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; /* Set command and argument. */ enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_WaitResponse(SDIOCx, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SEND_OP_COND command. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32Argument Argument used for the command. ** \param [in] pu32OCR Pointer to buffer which will store OCR content. ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd1_SendOpCond(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Argument, uint32_t *pu32OCR) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { stcCmdCfg.u8CmdIndex = CMD1_SEND_OP_COND; stcCmdCfg.u32Argument = u32Argument; stcCmdCfg.enRspIndex = SdiocCmdRspR3; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; /* Set command and argument. */ enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp3(SDIOCx, pu32OCR); } } } return enRet; } /** ******************************************************************************* ** \brief Send the ALL_SEND_CID command for asking any card to send the CID numbers ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32CID Pointer to buffer which will store CID content. ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd2_AllSendCID(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32CID[4]) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { stcCmdCfg.u8CmdIndex = CMD2_ALL_SEND_CID; stcCmdCfg.u32Argument = 0u; stcCmdCfg.enRspIndex = SdiocCmdRspR2; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; /* Set command and argument. */ enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp2(SDIOCx, u32CID); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SEND_RELATIVE_ADDR command for asking the card to publish a ** new relative address(RCA) ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] pu32RCA Pointer to buffer which will store RCA. ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd3_SendRelativeAddr(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32RCA) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { stcCmdCfg.u8CmdIndex = CMD3_SEND_RELATIVE_ADDR; stcCmdCfg.u32Argument = 0u; stcCmdCfg.enRspIndex = SdiocCmdRspR6; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; /* Set command and argument. */ enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp6(SDIOCx, pu32RCA); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SWITCH_FUNC command. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32Argument Argument used for the command. ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd6_SwitchFunc(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Argument, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { stcCmdCfg.u8CmdIndex = CMD6_SWITCH_FUNC; stcCmdCfg.u32Argument = u32Argument; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; /* Set command and argument. */ enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SELECT/DESELECT_CARD command for toggling a card between the ** stand-by and transfer states or between the programming and disconnect states. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32RCA Relative Sdcard Address. ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd7_SelectDeselectCard(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD7_SEL_DESEL_CARD; stcCmdCfg.u32Argument = (u32RCA << 16u); stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SEND_IF_COND command. Sends SD Memory Card interface ** condition, which includes host supply voltage information and asks ** the card whether card supports voltage ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] pu32IfCond Pointer to buffers for storing interface condition. ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd8_SendIfCond(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32IfCond) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Send CMD8 to verify SD card interface operating condition */ /* Argument: - [31:12]: Reserved (shall be set to '0') - [11:8]: Supply Voltage (VHS) 0x1 (Range: 2.7-3.6 V) - [7:0]: Check Pattern (recommended 0xAA) */ /* CMD Response: R7 */ stcCmdCfg.u8CmdIndex = CMD8_SEND_IF_COND; stcCmdCfg.u32Argument = SDMMC_CMD8_ARGUEMENT; stcCmdCfg.enRspIndex = SdiocCmdRspR7; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); /* Set command and argument. */ if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp7(SDIOCx, pu32IfCond); if (enRet == Ok) { if((*pu32IfCond & 0xFFu) != SDMMC_CMD8_CHECK_PATTERN) { enRet = Error; } } } } } return enRet; } /** ******************************************************************************* ** \brief Send the SEND_CSD command to addressed card which will sends its ** card-specificdata (CSD). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32RCA Relative Card Address ** \param [in] u32CSD Pointer to buffers for storing CSD contents. ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd9_SendCSD(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t u32CSD[4]) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD9_SEND_CSD; stcCmdCfg.u32Argument = (u32RCA << 16u); stcCmdCfg.enRspIndex = SdiocCmdRspR2; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp2(SDIOCx, u32CSD); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SEND_CID command to addressed card which will sends its card ** identification(CID). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32RCA Relative Card Address ** \param [in] u32CID Pointer to buffers for storing CID contents. ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd10_SendCID(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t u32CID[4]) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD10_SEND_CID; stcCmdCfg.u32Argument = (u32RCA << 16u); stcCmdCfg.enRspIndex = SdiocCmdRspR2; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp2(SDIOCx, u32CID); } } } return enRet; } /******************************************************************************* ** \brief Send the STOP_TRANSMISSION command to force the card to stop transmission. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** *******************************************************************************/ en_result_t SDMMC_Cmd12_StopTransmission(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD12_STOP_TRANSMISSION; stcCmdCfg.u32Argument = 0u; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SEND_STATUS to addressed card which will send its status ** register contents ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32RCA Relative Card Address ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd13_SendStatus(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD13_SEND_STATUS; stcCmdCfg.u32Argument = (u32RCA << 16u); stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SET_BLOCKLEN command and check the response ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32BlockLen Block length ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd16_SetBlockLength(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32BlockLen, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD16_SET_BLOCKLEN; stcCmdCfg.u32Argument = u32BlockLen; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the READ_SINGLE_BLOCK command and check the response ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32ReadAddr Data address ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd17_ReadSingleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32ReadAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD17_READ_SINGLE_BLOCK; stcCmdCfg.u32Argument = u32ReadAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Enable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the READ_MULTIPLE_BLOCK command and check the response ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32ReadAddr Data address ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd18_ReadMultipleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32ReadAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD18_READ_MULTIPLE_BLOCK; stcCmdCfg.u32Argument = u32ReadAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Enable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the WRITE_BLOCK command and check the response ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32WriteAddr Data address ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd24_WriteSingleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32WriteAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD24_WRITE_SINGLE_BLOCK; stcCmdCfg.u32Argument = u32WriteAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Enable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the WRITE_MULTIPLE_BLOCK command and check the response ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32WriteAddr Data address ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd25_WriteMultipleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32WriteAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD25_WRITE_MULTIPLE_BLOCK; stcCmdCfg.u32Argument = u32WriteAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Enable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the ERASE_WR_BLK_START command for setting the address of the ** first write block to be erased. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32StartAddr The start address will be erased ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd32_EraseWrBlkStart(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32StartAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD32_ERASE_WR_BLK_START; stcCmdCfg.u32Argument = u32StartAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the ERASE_WR_BLK_END command for setting the address of the ** last write block of the continuous range to be erased. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32EndAddr The last address will be erased ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd33_EraseWrBlkEnd(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32EndAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD33_ERASE_WR_BLK_END; stcCmdCfg.u32Argument = u32EndAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the ERASE_GRP_START command and check the response. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32StartAddr The start address will be erased ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd35_SetEraseStartAddr(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32StartAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD35_ERASE_GRP_START; stcCmdCfg.u32Argument = u32StartAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the ERASE_GRP_END command and check the response. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32EndAddr The end address will be erased ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd36_SetEraseEndAddr(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32EndAddr, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD36_ERASE_GRP_END; stcCmdCfg.u32Argument = u32EndAddr; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the ERASE command for erasing all previously selected write blocks. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd38_Erase(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { SDIOC_SetDataTimeout(SDIOCx, SdiocDtoSdclk_2_27); /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD38_ERASE; stcCmdCfg.u32Argument = 0u; stcCmdCfg.enRspIndex = SdiocCmdRspR1b; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1b(SDIOCx, pu32Resp1, 50u * SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the APP_CMD Command to interpret the following command as an ** application-specific command(ACMD). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32Argument Command argument(RCA) ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Cmd55_AppCmd(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Argument, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = CMD55_APP_CMD; stcCmdCfg.u32Argument = u32Argument; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SET_BUS_WIDTH(ACMD6) Command to set bus width. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32BusWidth The data bus width, '00'= 1bit or '10' = 4bits bus ** \arg SDMMC_BUS_WIDTH_1BIT 1 bits bus ** \arg SDMMC_BUS_WIDTH_4BIT 4 bits bus ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Acmd6_SetBusWidth(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32BusWidth, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = ACMD6_APP_SD_SET_BUSWIDTH; stcCmdCfg.u32Argument = u32BusWidth; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SD_STATUS(ACMD13) Command to ask the Status Register. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Acmd13_SdStatus(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = ACMD13_SD_APP_STATUS; stcCmdCfg.u32Argument = 0u; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Send the SD_SEND_OP_COND(ACMD41) command to negotiate the operation ** voltage range and get OCR. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32SdType Sdcard type ** \arg SdmmcHighCapacity SD memory card: Standard capacity ** \arg SdmmcHighCapacity SD memory card: High capacity ** \param [in] pu32OCR Pointer to the variable that will contain ** the OCR register contents. ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Acmd41_SdSendOpCond(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32SdType, uint32_t *pu32OCR) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if ((IS_VALID_SDIOC(SDIOCx)) && (NULL != pu32OCR)) { DDL_ASSERT(IS_VALID_SD_TYPE(u32SdType)); enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = ACMD41_SD_SEND_OP_COND; stcCmdCfg.u32Argument = SDMMC_ACMD41_VOLTAGE | u32SdType; stcCmdCfg.enRspIndex = SdiocCmdRspR3; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp3(SDIOCx, pu32OCR); if (enRet == Ok) { if (!(*pu32OCR & SDMMC_SD_OCR_BUSY)) { enRet = ErrorOperationInProgress; } } } } } return enRet; } /** ******************************************************************************* ** \brief Send the SEND_SCR(ACMD51) command to read the SD Configuration Register(SCR). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [out] pu32Resp1 Pointer to response data buffer ** ** \retval Ok Send successfully. ** \retval Error Send unsuccessfully. ** ******************************************************************************/ en_result_t SDMMC_Acmd51_SendSCR(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1) { en_result_t enRet = ErrorInvalidParameter; stc_sdioc_cmd_cfg_t stcCmdCfg = {0}; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitBusIdle(SDIOCx); if (enRet == Ok) { /* Set command and argument. */ stcCmdCfg.u8CmdIndex = ACMD51_SD_APP_SEND_SCR; stcCmdCfg.u32Argument = 0u; stcCmdCfg.enRspIndex = SdiocCmdRspR1; stcCmdCfg.enDataPresentEnable = Disable; stcCmdCfg.enCmdType = SdiocCmdNormal; enRet = SDIOC_SendCommand(SDIOCx, &stcCmdCfg); if (enRet == Ok) { /* Check for error conditions */ enRet = SDMMC_GetCmdResp1(SDIOCx, pu32Resp1, SDMMC_CMD_TIMEOUT); } } } return enRet; } /** ******************************************************************************* ** \brief Get Response R1(normal response command). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [out] pu32CmdResp1 received response value ** \param [in] u32Timeout timeout for waiting SDIOC idle ** ** \retval Ok Get successfully. ** \retval Error Get unsuccessfully. ** \retval ErrorInvalidParameter pu32CmdResp1 == NULL ** ******************************************************************************/ static en_result_t SDMMC_GetCmdResp1(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32CmdResp1, uint32_t u32Timeout) { uint32_t u32R1 = 0u; en_result_t enRet = ErrorInvalidParameter; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitResponse(SDIOCx, u32Timeout); if (enRet == Ok) { /* received response, retrieve it for analysis */ u32R1 = SDIOC_GetResponse(SDIOCx, SdiocRegResp01); if (u32R1 & SDMMC_R1_ERRORS) { enRet = Error; } if (pu32CmdResp1 != NULL) { *pu32CmdResp1 = u32R1; } } } return enRet; } /** ******************************************************************************* ** \brief Get Response R1(normal response command) with busy signal. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [out] pu32CmdResp1 received response value ** \param [in] u32Timeout timeout for waiting SDIOC idle ** ** \retval Ok Get successfully. ** \retval Error Get unsuccessfully. ** \retval ErrorInvalidParameter pu32CmdResp1 == NULL ** ******************************************************************************/ static en_result_t SDMMC_GetCmdResp1b(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32CmdResp1, uint32_t u32Timeout) { uint32_t u32R1 = 0u; en_result_t enRet = ErrorInvalidParameter; __IO uint32_t u32TmpCnt = u32Timeout; if (IS_VALID_SDIOC(SDIOCx)) { enRet = SDMMC_WaitResponse(SDIOCx, u32Timeout); if (enRet == Ok) { do { if (u32TmpCnt-- == 0u) { enRet = ErrorTimeout; } } while (Reset == SDIOC_GetStatus(SDIOCx, SdiocData0PinLvl)); if (enRet == Ok) { /* received response, retrieve it for analysis */ u32R1 = SDIOC_GetResponse(SDIOCx, SdiocRegResp01); if (u32R1 & SDMMC_R1_ERRORS) { enRet = Error; } if (pu32CmdResp1 != NULL) { *pu32CmdResp1 = u32R1; } } } } return enRet; } /** ******************************************************************************* ** \brief Get Response R2(CID, CSD register). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32CID_CSD Pointer to the variable that will contain the ** CID or CSD register contents ** ** \retval Ok Get successfully. ** \retval Error Get unsuccessfully. ** \retval ErrorInvalidParameter u32CID_CSD == NULL ** ******************************************************************************/ static en_result_t SDMMC_GetCmdResp2(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32CID_CSD[4]) { en_result_t enRet = ErrorInvalidParameter; if ((IS_VALID_SDIOC(SDIOCx)) && (NULL != u32CID_CSD)) { enRet = SDMMC_WaitResponse(SDIOCx, SDMMC_CMD_TIMEOUT); if (enRet == Ok) { /* received response */ u32CID_CSD[0] = SDIOC_GetResponse(SDIOCx, SdiocRegResp01); u32CID_CSD[1] = SDIOC_GetResponse(SDIOCx, SdiocRegResp23); u32CID_CSD[2] = SDIOC_GetResponse(SDIOCx, SdiocRegResp45); u32CID_CSD[3] = SDIOC_GetResponse(SDIOCx, SdiocRegResp67); } } return enRet; } /** ******************************************************************************* ** \brief Get Response R3(OCR register). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] pu32OCR Pointer to the variable that will contain ** the OCR register contents. ** ** \retval Ok Get successfully. ** \retval Error Get unsuccessfully. ** \retval ErrorInvalidParameter pu32OCR == NULL ** ******************************************************************************/ static en_result_t SDMMC_GetCmdResp3(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32OCR) { en_result_t enRet = ErrorInvalidParameter; if((IS_VALID_SDIOC(SDIOCx)) && (NULL != pu32OCR)) { enRet = SDMMC_WaitResponse(SDIOCx, SDMMC_CMD_TIMEOUT); if (enRet == Ok) { /* received response, retrieve it for analysis */ *pu32OCR = SDIOC_GetResponse(SDIOCx, SdiocRegResp01); } } return enRet; } /** ******************************************************************************* ** \brief Get Response R6(Published RCA response). ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] pu32RCA Pointer to the variable that will contain ** published RCA number ** ** \retval Ok Get successfully. ** \retval Error Get unsuccessfully. ** \retval ErrorInvalidParameter pu32RCA == NULL ** ******************************************************************************/ static en_result_t SDMMC_GetCmdResp6(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32RCA) { uint32_t u32R6 = 0ul; en_result_t enRet = ErrorInvalidParameter; if ((IS_VALID_SDIOC(SDIOCx)) && (NULL != pu32RCA)) { enRet = SDMMC_WaitResponse(SDIOCx, SDMMC_CMD_TIMEOUT); if (enRet == Ok) { /* received response, retrieve it. */ u32R6 = SDIOC_GetResponse(SDIOCx, SdiocRegResp01); if (!(u32R6 & (SDMMC_R6_GENERAL_UNKNOWN_ERROR | SDMMC_R6_ILLEGAL_CMD | SDMMC_R6_COM_CRC_ERROR))) { *pu32RCA = (u32R6 >> 16); } else { enRet = Error; } } } return enRet; } /** ******************************************************************************* ** \brief Get Response R7. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] pu32IfCond Pointer to the variable that will contain ** interface condition. ** ** \retval Ok Get successfully. ** \retval Error Get unsuccessfully. ** \retval ErrorInvalidParameter pu32IfCond == NULL ** ******************************************************************************/ static en_result_t SDMMC_GetCmdResp7(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32IfCond) { en_result_t enRet = ErrorInvalidParameter; if ((IS_VALID_SDIOC(SDIOCx)) && (NULL != pu32IfCond)) { enRet = SDMMC_WaitResponse(SDIOCx, SDMMC_CMD_TIMEOUT); if (enRet == Ok) { *pu32IfCond = SDIOC_GetResponse(SDIOCx, SdiocRegResp01); } } return enRet; } /** ******************************************************************************* ** \brief Wait for bus line idle ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** ** \retval Ok Command&Data line is free within a certain time ** \retval ErrorTimeout Command&Data line is still busy after a certain time. ** \retval ErrorInvalidParameter SDIOCx == NULL ** ******************************************************************************/ static en_result_t SDMMC_WaitBusIdle(M4_SDIOC_TypeDef *SDIOCx) { en_result_t enRet = ErrorInvalidParameter; uint32_t u32Retry = SDIOC_FLAG_CMDBUSY_LOOPS; en_flag_status_t enInhibitCmdStatus = Set; en_flag_status_t enInhibitDataStatus = Set; if (IS_VALID_SDIOC(SDIOCx)) { enRet = ErrorTimeout; while (u32Retry-- > 0ul) { enInhibitCmdStatus = SDIOC_GetStatus(SDIOCx, SdiocCommandInhibitCmd); enInhibitDataStatus = SDIOC_GetStatus(SDIOCx, SdiocCommandInhibitData); if ((Reset == enInhibitCmdStatus) || (Reset == enInhibitDataStatus)) { enRet = Ok; break; } } } return enRet; } /** ******************************************************************************* ** \brief Wait response ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** \param [in] u32Timeout timeout times ** ** \retval Ok Respond normal ** \retval ErrorTimeout Respond timeout. ** \retval ErrorInvalidParameter SDIOCx == NULL ** \retval ErrorAccessRights Card is removed. ** ******************************************************************************/ static en_result_t SDMMC_WaitResponse(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Timeout) { /* 8 is the number of required instructions cycles for the below loop statement. The Timeout is expressed in ms */ __IO uint32_t u32Count = u32Timeout * (SystemCoreClock / 8u /1000u); en_flag_status_t enErrorInt = Set; en_flag_status_t enCommandComplete = Set; en_result_t enRet = ErrorInvalidParameter; if (IS_VALID_SDIOC(SDIOCx)) { enRet = Ok; do { if (u32Count-- == 0u) { enRet = ErrorTimeout; break; } enErrorInt = SDIOC_GetNormalIrqFlag(SDIOCx, SdiocErrorInt); enCommandComplete = SDIOC_GetNormalIrqFlag(SDIOCx, SdiocCommandComplete); } while ((Reset == enErrorInt) && (Reset == enCommandComplete)); if (enRet == Ok) { if (Set == SDIOC_GetNormalIrqFlag(SDIOCx, SdiocErrorInt)) { enRet = Error; } else { if (false == SDMMC_GetCardDetection(SDIOCx)) { enRet = ErrorAccessRights; } else { if (Set == SDIOC_GetNormalIrqFlag(SDIOCx, SdiocCommandComplete)) { SDIOC_ClearNormalIrqFlag(SDIOCx, SdiocCommandComplete); } if (Set == SDIOC_GetNormalIrqFlag(SDIOCx, SdiocTransferComplete)) { SDIOC_ClearNormalIrqFlag(SDIOCx, SdiocTransferComplete); } } } } } return enRet; } /** ******************************************************************************* ** \brief Get card insertion status ** ** This function checks card is inserted or not. ** ** \param [in] SDIOCx Pointer to SDIOC instance register base ** \arg M4_SDIOC1 SDIOC unit 1 instance register base ** \arg M4_SDIOC2 SDIOC unit 2 instance register base ** ** \retval true Card is inserted ** \retval false Card is removed ** ******************************************************************************/ static bool SDMMC_GetCardDetection(M4_SDIOC_TypeDef *SDIOCx) { bool bRet = false; __IO uint32_t u32Count = 5000ul * (SystemCoreClock / 8ul /1000ul); /* Wait until card is stable */ do { if (Set == SDIOC_GetStatus(SDIOCx, SdiocCardStateStable)) { break; } } while (u32Count--); if (u32Count != 0ul) { bRet = (Set == SDIOC_GetStatus(SDIOCx, SdiocCardInserted)) ? true : false; } return bRet; } //@} // SdiocGroup /******************************************************************************* * EOF (not truncated) ******************************************************************************/