📄 lpc177x_8x_mci.c
字号:
if ( MCI_Status & DATA_ERR_INT_MASK )
{
MCI_DataErrorProcess();
return;
}
if ( MCI_Status & DATA_END_INT_MASK )
{
MCI_DATA_END_InterruptService();
return;
}
else if ( MCI_Status & FIFO_INT_MASK )
{
MCI_FIFOInterruptService();
return;
}
else if ( MCI_Status & CMD_INT_MASK )
{
MCI_CmdProcess();
return;
}
}
/******************************************************************************
** Function name: MCI_Set_MCIClock
**
** Descriptions: Set MCI clock rate, during initialization phase < 400K
** during data phase < 20Mhz.
**
** parameters: Clock rate to be set
** Returned value: None
**
******************************************************************************/
void MCI_Set_MCIClock( uint32_t ClockRate )
{
uint32_t i, ClkValue = 0;
if ( ClockRate == SLOW_RATE )
{
/* slow clock */
ClkValue |= MCLKDIV_SLOW;
}
else if (ClockRate == NORMAL_RATE)
{
/* normal clock */
ClkValue |= MCLKDIV_NORMAL;
}
LPC_MCI->CLOCK &= ~(0xFF); /* clear clock divider */
LPC_MCI->CLOCK |= (1 << 8) | ClkValue;
for ( i = 0; i < 0x10; i++ ); /* delay 3MCLK + 2PCLK before next write */
return;
}
/******************************************************************************
** Function name: SD_Set_BusWidth
**
** Descriptions: 1-bit bus or 4-bit bus.
**
** parameters: bus width
** Returned value: TRUE or FALSE
**
******************************************************************************/
uint32_t SD_Set_BusWidth( uint32_t width )
{
uint32_t i;
for ( i = 0; i < 0x10; i++ ); /* delay 3MCLK + 2PCLK */
if ( width == SD_1_BIT )
{
LPC_MCI->CLOCK &= ~(1 << 11); /* 1 bit bus */
}
else if ( width == SD_4_BIT )
{
LPC_MCI->CLOCK |= (1 << 11);/* 4 bit bus */
}
if ( MCI_Cmd_SendAcmdBusWidth( BUS_WIDTH_4BITS ) != MCI_FUNC_OK )
{
return(MCI_FUNC_FAILED);
}
return MCI_FUNC_OK;
}
/******************************************************************************
** Function name: MCI_Init
**
** Descriptions: Set MCI clock and power registers, setup VIC for
** data interrupt.
**
** parameters: powerActiveLevel: the power level that will make the card powered
**
** Returned value: true or fase, if VIC table is full, return false
**
******************************************************************************/
uint32_t MCI_Init(uint8_t powerActiveLevel )
{
uint32_t i, retval;
MCI_CardType = MCI_CARD_UNKNOWN;
dataSrcBlock = NULL;
dataDestBlock = NULL;
//_DBG_("MCI_Init");
LPC_SC->PCONP |= ( 1 << 28 ); /* Enable clock to the MCI block */
if ( LPC_MCI->CLOCK & (1 << 8) )
{
LPC_MCI->CLOCK &= ~(1 << 8);
}
if ( LPC_MCI->POWER & 0x02 )
{
LPC_MCI->POWER = 0x00;
}
for ( i = 0; i < 0x1000; i++ );
/* Disable all interrupts for now */
LPC_MCI->MASK0 = 0;
//SD_CLK
PINSEL_ConfigPin(0, 19, 2);
//SD_CMD
PINSEL_ConfigPin(0, 20, 2);
//SD_PWR
PINSEL_ConfigPin(1, 5, 2);
//SD_DAT_0
PINSEL_ConfigPin(1, 6, 2);
//SD_DAT_1
PINSEL_ConfigPin(1, 7, 2);
//SD_DAT_2
PINSEL_ConfigPin(1, 11, 2);
//SD_DAT_3
PINSEL_ConfigPin(1, 12, 2);
// SD_PWR is active high (follows the output of the SD Card interface block).
if(powerActiveLevel == LOW_LVL)
{
LPC_SC->SCS &= ~ 0x08;//Becase on EA board SD_PWR is active low
}
else
{
LPC_SC->SCS |= 0x08;
}
//Setting for timeout problem
LPC_MCI->DATATMR = 0x1FFFFFFF;
/*set up clocking default mode, clear any registers as needed */
LPC_MCI->COMMAND = 0;
LPC_MCI->DATACTRL = 0;
LPC_MCI->CLEAR = 0x7FF; /* clear all pending interrupts */
LPC_MCI->POWER = 0x02; /* power up */
while ( !(LPC_MCI->POWER & 0x02) );
for ( i = 0; i < 0x100; i++ );
/* During identification phase, the clock should be less than
400Khz. Once we pass this phase, the normal clock can be set up
to 25Mhz on SD card and 20Mhz on MMC card. */
MCI_Set_MCIClock( SLOW_RATE );
LPC_MCI->POWER |= 0x01; /* bit 1 is set already, from power up to power on */
for ( i = 0; i < 0x2000; i++ );
NVIC_EnableIRQ(MCI_IRQn);
retval = MCI_CardInit();
/* During the initialization phase, to simplify the process, the CMD related
interrupts are disabled. The DATA related interrupts are enabled when
the FIFOs are used and just before WRITE_BLOCK READ_BLOCK cmds are issues, and
disabled after the data block has been written and read. Please also note,
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;
}
/******************************************************************************
** Function name: MCI_SetOutputMode
**
** Descriptions:
**
** parameters: None
** Returned value: Card type.
**
******************************************************************************/
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);
}
else
{
/* Clear Open Drain output control for SD */
LPC_MCI->POWER &= ~(1 << MCI_PWRCTRL_OPENDRAIN_POS);
}
}
/******************************************************************************
** Function name: MCI_SendCmd
**
** Descriptions: The routine is used to send a CMD to the card
**
** parameters: CmdIndex, Argument, ExpectResp Flag, AllowTimeout flag
** Returned value: 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 timeout or not */
{
CmdData |= (1 << 8);
}
else
{
CmdData &= ~(1 << 8);
}
/*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;
}
/******************************************************************************
** Function name: MCI_GetCmdResp
**
** Descriptions: Get response from the card. This module is always used
** in pair with MCI_SendCmd()
**
** parameters: Expected cmd data, expect response flag, pointer to the
** response
** Expected cmd data should be the same as that in SendCmd()
** expect response flag could be EXPECT_NO_RESP
** EXPECT_SHORT_RESP
** EXPECT_LONG_RESP
** if GetCmdResp() is 0, check the pointer to the response
** field to get the response value, if GetCmdResp() returns
** non-zero, no need to check the response field, just resend
** command or bailout.
** Returned value: Response status, 0 is valid response.
**
******************************************************************************/
uint32_t MCI_GetCmdResp(uint32_t ExpectCmdData, uint32_t ExpectResp, uint32_t *CmdResp)
{
uint32_t CmdRespStatus = 0;
uint32_t LastCmdIndex;
//_DBG_("!!!!!!!!!!MCI_GetCmdResp");
if ( ExpectResp == EXPECT_NO_RESP )
{
return (0);
}
while (1)
{
// Get the status of the component
CmdRespStatus = LPC_MCI->STATUS;
if ( CmdRespStatus & (MCI_CMD_TIMEOUT) )
{
LPC_MCI->CLEAR = CmdRespStatus | MCI_CMD_TIMEOUT;
//_DBG_("!!!!!!!!!!MCI_GetCmdResp--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;
//_DBG_("!!!!!!!!!!MCI_GetCmdResp--MCI_CMD_CRC_FAIL");
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 (0);
}
/******************************************************************************
** Function name: MCI_CmdResp
**
** Descriptions:
**
** parameters: None
** Returned value:
**
******************************************************************************/
uint32_t MCI_CmdResp(uint32_t CmdIndex, uint32_t Argument,
uint32_t ExpectResp, uint32_t *CmdResp, uint32_t AllowTimeout)
{
uint32_t respStatus;
uint32_t respValue[4];
MCI_SendCmd(CmdIndex, Argument, ExpectResp, 0);
if((CmdResp != NULL) || (ExpectResp != EXPECT_NO_RESP))
{
respStatus = MCI_GetCmdResp(CmdIndex, ExpectResp, CmdResp);
}
return respStatus;
}
/******************************************************************************
** Function name: MCI_CardReset
**
** Descriptions: To reset the card, the CMD0 is used and then the card is
** in idle, . This is the very first command to be sent to
** initialize either MMC or SD card.
**
** parameters: None
** Returned value: Always MCI_FUNC_OK
**
******************************************************************************/
uint32_t MCI_CardReset(void)
{
/* Send CMD0 command repeatedly until the response is back correctly */
MCI_SendCmd(CMD0_GO_IDLE_STATE, 0x00000000, EXPECT_NO_RESP, 0);
return MCI_FUNC_OK;
}
/******************************************************************************
** Function name: MCI_Cmd_SendOpCond
**
** 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.
**
******************************************************************************/
uint32_t MCI_Cmd_SendOpCond( void )
{
uint32_t i, retryCount;
uint32_t respStatus;
uint32_t respValue[4];
uint32_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], 0);
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);
}
/******************************************************************************
** Function name: MCI_Cmd_SendIfCond
**
** 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.
**
******************************************************************************/
uint32_t MCI_Cmd_SendIfCond(void)
{
uint32_t i, retryCount;
uint32_t CmdArgument;
uint32_t respStatus;
uint32_t respValue[4];
uint32_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], 0);
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;
}
/******************************************************************************
** Function name: MCI_Cmd_SendACMD
**
** 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.
**
******************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -