📄 lpc177x_8x_mci.c
字号:
* @brief Do initialization for the card in the slot
*
* @details Try CMD1 first for MMC, if it's timeout, try CMD55
* and CMD41 for SD, if both failed, initialization faliure,
* bailout with unknown card type. Otherwise, return the
* card type, either MMC or SD. <<<KHOA_110708: checking>>>
*
* This is followed Figure 4-2: Card Initialization and
* Identification Flow (SD mode) in Physical Layer Simplified
* Specification Version 2.00 document
*
* @param None
*
* @return MCI_FUNC_OK if success
****************************************************************************/
int32_t MCI_CardInit( void )
{
uint32_t i;
int32_t retval = MCI_FUNC_FAILED;
MCI_CardType = MCI_CARD_UNKNOWN;
if (MCI_CardReset() != MCI_FUNC_OK)
{
return MCI_FUNC_FAILED;
}
/* Clear Open Drain output control for SD */
MCI_SetOutputMode(MCI_OUTPUT_MODE_PUSHPULL);
for ( i = 0; i < 0x3000; i++ );
retval = MCI_Cmd_SendIfCond();
if(retval == MCI_FUNC_BAD_PARAMETERS)
{
//Unknow card is unusable
return retval;
}
if(retval == MCI_FUNC_OK) /* Ver2.00 or later*/
{
//Check in case of High Capacity Supporting Host
if ((retval = MCI_Acmd_SendOpCond(1)) == MCI_FUNC_OK)
{
MCI_CardType = MCI_SDSC_V2_CARD;//SDSC
if(CCS )
{
MCI_CardType = MCI_SDHC_SDXC_CARD;//SDHC or SDXC
}
return MCI_FUNC_OK; /* Found the card, it's a hD */
}
}
if(retval != MCI_FUNC_OK) /* voltage mismatch (ver2.00)or ver1.X SD Card or not SD Card*/
{
//Check in case of Standard Capacity Supporting Host
if ((retval = MCI_Acmd_SendOpCond(0)) == MCI_FUNC_OK)
{
MCI_CardType = MCI_SDSC_V1_CARD;//Support Standard Capacity only
return MCI_FUNC_OK; /* Found the card, it's a SD */
}
}
if(retval != MCI_FUNC_OK)
{
/* Set Open Drain output control for MMC */
MCI_SetOutputMode(MCI_OUTPUT_MODE_OPENDRAIN);
for ( i = 0; i < 0x3000; i++ );
/* Try CMD1 first for MMC, if it's timeout, try CMD55 and CMD41 for SD,
if both failed, initialization faIlure, bailout. */
if (MCI_Cmd_SendOpCond() == MCI_FUNC_OK)
{
MCI_CardType = MCI_MMC_CARD;
return MCI_FUNC_OK; /* Found the card, it's a MMC */
}
}
/* tried both MMC and SD card, give up */
return MCI_FUNC_OK;
}
/************************************************************************//**
* @brief Get the type of card that is currently used in the slot
*
* @param None
*
* @return Card Type: MMC Card or SD card
****************************************************************************/
en_Mci_CardType MCI_GetCardType(void)
{
return MCI_CardType;
}
/************************************************************************//**
* @brief Get the all the Identifier (CID) of the card by sending the
* CMD2 (ALL_SEND_CID) command. Then parse 4-byte data obtained
* from the card by the CID meaning.
*
* @param[out] cidValue the CID Result after parsing the data from the card
*
* @return MCI_FUNC_OK if all success
****************************************************************************/
int32_t MCI_GetCID(st_Mci_CardId* cidValue)
{
uint32_t i, retryCount;
uint32_t respStatus;
uint32_t respValue[4];
/* This command is normally after CMD1(MMC) or ACMD41(SD). */
retryCount = 0x200;// 0x20; /* reset retry counter */
while ( retryCount > 0 )
{
#if 1
respStatus = MCI_CmdResp(CMD2_ALL_SEND_CID, 0, EXPECT_LONG_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
/* bit 0 and bit 2 must be zero, or it's timeout or CRC error */
//if ((!(respStatus & MCI_CMD_TIMEOUT)) && (!(respStatus & MCI_CMD_CRC_FAIL)))
if (!(respStatus & MCI_CMD_TIMEOUT))
{
// Parsing the data retrieved
if(cidValue != NULL)
{
cidValue->MID = (respValue[0] >> MCI_CID_MANUFACTURER_ID_WPOS) & MCI_CID_MANUFACTURER_ID_WBMASK;
cidValue->OID = (respValue[0] >> MCI_CID_OEMAPPLICATION_ID_WPOS) & MCI_CID_OEMAPPLICATION_ID_WBMASK;
cidValue->PNM_H = (respValue[0] >> MCI_CID_PRODUCTNAME_ID_H_WPOS) & MCI_CID_PRODUCTNAME_ID_H_WBMASK;
cidValue->PNM_L = (respValue[1] >> MCI_CID_PRODUCTNAME_ID_L_WPOS) & MCI_CID_PRODUCTNAME_ID_L_WBMASK;
cidValue->PRV = (respValue[2] >> MCI_CID_PRODUCTREVISION_ID_WPOS) & MCI_CID_PRODUCTREVISION_ID_WBMASK;
cidValue->PSN = (((respValue[2] >> MCI_CID_PRODUCTSERIALNUM_ID_H_WPOS) & MCI_CID_PRODUCTSERIALNUM_ID_H_WBMASK) << 8)
| ((respValue[3] >> MCI_CID_PRODUCTSERIALNUM_ID_L_WPOS) & MCI_CID_PRODUCTSERIALNUM_ID_L_WBMASK);
cidValue->reserved = (respValue[3] >> MCI_CID_RESERVED_ID_WPOS) & MCI_CID_RESERVED_ID_WBMASK;
cidValue->MDT = (respValue[3] >> MCI_CID_MANUFACTURINGDATE_ID_WPOS) & MCI_CID_MANUFACTURINGDATE_ID_WBMASK;
cidValue->CRC = (respValue[3] >> MCI_CID_CHECKSUM_ID_WPOS) & MCI_CID_CHECKSUM_ID_WBMASK;
cidValue->unused = (respValue[3] >> MCI_CID_UNUSED_ID_WPOS) & MCI_CID_UNUSED_ID_WBMASK;
}
return MCI_FUNC_OK; /* response is back and correct. */
}
#else
respCmdValue[0] = 0x00000000;
respCmdValue[1] = 0x00000000;
respCmdValue[2] = 0x00000000;
respCmdValue[3] = 0x00000000;
respStatus = MCI_CmdResp(CMD2_ALL_SEND_CID, 0, EXPECT_LONG_RESP, (uint32_t *)&respCmdValue[0], ALLOW_CMD_TIMER);
/* bit 0 and bit 2 must be zero, or it's timeout or CRC error */
if (!(respStatus & MCI_CMD_TIMEOUT))
{
// Parsing the data retrieved
if(cidValue != NULL)
{
cidValue->MID = (respCmdValue[0] >> MCI_CID_MANUFACTURER_ID_WPOS) & MCI_CID_MANUFACTURER_ID_WBMASK;
cidValue->OID = (respCmdValue[0] >> MCI_CID_OEMAPPLICATION_ID_WPOS) & MCI_CID_OEMAPPLICATION_ID_WBMASK;
cidValue->PNM_H = (respCmdValue[0] >> MCI_CID_PRODUCTNAME_ID_H_WPOS) & MCI_CID_PRODUCTNAME_ID_H_WBMASK;
cidValue->PNM_L = (respCmdValue[1] >> MCI_CID_PRODUCTNAME_ID_L_WPOS) & MCI_CID_PRODUCTNAME_ID_L_WBMASK;
cidValue->PRV = (respCmdValue[2] >> MCI_CID_PRODUCTREVISION_ID_WPOS) & MCI_CID_PRODUCTREVISION_ID_WBMASK;
cidValue->PSN = (((respCmdValue[2] >> MCI_CID_PRODUCTSERIALNUM_ID_H_WPOS) & MCI_CID_PRODUCTSERIALNUM_ID_H_WBMASK) << 8)
| (respCmdValue[3] >> MCI_CID_PRODUCTSERIALNUM_ID_L_WPOS) & MCI_CID_PRODUCTSERIALNUM_ID_L_WBMASK;
cidValue->reserved = (respCmdValue[3] >> MCI_CID_RESERVED_ID_WPOS) & MCI_CID_RESERVED_ID_WBMASK;
cidValue->MDT = (respCmdValue[3] >> MCI_CID_MANUFACTURINGDATE_ID_WPOS) & MCI_CID_MANUFACTURINGDATE_ID_WBMASK;
cidValue->CRC = (respCmdValue[3] >> MCI_CID_CHECKSUM_ID_WPOS) & MCI_CID_CHECKSUM_ID_WBMASK;
cidValue->unused = (respCmdValue[3] >> MCI_CID_UNUSED_ID_WPOS) & MCI_CID_UNUSED_ID_WBMASK;
}
return MCI_FUNC_OK; /* response is back and correct. */
}
#endif
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return MCI_FUNC_TIMEOUT;
}
/************************************************************************//**
* @brief Set the address for the card in the slot by sending CMD3
* (SET_RELATIVE_ADDR) command. To get the address of the card
* currently in used, needs to call MCI_GetCardAddress()
*
* @param None
*
* @return MCI_FUNC_OK if all success
****************************************************************************/
int32_t MCI_SetCardAddress( void )
{
uint32_t i, retryCount;
uint32_t respStatus;
uint32_t respValue;
uint32_t CmdArgument;
int32_t retval = MCI_FUNC_FAILED;
/* If it's a SD card, SET_RELATIVE_ADDR is to get the address
from the card and use this value in RCA, if it's a MMC, set default
RCA addr. 0x00010000. */
if ((MCI_CardType == MCI_SDSC_V1_CARD) ||
(MCI_CardType == MCI_SDSC_V2_CARD) ||
(MCI_CardType == MCI_SDHC_SDXC_CARD))
{
CmdArgument = 0;
}
else /* If it's unknown or MMC_CARD, fix the RCA address */
{
CmdArgument = 0x00010000;
}
retryCount = 0x20; /* reset retry counter */
while ( retryCount > 0 )
{
/* Send CMD3 command repeatedly until the response is back correctly */
respStatus = MCI_CmdResp(CMD3_SET_RELATIVE_ADDR, CmdArgument, EXPECT_SHORT_RESP, &respValue, ALLOW_CMD_TIMER);
if(respStatus & MCI_CMD_TIMEOUT)
{
retval = MCI_FUNC_TIMEOUT;
}
else if(!(XSHIFT_(respValue, MCI_CARDSTATUS_READYFORDATA_P0S) & 0x01))
{
retval = MCI_FUNC_NOT_READY;
}
else if((CARDSTATEOF(respValue) != MCI_CARDSTATE_IDENDTIFIED))
{
retval = MCI_FUNC_ERR_STATE;
}
else
{
CardRCA = respValue & 0xFFFF0000; /* Save the RCA value from SD card */
return (MCI_FUNC_OK); /* response is back and correct. */
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return retval;
}
/************************************************************************//**
* @brief Get the address for the card in the slot
*
* @param None
*
* @return MCI_FUNC_OK if all success
*
* @note This function must be called after MCI_SetCardAddress() executing
****************************************************************************/
uint32_t MCI_GetCardAddress(void)
{
return CardRCA;
}
/************************************************************************//**
* @brief Get the Card-Specific Data of in-slot card by sending CMD9
* (SEND_CSD) command
*
* @param[out] csdVal a buffer stored the value of CSD obtained from the card
*
* @return MCI_FUNC_OK if all success
*
* @note CMD9 (SEND_CSD) command should be sent only at standby state
* (STBY) after CMD3
****************************************************************************/
int32_t MCI_GetCSD(uint32_t* csdVal)
{
uint32_t i, retryCount;
uint32_t respStatus;
uint32_t respValue[4];
uint32_t CmdArgument;
if ((MCI_CardType == MCI_SDSC_V1_CARD) ||
(MCI_CardType == MCI_SDSC_V2_CARD) ||
(MCI_CardType == MCI_SDHC_SDXC_CARD))
{
CmdArgument = CardRCA;
}
else /* if MMC or unknown card type, use default RCA addr. */
{
CmdArgument = 0x00010000;
}
retryCount = 0x20;
while ( retryCount > 0 )
{
/* Send SET_BLOCK_LEN command before read and write */
LPC_MCI->CLEAR |= (MCI_CMD_TIMEOUT | MCI_CMD_CRC_FAIL | MCI_CMD_RESP_END);
respStatus = MCI_CmdResp(CMD9_SEND_CSD, CmdArgument, EXPECT_LONG_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
if ( !respStatus )
{
if(csdVal != NULL)
{
csdVal[0] = respValue[0];
csdVal[1] = respValue[1];
csdVal[2] = respValue[2];
csdVal[3] = respValue[3];
}
return (MCI_FUNC_OK);
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return (MCI_FUNC_FAILED);
}
/************************************************************************//**
* @brief Select the card by the specified address. This is done by sending
* out the CMD7 with the address argument to needed card
*
* @param None
*
* @return MCI_FUNC_OK if all success
*
* @note CMD7 (SELECT_CARD) command should be sent after CMD9 ((SEND_CSD).
* The state will be inter-changed between STBY to TRANS by this
* CMD7 command
****************************************************************************/
int32_t MCI_Cmd_SelectCard( void )
{
uint32_t i, retryCount;
uint32_t respStatus;
uint32_t respValue[4];
uint32_t CmdArgument;
int32_t retval = MCI_FUNC_FAILED;
if ((MCI_CardType == MCI_SDSC_V1_CARD) ||
(MCI_CardType == MCI_SDSC_V2_CARD) ||
(MCI_CardType == MCI_SDHC_SDXC_CARD))
{
CmdArgument = CardRCA;
}
else /* if MMC or unknown card type, use default RCA addr. */
{
CmdArgument = 0x00010000;
}
retryCount = 0x20;
while ( retryCount > 0 )
{
/* Send CMD7_SELECT_CARD command before read and write */
LPC_MCI->CLEAR |= (MCI_CMD_TIMEOUT | MCI_CMD_CRC_FAIL | MCI_CMD_RESP_END);
respStatus = MCI_CmdResp(CMD7_SELECT_CARD, CmdArgument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
if(respStatus)
{
retval = MCI_FUNC_FAILED;
}
else if(!(respValue[0] & _SHIFT(MCI_CARDSTATUS_READYFORDATA_P0S)))
{
retval = MCI_FUNC_NOT_READY;
}
else if(CARDSTATEOF(respValue[0]) != MCI_CARDSTATE_STBY)
{
/* Should be in STANDBY state now and ready */
retval = MCI_FUNC_ERR_STATE;
}
else
{
return MCI_FUNC_OK;
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return retval;
}
/************************************************************************//**
* @brief Get the status of the card. The return is from the card.
* By sending CMD13 (SEND_STATUS), the status of the card
* will be responded from card addressed
*
* @param[out] cardStatus the status returned from the card
*
* @return MCI_FUNC_OK if all success
****************************************************************************/
int32_t MCI_GetCardStatus(int32_t* cardStatus)
{
uint32_t i;
uint32_t retryCount;
uint32_t respStatus;
uint32_t respValue[4];
uint32_t CmdArgument;
int32_t retval = MCI_FUNC_FAILED;
if ((MCI_CardType == MCI_SDSC_V1_CARD) ||
(MCI_CardType == MCI_SDSC_V2_CARD) ||
(MCI_CardType == MCI_SDHC_SDXC_CARD))
{
CmdArgument = CardRCA;
}
else /* if MMC or unknown card type, use default RCA addr. */
{
CmdArgument = 0x00010000;
}
/* Note that, since it's called after the block write and read, this timeout
is important based on the clock you set for the data communication. */
retryCount = 0x20;
while ( retryCount > 0 )
{
/* Send SELECT_CARD command before read and write */
LPC_MCI->CLEAR |= (MCI_CMD_TIMEOUT | MCI_CMD_CRC_FAIL | MCI_CMD_RESP_END);
respStatus = MCI_CmdResp(CMD13_SEND_STATUS, CmdArgument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
if(respStatus)
{
retval = MCI_FUNC_FAILED;
}
else if(!(respValue[0] & _SHIFT(MCI_CARDSTATUS_READYFORDATA_P0S)))
{
retval = MCI_FUNC_NOT_READY;
}
else
{
/* The ready bit should be set, it should be in either TRAN or RCV state now */
if(cardStatus != NULL)
{
*cardStatus = respValue[0];
}
return MCI_FUNC_OK;
}
retryCount--;
for ( i = 0; i < 0x10; i++ );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -