📄 mci.c
字号:
DWORD MCI_GetCmdResp( DWORD ExpectCmdData, DWORD ExpectResp, DWORD *CmdResp )
{
DWORD CmdRespStatus = 0;
DWORD LastCmdIndex;
if ( ExpectResp == EXPECT_NO_RESP )
{
return ( 0 );
}
while ( 1 )
{
CmdRespStatus = MCI_STATUS;
if ( CmdRespStatus & (MCI_CMD_TIMEOUT) )
{
MCI_CLEAR = CmdRespStatus | MCI_CMD_TIMEOUT;
MCI_COMMAND = 0;
MCI_ARGUMENT = 0xFFFFFFFF;
return ( CmdRespStatus );
}
if ( CmdRespStatus & MCI_CMD_CRC_FAIL )
{
MCI_CLEAR = CmdRespStatus | MCI_CMD_CRC_FAIL;
LastCmdIndex = MCI_COMMAND & 0x003F;
if ( (LastCmdIndex == SEND_OP_COND) || (LastCmdIndex == SEND_APP_OP_COND)
|| (LastCmdIndex == STOP_TRANSMISSION) )
{
MCI_COMMAND = 0;
MCI_ARGUMENT = 0xFFFFFFFF;
break; /* ignore CRC error if it's a resp for SEND_OP_COND
or STOP_TRANSMISSION. */
}
else
{
return ( CmdRespStatus );
}
}
else if ( CmdRespStatus & MCI_CMD_RESP_END )
{
MCI_CLEAR = CmdRespStatus | MCI_CMD_RESP_END;
break; /* cmd response is received, expecting response */
}
}
if ( (MCI_RESP_CMD & 0x3F) != ExpectCmdData )
{
/* If the response is not R1, in the response field, the Expected Cmd data
won't be the same as the CMD data in SendCmd(). Below four cmds have
R2 or R3 response. We don't need to check if MCI_RESP_CMD is the same
as the Expected or not. */
if ( (ExpectCmdData != SEND_OP_COND) && (ExpectCmdData != SEND_APP_OP_COND)
&& (ExpectCmdData != ALL_SEND_CID) && (ExpectCmdData != SEND_CSD) )
{
CmdRespStatus = INVALID_RESPONSE; /* Reuse error status */
return ( INVALID_RESPONSE );
}
}
if ( ExpectResp == EXPECT_SHORT_RESP )
{
*CmdResp = MCI_RESP0;
}
else if ( ExpectResp == EXPECT_LONG_RESP )
{
*CmdResp = MCI_RESP0;
*(CmdResp+1) = MCI_RESP1;
*(CmdResp+2) = MCI_RESP2;
*(CmdResp+3) = MCI_RESP3;
}
return ( 0 ); /* Read MCI_RESP0 register assuming it's not long response. */
}
/******************************************************************************
** Function name: MCI_Go_Idle_State
**
** Descriptions: CMD0, the very first command to be sent to initialize
** either MMC or SD card.
**
** parameters: None
** Returned value: true or false, true if card has been initialized.
**
******************************************************************************/
DWORD MCI_Go_Idle_State( void )
{
DWORD retryCount;
DWORD respStatus;
DWORD respValue[4];
retryCount = 0x20;
while ( retryCount > 0 )
{
/* Send CMD0 command repeatedly until the response is back correctly */
MCI_SendCmd( GO_IDLE_STATE, 0x00000000, EXPECT_NO_RESP, 0 );
respStatus = MCI_GetCmdResp( GO_IDLE_STATE, EXPECT_NO_RESP, (DWORD *)respValue );
if ( respStatus == 0 )
{
break;
}
retryCount--;
}
if ( respStatus != 0 ) /* timeout, give up */
{
return ( FALSE );
}
return( TRUE );
}
/******************************************************************************
** Function name: MCI_Send_OP_Cond
**
** Descriptions: CMD1 for MMC
**
** parameters: None
** Returned value: true or false, true if card has response back before
** timeout, false is timeout on the command.
**
******************************************************************************/
DWORD MCI_Send_OP_Cond( void )
{
DWORD i, retryCount;
DWORD respStatus;
DWORD respValue[4];
retryCount = 0x200; /* reset retry counter */
while ( retryCount > 0 )
{
/* Send CMD1 command repeatedly until the response is back correctly */
MCI_SendCmd( SEND_OP_COND, OCR_INDEX, EXPECT_SHORT_RESP, 0 );
respStatus = MCI_GetCmdResp( SEND_OP_COND, EXPECT_SHORT_RESP, (DWORD *)&respValue[0] );
/* bit 0 and bit 2 must be zero, or it's timeout or CRC error */
if ( !(respStatus & MCI_CMD_TIMEOUT) && (respValue[0] & 0x80000000) )
{
return ( TRUE ); /* response is back and correct. */
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return( FALSE );
}
/******************************************************************************
** Function name: MCI_Send_ACMD
**
** Descriptions: CMD55, before sending an ACMD, call this routine first
**
** parameters: None
** Returned value: true or false, true if card has responded before timeout.
** false is timeout.
**
******************************************************************************/
DWORD MCI_Send_ACMD( void )
{
DWORD i, retryCount;
DWORD CmdArgument;
DWORD respStatus;
DWORD respValue[4];
if ( MCI_CardType == SD_CARD )
{
CmdArgument = CardRCA; /* Use the address from SET_RELATIVE_ADDR cmd */
}
else /* if MMC or unknown card type, use 0x0. */
{
CmdArgument = 0x00000000;
}
retryCount = 20;
while ( retryCount > 0 )
{
/* Send CMD55 command followed by an ACMD */
MCI_SendCmd( APP_CMD, CmdArgument, EXPECT_SHORT_RESP, 0 );
respStatus = MCI_GetCmdResp( APP_CMD, EXPECT_SHORT_RESP, (DWORD *)&respValue[0] );
if ( !respStatus && (respValue[0] & CARD_STATUS_ACMD_ENABLE) ) /* Check if APP_CMD enabled */
{
return( TRUE );
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return( FALSE );
}
/******************************************************************************
** Function name: MCI_Send_ACMD_OP_Cond
**
** Descriptions: If Send_OP_Cond is timeout, it's not a MMC card, try
** this combination to see if we can communicate with
** a SD card.
**
** parameters: None
** Returned value: true or false, true if card has been initialized.
**
******************************************************************************/
DWORD MCI_Send_ACMD_OP_Cond( void )
{
DWORD i, retryCount;
DWORD respStatus;
DWORD respValue[4];
/* timeout on SEND_OP_COND command on MMC, now, try SEND_APP_OP_COND
command to SD */
retryCount = 0x200; /* reset retry counter */
while ( retryCount > 0 )
{
MCI_POWER &= ~(1 << 6 ); /* Clear Open Drain output control for SD */
for ( i = 0; i < 0x3000; i++ );
if ( MCI_Send_ACMD() == FALSE )
{
continue;
}
/* Send ACMD41 command repeatedly until the response is back correctly */
MCI_SendCmd( SEND_APP_OP_COND, OCR_INDEX, EXPECT_SHORT_RESP, 0 );
respStatus = MCI_GetCmdResp( SEND_APP_OP_COND, EXPECT_SHORT_RESP, (DWORD *)&respValue[0] );
if ( !(respStatus & MCI_CMD_TIMEOUT) && (respValue[0] & 0x80000000) )
{
return ( TRUE ); /* response is back and correct. */
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return( FALSE );
}
/******************************************************************************
** Function name: MCI_CardInit
**
** Descriptions: 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.
**
** parameters: None
** Returned value: Card type.
**
******************************************************************************/
DWORD MCI_CardInit( void )
{
DWORD i, CardType;
if ( MCI_Go_Idle_State() == FALSE )
{
return( CARD_UNKNOWN );
}
MCI_POWER |= (1 << 6 ); /* Set Open Drain output control for MMC */
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 faliure, bailout. */
if ( MCI_Send_OP_Cond() == TRUE )
{
CardType = MMC_CARD;
return ( CardType ); /* Found the card, it's a MMC */
}
else if ( MCI_Send_ACMD_OP_Cond() == TRUE )
{
CardType = SD_CARD;
return ( CardType ); /* Found the card, it's a SD */
}
/* tried both MMC and SD card, give up */
return ( CARD_UNKNOWN );
}
/******************************************************************************
** Function name: MCI_Check_CID
**
** Descriptions: Send CMD2, ALL_SEND_CID
**
** parameters: None
** Returned value: If not timeout, return true.
**
******************************************************************************/
DWORD MCI_Check_CID( void )
{
DWORD i, retryCount;
DWORD respStatus;
DWORD respValue[4];
/* This command is normally after CMD1(MMC) or ACMD41(SD). */
retryCount = 0x20; /* reset retry counter */
while ( retryCount > 0 )
{
/* Send CMD2 command repeatedly until the response is back correctly */
MCI_SendCmd( ALL_SEND_CID, 0, EXPECT_LONG_RESP, 0 );
respStatus = MCI_GetCmdResp( ALL_SEND_CID, EXPECT_LONG_RESP, (DWORD *)&respValue[0] );
/* bit 0 and bit 2 must be zero, or it's timeout or CRC error */
if ( !(respStatus & MCI_CMD_TIMEOUT) )
{
return ( TRUE ); /* response is back and correct. */
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return ( FALSE );
}
/******************************************************************************
** Function name: MCI_Set_Address
**
** Descriptions: Send CMD3, STE_RELATIVE_ADDR, should after CMD2
**
** parameters: None
** Returned value: TRUE if response is back before timeout.
**
******************************************************************************/
DWORD MCI_Set_Address( void )
{
DWORD i, retryCount;
DWORD respStatus;
DWORD respValue[4];
DWORD CmdArgument;
/* 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 == SD_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 */
MCI_SendCmd( SET_RELATIVE_ADDR, CmdArgument, EXPECT_SHORT_RESP, 0 );
respStatus = MCI_GetCmdResp( SET_RELATIVE_ADDR, EXPECT_SHORT_RESP, (DWORD *)&respValue[0] );
/* bit 0 and bit 2 must be zero, or it's timeout or CRC error */
/* It should go to IDEN state and bit 8 should be 1 */
if ( !(respStatus & MCI_CMD_TIMEOUT) && ((respValue[0] & (0x0F << 8)) == 0x0500) )
{
CardRCA = respValue[0] & 0xFFFF0000; /* Save the RCA value from SD card */
return ( TRUE ); /* response is back and correct. */
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return ( FALSE );
}
/******************************************************************************
** Function name: MCI_Send_CSD
**
** Descriptions: CMD9, SEND_CSD cmd, it should be sent only at
** STBY state and after CMD3. See MMC and SD spec. state
** diagram.
**
** parameters: None
** Returned value: Response value
**
******************************************************************************/
DWORD MCI_Send_CSD( void )
{
DWORD i, retryCount;
DWORD respStatus;
DWORD respValue[4];
DWORD CmdArgument;
if ( MCI_CardType == SD_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 */
MCI_CLEAR |= (MCI_CMD_TIMEOUT | MCI_CMD_CRC_FAIL | MCI_CMD_RESP_END);
MCI_SendCmd( SEND_CSD, CmdArgument, EXPECT_LONG_RESP, 0 );
respStatus = MCI_GetCmdResp( SEND_CSD, EXPECT_LONG_RESP, (DWORD *)&respValue[0] );
if ( !respStatus )
{
return ( TRUE );
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -