1642 lines
62 KiB
C
1642 lines
62 KiB
C
/*******************************************************************************
|
|
* 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)
|
|
******************************************************************************/
|