📄 lpc177x_8x_mci.c
字号:
before WRITE_BLOCK only TX related data interrupts are enabled, and before
READ_BLOCK only RX related data interrupts are enabled. */
return MCI_FUNC_OK;
}
/************************************************************************//**
* @brief Set output in open drain mode or pushpull mode
*
* @param[in] mode the mode going to set
*
* @return None
***************************************************************************/
void MCI_SetOutputMode(uint32_t mode)
{
if(mode == MCI_OUTPUT_MODE_OPENDRAIN)
{
/* Set Open Drain output control for MMC */
LPC_MCI->POWER |= (1 << MCI_PWRCTRL_OPENDRAIN_POS) & MCI_PWRCTRL_BMASK;
}
else
{
/* Clear Open Drain output control for SD */
LPC_MCI->POWER &= (~(1 << MCI_PWRCTRL_OPENDRAIN_POS) & MCI_PWRCTRL_BMASK);
}
}
/************************************************************************//**
* @brief The routine is used to send a CMD to the card
*
* @param[in] CmdIndex the command to be sent to cards
*
* @param[in] Argument the argument follows the command
*
* @param[in] ExpectResp the response type for the command. They may be:
* - EXPECT_NO_RESP: means no response required
* - EXPECT_SHORT_RESP: means a response in a word needed
* - EXPECT_LONG_RESP: means a response in 4 words needed
*
* @param[in] AllowTimeout allow timeout the command or not
*
* @return None
***************************************************************************/
void MCI_SendCmd(uint32_t CmdIndex, uint32_t Argument, uint32_t ExpectResp, uint32_t AllowTimeout)
{
uint32_t i, CmdData = 0;
uint32_t CmdStatus;
/* the command engine must be disabled when we modify the argument
or the peripheral resends */
while ( (CmdStatus = LPC_MCI->STATUS) & MCI_CMD_ACTIVE ) /* Command in progress. */
{
LPC_MCI->COMMAND = 0;
LPC_MCI->CLEAR = CmdStatus | MCI_CMD_ACTIVE;
}
for ( i = 0; i < 0x100; i++ );
/*set the command details, the CmdIndex should 0 through 0x3F only */
CmdData |= (CmdIndex & 0x3F); /* bit 0 through 5 only */
if ( ExpectResp == EXPECT_NO_RESP ) /* no response */
{
CmdData &= ~((1 << 6) | (1 << 7)); /* Clear long response bit as well */
}
else if ( ExpectResp == EXPECT_SHORT_RESP ) /* expect short response */
{
CmdData |= (1 << 6);
}
else if ( ExpectResp == EXPECT_LONG_RESP ) /* expect long response */
{
CmdData |= (1 << 6) | (1 << 7);
}
if ( AllowTimeout == ALLOW_CMD_TIMER ) /* allow timeout or not */
{
CmdData &= ~ MCI_DISABLE_CMD_TIMER;
}
else
{
CmdData |= MCI_DISABLE_CMD_TIMER;
}
/*send the command*/
CmdData |= (1 << 10); /* This bit needs to be set last. */
LPC_MCI->ARGUMENT = Argument; /* Set the argument first, finally command */
LPC_MCI->COMMAND = CmdData;
return;
}
/************************************************************************//**
* @brief The routine is to get the reponse from card after commands.
* This function is always used in pair of MCI_SendCmd() func
*
* @param[in] ExpectCmdData specify the command of which the data will be
* retrieved. This field should be the same with CmdIndex of
* MCI_SendCmd() function.
*
* @param[in] ExpectResp the response type for the command. They may be:
* - EXPECT_NO_RESP: means no response required
* - EXPECT_SHORT_RESP: means a response in a word needed
* - EXPECT_LONG_RESP: means a response in 4 words needed
*
* @param[out] CmdResp the buffer stored the data replied from cards
*
* @return MCI_FUNC_OK in case of success
***************************************************************************/
int32_t MCI_GetCmdResp(uint32_t ExpectCmdData, uint32_t ExpectResp, uint32_t *CmdResp)
{
uint32_t CmdRespStatus = 0;
uint32_t LastCmdIndex;
if ( ExpectResp == EXPECT_NO_RESP )
{
return MCI_FUNC_OK;
}
while (1)
{
// Get the status of the component
CmdRespStatus = LPC_MCI->STATUS;
if ( CmdRespStatus & (MCI_CMD_TIMEOUT) )
{
LPC_MCI->CLEAR = CmdRespStatus | MCI_CMD_TIMEOUT;
LPC_MCI->COMMAND = 0;
LPC_MCI->ARGUMENT = 0xFFFFFFFF;
return (CmdRespStatus);
}
if ( CmdRespStatus & MCI_CMD_CRC_FAIL )
{
LPC_MCI->CLEAR = CmdRespStatus | MCI_CMD_CRC_FAIL;
LastCmdIndex = LPC_MCI->COMMAND & 0x003F;
if ( (LastCmdIndex == CMD1_SEND_OP_COND) || (LastCmdIndex == ACMD41_SEND_APP_OP_COND)
|| (LastCmdIndex == CMD12_STOP_TRANSMISSION) )
{
LPC_MCI->COMMAND = 0;
LPC_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)
{
LPC_MCI->CLEAR = CmdRespStatus | MCI_CMD_RESP_END;
break; /* cmd response is received, expecting response */
}
}
if ((LPC_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 != CMD1_SEND_OP_COND) && (ExpectCmdData != ACMD41_SEND_APP_OP_COND)
&& (ExpectCmdData != CMD2_ALL_SEND_CID) && (ExpectCmdData != CMD9_SEND_CSD))
{
CmdRespStatus = INVALID_RESPONSE; /* Reuse error status */
return (INVALID_RESPONSE);
}
}
/* Read MCI_RESP0 register assuming it's not long response. */
if (CmdResp != NULL)
{
if (ExpectResp == EXPECT_SHORT_RESP)
{
*(CmdResp + 0) = LPC_MCI->RESP0;
*(CmdResp + 1) = 0;
*(CmdResp + 2) = 0;
*(CmdResp + 3) = 0;
}
else if (ExpectResp == EXPECT_LONG_RESP)
{
*(CmdResp + 0) = LPC_MCI->RESP0;
*(CmdResp + 1) = LPC_MCI->RESP1;
*(CmdResp + 2) = LPC_MCI->RESP2;
*(CmdResp + 3) = LPC_MCI->RESP3;
}
}
return MCI_FUNC_OK;
}
/************************************************************************//**
* @brief The routine is to send command to cards then get back the
* reponses (if required).
*
* @param[in] CmdIndex the command to be sent to cards
*
* @param[in] Argument the argument follows the command
*
* @param[in] ExpectResp the response type for the command. They may be:
* - EXPECT_NO_RESP: means no response required
* - EXPECT_SHORT_RESP: means a response in a word needed
* - EXPECT_LONG_RESP: means a response in 4 words needed
*
* @param[out] CmdResp the buffer stored the data replied from cards
*
* @param[in] AllowTimeout allow timeout the command or not
*
* @return MCI_FUNC_OK in case of success
***************************************************************************/
int32_t MCI_CmdResp(uint32_t CmdIndex, uint32_t Argument,
uint32_t ExpectResp, uint32_t *CmdResp, uint32_t AllowTimeout)
{
int32_t respStatus;
MCI_SendCmd(CmdIndex, Argument, ExpectResp, AllowTimeout);
if((CmdResp != NULL) || (ExpectResp != EXPECT_NO_RESP))
{
respStatus = MCI_GetCmdResp(CmdIndex, ExpectResp, CmdResp);
}
else
{
respStatus = MCI_FUNC_BAD_PARAMETERS;
}
return respStatus;
}
/************************************************************************//**
* @brief To reset the card, the CMD0 is sent and then the card is put
* in idle state. This is the very first command to be sent to
* initialize either MMC or SD card.
*
* @param None
*
* @return Always MCI_FUNC_OK
***************************************************************************/
int32_t MCI_CardReset(void)
{
/* Because CMD0 command to put the device to idle state does not need response
since, it's only sending commad */
MCI_SendCmd(CMD0_GO_IDLE_STATE, 0x00000000, EXPECT_NO_RESP, 0);
return MCI_FUNC_OK;
}
/************************************************************************//**
* @brief Send CMD1 (SEND_OP_COND) to card.
*
* @param None
*
* @return MCI_FUNC_OK if all success
****************************************************************************/
int32_t MCI_Cmd_SendOpCond( void )
{
uint32_t i, retryCount;
uint32_t respStatus;
uint32_t respValue[4];
int32_t retval = MCI_FUNC_FAILED;
retryCount = 0x200; /* reset retry counter */
while ( retryCount > 0 )
{
respStatus = MCI_CmdResp(CMD1_SEND_OP_COND, OCR_INDEX, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
if(respStatus & MCI_CMD_TIMEOUT)
{
retval = MCI_FUNC_TIMEOUT;
}
else if ((respValue[0] & 0x80000000) == 0)
{
//The card has not finished the power up routine
retval = MCI_FUNC_BUS_NOT_IDLE;
}
else
{
retval = MCI_FUNC_OK;
break;
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return(retval);
}
/************************************************************************//**
* @brief Send CMD8 (SEND_IF_COND) for interface condition to card.
*
* @param None
*
* @return MCI_FUNC_OK if all success
****************************************************************************/
int32_t MCI_Cmd_SendIfCond(void)
{
uint32_t i, retryCount;
uint32_t CmdArgument;
uint32_t respStatus;
uint32_t respValue[4];
int32_t retval = MCI_FUNC_FAILED;
uint8_t voltageSupplied = 0x01;//in range 2.7-3.6V
uint8_t checkPattern = 0xAA;
CmdArgument = (voltageSupplied << MCI_CMD8_VOLTAGESUPPLIED_POS) | checkPattern;
retryCount = 20;
while ( retryCount > 0 )
{
respStatus = MCI_CmdResp(CMD8_SEND_IF_COND, CmdArgument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
if(respStatus & MCI_CMD_TIMEOUT)
{
//Consider as no response
retval = MCI_FUNC_TIMEOUT;
}
else if ((respValue[0] & MCI_CMD8_CHECKPATTERN_BMASK) != checkPattern)
{
retval = MCI_FUNC_FAILED;
}
else if (((respValue[0] >> MCI_CMD8_VOLTAGESUPPLIED_POS) & MCI_CMD8_VOLTAGESUPPLIED_BMASK)
!= voltageSupplied)
{
retval = MCI_FUNC_BAD_PARAMETERS;
}
else
{
retval = MCI_FUNC_OK;
break;
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return retval;
}
/************************************************************************//**
* @brief Send CMD55 (APP_CMD) to indicate to the card that the next
* command is an application specific command rather than a
* standard command. Before an ACMD, call this routine first
*
* @param None
*
* @return MCI_FUNC_OK if all success
****************************************************************************/
int32_t MCI_Cmd_SendACMD( void )
{
uint32_t i, retryCount;
uint32_t CmdArgument;
uint32_t respStatus;
uint32_t respValue[4];
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; /* Use the address from SET_RELATIVE_ADDR cmd */
}
else /* if MMC or unknown card type, use 0x0. */
{
CmdArgument = 0x00000000;
}
retryCount = 20;
while ( retryCount > 0 )
{
respStatus = MCI_CmdResp(CMD55_APP_CMD, CmdArgument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
if(respStatus != 0)
{
retval = MCI_FUNC_FAILED;
}
else if (respValue[0] & CARD_STATUS_ACMD_ENABLE)
{
retval = MCI_FUNC_OK;
break;
}
else
{
retval = MCI_FUNC_NOT_READY;
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return retval;
}
/************************************************************************//**
* @brief Send ACMD41 (SEND_APP_OP_COND) to Host Capacity Support (HCS)
* information and asks the accessed card to send its operating
* condition (OCR).
*
* @param[in] hcsVal input the Host Capacity Support
*
* @return MCI_FUNC_OK if all success
*
* @note If SEND_APP_OP_COND is timeout, the card in the slot is not MMC
* type, try this combination to see if we can communicate with
* a SD type.
****************************************************************************/
int32_t MCI_Acmd_SendOpCond(uint8_t hcsVal)
{
uint32_t i, retryCount;
uint32_t respStatus, argument;
uint32_t respValue[4];
int32_t retval = MCI_FUNC_FAILED;
argument = OCR_INDEX | (hcsVal << MCI_ACMD41_HCS_POS);
/* 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 )
{
/* Clear Open Drain output control for SD */
MCI_SetOutputMode(MCI_OUTPUT_MODE_PUSHPULL);
for ( i = 0; i < 0x3000; i++ );
if ((retval = MCI_Cmd_SendACMD()) == MCI_FUNC_OK)
{
respStatus = MCI_CmdResp(ACMD41_SEND_APP_OP_COND, argument, EXPECT_SHORT_RESP, (uint32_t *)&respValue[0], ALLOW_CMD_TIMER);
if(respStatus & MCI_CMD_TIMEOUT)
{
retval = MCI_FUNC_TIMEOUT;
}
else if (!(respValue[0] & 0x80000000))
{
retval = MCI_FUNC_BUS_NOT_IDLE;
}
else
{
CCS = (respValue[0]&(1<<30)) ? 1:0;
retval = MCI_FUNC_OK;
break;
}
}
for ( i = 0; i < 0x20; i++ );
retryCount--;
}
return retval;
}
/************************************************************************//**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -