diff --git a/sd_card.c b/sd_card.c new file mode 100644 index 0000000..02945a0 --- /dev/null +++ b/sd_card.c @@ -0,0 +1,1319 @@ +/******************************************************************************* + * 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 sd_card.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" +#include "sd_card.h" + +/** + ******************************************************************************* + ** \addtogroup SdiocGroup + ******************************************************************************/ +//@{ + +/******************************************************************************* + * Local type definitions ('typedef') + ******************************************************************************/ +typedef enum en_sd_card_type +{ + SdCardSdsc = 0u, + SdCardSdhcSdxc = 1u, + SdCardSecured = 3u, +} en_sd_card_type_t; + +/******************************************************************************* + * Local pre-processor symbols/macros ('#define') + ******************************************************************************/ + +/*!< Card Command Class supported. */ +#define SDMMC_CARD_CCCC_ERASE (0x00000020u) + +/*!< Card locked */ +#define SDMMC_CARD_LOCKED (0x02000000u) + +/*!< Voltage trial times */ +#define SD_CARD_MAX_VOLT_TRIAL (0x0000FFFFu) + +/*!< High speed */ +#define SD_CHECK_FUNCTION_HIGH_SPEED (0x00FFFF01u) +#define SD_SET_FUNCTION_HIGH_SPEED (0x80FFFF01u) + +/*!< Block size is 512 bytes */ +#define SD_CARD_BLOCK_SIZE (512u) + +/*!< SDIOC buffer align size */ +#define SDIOC_BUF_ALIGN_SIZE (4ul) + +/*!< Log Block Number for 2G bytes Cards */ +#define SD_CARD_CAPACITY (0x400000u) + +/*!< Card power up status bit (busy) */ +#define SD_CARD_OCR_BUSY (0x80000000ul) + +#define SD_CARD_OP_NONE (0x00000000u) /*!< None */ +#define SD_CARD_OP_READ_SINGLE_BLOCK (0x00000001u) /*!< Read single block operation */ +#define SD_CARD_OP_READ_MULTIPLE_BLOCK (0x00000002u) /*!< Read multiple blocks operation */ +#define SD_CARD_OP_WRITE_SINGLE_BLOCK (0x00000010u) /*!< Write single block operation */ +#define SD_CARD_OP_WRITE_MULTIPLE_BLOCK (0x00000020u) /*!< Write multiple blocks operation */ +#define SD_CARD_OP_IT (0x00000008u) /*!< Process in Interrupt mode */ +#define SD_CARD_OP_DMA (0x00000080u) /*!< Process in DMA mode */ + +/*!< the SD card relative card address. */ +#define RelCardAddress(handle) ((handle)->stcSdCardInfo.u32RelCardAddr) +#define IsCardProgramming(handle) ((SdmmcCardStatePgm == (handle)->stcCardStatus.CURRENT_STATE) ? true : false) +#define IsCardReadyForData(handle) ((1u == (handle)->stcCardStatus.READY_FOR_DATA) ? true : false) + +#define IS_DMA_CFG_VALID(handle) \ +( (NULL != (handle)->pstcDmaInitCfg) && \ + (NULL != (handle)->pstcDmaInitCfg->DMAx)) + +/*!< the SD card use DMA unit && channel. */ +#define DMA_Unit(handle) ((handle)->pstcDmaInitCfg->DMAx) +#define DMA_CH(handle) ((handle)->pstcDmaInitCfg->enDmaCh) + +/*!< Parameter valid check for buffer address. */ +#define IS_VALID_TRANSFER_BUF_ALIGN(x) (!((SDIOC_BUF_ALIGN_SIZE-1ul) & ((uint32_t)(x)))) + +/*!< Parameter valid check for SDIOC command value. */ +#define IS_VALID_TRANSFER_BUF_LEN(x) (!((SD_CARD_BLOCK_SIZE - 1u) & (x))) + +/******************************************************************************* + * Global variable definitions (declared in header file with 'extern') + ******************************************************************************/ + +/******************************************************************************* + * Local function prototypes ('static') + ******************************************************************************/ +static en_result_t SdCardInitSd(stc_sd_handle_t *handle); +static en_result_t SdCardPowerON(stc_sd_handle_t *handle); +static en_result_t SdCardInitHost(const stc_sd_handle_t *handle); +static en_result_t SdCardSetSpeed(stc_sd_handle_t *handle); +static en_result_t SdCardSetBusWidth(stc_sd_handle_t *handle); +static en_result_t SdCardCheckReayForData(stc_sd_handle_t *handle, + uint32_t u32Timeout); +static en_result_t DmaSdiocTxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8TxBuf, + uint16_t u16len); +static en_result_t DmaSdiocRxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8RxBuf, + uint16_t u16len); + +/******************************************************************************* + * Local variable definitions ('static') + ******************************************************************************/ + +/******************************************************************************* + * Function implementation - global ('extern') and local ('static') + ******************************************************************************/ + +/** + ******************************************************************************* + ** \brief Initialize SD. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] pstcInitCfg The pointer of SD configure structure + ** \arg This parameter detail refer @ref stc_sdcard_init_t + ** + ** \retval Ok Initialize SD successfully. + ** \retval Error Initialize SD unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - pstcInitCfg == NULL + ** + ******************************************************************************/ +en_result_t SDCARD_Init(stc_sd_handle_t *handle, + const stc_sdcard_init_t *pstcInitCfg) +{ + en_result_t enRet = ErrorInvalidParameter; + + if ((NULL != handle) && (NULL != pstcInitCfg)) + { + handle->pstcCardInitCfg = pstcInitCfg; + + enRet = SdCardInitHost(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardPowerON(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardInitSd(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardSetBusWidth(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardSetSpeed(handle); + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Set SD Card device Read/Write mode. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] enDevMode Read/Write mode + ** \arg SdCardDmaMode DMA mode transfer + ** \arg SdCardPollingMode Polling mode transfer + ** + ** \retval Ok Set successfully. + ** \retval ErrorInvalidParameter handle pointer is NULL. + ** + ******************************************************************************/ +en_result_t SDCARD_SetDeviceMode(stc_sd_handle_t *handle, + en_sd_card_device_mode_t enDevMode) +{ + en_result_t enRet = ErrorInvalidParameter; + + if (NULL != handle) + { + handle->enDevMode = enDevMode; + enRet = Ok; + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Get SD Card device Read/Write mode. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval SdCardDmaMode DMA mode transfer + ** \retval SdCardPollingMode Polling mode transfer + ** + ******************************************************************************/ +en_sd_card_device_mode_t SDCARD_GetDeviceMode(const stc_sd_handle_t *handle) +{ + DDL_ASSERT(NULL != handle); + + return handle->enDevMode; +} + +/** + ******************************************************************************* + ** \brief Get Card specified Data information. + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Get successfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** + ******************************************************************************/ +en_result_t SDCARD_GetCardCSD(stc_sd_handle_t *handle) +{ + uint32_t u32Csize = 0ul; + uint32_t u32NumSector = 0ul; + uint32_t u32CsizeMulti = 0ul; + stc_sdcard_csd_v1_t *pstcCsdSd = NULL; + stc_sdcard_csd_v2_t *pstcCsdSdHc = NULL; + en_result_t enRet = ErrorInvalidParameter; + + if (NULL != handle) + { + /* High Capacity CSD Version 2.0*/ + if ((handle->CSD[3] & 0x00FF0000ul) == 0x00400000ul) + { + pstcCsdSdHc = (stc_sdcard_csd_v2_t *)&handle->CSD[0]; + u32Csize = ((unsigned int)pstcCsdSdHc->C_SIZE3 << 16ul) + + ((unsigned int)pstcCsdSdHc->C_SIZE2 << 8ul) + + pstcCsdSdHc->C_SIZE1; + + u32NumSector = (u32Csize + 1ul) << 10ul; + + handle->stcSdCardInfo.u32Class = (((uint32_t)pstcCsdSdHc->CCC2) << 4u) | ((uint32_t)pstcCsdSdHc->CCC1); + handle->stcSdCardInfo.u32BlockSize = 1ul << (pstcCsdSdHc->READ_BL_LEN); + } + else /* Standard Capacity CSD Version 1.xx */ + { + pstcCsdSd = (stc_sdcard_csd_v1_t *)&handle->CSD[0]; + + u32Csize = ((unsigned int)pstcCsdSd->C_SIZE3 << 10) + + ((unsigned int)pstcCsdSd->C_SIZE2 << 2) + + pstcCsdSd->C_SIZE1; + + u32CsizeMulti = ((uint32_t)(pstcCsdSd->C_SIZE_MULTI2) << 1) + (uint32_t)pstcCsdSd->C_SIZE_MULTI1; + u32NumSector = (u32Csize + 1ul) << (u32CsizeMulti + 2ul); + + if (pstcCsdSd->READ_BL_LEN == 0x0Au) + { + u32NumSector *= 2ul; + } + else if (pstcCsdSd->READ_BL_LEN == 0x0Bu) + { + u32NumSector *= 4ul; + } + else + { + /* Do nothing: only avoid MISRA warning */ + } + + handle->stcSdCardInfo.u32Class = ((uint32_t)pstcCsdSd->CCC2 << 4) | (uint32_t)pstcCsdSd->CCC1; + handle->stcSdCardInfo.u32BlockSize = 1ul << (pstcCsdSd->READ_BL_LEN); + } + + handle->stcSdCardInfo.u32BlockNbr = u32NumSector; + handle->stcSdCardInfo.u32LogBlockNbr = (handle->stcSdCardInfo.u32BlockNbr) * ((handle->stcSdCardInfo.u32BlockSize) / SD_CARD_BLOCK_SIZE); + handle->stcSdCardInfo.u32LogBlockSize = SD_CARD_BLOCK_SIZE; + enRet = Ok; + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Erase SD card blocks. + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32BlkStartAddr Block start address + ** \param [in] u32BlkEndAddr Block end address + ** \param [in] u32Timeout Erase timeout value + ** + ** \retval Ok Erase successfully. + ** \retval Error Erase unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - u32BlkStartAddr out of range + ** - u32BlkEndAddr out of range + ** + ******************************************************************************/ +en_result_t SDCARD_Erase(stc_sd_handle_t *handle, + uint32_t u32BlkStartAddr, + uint32_t u32BlkEndAddr, + uint32_t u32Timeout) +{ + en_result_t enCmdRet = Error; + __IO uint32_t u32TimeCount = u32Timeout * (SystemCoreClock / 8u / 1000u); + + if ((NULL == handle) || + (u32BlkStartAddr > u32BlkEndAddr) || + (u32BlkEndAddr > handle->stcSdCardInfo.u32BlockNbr)) + { + return ErrorInvalidParameter; + } + + /* Check if the card command class supports erase command */ + if (!(handle->stcSdCardInfo.u32Class & SDMMC_CARD_CCCC_ERASE)) + { + return ErrorAccessRights; + } + + if ((SDIOC_GetResponse(handle->SDIOCx, SdiocRegResp01) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + { + return ErrorAccessRights; + } + + /* Check the Card capacity in term of Logical number of blocks */ + if (handle->stcSdCardInfo.u32CardType != SdCardSdhcSdxc) + { + u32BlkStartAddr *= SD_CARD_BLOCK_SIZE; + u32BlkEndAddr *= SD_CARD_BLOCK_SIZE; + } + + /* Send CMD35 ERASE_GRP_START with argument as address */ + enCmdRet = SDMMC_Cmd32_EraseWrBlkStart(handle->SDIOCx, u32BlkStartAddr, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* Send CMD36 ERASE_GRP_END with argument as address */ + enCmdRet = SDMMC_Cmd33_EraseWrBlkEnd(handle->SDIOCx, u32BlkEndAddr, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SDMMC_Cmd38_Erase(handle->SDIOCx, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SdCardCheckReayForData(handle, u32TimeCount); + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Read block data from SD card + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32BlockAddr Block address + ** \param [in] u16BlockCnt Block Count + ** \param [in] pu8Data Pointer to buffer which will store SD Card data. + ** \param [in] u32Timeout Transfer timeout + ** + ** \retval Ok Read successfully. + ** \retval Error Read unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - pu8Data == NULL + ** - u16BlockCnt == 0 + ** - (u32BlockAddr + u16BlockCnt) out of range + ** + ******************************************************************************/ +en_result_t SDCARD_ReadBlocks(stc_sd_handle_t *handle, + uint32_t u32BlockAddr, + uint16_t u16BlockCnt, + uint8_t *pu8Data, + uint32_t u32Timeout) +{ + en_result_t enCmdRet; + stc_sdioc_data_cfg_t stcDataCfg; + uint8_t *pu8TempBuf = (uint8_t *)pu8Data; + uint32_t u32TimeCount = u32Timeout * (SystemCoreClock / 8u / 1000u); + __IO uint32_t u32Count = u32TimeCount; + en_sd_card_device_mode_t enDeviceMode = SDCARD_GetDeviceMode(handle); + en_flag_status_t enStatus = Reset; + en_flag_status_t enIrqFlag = Reset; + + if (NULL == handle) + { + return ErrorInvalidParameter; + } + + if ((NULL == pu8Data) || (0u == u16BlockCnt)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_PARAM; + return ErrorInvalidParameter; + } + + handle->u32ErrorCode = SD_CARD_ERROR_NONE; + + if ((u32BlockAddr + u16BlockCnt) > (handle->stcSdCardInfo.u32LogBlockNbr)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_ADDR_OUT_OF_RANGE; + return ErrorInvalidParameter; + } + + if (handle->stcSdCardInfo.u32CardType != SdCardSdhcSdxc) + { + u32BlockAddr *= SD_CARD_BLOCK_SIZE; + } + + /* Set Block Size for Card */ + enCmdRet = SDMMC_Cmd16_SetBlockLength(handle->SDIOCx, SD_CARD_BLOCK_SIZE, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + stcDataCfg.u16BlkCnt = u16BlockCnt; + stcDataCfg.u16BlkSize = SD_CARD_BLOCK_SIZE; + stcDataCfg.enDataTimeOut = SdiocDtoSdclk_2_27; + stcDataCfg.enTransferDir = SdiocTransferToHost; + stcDataCfg.enAutoCmd12Enable = (u16BlockCnt > 1u) ? Enable:Disable; + stcDataCfg.enTransferMode = (u16BlockCnt > 1u) ? SdiocTransferMultiple:SdiocTransferSingle; + enCmdRet = SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (enDeviceMode == SdCardDmaMode) + { + if (IS_DMA_CFG_VALID(handle)) + { + DmaSdiocRxConfig(DMA_Unit(handle), DMA_CH(handle), handle->SDIOCx, pu8TempBuf, u16BlockCnt * SD_CARD_BLOCK_SIZE); + } + } + + /* Read block(s) in polling mode */ + if (1u == u16BlockCnt) + { + handle->Context = SD_CARD_OP_READ_SINGLE_BLOCK; + /* Read Single Block command */ + enCmdRet = SDMMC_Cmd17_ReadSingleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + else + { + handle->Context = SD_CARD_OP_READ_MULTIPLE_BLOCK; + /* Read Multi Block command */ + enCmdRet = SDMMC_Cmd18_ReadMultipleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (SdCardPollingMode == enDeviceMode) + { + /* Poll on SDIO flags */ + while (u16BlockCnt) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocBufferReadEnble); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocBufferReadReady); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + SDIOC_ReadBuffer(handle->SDIOCx, pu8TempBuf, SD_CARD_BLOCK_SIZE); + + u16BlockCnt--; + u32Count = u32TimeCount; + pu8TempBuf += SD_CARD_BLOCK_SIZE; + } + + if (0ul == u32Count--) + { + return ErrorTimeout; + } + } + } + + for (u32Count = u32TimeCount; u32Count > 0ul; u32Count--) + { + if (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete)) + { + break; + } + } + + if (0ul == u32Count) + { + return ErrorTimeout; + } + else + { + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + } + + /* check whether Data transfer stops */ + if (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocErrorInt)) + { + enCmdRet = Error; + } + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Write block data to SD card + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32BlockAddr Block address + ** \param [in] u16BlockCnt Block Count + ** \param [in] pu8Data Pointer to buffer which contains data to be send to SD Card. + ** \param [in] u32Timeout Transfer timeout + ** + ** \retval Ok Write successfully. + ** \retval Error Write unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - pu8Data == NULL + ** - u16BlockCnt == 0 + ** - (u32BlockAddr + u16BlockCnt) out of range + ** + ******************************************************************************/ +en_result_t SDCARD_WriteBlocks(stc_sd_handle_t *handle, + uint32_t u32BlockAddr, + uint16_t u16BlockCnt, + uint8_t *pu8Data, + uint32_t u32Timeout) +{ + en_result_t enCmdRet; + stc_sdioc_data_cfg_t stcDataCfg; + uint8_t *pu8TempBuf = (uint8_t *)pu8Data; + uint32_t u32TimeCount = u32Timeout * (SystemCoreClock / 50ul / 1000ul); + __IO uint32_t u32Count = u32TimeCount; + en_sd_card_device_mode_t enDeviceMode = SDCARD_GetDeviceMode(handle); + en_flag_status_t enStatus = Reset; + en_flag_status_t enIrqFlag = Reset; + + if (NULL == handle) + { + return ErrorInvalidParameter; + } + + if ((NULL == pu8Data) || (0u == u16BlockCnt)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_PARAM; + return ErrorInvalidParameter; + } + + handle->u32ErrorCode = SD_CARD_ERROR_NONE; + + if ((u32BlockAddr + u16BlockCnt) > (handle->stcSdCardInfo.u32LogBlockNbr)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_ADDR_OUT_OF_RANGE; + return ErrorInvalidParameter; + } + + /* Set Block Size for Card */ + enCmdRet = SDMMC_Cmd16_SetBlockLength(handle->SDIOCx, SD_CARD_BLOCK_SIZE, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + stcDataCfg.u16BlkCnt = u16BlockCnt; + stcDataCfg.u16BlkSize = SD_CARD_BLOCK_SIZE; + stcDataCfg.enDataTimeOut = SdiocDtoSdclk_2_27; + stcDataCfg.enTransferDir = SdiocTransferToCard; + stcDataCfg.enAutoCmd12Enable = (u16BlockCnt > 1u) ? Enable:Disable; + stcDataCfg.enTransferMode = (u16BlockCnt > 1u) ? SdiocTransferMultiple:SdiocTransferSingle; + enCmdRet = SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (handle->stcSdCardInfo.u32CardType != SdCardSdhcSdxc) + { + u32BlockAddr *= SD_CARD_BLOCK_SIZE; + } + + if (enDeviceMode == SdCardDmaMode) + { + if (IS_DMA_CFG_VALID(handle)) + { + DmaSdiocTxConfig(DMA_Unit(handle), DMA_CH(handle), handle->SDIOCx, pu8TempBuf, u16BlockCnt * SD_CARD_BLOCK_SIZE); + } + } + + /* Write block(s) in polling mode */ + if (1u == u16BlockCnt) + { + /* Read Single Block command */ + enCmdRet = SDMMC_Cmd24_WriteSingleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + else + { + /* Read Multi Block command */ + enCmdRet = SDMMC_Cmd25_WriteMultipleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (SdCardPollingMode == enDeviceMode) + { + /* Poll on SDIO flags */ + while (u16BlockCnt) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocBufferWriteEnble); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocBufferWriteReady); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + /* Write data to SDIO Tx Buffer */ + SDIOC_WriteBuffer(handle->SDIOCx, pu8TempBuf, SD_CARD_BLOCK_SIZE); + + u16BlockCnt--; + u32Count = u32TimeCount; + pu8TempBuf += SD_CARD_BLOCK_SIZE; + } + + if (u32Count-- == 0ul) + { + return ErrorTimeout; + } + } + } + + for (u32Count = u32TimeCount; u32Count > 0ul; u32Count--) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocData0PinLvl); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + break; + } + } + + if (0u == u32Count) + { + return ErrorTimeout; + } + else + { + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + } + + enCmdRet = SdCardCheckReayForData(handle, u32TimeCount); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* check whether Data transfer stops */ + if(Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocErrorInt)) + { + return Error; + } + + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocBufferWriteReady); + + return Ok; +} + +/** + ****************************************************************************** + ** \brief Set SD bus width. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Set SD bus width successfully. + ** \retval Error Set SD bus width unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcCfg + ** - enBusWidth is invalid. + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardSetBusWidth(stc_sd_handle_t *handle) +{ + uint32_t u32CmdArg = 0ul; + en_result_t enCmdRet = Ok; + + if ((NULL == handle) || (NULL == handle->pstcCardInitCfg)) + { + return ErrorInvalidParameter; + } + + switch (handle->pstcCardInitCfg->enBusWidth) + { + case SdiocBusWidth1Bit: + u32CmdArg = 0u; + break; + case SdiocBusWidth4Bit: + u32CmdArg = 2u; + break; + default: + enCmdRet = ErrorInvalidParameter; + break; + } + + if (Ok != enCmdRet) + { + return enCmdRet; + } + + enCmdRet = SDMMC_Cmd55_AppCmd(handle->SDIOCx, (RelCardAddress(handle) << 16u), (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SDMMC_Acmd6_SetBusWidth(handle->SDIOCx, u32CmdArg, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SDIOC_SetBusWidth(handle->SDIOCx, handle->pstcCardInitCfg->enBusWidth); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + return Ok; +} + +/** + ****************************************************************************** + ** \brief Set SD high speed mode. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Set SD bus width successfully. + ** \retval Ok Set SD bus width unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcCfg + ** - u32Freq is invalid. + ** + ******************************************************************************/ +static en_result_t SdCardSetSpeed(stc_sd_handle_t *handle) +{ + uint8_t au8TempBuf[64] = {0}; + uint32_t u32TimeCount = 2000 * (SystemCoreClock / 8u / 1000u); + __IO uint32_t u32Count = u32TimeCount; + en_flag_status_t enStatus = Reset; + en_flag_status_t enIrqFlag = Reset; + + en_result_t enCmdRet = ErrorInvalidParameter; + stc_sdioc_data_cfg_t stcDataCfg; + uint32_t u32Arg = SD_SET_FUNCTION_HIGH_SPEED; + + if ((NULL != handle) && (NULL != handle->pstcCardInitCfg)) + { + enCmdRet = Ok; + if (SdiocHighSpeedMode == handle->pstcCardInitCfg->enSpeedMode) + { + /* Set Block Size for Card */ + enCmdRet = SDMMC_Cmd16_SetBlockLength(handle->SDIOCx, 64u, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet == Ok) + { + stcDataCfg.u16BlkCnt = 1u; + stcDataCfg.u16BlkSize = 64u; + stcDataCfg.enDataTimeOut = SdiocDtoSdclk_2_27; + stcDataCfg.enTransferDir = SdiocTransferToHost; + stcDataCfg.enAutoCmd12Enable = Disable; + stcDataCfg.enTransferMode = SdiocTransferSingle; + enCmdRet = SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg); + if (enCmdRet == Ok) + { + enCmdRet = SDMMC_Cmd6_SwitchFunc(handle->SDIOCx, u32Arg, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet == Ok) + { + while (u32Count--) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocBufferReadEnble); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocBufferReadReady); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + SDIOC_ReadBuffer(handle->SDIOCx, au8TempBuf, sizeof(au8TempBuf)); + break; + } + } + + if (0ul == u32Count) + { + return ErrorTimeout; + } + + u32Count = u32TimeCount; + while (u32Count--) + { + if (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete)) + { + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + break; + } + } + + if (0ul == u32Count) + { + return ErrorTimeout; + } + + /* Check whether switch function with error or transfer error occur */ + if ((!(au8TempBuf[16] & 0x01)) || + (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocErrorInt))) + { + enCmdRet = Error; + } + } + } + } + } + + if (enCmdRet == Ok) + { + SDIOC_SetSpeedMode(handle->SDIOCx, handle->pstcCardInitCfg->enSpeedMode); + + enCmdRet = SDIOC_SetClk(handle->SDIOCx, handle->pstcCardInitCfg->enClkFreq); + } + } + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Initialize SDIO Host + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok SDIO host initialized successfully + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcInitCfg + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardInitHost(const stc_sd_handle_t *handle) +{ + en_result_t enRet = Ok; + + if ((NULL == handle) || (NULL == handle->pstcCardInitCfg)) + { + return ErrorInvalidParameter; + } + + /* Enable SD clock supply */ + if (M4_SDIOC1 == handle->SDIOCx) + { + PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_SDIOC1, Enable); + } + else if (M4_SDIOC2 == handle->SDIOCx) + { + PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_SDIOC2, Enable); + } + else + { + return ErrorInvalidParameter; + } + + /* Set mode: SD */ + SDIOC_SetMode(handle->SDIOCx, SdiocModeSD); + + enRet = SDIOC_Init(handle->SDIOCx, handle->pstcCardInitCfg->pstcInitCfg); + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Initialize SD bus + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok SDIO bus cmd operate successfully. + ** \retval Error SDIO bus cmd operate unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcCfg + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardInitSd(stc_sd_handle_t *handle) +{ + en_result_t enCmdRet = Ok; + + if(NULL == handle) + { + return ErrorInvalidParameter; + } + + if (handle->stcSdCardInfo.u32CardType != SdCardSecured) + { + /* Send CMD2 ALL_SEND_CID */ + enCmdRet = SDMMC_Cmd2_AllSendCID(handle->SDIOCx, handle->CID); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* Send CMD3 SET_REL_ADDR with argument 0 */ + /* SD Card publishes its RCA. */ + enCmdRet = SDMMC_Cmd3_SendRelativeAddr(handle->SDIOCx, &(handle->RCA)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* Get the SD card RCA */ + RelCardAddress(handle) = handle->RCA; + + /* Send CMD9 SEND_CSD with argument as card's RCA */ + enCmdRet = SDMMC_Cmd9_SendCSD(handle->SDIOCx, RelCardAddress(handle), handle->CSD); + if (enCmdRet != Ok) + { + return enCmdRet; + } + } + + /* Get CSD parameters */ + enCmdRet = SDCARD_GetCardCSD(handle); + if (enCmdRet == Ok) + { + /* Select the Card */ + enCmdRet = SDMMC_Cmd7_SelectDeselectCard(handle->SDIOCx, RelCardAddress(handle), (uint32_t *)(&handle->stcCardStatus)); + } + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Activate SD in power-on stage + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Activate successfully. + ** \retval Error Activate unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == handle + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardPowerON(stc_sd_handle_t *handle) +{ + uint32_t u32IfCond = 0u; + __IO uint32_t u32Count = 0ul; + en_result_t enCmdRet = Error; + + if (NULL == handle) + { + return ErrorInvalidParameter; + } + + handle->u32ErrorCode = SD_CARD_ERROR_NONE; + + /* CMD0: GO_IDLE_STATE */ + enCmdRet = SDMMC_Cmd0_GoIdleState(handle->SDIOCx); + if (enCmdRet != Ok) + { + handle->u32ErrorCode |= SD_CARD_ERROR_GENERAL_UNKNOWN_ERR; + return enCmdRet; + } + + /* Reset OCR valude */ + handle->OCR = 0ul; + + /* CMD8: SEND_IF_COND: Command available only on V2.0 cards */ + enCmdRet = SDMMC_Cmd8_SendIfCond(handle->SDIOCx, &u32IfCond); + if (enCmdRet != Ok) + { + handle->stcSdCardInfo.u32CardVersion = SdCardVer1x; + + /* Send ACMD41 SD_APP_OP_COND with Argument 0x00100000 */ + while (SD_CARD_OCR_BUSY != (handle->OCR & SD_CARD_OCR_BUSY)) + { + if (SD_CARD_MAX_VOLT_TRIAL == u32Count++) + { + handle->u32ErrorCode |= SD_CARD_ERROR_INVALID_VOLTRANGE; + return enCmdRet; + } + + /* SEND CMD55 APP_CMD with RCA as 0 */ + enCmdRet = SDMMC_Cmd55_AppCmd(handle->SDIOCx, 0u, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + continue; + } + + /* Send CMD41 */ + enCmdRet = SDMMC_Acmd41_SdSendOpCond(handle->SDIOCx, SdmmcStanderdCapacity, &handle->OCR); + if (enCmdRet == Error) + { + handle->u32ErrorCode |= SD_CARD_ERROR_UNSUPPORTED_FEATURE; + return enCmdRet; + } + } + + /* Card type is SDSC */ + handle->stcSdCardInfo.u32CardType = SdCardSdsc; + } + else + { + handle->stcSdCardInfo.u32CardVersion = SdCardVer2x; + + /* Send ACMD41 SD_APP_OP_COND with Argument 0x40100000 */ + while (SD_CARD_OCR_BUSY != (handle->OCR & SD_CARD_OCR_BUSY)) + { + if (SD_CARD_MAX_VOLT_TRIAL == u32Count++) + { + handle->u32ErrorCode |= SD_CARD_ERROR_INVALID_VOLTRANGE; + return Error; + } + + /* SEND CMD55 APP_CMD with RCA as 0 */ + enCmdRet = SDMMC_Cmd55_AppCmd(handle->SDIOCx, 0u, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + continue; + } + + /* Send CMD41 */ + enCmdRet = SDMMC_Acmd41_SdSendOpCond(handle->SDIOCx, SdmmcHighCapacity, &handle->OCR); + if (enCmdRet == Error) + { + handle->u32ErrorCode |= SD_CARD_ERROR_UNSUPPORTED_FEATURE; + return enCmdRet; + } + } + + if ((handle->OCR & SdmmcHighCapacity) == SdmmcHighCapacity) + { + handle->stcSdCardInfo.u32CardType = SdCardSdhcSdxc; + } + else + { + handle->stcSdCardInfo.u32CardType = SdCardSdsc; + } + } + + return Ok; +} + +/** + ******************************************************************************* + ** \brief Checks if the SD card is ready for data. + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32Timeout Retry to get card status time + ** + ** \retval Ok Card is ready for data + ** \retval Error Card is not ready for data + ** \retval ErrorInvalidParameter NULL == handle + ** + ******************************************************************************/ +static en_result_t SdCardCheckReayForData(stc_sd_handle_t *handle, uint32_t u32Timeout) +{ + en_result_t enRet = ErrorInvalidParameter; + + if (NULL != handle) + { + do + { + enRet = SDMMC_Cmd13_SendStatus(handle->SDIOCx, RelCardAddress(handle), (uint32_t *)(&handle->stcCardStatus)); + if (Ok != enRet) + { + break; + } + } while ((--u32Timeout) && (false == IsCardReadyForData(handle))); + + if (0u == u32Timeout) + { + enRet = ErrorTimeout; + } + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Configures the DMA Channel for SDIO Tx request. + ** + ** \param [in] DMAx The pointer to DMAC register base + ** \arg M4_DMA1 DMAC unit 1 instance register base + ** \arg M4_DMA2 DMAC unit 2 instance register base + ** \param [in] enCh The specified DMAC channel. + ** \arg DmaCh0 DMAC channel 0 + ** \arg DmaCh1 DMAC channel 1 + ** \arg DmaCh2 DMAC channel 2 + ** \arg DmaCh3 DMAC channel 3 + ** \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] pu8TxBuf Pointer to the Tx buffer + ** \param [in] u16len Tx buffer size + ** + ** \retval Ok Set successfully. + ** \retval ErrorInvalidParameter Set unsuccessfully. + ** + ******************************************************************************/ +static en_result_t DmaSdiocTxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8TxBuf, + uint16_t u16len) +{ + stc_dma_config_t stcDmaInit; + uint32_t u32Fcg0Periph = (M4_DMA1 == DMAx) ? PWC_FCG0_PERIPH_DMA1 : PWC_FCG0_PERIPH_DMA2; + en_event_src_t enEvtSrc = (M4_SDIOC1 == SDIOCx) ? EVT_SDIOC1_DMAW : EVT_SDIOC2_DMAW; + en_result_t enRet = ErrorInvalidParameter; + + if ((NULL != pu8TxBuf) && \ + (IS_VALID_TRANSFER_BUF_LEN(u16len)) && \ + (IS_VALID_TRANSFER_BUF_ALIGN(pu8TxBuf))) + { + /* Enable peripheral clock */ + PWC_Fcg0PeriphClockCmd(u32Fcg0Periph, Enable); + + /* Enable DMA. */ + DMA_Cmd(DMAx, Enable); + + /* Initialize DMA. */ + MEM_ZERO_STRUCT(stcDmaInit); + stcDmaInit.u16BlockSize = SD_CARD_BLOCK_SIZE/4u; /* Set data block size. */ + stcDmaInit.u16TransferCnt = u16len/SD_CARD_BLOCK_SIZE; /* Set transfer count. */ + stcDmaInit.u32SrcAddr = (uint32_t)(&pu8TxBuf[0]); /* Set source address. */ + stcDmaInit.u32DesAddr = (uint32_t)(&SDIOCx->BUF0); /* Set destination address. */ + stcDmaInit.stcDmaChCfg.enSrcInc = AddressIncrease; /* Set source address mode. */ + stcDmaInit.stcDmaChCfg.enDesInc = AddressFix; /* Set destination address mode. */ + stcDmaInit.stcDmaChCfg.enTrnWidth = Dma32Bit; /* Set data width 8bit. */ + DMA_InitChannel(DMAx, enCh, &stcDmaInit); + + /* Enable the specified DMA channel. */ + DMA_ChannelCmd(DMAx, enCh, Enable); + + /* Clear DMA flag. */ + DMA_ClearIrqFlag(DMAx, enCh, TrnCpltIrq); + DMA_ClearIrqFlag(DMAx, enCh, BlkTrnCpltIrq); + + /* Enable peripheral circuit trigger function. */ + PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable); + + /* Set DMA trigger source. */ + DMA_SetTriggerSrc(DMAx, enCh, enEvtSrc); + + enRet = Ok; + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Configures the DMA Channel for SDIO Rx request. + ** + ** \param [in] DMAx The pointer to DMAC register base + ** \arg M4_DMA1 DMAC unit 1 instance register base + ** \arg M4_DMA2 DMAC unit 2 instance register base + ** \param [in] enCh The specified DMAC channel. + ** \arg DmaCh0 DMAC channel 0 + ** \arg DmaCh1 DMAC channel 1 + ** \arg DmaCh2 DMAC channel 2 + ** \arg DmaCh3 DMAC channel 3 + ** \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] pu8RxBuf Pointer to the Rx buffer + ** \param [in] u16len Rx buffer size + ** + ** \retval Ok Set successfully. + ** \retval ErrorInvalidParameter Set unsuccessfully. + ** + ******************************************************************************/ +static en_result_t DmaSdiocRxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8RxBuf, + uint16_t u16len) +{ + stc_dma_config_t stcDmaInit; + uint32_t u32Fcg0Periph = (M4_DMA1 == DMAx) ? PWC_FCG0_PERIPH_DMA1 : PWC_FCG0_PERIPH_DMA2; + en_event_src_t enEvtSrc = (M4_SDIOC1 == SDIOCx) ? EVT_SDIOC1_DMAR : EVT_SDIOC2_DMAR; + en_result_t enRet = ErrorInvalidParameter; + + if ((NULL != pu8RxBuf) && \ + (IS_VALID_TRANSFER_BUF_LEN(u16len)) && \ + (IS_VALID_TRANSFER_BUF_ALIGN(pu8RxBuf))) + { + /* Enable peripheral clock */ + PWC_Fcg0PeriphClockCmd(u32Fcg0Periph,Enable); + + /* Enable DMA. */ + DMA_Cmd(DMAx, Enable); + + /* Initialize DMA. */ + MEM_ZERO_STRUCT(stcDmaInit); + stcDmaInit.u16BlockSize = SD_CARD_BLOCK_SIZE/4u; /* Set data block size. */ + stcDmaInit.u16TransferCnt = u16len/SD_CARD_BLOCK_SIZE; /* Set transfer count. */ + stcDmaInit.u32SrcAddr = (uint32_t)(&SDIOCx->BUF0); /* Set source address. */ + stcDmaInit.u32DesAddr = (uint32_t)(&pu8RxBuf[0]); /* Set destination address. */ + stcDmaInit.stcDmaChCfg.enSrcInc = AddressFix; /* Set source address mode. */ + stcDmaInit.stcDmaChCfg.enDesInc = AddressIncrease; /* Set destination address mode. */ + stcDmaInit.stcDmaChCfg.enTrnWidth = Dma32Bit; /* Set data width 8bit. */ + DMA_InitChannel(DMAx, enCh, &stcDmaInit); + + /* Enable the specified DMA channel. */ + DMA_ChannelCmd(DMAx, enCh, Enable); + + /* Clear DMA flag. */ + DMA_ClearIrqFlag(DMAx, enCh, TrnCpltIrq); + DMA_ClearIrqFlag(DMAx, enCh, BlkTrnCpltIrq); + + /* Enable peripheral circuit trigger function. */ + PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable); + + /* Set DMA trigger source. */ + DMA_SetTriggerSrc(DMAx, enCh, enEvtSrc); + + enRet = Ok; + } + + return enRet; +} + +/** + * @brief Get the current card status. + * @param [in] handle Pointer to a @ref stc_sd_handle_t structure + * @param [out] pu32CardStatus Pointer to the value of current card status + * @retval int32_t: + * - LL_OK: Get card status success + * - LL_ERR: Refer to u32ErrorCode for the reason of error + * - LL_ERR_INVD_PARAM: An invalid parameter was write to the send command + * - LL_ERR_TIMEOUT: Send command timeout + */ +static en_result_t SD_GetCurrCardStatus(stc_sd_handle_t *handle, uint32_t *pu32CardStatus) +{ + en_result_t i32Ret; + + /* Send Status command */ + i32Ret = SDMMC_Cmd13_SendStatus(handle->SDIOCx, (uint32_t)(handle->stcSdCardInfo.u32RelCardAddr), (uint32_t *)&handle->u32ErrorCode); + if (Ok != i32Ret) { + return i32Ret; + } + /* Get SD card status */ + *pu32CardStatus = SDIOC_GetResponse(handle->SDIOCx, SdiocRegResp01); + + return i32Ret; +} + +/** + * @brief Get the current sd card state. + * @param [in] handle Pointer to a @ref stc_sd_handle_t structure + * @param [out] peCardState Pointer to a @ref en_sd_card_state_t enumeration + * @retval int32_t: + * - LL_OK: Get sd card state success + * - LL_ERR: Refer to u32ErrorCode for the reason of error + * - LL_ERR_INVD_PARAM: handle == NULL or peCardState == NULL or + * An invalid parameter was write to the send command + * - LL_ERR_TIMEOUT: Send command timeout + */ +en_result_t SD_GetCardState(stc_sd_handle_t *handle, en_sd_card_state_t *peCardState) +{ + en_result_t i32Ret; + uint32_t u32Response = 0UL; + + if ((NULL == peCardState) || (NULL == handle)) { + i32Ret = ErrorInvalidParameter; + } else { + i32Ret = SD_GetCurrCardStatus(handle, &u32Response); + *peCardState = (en_sd_card_state_t)(uint32_t)((u32Response >> 9) & 0x0FU); + } + + return i32Ret; +} + +//@} // SdiocGroup + +/******************************************************************************* + * EOF (not truncated) + ******************************************************************************/ diff --git a/sd_card.h b/sd_card.h new file mode 100644 index 0000000..93eb041 --- /dev/null +++ b/sd_card.h @@ -0,0 +1,404 @@ +/******************************************************************************* + * 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 sd_card.h + ** + ** A detailed description is available at + ** @link SdiocGroup SDIOC description @endlink + ** + ** - 2018-11-15 CDT First version for Device Driver Library of SDIOC. + ** + ******************************************************************************/ +#ifndef __SD_CARD_H__ +#define __SD_CARD_H__ + +/******************************************************************************* + * Include files + ******************************************************************************/ +#include "sdmmc_cmd.h" + +/* C binding of definitions if building with C++ compiler */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + ******************************************************************************* + ** \defgroup SdiocGroup Secure Digital Input and Output Controller(SDIOC) + ** + ******************************************************************************/ +//@{ + +/******************************************************************************* + * Global type definitions ('typedef') + ******************************************************************************/ + +/** + ******************************************************************************* + ** \brief SD Card version definition + ** + ******************************************************************************/ + /** + * @brief SD Card State enumeration structure definition + */ +typedef enum { + SD_CARD_STAT_IDLE = 0x00U, /*!< Card state is idle */ + SD_CARD_STAT_RDY = 0x01U, /*!< Card state is ready */ + SD_CARD_STAT_IDENTIFY = 0x02U, /*!< Card is in identification state */ + SD_CARD_STAT_STANDBY = 0x03U, /*!< Card is in standby state */ + SD_CARD_STAT_TRANS = 0x04U, /*!< Card is in transfer state */ + SD_CARD_STAT_TX_DATA = 0x05U, /*!< Card is sending an operation */ + SD_CARD_STAT_RX_DATA = 0x06U, /*!< Card is receiving operation information */ + SD_CARD_STAT_PGM = 0x07U, /*!< Card is in programming state */ + SD_CARD_STAT_DISCONNECT = 0x08U /*!< Card is disconnected */ +} en_sd_card_state_t; + + +typedef enum en_sd_card_version +{ + SdCardVer1x = 0u, ///< SD Card version: 1.x + SdCardVer2x = 1u, ///< SD Card version: 2.x +} en_sd_card_version_t; + +/** + ******************************************************************************* + ** \brief SD Card device Read/Write mode + ** + ******************************************************************************/ +typedef enum en_sd_card_device_mode +{ + SdCardPollingMode = 0u, ///< Polling mode transfer + SdCardDmaMode = 1u, ///< DMA mode transfer +} en_sd_card_device_mode_t; + +/** + ******************************************************************************* + ** \brief SD Card Information Structure definition + ** + ******************************************************************************/ +typedef struct stc_sd_card_info +{ + uint32_t u32CardType; ///< Specifies the card Type + + uint32_t u32CardVersion; ///< Specifies the card version + + uint32_t u32Class; ///< Specifies the class of the card class + + uint32_t u32RelCardAddr; ///< Specifies the Relative Card Address + + uint32_t u32BlockNbr; ///< Specifies the Card Capacity in blocks + + uint32_t u32BlockSize; ///< Specifies one block size in bytes + + uint32_t u32LogBlockNbr; ///< Specifies the Card logical Capacity in blocks + + uint32_t u32LogBlockSize; ///< Specifies logical block size in bytes + +} stc_sd_card_info_t; + +/** + ******************************************************************************* + ** \brief CSD Register ver1.0(for Standard Capacity Card) + ** + ******************************************************************************/ +typedef struct stc_sdcard_csd_v1 +{ + /* Byte 1 */ + uint8_t RESERVE1 : 2; + uint8_t FILE_FORMAT : 2; + uint8_t TMP_WRITE_PROTECT : 1; + uint8_t PERM_WRITE_PROTECT : 1; + uint8_t COPY : 1; + uint8_t FILE_FORMAT_GRP : 1; + + /* Byte 2 */ + uint8_t RESERVE2 : 5; + uint8_t WRITE_BL_PARTIAL : 1; + uint8_t WRITE_BL_LEN1 : 2; + /* Byte 3 */ + uint8_t WRITE_BL_LEN2 : 2; + uint8_t R2W_FACTOR : 3; + uint8_t RESERVE3 : 2; + uint8_t WP_GRP_ENABLE : 1; + + /* Byte 4 */ + uint8_t WP_GRP_SIZE : 7; + uint8_t SECTOR_SIZE1 : 1; + /* Byte 5 */ + uint8_t SECTOR_SIZE2 : 6; + uint8_t ERASE_BLK_EN : 1; + uint8_t C_SIZE_MULTI1 : 1; + /* Byte 6 */ + uint8_t C_SIZE_MULTI2 : 2; + uint8_t CDD_W_CURR_MAX : 3; + uint8_t CDD_W_CURR_MIN : 3; + + /* Byte 7 */ + uint8_t VDD_R_CURR_MAX : 3; + uint8_t VDD_R_CURR_MIN : 3; + uint8_t C_SIZE1 : 2; + /* Byte 8 */ + uint8_t C_SIZE2 : 8; + /* Byte 9 */ + uint8_t C_SIZE3 : 2; + uint8_t RESERVED4 : 2; + uint8_t DSR_IMP : 1; + uint8_t READ_BLK_MISALIGH : 1; + uint8_t WRITE_BLK_MISALIGN : 1; + uint8_t READ_BL_PARTIAL : 1; + + /* Byte 10 */ + uint8_t READ_BL_LEN : 4; + uint8_t CCC1 : 4; + /* Byte 11 */ + uint8_t CCC2 : 8; + + /* Byte 12 */ + uint8_t TRAN_SPEED : 8; + + /* Byte 13 */ + uint8_t NSAC : 8; + + /* Byte 14 */ + uint8_t TAAC : 8; + + /* Byte 15 */ + uint8_t RESERVE5 : 6; + uint8_t CSD_STRUCTURE : 2; +}stc_sdcard_csd_v1_t; + +/** + ******************************************************************************* + ** \brief CSD Register ver2.0(for High Capacity Card) + ** + ******************************************************************************/ +typedef struct stc_sdcard_csd_v2 +{ + /* Byte 1 */ + uint8_t RESERVED1 : 2; + uint8_t FILE_FORMAT : 2; + uint8_t TMP_WRITE_PROTECT : 1; + uint8_t PERM_WRITE_PROTECT : 1; + uint8_t COPY : 1; + uint8_t FILE_FORMAT_GRP : 1; + + /* Byte 2 */ + uint8_t RESERVED2 : 5; + uint8_t WRITE_BL_PARTIAL : 1; + uint8_t WRITE_BL_LEN1 : 2; + /* Byte 3 */ + uint8_t WRITE_BL_LEN2 : 2; + uint8_t R2W_FACTOR : 3; + uint8_t RESERVED3 : 2; + uint8_t WP_GRP_ENABLE : 1; + + /* Byte 4 */ + uint8_t WP_GRP_SIZE : 7; + uint8_t SECTOR_SIZE1 : 1; + /* Byte 5 */ + uint8_t SECTOR_SIZE2 : 6; + uint8_t ERASE_BLK_EN : 1; + uint8_t RESERVED4 : 1; + + /* Byte 6 */ + uint8_t C_SIZE1 : 8; + /* Byte 7 */ + uint8_t C_SIZE2 : 8; + /* Byte 8 */ + uint8_t C_SIZE3 : 6; + uint8_t RESERVED5 : 2; + + /* Byte 9 */ + uint8_t RESERVED6 : 4; + uint8_t DSR_IMP : 1; + uint8_t READ_BLK_MISALIGH : 1; + uint8_t WRITE_BLK_MISALIGN : 1; + uint8_t READ_BL_PARTIAL : 1; + + /* Byte 10 */ + uint8_t READ_BL_LEN : 4; + uint8_t CCC1 : 4; + + /* Byte 11 */ + uint8_t CCC2 : 8; + + /* Byte 12 */ + uint8_t TRAN_SPEED : 8; + + /* Byte 13 */ + uint8_t NSAC : 8; + + /* Byte 14 */ + uint8_t TAAC : 8; + + /* Byte 15 */ + uint8_t RESERVED7 : 6; + uint8_t CSD_STRUCTURE : 2; +} stc_sdcard_csd_v2_t; + +/** + ******************************************************************************* + ** \brief SD Card initilization parameters + ** + ******************************************************************************/ +typedef struct stc_sdcard_init +{ + en_sdioc_bus_width_t enBusWidth; ///< Specifies the SDIOC bus width. + ///< This parameter can be a value of @ref en_sdioc_bus_width_t + + en_sdioc_clk_freq_t enClkFreq; ///< Specifies the SDIOC clock frequency. + ///< This parameter can be a value of @ref en_sdioc_clk_freq_t + + en_sdioc_speed_mode_t enSpeedMode; ///< Specifies the SDIOC speed mode. + ///< This parameter can be a value of @ref en_sdioc_speed_mode_t + + const stc_sdioc_init_t *pstcInitCfg; ///< SD required parameters + ///< and this structure detail refer @ref stc_sdioc_init_t +} stc_sdcard_init_t; + +/** + ******************************************************************************* + ** \brief SD Card use DMA unit/channel parameters + ** + ******************************************************************************/ +typedef struct stc_sdcard_dma_init +{ + M4_DMA_TypeDef *DMAx; ///< Pointer to DMA registers base address + ///< and this structure detail refer @ref M4_DMA_TypeDef + + en_dma_channel_t enDmaCh; ///< Specifies the DMA channel. + ///< This parameter can be a value of @ref en_dma_channel_t +} stc_sdcard_dma_init_t; + +/** + ******************************************************************************* + ** \brief SD handle Structure definition + ** + ******************************************************************************/ +typedef struct stc_sd_handle +{ + M4_SDIOC_TypeDef *SDIOCx; ///< Pointer to SD registers base address + ///< and this structure detail refer @ref M4_SDIOC_TypeDef + + en_sd_card_device_mode_t enDevMode; ///< SD Card Write/Read mode and this parameter can be a value of @ref en_sd_card_device_mode_t + + const stc_sdcard_dma_init_t *pstcDmaInitCfg; ///< Pointer to SD Card initialization parameters + ///< and this structure detail refer @ref stc_sdcard_init_t + + const stc_sdcard_init_t *pstcCardInitCfg; ///< Pointer to SD Card initialization parameters + ///< and this structure detail refer @ref stc_sdcard_init_t + + __IO uint32_t Context; ///< SD transfer context + + __IO uint32_t u32ErrorCode; ///< SD Card Error codes + + stc_sd_card_info_t stcSdCardInfo; ///< SD Card information + ///< and this structure detail refer @ref stc_sd_card_info_t + + stc_sdmmc_resp_card_status_t stcCardStatus; ///< SD Card status + ///< and this structure detail refer @ref stc_sdmmc_resp_card_status_t + + uint32_t OCR; ///< SD Card Operation Condition Register + + uint32_t CID[4]; ///< SD Card IDentification + + uint32_t CSD[4]; ///< SD Card Specific Data + + uint32_t DSR; ///< DSR value + + uint32_t RCA; ///< RCA value + + uint32_t SCR[2]; ///< SD Card Configuration Register + + uint32_t CSR; ///< SD Card Status Register +}stc_sd_handle_t; + + +/******************************************************************************* + * Global pre-processor symbols/macros ('#define') + ******************************************************************************/ + +#define SD_CARD_ERROR_NONE (SDMMC_ERROR_NONE) /*!< No error */ +#define SD_CARD_ERROR_CMD_CRC_FAIL (SDMMC_ERROR_CMD_CRC_FAIL) /*!< Command response received (but CRC check failed) */ +#define SD_CARD_ERROR_DATA_CRC_FAIL (SDMMC_ERROR_DATA_CRC_FAIL) /*!< Data block sent/received (CRC check failed) */ +#define SD_CARD_ERROR_CMD_RSP_TIMEOUT (SDMMC_ERROR_CMD_RSP_TIMEOUT) /*!< Command response timeout */ +#define SD_CARD_ERROR_DATA_TIMEOUT (SDMMC_ERROR_DATA_TIMEOUT) /*!< Data timeout */ +#define SD_CARD_ERROR_TX_UNDERRUN (SDMMC_ERROR_TX_UNDERRUN) /*!< Transmit FIFO underrun */ +#define SD_CARD_ERROR_RX_OVERRUN (SDMMC_ERROR_RX_OVERRUN) /*!< Receive FIFO overrun */ +#define SD_CARD_ERROR_ADDR_MISALIGNED (SDMMC_ERROR_ADDR_MISALIGNED) /*!< Misaligned address */ +#define SD_CARD_ERROR_BLOCK_LEN_ERR (SDMMC_ERROR_BLOCK_LEN_ERR) /*!< Transferred block length is not allowed for the card or the + number of transferred bytes does not match the block length */ +#define SD_CARD_ERROR_ERASE_SEQ_ERR (SDMMC_ERROR_ERASE_SEQ_ERR) /*!< An error in the sequence of erase command occurs */ +#define SD_CARD_ERROR_BAD_ERASE_PARAM (SDMMC_ERROR_BAD_ERASE_PARAM) /*!< An invalid selection for erase groups */ +#define SD_CARD_ERROR_WRITE_PROT_VIOLATION (SDMMC_ERROR_WRITE_PROT_VIOLATION) /*!< Attempt to program a write protect block */ +#define SD_CARD_ERROR_LOCK_UNLOCK_FAILED (SDMMC_ERROR_LOCK_UNLOCK_FAILED) /*!< Sequence or password error has been detected in unlock + command or if there was an attempt to access a locked card */ +#define SD_CARD_ERROR_COM_CRC_FAILED (SDMMC_ERROR_COM_CRC_FAILED) /*!< CRC check of the previous command failed */ +#define SD_CARD_ERROR_ILLEGAL_CMD (SDMMC_ERROR_ILLEGAL_CMD) /*!< Command is not legal for the card state */ +#define SD_CARD_ERROR_CARD_ECC_FAILED (SDMMC_ERROR_CARD_ECC_FAILED) /*!< Card internal ECC was applied but failed to correct the data */ +#define SD_CARD_ERROR_CC_ERR (SDMMC_ERROR_CC_ERR) /*!< Internal card controller error */ +#define SD_CARD_ERROR_GENERAL_UNKNOWN_ERR (SDMMC_ERROR_GENERAL_UNKNOWN_ERR) /*!< General or unknown error */ +#define SD_CARD_ERROR_STREAM_READ_UNDERRUN (SDMMC_ERROR_STREAM_READ_UNDERRUN) /*!< The card could not sustain data reading in stream rmode */ +#define SD_CARD_ERROR_STREAM_WRITE_OVERRUN (SDMMC_ERROR_STREAM_WRITE_OVERRUN) /*!< The card could not sustain data programming in stream mode */ +#define SD_CARD_ERROR_CID_CSD_OVERWRITE (SDMMC_ERROR_CID_CSD_OVERWRITE) /*!< CID/CSD overwrite error */ +#define SD_CARD_ERROR_WP_ERASE_SKIP (SDMMC_ERROR_WP_ERASE_SKIP) /*!< Only partial address space was erased */ +#define SD_CARD_ERROR_CARD_ECC_DISABLED (SDMMC_ERROR_CARD_ECC_DISABLED) /*!< Command has been executed without using internal ECC */ +#define SD_CARD_ERROR_ERASE_RESET (SDMMC_ERROR_ERASE_RESET) /*!< Erase sequence was cleared before executing because an out + of erase sequence command was received */ +#define SD_CARD_ERROR_AKE_SEQ_ERR (SDMMC_ERROR_AKE_SEQ_ERR) /*!< Error in sequence of authentication */ +#define SD_CARD_ERROR_INVALID_VOLTRANGE (SDMMC_ERROR_INVALID_VOLTRANGE) /*!< Error in case of invalid voltage range */ +#define SD_CARD_ERROR_ADDR_OUT_OF_RANGE (SDMMC_ERROR_ADDR_OUT_OF_RANGE) /*!< Error when addressed block is out of range */ +#define SD_CARD_ERROR_REQUEST_NOT_APPLICABLE (SDMMC_ERROR_REQUEST_NOT_APPLICABLE)/*!< Error when command request is not applicable */ +#define SD_CARD_ERROR_PARAM (SDMMC_ERROR_INVALID_PARAMETER) /*!< the used parameter is not valid */ +#define SD_CARD_ERROR_UNSUPPORTED_FEATURE (SDMMC_ERROR_UNSUPPORTED_FEATURE) /*!< Error when feature is not insupported */ +#define SD_CARD_ERROR_BUSY (SDMMC_ERROR_BUSY) /*!< Error when transfer process is busy */ +#define SD_CARD_ERROR_DMA (SDMMC_ERROR_DMA) /*!< Error while DMA transfer */ +#define SD_CARD_ERROR_TIMEOUT (SDMMC_ERROR_TIMEOUT) /*!< Timeout error */ + +/******************************************************************************* + * Global variable definitions ('extern') + ******************************************************************************/ + +/******************************************************************************* + * Global function prototypes (definition in C source) + ******************************************************************************/ + +en_result_t SDCARD_Init(stc_sd_handle_t *handle, + const stc_sdcard_init_t *pstcInitCfg); +en_result_t SDCARD_SetDeviceMode(stc_sd_handle_t *handle, + en_sd_card_device_mode_t enDevMode); +en_sd_card_device_mode_t SDCARD_GetDeviceMode(const stc_sd_handle_t *handle); +en_result_t SDCARD_GetCardCSD(stc_sd_handle_t *handle); +en_result_t SDCARD_Erase(stc_sd_handle_t *handle, + uint32_t u32BlkStartAddr, + uint32_t u32BlkEndAddr, + uint32_t u32Timeout); +en_result_t SDCARD_ReadBlocks( stc_sd_handle_t *handle, + uint32_t u32BlockAddr, + uint16_t u16BlockCnt, + uint8_t *pu8Data, + uint32_t u32Timeout); +en_result_t SDCARD_WriteBlocks( stc_sd_handle_t *handle, + uint32_t u32BlockAddr, + uint16_t u16BlockCnt, + uint8_t *pu8Data, + uint32_t u32Timeout); +en_result_t SD_GetCardState(stc_sd_handle_t *handle, en_sd_card_state_t *peCardState); +//@} // SdiocGroup + +#ifdef __cplusplus +} +#endif + +#endif /* __SD_CARD_H__ */ + +/******************************************************************************* + * EOF (not truncated) + ******************************************************************************/ diff --git a/sd_card_1.c b/sd_card_1.c new file mode 100644 index 0000000..568cb05 --- /dev/null +++ b/sd_card_1.c @@ -0,0 +1,1268 @@ +/******************************************************************************* + * 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 sd_card.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" +#include "sd_card.h" + +/** + ******************************************************************************* + ** \addtogroup SdiocGroup + ******************************************************************************/ +//@{ + +/******************************************************************************* + * Local type definitions ('typedef') + ******************************************************************************/ +typedef enum en_sd_card_type +{ + SdCardSdsc = 0u, + SdCardSdhcSdxc = 1u, + SdCardSecured = 3u, +} en_sd_card_type_t; + +/******************************************************************************* + * Local pre-processor symbols/macros ('#define') + ******************************************************************************/ + +/*!< Card Command Class supported. */ +#define SDMMC_CARD_CCCC_ERASE (0x00000020u) + +/*!< Card locked */ +#define SDMMC_CARD_LOCKED (0x02000000u) + +/*!< Voltage trial times */ +#define SD_CARD_MAX_VOLT_TRIAL (0x0000FFFFu) + +/*!< High speed */ +#define SD_CHECK_FUNCTION_HIGH_SPEED (0x00FFFF01u) +#define SD_SET_FUNCTION_HIGH_SPEED (0x80FFFF01u) + +/*!< Block size is 512 bytes */ +#define SD_CARD_BLOCK_SIZE (512u) + +/*!< SDIOC buffer align size */ +#define SDIOC_BUF_ALIGN_SIZE (4ul) + +/*!< Log Block Number for 2G bytes Cards */ +#define SD_CARD_CAPACITY (0x400000u) + +/*!< Card power up status bit (busy) */ +#define SD_CARD_OCR_BUSY (0x80000000ul) + +#define SD_CARD_OP_NONE (0x00000000u) /*!< None */ +#define SD_CARD_OP_READ_SINGLE_BLOCK (0x00000001u) /*!< Read single block operation */ +#define SD_CARD_OP_READ_MULTIPLE_BLOCK (0x00000002u) /*!< Read multiple blocks operation */ +#define SD_CARD_OP_WRITE_SINGLE_BLOCK (0x00000010u) /*!< Write single block operation */ +#define SD_CARD_OP_WRITE_MULTIPLE_BLOCK (0x00000020u) /*!< Write multiple blocks operation */ +#define SD_CARD_OP_IT (0x00000008u) /*!< Process in Interrupt mode */ +#define SD_CARD_OP_DMA (0x00000080u) /*!< Process in DMA mode */ + +/*!< the SD card relative card address. */ +#define RelCardAddress(handle) ((handle)->stcSdCardInfo.u32RelCardAddr) +#define IsCardProgramming(handle) ((SdmmcCardStatePgm == (handle)->stcCardStatus.CURRENT_STATE) ? true : false) +#define IsCardReadyForData(handle) ((1u == (handle)->stcCardStatus.READY_FOR_DATA) ? true : false) + +#define IS_DMA_CFG_VALID(handle) \ +( (NULL != (handle)->pstcDmaInitCfg) && \ + (NULL != (handle)->pstcDmaInitCfg->DMAx)) + +/*!< the SD card use DMA unit && channel. */ +#define DMA_Unit(handle) ((handle)->pstcDmaInitCfg->DMAx) +#define DMA_CH(handle) ((handle)->pstcDmaInitCfg->enDmaCh) + +/*!< Parameter valid check for buffer address. */ +#define IS_VALID_TRANSFER_BUF_ALIGN(x) (!((SDIOC_BUF_ALIGN_SIZE-1ul) & ((uint32_t)(x)))) + +/*!< Parameter valid check for SDIOC command value. */ +#define IS_VALID_TRANSFER_BUF_LEN(x) (!((SD_CARD_BLOCK_SIZE - 1u) & (x))) + +/******************************************************************************* + * Global variable definitions (declared in header file with 'extern') + ******************************************************************************/ + +/******************************************************************************* + * Local function prototypes ('static') + ******************************************************************************/ +static en_result_t SdCardInitSd(stc_sd_handle_t *handle); +static en_result_t SdCardPowerON(stc_sd_handle_t *handle); +static en_result_t SdCardInitHost(const stc_sd_handle_t *handle); +static en_result_t SdCardSetSpeed(stc_sd_handle_t *handle); +static en_result_t SdCardSetBusWidth(stc_sd_handle_t *handle); +static en_result_t SdCardCheckReayForData(stc_sd_handle_t *handle, + uint32_t u32Timeout); +static en_result_t DmaSdiocTxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8TxBuf, + uint16_t u16len); +static en_result_t DmaSdiocRxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8RxBuf, + uint16_t u16len); + +/******************************************************************************* + * Local variable definitions ('static') + ******************************************************************************/ + +/******************************************************************************* + * Function implementation - global ('extern') and local ('static') + ******************************************************************************/ + +/** + ******************************************************************************* + ** \brief Initialize SD. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] pstcInitCfg The pointer of SD configure structure + ** \arg This parameter detail refer @ref stc_sdcard_init_t + ** + ** \retval Ok Initialize SD successfully. + ** \retval Error Initialize SD unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - pstcInitCfg == NULL + ** + ******************************************************************************/ +en_result_t SDCARD_Init(stc_sd_handle_t *handle, + const stc_sdcard_init_t *pstcInitCfg) +{ + en_result_t enRet = ErrorInvalidParameter; + + if ((NULL != handle) && (NULL != pstcInitCfg)) + { + handle->pstcCardInitCfg = pstcInitCfg; + + enRet = SdCardInitHost(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardPowerON(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardInitSd(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardSetBusWidth(handle); + if (enRet != Ok) + { + return enRet; + } + + enRet = SdCardSetSpeed(handle); + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Set SD Card device Read/Write mode. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] enDevMode Read/Write mode + ** \arg SdCardDmaMode DMA mode transfer + ** \arg SdCardPollingMode Polling mode transfer + ** + ** \retval Ok Set successfully. + ** \retval ErrorInvalidParameter handle pointer is NULL. + ** + ******************************************************************************/ +en_result_t SDCARD_SetDeviceMode(stc_sd_handle_t *handle, + en_sd_card_device_mode_t enDevMode) +{ + en_result_t enRet = ErrorInvalidParameter; + + if (NULL != handle) + { + handle->enDevMode = enDevMode; + enRet = Ok; + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Get SD Card device Read/Write mode. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval SdCardDmaMode DMA mode transfer + ** \retval SdCardPollingMode Polling mode transfer + ** + ******************************************************************************/ +en_sd_card_device_mode_t SDCARD_GetDeviceMode(const stc_sd_handle_t *handle) +{ + DDL_ASSERT(NULL != handle); + + return handle->enDevMode; +} + +/** + ******************************************************************************* + ** \brief Get Card specified Data information. + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Get successfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** + ******************************************************************************/ +en_result_t SDCARD_GetCardCSD(stc_sd_handle_t *handle) +{ + uint32_t u32Csize = 0ul; + uint32_t u32NumSector = 0ul; + uint32_t u32CsizeMulti = 0ul; + stc_sdcard_csd_v1_t *pstcCsdSd = NULL; + stc_sdcard_csd_v2_t *pstcCsdSdHc = NULL; + en_result_t enRet = ErrorInvalidParameter; + + if (NULL != handle) + { + /* High Capacity CSD Version 2.0*/ + if ((handle->CSD[3] & 0x00FF0000ul) == 0x00400000ul) + { + pstcCsdSdHc = (stc_sdcard_csd_v2_t *)&handle->CSD[0]; + u32Csize = ((unsigned int)pstcCsdSdHc->C_SIZE3 << 16ul) + + ((unsigned int)pstcCsdSdHc->C_SIZE2 << 8ul) + + pstcCsdSdHc->C_SIZE1; + + u32NumSector = (u32Csize + 1ul) << 10ul; + + handle->stcSdCardInfo.u32Class = (((uint32_t)pstcCsdSdHc->CCC2) << 4u) | ((uint32_t)pstcCsdSdHc->CCC1); + handle->stcSdCardInfo.u32BlockSize = 1ul << (pstcCsdSdHc->READ_BL_LEN); + } + else /* Standard Capacity CSD Version 1.xx */ + { + pstcCsdSd = (stc_sdcard_csd_v1_t *)&handle->CSD[0]; + + u32Csize = ((unsigned int)pstcCsdSd->C_SIZE3 << 10) + + ((unsigned int)pstcCsdSd->C_SIZE2 << 2) + + pstcCsdSd->C_SIZE1; + + u32CsizeMulti = ((uint32_t)(pstcCsdSd->C_SIZE_MULTI2) << 1) + (uint32_t)pstcCsdSd->C_SIZE_MULTI1; + u32NumSector = (u32Csize + 1ul) << (u32CsizeMulti + 2ul); + + if (pstcCsdSd->READ_BL_LEN == 0x0Au) + { + u32NumSector *= 2ul; + } + else if (pstcCsdSd->READ_BL_LEN == 0x0Bu) + { + u32NumSector *= 4ul; + } + else + { + /* Do nothing: only avoid MISRA warning */ + } + + handle->stcSdCardInfo.u32Class = ((uint32_t)pstcCsdSd->CCC2 << 4) | (uint32_t)pstcCsdSd->CCC1; + handle->stcSdCardInfo.u32BlockSize = 1ul << (pstcCsdSd->READ_BL_LEN); + } + + handle->stcSdCardInfo.u32BlockNbr = u32NumSector; + handle->stcSdCardInfo.u32LogBlockNbr = (handle->stcSdCardInfo.u32BlockNbr) * ((handle->stcSdCardInfo.u32BlockSize) / SD_CARD_BLOCK_SIZE); + handle->stcSdCardInfo.u32LogBlockSize = SD_CARD_BLOCK_SIZE; + enRet = Ok; + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Erase SD card blocks. + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32BlkStartAddr Block start address + ** \param [in] u32BlkEndAddr Block end address + ** \param [in] u32Timeout Erase timeout value + ** + ** \retval Ok Erase successfully. + ** \retval Error Erase unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - u32BlkStartAddr out of range + ** - u32BlkEndAddr out of range + ** + ******************************************************************************/ +en_result_t SDCARD_Erase(stc_sd_handle_t *handle, + uint32_t u32BlkStartAddr, + uint32_t u32BlkEndAddr, + uint32_t u32Timeout) +{ + en_result_t enCmdRet = Error; + __IO uint32_t u32TimeCount = u32Timeout * (SystemCoreClock / 8u / 1000u); + + if ((NULL == handle) || + (u32BlkStartAddr > u32BlkEndAddr) || + (u32BlkEndAddr > handle->stcSdCardInfo.u32BlockNbr)) + { + return ErrorInvalidParameter; + } + + /* Check if the card command class supports erase command */ + if (!(handle->stcSdCardInfo.u32Class & SDMMC_CARD_CCCC_ERASE)) + { + return ErrorAccessRights; + } + + if ((SDIOC_GetResponse(handle->SDIOCx, SdiocRegResp01) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + { + return ErrorAccessRights; + } + + /* Check the Card capacity in term of Logical number of blocks */ + if (handle->stcSdCardInfo.u32CardType != SdCardSdhcSdxc) + { + u32BlkStartAddr *= SD_CARD_BLOCK_SIZE; + u32BlkEndAddr *= SD_CARD_BLOCK_SIZE; + } + + /* Send CMD35 ERASE_GRP_START with argument as address */ + enCmdRet = SDMMC_Cmd32_EraseWrBlkStart(handle->SDIOCx, u32BlkStartAddr, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* Send CMD36 ERASE_GRP_END with argument as address */ + enCmdRet = SDMMC_Cmd33_EraseWrBlkEnd(handle->SDIOCx, u32BlkEndAddr, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SDMMC_Cmd38_Erase(handle->SDIOCx, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SdCardCheckReayForData(handle, u32TimeCount); + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Read block data from SD card + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32BlockAddr Block address + ** \param [in] u16BlockCnt Block Count + ** \param [in] pu8Data Pointer to buffer which will store SD Card data. + ** \param [in] u32Timeout Transfer timeout + ** + ** \retval Ok Read successfully. + ** \retval Error Read unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - pu8Data == NULL + ** - u16BlockCnt == 0 + ** - (u32BlockAddr + u16BlockCnt) out of range + ** + ******************************************************************************/ +en_result_t SDCARD_ReadBlocks(stc_sd_handle_t *handle, + uint32_t u32BlockAddr, + uint16_t u16BlockCnt, + uint8_t *pu8Data, + uint32_t u32Timeout) +{ + en_result_t enCmdRet; + stc_sdioc_data_cfg_t stcDataCfg; + uint8_t *pu8TempBuf = (uint8_t *)pu8Data; + uint32_t u32TimeCount = u32Timeout * (SystemCoreClock / 8u / 1000u); + __IO uint32_t u32Count = u32TimeCount; + en_sd_card_device_mode_t enDeviceMode = SDCARD_GetDeviceMode(handle); + en_flag_status_t enStatus = Reset; + en_flag_status_t enIrqFlag = Reset; + + if (NULL == handle) + { + return ErrorInvalidParameter; + } + + if ((NULL == pu8Data) || (0u == u16BlockCnt)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_PARAM; + return ErrorInvalidParameter; + } + + handle->u32ErrorCode = SD_CARD_ERROR_NONE; + + if ((u32BlockAddr + u16BlockCnt) > (handle->stcSdCardInfo.u32LogBlockNbr)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_ADDR_OUT_OF_RANGE; + return ErrorInvalidParameter; + } + + if (handle->stcSdCardInfo.u32CardType != SdCardSdhcSdxc) + { + u32BlockAddr *= SD_CARD_BLOCK_SIZE; + } + + /* Set Block Size for Card */ + enCmdRet = SDMMC_Cmd16_SetBlockLength(handle->SDIOCx, SD_CARD_BLOCK_SIZE, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + stcDataCfg.u16BlkCnt = u16BlockCnt; + stcDataCfg.u16BlkSize = SD_CARD_BLOCK_SIZE; + stcDataCfg.enDataTimeOut = SdiocDtoSdclk_2_27; + stcDataCfg.enTransferDir = SdiocTransferToHost; + stcDataCfg.enAutoCmd12Enable = (u16BlockCnt > 1u) ? Enable:Disable; + stcDataCfg.enTransferMode = (u16BlockCnt > 1u) ? SdiocTransferMultiple:SdiocTransferSingle; + enCmdRet = SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (enDeviceMode == SdCardDmaMode) + { + if (IS_DMA_CFG_VALID(handle)) + { + DmaSdiocRxConfig(DMA_Unit(handle), DMA_CH(handle), handle->SDIOCx, pu8TempBuf, u16BlockCnt * SD_CARD_BLOCK_SIZE); + } + } + + /* Read block(s) in polling mode */ + if (1u == u16BlockCnt) + { + handle->Context = SD_CARD_OP_READ_SINGLE_BLOCK; + /* Read Single Block command */ + enCmdRet = SDMMC_Cmd17_ReadSingleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + else + { + handle->Context = SD_CARD_OP_READ_MULTIPLE_BLOCK; + /* Read Multi Block command */ + enCmdRet = SDMMC_Cmd18_ReadMultipleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (SdCardPollingMode == enDeviceMode) + { + /* Poll on SDIO flags */ + while (u16BlockCnt) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocBufferReadEnble); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocBufferReadReady); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + SDIOC_ReadBuffer(handle->SDIOCx, pu8TempBuf, SD_CARD_BLOCK_SIZE); + + u16BlockCnt--; + u32Count = u32TimeCount; + pu8TempBuf += SD_CARD_BLOCK_SIZE; + } + + if (0ul == u32Count--) + { + return ErrorTimeout; + } + } + } + + for (u32Count = u32TimeCount; u32Count > 0ul; u32Count--) + { + if (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete)) + { + break; + } + } + + if (0ul == u32Count) + { + return ErrorTimeout; + } + else + { + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + } + + /* check whether Data transfer stops */ + if (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocErrorInt)) + { + enCmdRet = Error; + } + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Write block data to SD card + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32BlockAddr Block address + ** \param [in] u16BlockCnt Block Count + ** \param [in] pu8Data Pointer to buffer which contains data to be send to SD Card. + ** \param [in] u32Timeout Transfer timeout + ** + ** \retval Ok Write successfully. + ** \retval Error Write unsuccessfully. + ** \retval ErrorInvalidParameter If one of following cases matches: + ** - handle == NULL + ** - pu8Data == NULL + ** - u16BlockCnt == 0 + ** - (u32BlockAddr + u16BlockCnt) out of range + ** + ******************************************************************************/ +en_result_t SDCARD_WriteBlocks(stc_sd_handle_t *handle, + uint32_t u32BlockAddr, + uint16_t u16BlockCnt, + uint8_t *pu8Data, + uint32_t u32Timeout) +{ + en_result_t enCmdRet; + stc_sdioc_data_cfg_t stcDataCfg; + uint8_t *pu8TempBuf = (uint8_t *)pu8Data; + uint32_t u32TimeCount = u32Timeout * (SystemCoreClock / 50ul / 1000ul); + __IO uint32_t u32Count = u32TimeCount; + en_sd_card_device_mode_t enDeviceMode = SDCARD_GetDeviceMode(handle); + en_flag_status_t enStatus = Reset; + en_flag_status_t enIrqFlag = Reset; + + if (NULL == handle) + { + return ErrorInvalidParameter; + } + + if ((NULL == pu8Data) || (0u == u16BlockCnt)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_PARAM; + return ErrorInvalidParameter; + } + + handle->u32ErrorCode = SD_CARD_ERROR_NONE; + + if ((u32BlockAddr + u16BlockCnt) > (handle->stcSdCardInfo.u32LogBlockNbr)) + { + handle->u32ErrorCode |= SD_CARD_ERROR_ADDR_OUT_OF_RANGE; + return ErrorInvalidParameter; + } + + /* Set Block Size for Card */ + enCmdRet = SDMMC_Cmd16_SetBlockLength(handle->SDIOCx, SD_CARD_BLOCK_SIZE, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + stcDataCfg.u16BlkCnt = u16BlockCnt; + stcDataCfg.u16BlkSize = SD_CARD_BLOCK_SIZE; + stcDataCfg.enDataTimeOut = SdiocDtoSdclk_2_27; + stcDataCfg.enTransferDir = SdiocTransferToCard; + stcDataCfg.enAutoCmd12Enable = (u16BlockCnt > 1u) ? Enable:Disable; + stcDataCfg.enTransferMode = (u16BlockCnt > 1u) ? SdiocTransferMultiple:SdiocTransferSingle; + enCmdRet = SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (handle->stcSdCardInfo.u32CardType != SdCardSdhcSdxc) + { + u32BlockAddr *= SD_CARD_BLOCK_SIZE; + } + + if (enDeviceMode == SdCardDmaMode) + { + if (IS_DMA_CFG_VALID(handle)) + { + DmaSdiocTxConfig(DMA_Unit(handle), DMA_CH(handle), handle->SDIOCx, pu8TempBuf, u16BlockCnt * SD_CARD_BLOCK_SIZE); + } + } + + /* Write block(s) in polling mode */ + if (1u == u16BlockCnt) + { + /* Read Single Block command */ + enCmdRet = SDMMC_Cmd24_WriteSingleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + else + { + /* Read Multi Block command */ + enCmdRet = SDMMC_Cmd25_WriteMultipleBlock(handle->SDIOCx, u32BlockAddr, (uint32_t *)(&handle->stcCardStatus)); + } + + if (enCmdRet != Ok) + { + return enCmdRet; + } + + if (SdCardPollingMode == enDeviceMode) + { + /* Poll on SDIO flags */ + while (u16BlockCnt) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocBufferWriteEnble); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocBufferWriteReady); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + /* Write data to SDIO Tx Buffer */ + SDIOC_WriteBuffer(handle->SDIOCx, pu8TempBuf, SD_CARD_BLOCK_SIZE); + + u16BlockCnt--; + u32Count = u32TimeCount; + pu8TempBuf += SD_CARD_BLOCK_SIZE; + } + + if (u32Count-- == 0ul) + { + return ErrorTimeout; + } + } + } + + for (u32Count = u32TimeCount; u32Count > 0ul; u32Count--) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocData0PinLvl); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + break; + } + } + + if (0u == u32Count) + { + return ErrorTimeout; + } + else + { + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + } + + enCmdRet = SdCardCheckReayForData(handle, u32TimeCount); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* check whether Data transfer stops */ + if(Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocErrorInt)) + { + return Error; + } + + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocBufferWriteReady); + + return Ok; +} + +/** + ****************************************************************************** + ** \brief Set SD bus width. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Set SD bus width successfully. + ** \retval Error Set SD bus width unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcCfg + ** - enBusWidth is invalid. + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardSetBusWidth(stc_sd_handle_t *handle) +{ + uint32_t u32CmdArg = 0ul; + en_result_t enCmdRet = Ok; + + if ((NULL == handle) || (NULL == handle->pstcCardInitCfg)) + { + return ErrorInvalidParameter; + } + + switch (handle->pstcCardInitCfg->enBusWidth) + { + case SdiocBusWidth1Bit: + u32CmdArg = 0u; + break; + case SdiocBusWidth4Bit: + u32CmdArg = 2u; + break; + default: + enCmdRet = ErrorInvalidParameter; + break; + } + + if (Ok != enCmdRet) + { + return enCmdRet; + } + + enCmdRet = SDMMC_Cmd55_AppCmd(handle->SDIOCx, (RelCardAddress(handle) << 16u), (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SDMMC_Acmd6_SetBusWidth(handle->SDIOCx, u32CmdArg, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + enCmdRet = SDIOC_SetBusWidth(handle->SDIOCx, handle->pstcCardInitCfg->enBusWidth); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + return Ok; +} + +/** + ****************************************************************************** + ** \brief Set SD high speed mode. + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Set SD bus width successfully. + ** \retval Ok Set SD bus width unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcCfg + ** - u32Freq is invalid. + ** + ******************************************************************************/ +static en_result_t SdCardSetSpeed(stc_sd_handle_t *handle) +{ + uint8_t au8TempBuf[64] = {0}; + uint32_t u32TimeCount = 2000 * (SystemCoreClock / 8u / 1000u); + __IO uint32_t u32Count = u32TimeCount; + en_flag_status_t enStatus = Reset; + en_flag_status_t enIrqFlag = Reset; + + en_result_t enCmdRet = ErrorInvalidParameter; + stc_sdioc_data_cfg_t stcDataCfg; + uint32_t u32Arg = SD_SET_FUNCTION_HIGH_SPEED; + + if ((NULL != handle) && (NULL != handle->pstcCardInitCfg)) + { + enCmdRet = Ok; + if (SdiocHighSpeedMode == handle->pstcCardInitCfg->enSpeedMode) + { + /* Set Block Size for Card */ + enCmdRet = SDMMC_Cmd16_SetBlockLength(handle->SDIOCx, 64u, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet == Ok) + { + stcDataCfg.u16BlkCnt = 1u; + stcDataCfg.u16BlkSize = 64u; + stcDataCfg.enDataTimeOut = SdiocDtoSdclk_2_27; + stcDataCfg.enTransferDir = SdiocTransferToHost; + stcDataCfg.enAutoCmd12Enable = Disable; + stcDataCfg.enTransferMode = SdiocTransferSingle; + enCmdRet = SDIOC_ConfigData(handle->SDIOCx, &stcDataCfg); + if (enCmdRet == Ok) + { + enCmdRet = SDMMC_Cmd6_SwitchFunc(handle->SDIOCx, u32Arg, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet == Ok) + { + while (u32Count--) + { + enStatus = SDIOC_GetStatus(handle->SDIOCx, SdiocBufferReadEnble); + enIrqFlag = SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocBufferReadReady); + if ((Set == enStatus) && (Set == enIrqFlag)) + { + SDIOC_ReadBuffer(handle->SDIOCx, au8TempBuf, sizeof(au8TempBuf)); + break; + } + } + + if (0ul == u32Count) + { + return ErrorTimeout; + } + + u32Count = u32TimeCount; + while (u32Count--) + { + if (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete)) + { + SDIOC_ClearNormalIrqFlag(handle->SDIOCx, SdiocTransferComplete); + break; + } + } + + if (0ul == u32Count) + { + return ErrorTimeout; + } + + /* Check whether switch function with error or transfer error occur */ + if ((!(au8TempBuf[16] & 0x01)) || + (Set == SDIOC_GetNormalIrqFlag(handle->SDIOCx, SdiocErrorInt))) + { + enCmdRet = Error; + } + } + } + } + } + + if (enCmdRet == Ok) + { + SDIOC_SetSpeedMode(handle->SDIOCx, handle->pstcCardInitCfg->enSpeedMode); + + enCmdRet = SDIOC_SetClk(handle->SDIOCx, handle->pstcCardInitCfg->enClkFreq); + } + } + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Initialize SDIO Host + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok SDIO host initialized successfully + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcInitCfg + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardInitHost(const stc_sd_handle_t *handle) +{ + en_result_t enRet = Ok; + + if ((NULL == handle) || (NULL == handle->pstcCardInitCfg)) + { + return ErrorInvalidParameter; + } + + /* Enable SD clock supply */ + if (M4_SDIOC1 == handle->SDIOCx) + { + PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_SDIOC1, Enable); + } + else if (M4_SDIOC2 == handle->SDIOCx) + { + PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_SDIOC2, Enable); + } + else + { + return ErrorInvalidParameter; + } + + /* Set mode: SD */ + SDIOC_SetMode(handle->SDIOCx, SdiocModeSD); + + enRet = SDIOC_Init(handle->SDIOCx, handle->pstcCardInitCfg->pstcInitCfg); + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Initialize SD bus + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok SDIO bus cmd operate successfully. + ** \retval Error SDIO bus cmd operate unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == pstcCfg + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardInitSd(stc_sd_handle_t *handle) +{ + en_result_t enCmdRet = Ok; + + if(NULL == handle) + { + return ErrorInvalidParameter; + } + + if (handle->stcSdCardInfo.u32CardType != SdCardSecured) + { + /* Send CMD2 ALL_SEND_CID */ + enCmdRet = SDMMC_Cmd2_AllSendCID(handle->SDIOCx, handle->CID); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* Send CMD3 SET_REL_ADDR with argument 0 */ + /* SD Card publishes its RCA. */ + enCmdRet = SDMMC_Cmd3_SendRelativeAddr(handle->SDIOCx, &(handle->RCA)); + if (enCmdRet != Ok) + { + return enCmdRet; + } + + /* Get the SD card RCA */ + RelCardAddress(handle) = handle->RCA; + + /* Send CMD9 SEND_CSD with argument as card's RCA */ + enCmdRet = SDMMC_Cmd9_SendCSD(handle->SDIOCx, RelCardAddress(handle), handle->CSD); + if (enCmdRet != Ok) + { + return enCmdRet; + } + } + + /* Get CSD parameters */ + enCmdRet = SDCARD_GetCardCSD(handle); + if (enCmdRet == Ok) + { + /* Select the Card */ + enCmdRet = SDMMC_Cmd7_SelectDeselectCard(handle->SDIOCx, RelCardAddress(handle), (uint32_t *)(&handle->stcCardStatus)); + } + + return enCmdRet; +} + +/** + ******************************************************************************* + ** \brief Activate SD in power-on stage + ** + ** \param [in] handle Pointer to SD handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** + ** \retval Ok Activate successfully. + ** \retval Error Activate unsuccessfully. + ** \retval ErrorInvalidParameter If one of following conditions matches: + ** - NULL == handle + ** - Other invalid configuration + ** + ******************************************************************************/ +static en_result_t SdCardPowerON(stc_sd_handle_t *handle) +{ + uint32_t u32IfCond = 0u; + __IO uint32_t u32Count = 0ul; + en_result_t enCmdRet = Error; + + if (NULL == handle) + { + return ErrorInvalidParameter; + } + + handle->u32ErrorCode = SD_CARD_ERROR_NONE; + + /* CMD0: GO_IDLE_STATE */ + enCmdRet = SDMMC_Cmd0_GoIdleState(handle->SDIOCx); + if (enCmdRet != Ok) + { + handle->u32ErrorCode |= SD_CARD_ERROR_GENERAL_UNKNOWN_ERR; + return enCmdRet; + } + + /* Reset OCR valude */ + handle->OCR = 0ul; + + /* CMD8: SEND_IF_COND: Command available only on V2.0 cards */ + enCmdRet = SDMMC_Cmd8_SendIfCond(handle->SDIOCx, &u32IfCond); + if (enCmdRet != Ok) + { + handle->stcSdCardInfo.u32CardVersion = SdCardVer1x; + + /* Send ACMD41 SD_APP_OP_COND with Argument 0x00100000 */ + while (SD_CARD_OCR_BUSY != (handle->OCR & SD_CARD_OCR_BUSY)) + { + if (SD_CARD_MAX_VOLT_TRIAL == u32Count++) + { + handle->u32ErrorCode |= SD_CARD_ERROR_INVALID_VOLTRANGE; + return enCmdRet; + } + + /* SEND CMD55 APP_CMD with RCA as 0 */ + enCmdRet = SDMMC_Cmd55_AppCmd(handle->SDIOCx, 0u, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + continue; + } + + /* Send CMD41 */ + enCmdRet = SDMMC_Acmd41_SdSendOpCond(handle->SDIOCx, SdmmcStanderdCapacity, &handle->OCR); + if (enCmdRet == Error) + { + handle->u32ErrorCode |= SD_CARD_ERROR_UNSUPPORTED_FEATURE; + return enCmdRet; + } + } + + /* Card type is SDSC */ + handle->stcSdCardInfo.u32CardType = SdCardSdsc; + } + else + { + handle->stcSdCardInfo.u32CardVersion = SdCardVer2x; + + /* Send ACMD41 SD_APP_OP_COND with Argument 0x40100000 */ + while (SD_CARD_OCR_BUSY != (handle->OCR & SD_CARD_OCR_BUSY)) + { + if (SD_CARD_MAX_VOLT_TRIAL == u32Count++) + { + handle->u32ErrorCode |= SD_CARD_ERROR_INVALID_VOLTRANGE; + return Error; + } + + /* SEND CMD55 APP_CMD with RCA as 0 */ + enCmdRet = SDMMC_Cmd55_AppCmd(handle->SDIOCx, 0u, (uint32_t *)(&handle->stcCardStatus)); + if (enCmdRet != Ok) + { + continue; + } + + /* Send CMD41 */ + enCmdRet = SDMMC_Acmd41_SdSendOpCond(handle->SDIOCx, SdmmcHighCapacity, &handle->OCR); + if (enCmdRet == Error) + { + handle->u32ErrorCode |= SD_CARD_ERROR_UNSUPPORTED_FEATURE; + return enCmdRet; + } + } + + if ((handle->OCR & SdmmcHighCapacity) == SdmmcHighCapacity) + { + handle->stcSdCardInfo.u32CardType = SdCardSdhcSdxc; + } + else + { + handle->stcSdCardInfo.u32CardType = SdCardSdsc; + } + } + + return Ok; +} + +/** + ******************************************************************************* + ** \brief Checks if the SD card is ready for data. + ** + ** \param [in] handle Pointer to SD Card handle + ** \arg This parameter detail refer @ref stc_sd_handle_t + ** \param [in] u32Timeout Retry to get card status time + ** + ** \retval Ok Card is ready for data + ** \retval Error Card is not ready for data + ** \retval ErrorInvalidParameter NULL == handle + ** + ******************************************************************************/ +static en_result_t SdCardCheckReayForData(stc_sd_handle_t *handle, uint32_t u32Timeout) +{ + en_result_t enRet = ErrorInvalidParameter; + + if (NULL != handle) + { + do + { + enRet = SDMMC_Cmd13_SendStatus(handle->SDIOCx, RelCardAddress(handle), (uint32_t *)(&handle->stcCardStatus)); + if (Ok != enRet) + { + break; + } + } while ((--u32Timeout) && (false == IsCardReadyForData(handle))); + + if (0u == u32Timeout) + { + enRet = ErrorTimeout; + } + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Configures the DMA Channel for SDIO Tx request. + ** + ** \param [in] DMAx The pointer to DMAC register base + ** \arg M4_DMA1 DMAC unit 1 instance register base + ** \arg M4_DMA2 DMAC unit 2 instance register base + ** \param [in] enCh The specified DMAC channel. + ** \arg DmaCh0 DMAC channel 0 + ** \arg DmaCh1 DMAC channel 1 + ** \arg DmaCh2 DMAC channel 2 + ** \arg DmaCh3 DMAC channel 3 + ** \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] pu8TxBuf Pointer to the Tx buffer + ** \param [in] u16len Tx buffer size + ** + ** \retval Ok Set successfully. + ** \retval ErrorInvalidParameter Set unsuccessfully. + ** + ******************************************************************************/ +static en_result_t DmaSdiocTxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8TxBuf, + uint16_t u16len) +{ + stc_dma_config_t stcDmaInit; + uint32_t u32Fcg0Periph = (M4_DMA1 == DMAx) ? PWC_FCG0_PERIPH_DMA1 : PWC_FCG0_PERIPH_DMA2; + en_event_src_t enEvtSrc = (M4_SDIOC1 == SDIOCx) ? EVT_SDIOC1_DMAW : EVT_SDIOC2_DMAW; + en_result_t enRet = ErrorInvalidParameter; + + if ((NULL != pu8TxBuf) && \ + (IS_VALID_TRANSFER_BUF_LEN(u16len)) && \ + (IS_VALID_TRANSFER_BUF_ALIGN(pu8TxBuf))) + { + /* Enable peripheral clock */ + PWC_Fcg0PeriphClockCmd(u32Fcg0Periph, Enable); + + /* Enable DMA. */ + DMA_Cmd(DMAx, Enable); + + /* Initialize DMA. */ + MEM_ZERO_STRUCT(stcDmaInit); + stcDmaInit.u16BlockSize = SD_CARD_BLOCK_SIZE/4u; /* Set data block size. */ + stcDmaInit.u16TransferCnt = u16len/SD_CARD_BLOCK_SIZE; /* Set transfer count. */ + stcDmaInit.u32SrcAddr = (uint32_t)(&pu8TxBuf[0]); /* Set source address. */ + stcDmaInit.u32DesAddr = (uint32_t)(&SDIOCx->BUF0); /* Set destination address. */ + stcDmaInit.stcDmaChCfg.enSrcInc = AddressIncrease; /* Set source address mode. */ + stcDmaInit.stcDmaChCfg.enDesInc = AddressFix; /* Set destination address mode. */ + stcDmaInit.stcDmaChCfg.enTrnWidth = Dma32Bit; /* Set data width 8bit. */ + DMA_InitChannel(DMAx, enCh, &stcDmaInit); + + /* Enable the specified DMA channel. */ + DMA_ChannelCmd(DMAx, enCh, Enable); + + /* Clear DMA flag. */ + DMA_ClearIrqFlag(DMAx, enCh, TrnCpltIrq); + DMA_ClearIrqFlag(DMAx, enCh, BlkTrnCpltIrq); + + /* Enable peripheral circuit trigger function. */ + PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable); + + /* Set DMA trigger source. */ + DMA_SetTriggerSrc(DMAx, enCh, enEvtSrc); + + enRet = Ok; + } + + return enRet; +} + +/** + ******************************************************************************* + ** \brief Configures the DMA Channel for SDIO Rx request. + ** + ** \param [in] DMAx The pointer to DMAC register base + ** \arg M4_DMA1 DMAC unit 1 instance register base + ** \arg M4_DMA2 DMAC unit 2 instance register base + ** \param [in] enCh The specified DMAC channel. + ** \arg DmaCh0 DMAC channel 0 + ** \arg DmaCh1 DMAC channel 1 + ** \arg DmaCh2 DMAC channel 2 + ** \arg DmaCh3 DMAC channel 3 + ** \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] pu8RxBuf Pointer to the Rx buffer + ** \param [in] u16len Rx buffer size + ** + ** \retval Ok Set successfully. + ** \retval ErrorInvalidParameter Set unsuccessfully. + ** + ******************************************************************************/ +static en_result_t DmaSdiocRxConfig(M4_DMA_TypeDef* DMAx, + en_dma_channel_t enCh, + M4_SDIOC_TypeDef *SDIOCx, + uint8_t *pu8RxBuf, + uint16_t u16len) +{ + stc_dma_config_t stcDmaInit; + uint32_t u32Fcg0Periph = (M4_DMA1 == DMAx) ? PWC_FCG0_PERIPH_DMA1 : PWC_FCG0_PERIPH_DMA2; + en_event_src_t enEvtSrc = (M4_SDIOC1 == SDIOCx) ? EVT_SDIOC1_DMAR : EVT_SDIOC2_DMAR; + en_result_t enRet = ErrorInvalidParameter; + + if ((NULL != pu8RxBuf) && \ + (IS_VALID_TRANSFER_BUF_LEN(u16len)) && \ + (IS_VALID_TRANSFER_BUF_ALIGN(pu8RxBuf))) + { + /* Enable peripheral clock */ + PWC_Fcg0PeriphClockCmd(u32Fcg0Periph,Enable); + + /* Enable DMA. */ + DMA_Cmd(DMAx, Enable); + + /* Initialize DMA. */ + MEM_ZERO_STRUCT(stcDmaInit); + stcDmaInit.u16BlockSize = SD_CARD_BLOCK_SIZE/4u; /* Set data block size. */ + stcDmaInit.u16TransferCnt = u16len/SD_CARD_BLOCK_SIZE; /* Set transfer count. */ + stcDmaInit.u32SrcAddr = (uint32_t)(&SDIOCx->BUF0); /* Set source address. */ + stcDmaInit.u32DesAddr = (uint32_t)(&pu8RxBuf[0]); /* Set destination address. */ + stcDmaInit.stcDmaChCfg.enSrcInc = AddressFix; /* Set source address mode. */ + stcDmaInit.stcDmaChCfg.enDesInc = AddressIncrease; /* Set destination address mode. */ + stcDmaInit.stcDmaChCfg.enTrnWidth = Dma32Bit; /* Set data width 8bit. */ + DMA_InitChannel(DMAx, enCh, &stcDmaInit); + + /* Enable the specified DMA channel. */ + DMA_ChannelCmd(DMAx, enCh, Enable); + + /* Clear DMA flag. */ + DMA_ClearIrqFlag(DMAx, enCh, TrnCpltIrq); + DMA_ClearIrqFlag(DMAx, enCh, BlkTrnCpltIrq); + + /* Enable peripheral circuit trigger function. */ + PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS, Enable); + + /* Set DMA trigger source. */ + DMA_SetTriggerSrc(DMAx, enCh, enEvtSrc); + + enRet = Ok; + } + + return enRet; +} + +//@} // SdiocGroup + +/******************************************************************************* + * EOF (not truncated) + ******************************************************************************/ diff --git a/sdmmc_cmd.c b/sdmmc_cmd.c new file mode 100644 index 0000000..2bdaa1b --- /dev/null +++ b/sdmmc_cmd.c @@ -0,0 +1,1641 @@ +/******************************************************************************* + * 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 = true;//(Set == SDIOC_GetStatus(SDIOCx, SdiocCardInserted)) ? true : false; + } + + return bRet; +} + +//@} // SdiocGroup + +/******************************************************************************* + * EOF (not truncated) + ******************************************************************************/ diff --git a/sdmmc_cmd.h b/sdmmc_cmd.h new file mode 100644 index 0000000..9890e53 --- /dev/null +++ b/sdmmc_cmd.h @@ -0,0 +1,311 @@ +/******************************************************************************* + * 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.h + ** + ** A detailed description is available at + ** @link SdiocGroup SDIOC description @endlink + ** + ** - 2018-11-15 CDT First version for Device Driver Library of SDIOC. + ** + ******************************************************************************/ +#ifndef __SDMMC_CMD_H__ +#define __SDMMC_CMD_H__ + +/******************************************************************************* + * Include files + ******************************************************************************/ +#include "hc32_ddl.h" +#include "hc32f460_utility.h" + +/* C binding of definitions if building with C++ compiler */ +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + ******************************************************************************* + ** \defgroup SdiocGroup Secure Digital Input and Output Controller(SDIOC) + ** + ******************************************************************************/ +//@{ + +/******************************************************************************* + * Global type definitions ('typedef') + ******************************************************************************/ +/** + ******************************************************************************* + ** \brief SD/eMMC/SDIO card status + ** + ******************************************************************************/ +typedef enum en_sdmmc_card_state +{ + SdmmcCardStateIdle = 0u, ///< Card state: Idle State + SdmmcCardStateReady = 1u, ///< Card state: Ready State + SdmmcCardStateIdent = 2u, ///< Card state: Identification State + SdmmcCardStateStby = 3u, ///< Card state: Stand-by State + SdmmcCardStateTran = 4u, ///< Card state: Transfer State + SdmmcCardStateSendData = 5u, ///< Card state: Sending-data State + SdmmcCardStateRcvData = 6u, ///< Card state: Receive-data State + SdmmcCardStatePgm = 7u, ///< Card state: Programming State + SdmmcCardStateDis = 8u, ///< Card state: Disconnect State +} en_sdmmc_card_state_t; + +/** + ******************************************************************************* + ** \brief SD/eMMC/SDIO card capacity. + ** + ******************************************************************************/ +typedef enum sdmmc_capacity +{ + SdmmcStanderdCapacity = 0x00000000u, ///< Card capacity: Standard Capacity + SdmmcHighCapacity = 0x40000000u, ///< Card capacity: High Capacity +} sdmmc_capacity_t; + +/** + ******************************************************************************* + ** \brief SD/eMMC/SDIO card response data structure. + ** + ******************************************************************************/ +typedef struct stc_sdmmc_resp_card_status +{ + uint32_t RESERVE1 :3; ///< RESERVE + uint32_t AKE_SEQ_ERROR :1; ///< Error in the sequence of the authentication process + uint32_t RESERVE2 :1; ///< RESERVE + uint32_t APP_CMD :1; ///< The card will expect ACMD, or an indication that the command has been interpreted as ACMD + uint32_t RESERVE3 :2; ///< RESERVE + uint32_t READY_FOR_DATA :1; ///< Corresponds to buffer empty signaling on the bus + uint32_t CURRENT_STATE :4; ///< The state of the card when receiving the command. + + uint32_t ERASE_RESET :1; ///< An erase sequence was cleared before executing because an out of erase sequence command was received + uint32_t CARD_ECC_DISABLE :1; ///< The command has been executed without using the internal ECC. + uint32_t WP_ERASE_SKIP :1; ///< Set when only partial address space was erased due to existing write protected blocks or the temporary or permanent write protected card was erased. + uint32_t CSD_OVERWRITE :1; ///< - The read only section of the CSD does not match the card content. + ///< - An attempt to reverse the copy (set as original) or permanent WP (unprotected) bits was made. + uint32_t RESERVE4 :2; ///< RESERVE + uint32_t ERRORR :1; ///< A general or an unknown error occurred during the operation. + uint32_t CC_ERROR :1; ///< Internal card controller error + uint32_t CARD_ECC_FAIL :1; ///< Card internal ECC was applied but failed to correct the data. + uint32_t ILLEGAL_CMD :1; ///< Command not legal for the card state + uint32_t COM_CRC_ERROR :1; ///< The CRC check of the previous command failed. + uint32_t LOCK_UNLOCK_FAIL :1; ///< Set when a sequence or password error has been detected in lock/unlock card command. + uint32_t CARD_IS_LOCKED :1; ///< When set, signals that the card is locked by the host + uint32_t WP_VIOLATION :1; ///< Set when the host attempts to write to a protected block or to the temporary or permanent write protected card. + uint32_t ERASE_PARAM :1; ///< An invalid selection of write-blocks for erase occurred. + uint32_t ERASE_SEQ_ERR :1; ///< An error in the sequence of erase commands occurred. + uint32_t BLOCK_LEN_ERR :1; ///< The transferred block length is not allowed for this card, or the number of transferred bytes does not match the block length. + uint32_t ADDRESS_ERROR :1; ///< A misaligned address which did not match the block length was used in the command. + uint32_t OUT_OF_RANGE :1; ///< The command’s argument was out of the allowed range for this card. +} stc_sdmmc_resp_card_status_t; + +/******************************************************************************* + * Global pre-processor symbols/macros ('#define') + ******************************************************************************/ +/** + ******************************************************************************* + ** \brief SDMMC Commands Index + ** + ******************************************************************************/ +#define CMD0_GO_IDLE_STATE (0u) /*!< Resets the SD memory card. */ +#define CMD1_SEND_OP_COND (1u) /*!< Sends host capacity support information and activates the card's initialization process. */ +#define CMD2_ALL_SEND_CID (2u) /*!< Asks any card connected to the host to send the CID numbers on the CMD line. */ +#define CMD3_SEND_RELATIVE_ADDR (3u) /*!< Asks the card to publish a new relative address (RCA). */ +#define CMD_SET_DSR (4u) /*!< Programs the DSR of all cards. */ +#define CMD_SDMMC_SEN_OP_COND (5u) /*!< Sends host capacity support information (HCS) and asks the accessed card to send its + operating condition register (OCR) content in the response on the CMD line. */ +#define CMD6_SWITCH_FUNC (6u) /*!< Checks switchable function (mode 0) and switch card function (mode 1). */ +#define CMD7_SEL_DESEL_CARD (7u) /*!< Selects the card by its own relative address and gets deselected by any other address */ +#define CMD8_SEND_IF_COND (8u) /*!< Sends SD Memory Card interface condition, which includes host supply voltage information + and asks the card whether card supports voltage. */ +#define CMD9_SEND_CSD (9u) /*!< Addressed card sends its card specific data (CSD) on the CMD line. */ +#define CMD10_SEND_CID (10u) /*!< Addressed card sends its card identification (CID) on the CMD line. */ +#define CMD11_READ_DAT_UNTIL_STOP (11u) /*!< SD card doesn't support it. */ +#define CMD12_STOP_TRANSMISSION (12u) /*!< Forces the card to stop transmission. */ +#define CMD13_SEND_STATUS (13u) /*!< Addressed card sends its status register. */ +#define CMD14_HS_BUSTEST_READ (14u) /*!< Reserved */ +#define CMD15_GO_INACTIVE_STATE (15u) /*!< Sends an addressed card into the inactive state. */ +#define CMD16_SET_BLOCKLEN (16u) /*!< Sets the block length (in bytes for SDSC) for all following block commands + (read, write, lock). Default block length is fixed to 512 Bytes. Not effective + for SDHS and SDXC. */ +#define CMD17_READ_SINGLE_BLOCK (17u) /*!< Reads single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of + fixed 512 bytes in case of SDHC and SDXC. */ +#define CMD18_READ_MULTIPLE_BLOCK (18u) /*!< Continuously transfers data blocks from card to host until interrupted by + STOP_TRANSMISSION command. */ +#define CMD19_HS_BUSTEST_WRITE (19u) /*!< 64 bytes tuning pattern is sent for SDR50 and SDR104. */ +#define CMD20_WRITE_DAT_UNTIL_STOP (20u) /*!< Speed class control command. */ +#define CMD23_SET_BLOCK_COUNT (23u) /*!< Specify block count for CMD18 and CMD25. */ +#define CMD24_WRITE_SINGLE_BLOCK (24u) /*!< Writes single block of size selected by SET_BLOCKLEN in case of SDSC, and a block of + fixed 512 bytes in case of SDHC and SDXC. */ +#define CMD25_WRITE_MULTIPLE_BLOCK (25u) /*!< Continuously writes blocks of data until a STOP_TRANSMISSION follows. */ +#define CMD26_PROG_CID (26u) /*!< Reserved for manufacturers. */ +#define CMD27_PROG_CSD (27u) /*!< Programming of the programmable bits of the CSD. */ +#define CMD28_SET_WRITE_PROT (28u) /*!< Sets the write protection bit of the addressed group. */ +#define CMD29_CLR_WRITE_PROT (29u) /*!< Clears the write protection bit of the addressed group. */ +#define CMD30_SEND_WRITE_PROT (30u) /*!< Asks the card to send the status of the write protection bits. */ +#define CMD32_ERASE_WR_BLK_START (32u) /*!< Sets the address of the first write block to be erased. (For SD card only). */ +#define CMD33_ERASE_WR_BLK_END (33u) /*!< Sets the address of the last write block of the continuous range to be erased. */ +#define CMD35_ERASE_GRP_START (35u) /*!< Sets the address of the first write block to be erased. Reserved for each command + system set by switch function command (CMD6). */ +#define CMD36_ERASE_GRP_END (36u) /*!< Sets the address of the last write block of the continuous range to be erased. + Reserved for each command system set by switch function command (CMD6). */ +#define CMD38_ERASE (38u) /*!< Reserved for SD security applications. */ +#define CMD39_FAST_IO (39u) /*!< SD card doesn't support it (Reserved). */ +#define CMD40_GO_IRQ_STATE (40u) /*!< SD card doesn't support it (Reserved). */ +#define CMD42_LOCK_UNLOCK (42u) /*!< Sets/resets the password or lock/unlock the card. The size of the data block is set by + the SET_BLOCK_LEN command. */ +#define CMD55_APP_CMD (55u) /*!< Indicates to the card that the next command is an application specific command rather + than a standard command. */ +#define CMD56_GEN_CMD (56u) /*!< Used either to transfer a data block to the card or to get a data block from the card + for general purpose/application specific commands. */ +#define CMD64_NO_CMD (64u) /*!< No command */ + +/** + ******************************************************************************* + ** \brief SDMMC_APP_CMD Commands Index + ** + ******************************************************************************/ +#define ACMD6_APP_SD_SET_BUSWIDTH (6u) /*!< (ACMD6) Defines the data bus width to be used for data transfer. The allowed data bus + widths are given in SCR register. */ +#define ACMD13_SD_APP_STATUS (13u) /*!< (ACMD13) Sends the SD status. */ +#define ACMD22_SD_APP_SEND_NUM_WRITE_BLOCKS (22u) /*!< (ACMD22) Sends the number of the written (without errors) write blocks. Responds with + 32bit+CRC data block. */ +#define ACMD41_SD_SEND_OP_COND (41u) /*!< (ACMD41) Sends host capacity support information (HCS) and asks the accessed card to + send its operating condition register (OCR) content in the response on the CMD line. */ +#define ACMD42_SET_CLR_CARD_DETECT (42u) /*!< (ACMD42) Connect/Disconnect the 50 KOhm pull-up resistor on CD/DAT3 (pin 1) of the card */ +#define ACMD51_SD_APP_SEND_SCR (51u) /*!< Reads the SD Configuration Register (SCR). */ +#define ACMD52_RW_DIRECT (52u) /*!< For SD I/O card only, reserved for security specification. */ +#define ACMD53_RW_EXTENDED (53u) /*!< For SD I/O card only, reserved for security specification. */ + +/** + ******************************************************************************* + ** \brief SD Card Specific security commands Commands Index + ** + ******************************************************************************/ +#define ACMD43_GET_MKB (43u) +#define ACMD44_GET_MID (44u) +#define ACMD45_SET_CER_RN1 (45u) +#define ACMD46_GET_CER_RN2 (46u) +#define ACMD47_SET_CER_RES2 (47u) +#define ACMD48_GET_CER_RES1 (48u) +#define ACMD18_SECURE_READ_MULTIPLE_BLOCK (18u) +#define ACMD25_SECURE_WRITE_MULTIPLE_BLOCK (25u) +#define ACMD38_SECURE_ERASE (38u) +#define ACMD49_CHANGE_SECURE_AREA (49u) +#define ACMD48_SECURE_WRITE_MKB (48u) + +/** + ******************************************************************************* + ** \brief Media voltage supported. + ** + ******************************************************************************/ +#define SDMMC_SD_VOLT_1_7 (0x00000010ul) /* Low voltage card minimum */ +#define SDMMC_SD_VOLT_1_8 (0x00000020ul) +#define SDMMC_SD_VOLT_1_9 (0x00000040ul) +#define SDMMC_SD_VOLT_2_0 (0x00000080ul) +#define SDMMC_SD_VOLT_2_1 (0x00000100ul) /* Basic communication minimum */ +#define SDMMC_SD_VOLT_2_2 (0x00000200ul) +#define SDMMC_SD_VOLT_2_3 (0x00000400ul) +#define SDMMC_SD_VOLT_2_4 (0x00000800ul) +#define SDMMC_SD_VOLT_2_5 (0x00001000ul) +#define SDMMC_SD_VOLT_2_6 (0x00002000ul) +#define SDMMC_SD_VOLT_2_7 (0x00004000ul) +#define SDMMC_SD_VOLT_2_8 (0x00008000ul) /* Memory access minimum */ +#define SDMMC_SD_VOLT_2_9 (0x00010000ul) +#define SDMMC_SD_VOLT_3_0 (0x00020000ul) +#define SDMMC_SD_VOLT_3_1 (0x00040000ul) +#define SDMMC_SD_VOLT_3_2 (0x00080000ul) +#define SDMMC_SD_VOLT_3_3 (0x00100000ul) +#define SDMMC_SD_VOLT_3_4 (0x00200000ul) +#define SDMMC_SD_VOLT_3_5 (0x00400000ul) +#define SDMMC_SD_VOLT_3_6 (0x00800000ul) + + +#define SDMMC_ERROR_NONE (0x00000000ul) /*!< No error */ +#define SDMMC_ERROR_CMD_CRC_FAIL (0x00000001ul) /*!< Command response received (but CRC check failed) */ +#define SDMMC_ERROR_DATA_CRC_FAIL (0x00000002ul) /*!< Data block sent/received (CRC check failed) */ +#define SDMMC_ERROR_CMD_RSP_TIMEOUT (0x00000004ul) /*!< Command response timeout */ +#define SDMMC_ERROR_DATA_TIMEOUT (0x00000008ul) /*!< Data timeout */ +#define SDMMC_ERROR_TX_UNDERRUN (0x00000010ul) /*!< Transmit FIFO underrun */ +#define SDMMC_ERROR_RX_OVERRUN (0x00000020ul) /*!< Receive FIFO overrun */ +#define SDMMC_ERROR_ADDR_MISALIGNED (0x00000040ul) /*!< Misaligned address */ +#define SDMMC_ERROR_BLOCK_LEN_ERR (0x00000080ul) /*!< Transferred block length is not allowed for the card or the + number of transferred bytes does not match the block length */ +#define SDMMC_ERROR_ERASE_SEQ_ERR (0x00000100ul) /*!< An error in the sequence of erase command occurs */ +#define SDMMC_ERROR_BAD_ERASE_PARAM (0x00000200ul) /*!< An invalid selection for erase groups */ +#define SDMMC_ERROR_WRITE_PROT_VIOLATION (0x00000400ul) /*!< Attempt to program a write protect block */ +#define SDMMC_ERROR_LOCK_UNLOCK_FAILED (0x00000800ul) /*!< Sequence or password error has been detected in unlock + command or if there was an attempt to access a locked card */ +#define SDMMC_ERROR_COM_CRC_FAILED (0x00001000ul) /*!< CRC check of the previous command failed */ +#define SDMMC_ERROR_ILLEGAL_CMD (0x00002000ul) /*!< Command is not legal for the card state */ +#define SDMMC_ERROR_CARD_ECC_FAILED (0x00004000ul) /*!< Card internal ECC was applied but failed to correct the data */ +#define SDMMC_ERROR_CC_ERR (0x00008000ul) /*!< Internal card controller error */ +#define SDMMC_ERROR_GENERAL_UNKNOWN_ERR (0x00010000ul) /*!< General or unknown error */ +#define SDMMC_ERROR_STREAM_READ_UNDERRUN (0x00020000ul) /*!< The card could not sustain data reading in stream rmode */ +#define SDMMC_ERROR_STREAM_WRITE_OVERRUN (0x00040000ul) /*!< The card could not sustain data programming in stream mode */ +#define SDMMC_ERROR_CID_CSD_OVERWRITE (0x00080000ul) /*!< CID/CSD overwrite error */ +#define SDMMC_ERROR_WP_ERASE_SKIP (0x00100000ul) /*!< Only partial address space was erased */ +#define SDMMC_ERROR_CARD_ECC_DISABLED (0x00200000ul) /*!< Command has been executed without using internal ECC */ +#define SDMMC_ERROR_ERASE_RESET (0x00400000ul) /*!< Erase sequence was cleared before executing because an out + of erase sequence command was received */ +#define SDMMC_ERROR_AKE_SEQ_ERR (0x00800000ul) /*!< Error in sequence of authentication */ +#define SDMMC_ERROR_INVALID_VOLTRANGE (0x01000000ul) /*!< Error in case of invalid voltage range */ +#define SDMMC_ERROR_ADDR_OUT_OF_RANGE (0x02000000ul) /*!< Error when addressed block is out of range */ +#define SDMMC_ERROR_REQUEST_NOT_APPLICABLE (0x04000000ul) /*!< Error when command request is not applicable */ +#define SDMMC_ERROR_INVALID_PARAMETER (0x08000000ul) /*!< the used parameter is not valid */ +#define SDMMC_ERROR_UNSUPPORTED_FEATURE (0x10000000ul) /*!< Error when feature is not insupported */ +#define SDMMC_ERROR_BUSY (0x20000000ul) /*!< Error when transfer process is busy */ +#define SDMMC_ERROR_DMA (0x40000000ul) /*!< Error while DMA transfer */ +#define SDMMC_ERROR_TIMEOUT (0x80000000ul) /*!< Timeout error */ + +/******************************************************************************* + * Global variable definitions ('extern') + ******************************************************************************/ + +/******************************************************************************* + * Global function prototypes (definition in C source) + ******************************************************************************/ +en_result_t SDMMC_Cmd0_GoIdleState(M4_SDIOC_TypeDef *SDIOCx); +en_result_t SDMMC_Cmd1_SendOpCond(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Argument, uint32_t *pu32OCR); +en_result_t SDMMC_Cmd2_AllSendCID(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32CID[4]); +en_result_t SDMMC_Cmd3_SendRelativeAddr(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32RCA); +en_result_t SDMMC_Cmd6_SwitchFunc(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Argument, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd7_SelectDeselectCard(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd8_SendIfCond(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32IfCond); +en_result_t SDMMC_Cmd9_SendCSD(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t u32CSD[4]); +en_result_t SDMMC_Cmd10_SendCID(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t u32CID[4]); +en_result_t SDMMC_Cmd12_StopTransmission(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd13_SendStatus(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32RCA, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd16_SetBlockLength(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32BlockLen, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd17_ReadSingleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32ReadAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd18_ReadMultipleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32ReadAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd24_WriteSingleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32WriteAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd25_WriteMultipleBlock(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32WriteAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd32_EraseWrBlkStart(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32StartAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd33_EraseWrBlkEnd(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32EndAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd35_SetEraseStartAddr(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32StartAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd36_SetEraseEndAddr(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32EndAddr, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd38_Erase(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1); +en_result_t SDMMC_Cmd55_AppCmd(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32Argument, uint32_t *pu32Resp1); +en_result_t SDMMC_Acmd6_SetBusWidth(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32BusWidth, uint32_t *pu32Resp1); +en_result_t SDMMC_Acmd13_SdStatus(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1); +en_result_t SDMMC_Acmd41_SdSendOpCond(M4_SDIOC_TypeDef *SDIOCx, uint32_t u32SdType, uint32_t *pu32OCR); +en_result_t SDMMC_Acmd51_SendSCR(M4_SDIOC_TypeDef *SDIOCx, uint32_t *pu32Resp1); + +//@} // SdiocGroup + +#ifdef __cplusplus +} +#endif + +#endif /* __SDMMC_CMD_H__ */ + +/******************************************************************************* + * EOF (not truncated) + ******************************************************************************/ diff --git a/sdmmc_cmd_1.c b/sdmmc_cmd_1.c new file mode 100644 index 0000000..6b0d673 --- /dev/null +++ b/sdmmc_cmd_1.c @@ -0,0 +1,1641 @@ +/******************************************************************************* + * 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) + ******************************************************************************/