📄 lpc177x_8x_mci.c
字号:
/* Should be in STANDBY state now and ready */
retval = MCI_FUNC_ERR_STATE;
}
else
{
return MCI_FUNC_OK;
}
}
}
return retval;
}
/*********************************************************************//**
* @brief Called by MCI interrupt handler to simplify the command
* process.
*
* @param None
*
* @return None
*
* @note In card initialization, the commnad interrupts are disabled
*************************************************************************/
void MCI_CmdProcess( void )
{
uint32_t MCIStatus;
MCIStatus = LPC_MCI->STATUS;
if ( MCIStatus & MCI_CMD_CRC_FAIL )
{
LPC_MCI->CLEAR = MCI_CMD_CRC_FAIL;
}
if ( MCIStatus & MCI_CMD_TIMEOUT )
{
LPC_MCI->CLEAR = MCI_CMD_TIMEOUT;
}
/* Cmd Resp End or Cmd Sent */
if ( MCIStatus & MCI_CMD_RESP_END )
{
LPC_MCI->CLEAR = MCI_CMD_RESP_END;
}
if ( MCIStatus & MCI_CMD_SENT )
{
LPC_MCI->CLEAR = MCI_CMD_SENT;
}
if ( MCIStatus & MCI_CMD_ACTIVE )
{
LPC_MCI->CLEAR = MCI_CMD_ACTIVE;
}
return;
}
/*********************************************************************//**
* @brief Called by MCI interrupt handler to manage error on the bus
*
* @param None
*
* @return None
*************************************************************************/
void MCI_DataErrorProcess( void )
{
uint32_t MCIStatus;
MCIStatus = LPC_MCI->STATUS;
if ( MCIStatus & MCI_DATA_CRC_FAIL )
{
LPC_MCI->CLEAR = MCI_DATA_CRC_FAIL;
}
if ( MCIStatus & MCI_DATA_TIMEOUT )
{
LPC_MCI->CLEAR = MCI_DATA_TIMEOUT;
}
/* Underrun or overrun */
if ( MCIStatus & MCI_TX_UNDERRUN )
{
LPC_MCI->CLEAR = MCI_TX_UNDERRUN;
}
if ( MCIStatus & MCI_RX_OVERRUN )
{
LPC_MCI->CLEAR = MCI_RX_OVERRUN;
}
/* Start bit error on data signal */
if ( MCIStatus & MCI_START_BIT_ERR )
{
LPC_MCI->CLEAR = MCI_START_BIT_ERR;
}
Mci_Data_Xfer_End = 0;
Mci_Data_Xfer_ERR = MCIStatus;
return;
}
/*********************************************************************//**
* @brief Called by MCI interrupt handler. This is the last interrupt
* manipulates the process of the data-block write and read
* to/with card
*
* @details This service is also used with/without DMA support. It simply
* clears the flag messages the in-process data-block transfer
* has been done/ended
*
* @param None
*
* @return None
*************************************************************************/
void MCI_DATA_END_InterruptService( void )
{
uint32_t MCIStatus;
MCIStatus = LPC_MCI->STATUS;
if ( MCIStatus & MCI_DATA_END ) /* Data end, and Data block end */
{
LPC_MCI->CLEAR = MCI_DATA_END;
Mci_Data_Xfer_End = 0;
Mci_Data_Xfer_ERR = 0;
MCI_TXDisable();
MCI_RXDisable();
return;
}
if ( MCIStatus & MCI_DATA_BLK_END )
{
LPC_MCI->CLEAR = MCI_DATA_BLK_END;
//MCI_TXDisable();
return;
}
/* Tx active */
if ( MCIStatus & MCI_TX_ACTIVE )
{
}
/* Rx active */
if ( MCIStatus & MCI_RX_ACTIVE )
{
}
return;
}
/*********************************************************************//**
* @brief Called by MCI interrupt handler if requiring to using FIFO
* for data transferring. It copy data to/from FIFO register
* from/to a data buffer.
*
* @param None
*
* @return None
*
* @note This function is done without DMA transfer support
**********************************************************************/
void MCI_FIFOInterruptService( void )
{
#if !MCI_DMA_ENABLED
uint32_t MCIStatus;
MCIStatus = LPC_MCI->STATUS;
if ( MCIStatus & (FIFO_TX_INT_MASK ) )
{
/* empty is multiple of 512 block size */
if ( MCIStatus & MCI_TX_HALF_EMPTY )
{
//There's no data, return
if(dataSrcBlock == NULL)
return;
/* write 8 words to fifo */
MCI_WriteFifo((uint32_t *)&dataSrcBlock[txBlockCnt]);
txBlockCnt += 32;
}
if (txBlockCnt == BLOCK_LENGTH) /* block complete */
{
dataSrcBlock += BLOCK_LENGTH;
txBlockCnt = 0;
/* disable FIFO int until next block write */
//LPC_MCI->MASK0 &= ~(FIFO_TX_INT_MASK);
/* wait for SD card to complete sending data i.e MCI_DATA_BLK_END interrupt */
}
}
else if ( MCIStatus & (FIFO_RX_INT_MASK) )
{
/* if using RX_HALF_FULL remove one ReadFIFO below */
if ( MCIStatus & MCI_RX_HALF_FULL )
{
//There's no store data, return
if(dataDestBlock == NULL)
return;
/* read 8 words from fifo */
MCI_ReadFifo((uint32_t *)&dataDestBlock[rxBlockCnt]);
rxBlockCnt += 32;
}
/* block complete */
if (rxBlockCnt == BLOCK_LENGTH)
{
dataDestBlock += BLOCK_LENGTH;
rxBlockCnt = 0;
}
}
#endif
return;
}
/*********************************************************************//**
* @brief MCI_IRQHandler is to manage the reasons that cause the
* interrupt.
*
* @details It controls the data-block writing and reading by access
* the FIFO register.
* It handle the state changes on the MCI bus...
*
* @param None
*
* @return None
**********************************************************************/
void MCI_IRQHandler (void)
{
uint32_t MCI_Status;
MCI_Status = LPC_MCI->STATUS;
/* handle MCI_STATUS interrupt */
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;
}
}
/**
* @}
*/
/** @addtogroup MCI_Public_Functions
* @{
*/
/*********************************************************************//**
* @brief Set MCI clock rate, during initialization phase < 400K
* during data phase < 20Mhz
*
* @param[in] ClockRate Clock rate to be set
*
* @return None
**********************************************************************/
void MCI_Set_MCIClock( uint32_t ClockRate )
{
uint32_t i, ClkValue = 0;
if ( ClockRate == MCI_SLOW_RATE )
{
/* slow clock */
ClkValue |= MCLKDIV_SLOW;
}
else if (ClockRate == MCI_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;
}
/**********************************************************************//**
* @brief Set the Width to 1-bit Bus or 4-bit Bus
*
* @param[in] width buswidth expected to set
*
* @return MCI_FUNC_OK in case of success
*************************************************************************/
int32_t MCI_SetBusWidth( 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_Acmd_SendBusWidth( BUS_WIDTH_4BITS ) != MCI_FUNC_OK )
{
return(MCI_FUNC_FAILED);
}
return MCI_FUNC_OK;
}
/************************************************************************//**
* @brief Do initialization the MCI block as set its clock, registers,
* setup NVIC for interrupts, configure the pins used for MCI
* function, do initialize the card in slot...
*
* @param[in] powerActiveLevel the power level to activate the card in slot
*
* @return MCI_FUNC_OK in case of success
***************************************************************************/
int32_t MCI_Init(uint8_t powerActiveLevel )
{
uint32_t i;
MCI_CardType = MCI_CARD_UNKNOWN;
// Following block of code added to ensure card VCC drops to zero
// before card is initialized
// Force all MCI control pins to basic I/O mode
LPC_IOCON->P1_2 &= ~0x1F; /* SD_CLK @ P1.2 */
LPC_IOCON->P1_3 &= ~0x1F; /* SD_CMD @ P1.3 */
LPC_IOCON->P1_5 &= ~0x1F; /* SD_PWR @ P1.5 */
LPC_IOCON->P1_6 &= ~0x1F; /* SD_DAT_0 @ P1.6 */
LPC_IOCON->P1_7 &= ~0x1F; /* SD_DAT_1 @ P1.7 */
LPC_IOCON->P1_11 &= ~0x1F; /* SD_DAT_2 @ P1.11 */
LPC_IOCON->P1_12 &= 0x1F; /* SD_DAT_3 @ P1.12 */
// Set all MCI pins to outputs
LPC_GPIO1->DIR |= 0x18EC;
// Force all pins low (except power control pin)
LPC_GPIO1->CLR = 0x1000;
LPC_GPIO1->CLR = 0x0800;
LPC_GPIO1->CLR = 0x0080;
LPC_GPIO1->CLR = 0x0040;
LPC_GPIO1->SET = 0x0020;
LPC_GPIO1->CLR = 0x0008;
LPC_GPIO1->CLR = 0x0004;
// Crude delay of 50ms at 120MHz
for ( i = 0; i < 0x100000; i++ );
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(1, 2, 2);
//SD_CMD
PINSEL_ConfigPin(1, 3, 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(MCI_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);
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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -