📄 lpc177x_8x_mci.c
字号:
/**********************************************************************
* $Id$ lpc177x_8x_mci.c 2011-06-02
*//**
* @file lpc177x_8x_mci.c
* @brief Contains all functions support for MCI firmware library
* on LPC177x_8x
* @version 1.0
* @date 02. June. 2011
* @author NXP MCU SW Application Team
*
* Copyright(C) 2011, NXP Semiconductor
* All rights reserved.
*
***********************************************************************
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* products. This software is supplied "AS IS" without any warranties.
* NXP Semiconductors assumes no responsibility or liability for the
* use of the software, conveys no license or title under any patent,
* copyright, or mask work right to the product. NXP Semiconductors
* reserves the right to make changes in the software without
* notification. NXP Semiconductors also make no representation or
* warranty that such application will be suitable for the specified
* use without further testing or modification.
**********************************************************************/
#include "lpc177x_8x.h"
#include "lpc_types.h"
#include "lpc177x_8x_mci.h"
#include "lpc177x_8x_gpdma.h"
#include "lpc177x_8x_clkpwr.h"
#include "debug_frmwrk.h"
#define DMA_MCI_SIZE BLOCK_LENGTH
#define MCI_DMA_WRITE_CHANNEL (0)
#define MCI_DMA_READ_CHANNEL (1)
#define _SHIFT(x) (1 << x)
#define _XSHIFT(x, y) (x << y)
#define _SHIFT_(x) (1 >> x)
#define _XSHIFT_(x, y) (x >> y)
#define MCI_CARDSTATUS_READYFORDATA_P0S (8)
#define MCI_CARDSTATUS_CURRENTSTATE_POS (9)
#define MCI_CARDSTATUS_CURRENTSTATE_BMASK (0x0F)
#define CARDSTATEOF(x) (_XSHIFT(x, MCI_CARDSTATUS_CURRENTSTATE_POS) & MCI_CARDSTATUS_CURRENTSTATE_BMASK)
#define MCI_CMD8_VOLTAGESUPPLIED_POS (8)
#define MCI_CMD8_VOLTAGESUPPLIED_BMASK (0xFF)
#define MCI_CMD8_CHECKPATTERN_POS (0)
#define MCI_CMD8_CHECKPATTERN_BMASK (0xFF)
#define MCI_ACMD41_HCS_POS (30)
#define MCI_OUTPUT_MODE_PUSHPULL (0)
#define MCI_OUTPUT_MODE_OPENDRAIN (1)
#define MCI_PWRCTRL_OPENDRAIN_POS (6)
#define MCI_PWRCTRL_OPENDRAIN_NUMBIT (1)
#define MCI_PWRCTRL_OPENDRAIN_BMASK (0x01)
#define MCI_CID_MANUFACTURER_ID_WPOS (24) //in word 0
#define MCI_CID_MANUFACTURER_ID_WBMASK (0xFF)
#define MCI_CID_OEMAPPLICATION_ID_WPOS (8) //in word 0
#define MCI_CID_OEMAPPLICATION_ID_WBMASK (0xFFFF)
#define MCI_CID_PRODUCTNAME_ID_H_WPOS (0) //in word 0
#define MCI_CID_PRODUCTNAME_ID_H_WBMASK (0xFF)
#define MCI_CID_PRODUCTNAME_ID_L_WPOS (0) //in word 1
#define MCI_CID_PRODUCTNAME_ID_L_WBMASK (0xFFFFFFFF)
#define MCI_CID_PRODUCTREVISION_ID_WPOS (24) //in word 2
#define MCI_CID_PRODUCTREVISION_ID_WBMASK (0xFF)
#define MCI_CID_PRODUCTSERIALNUM_ID_H_WPOS (0) //in word 2
#define MCI_CID_PRODUCTSERIALNUM_ID_H_WBMASK (0x00FFFFFF)
#define MCI_CID_PRODUCTSERIALNUM_ID_L_WPOS (24) //in word 3
#define MCI_CID_PRODUCTSERIALNUM_ID_L_WBMASK (0xFF)
#define MCI_CID_PRODUCTSERIALNUM_ID_WBMASK (0xFFFFFFFF)
#define MCI_CID_RESERVED_ID_WPOS (20) //in word 3
#define MCI_CID_RESERVED_ID_WBMASK (0x1F)
#define MCI_CID_MANUFACTURINGDATE_ID_WPOS (8) //in word 3
#define MCI_CID_MANUFACTURINGDATE_ID_WBMASK (0x0FFF)
#define MCI_CID_CHECKSUM_ID_WPOS (1) //in word 3
#define MCI_CID_CHECKSUM_ID_WBMASK (0x7F)
#define MCI_CID_UNUSED_ID_WPOS (0) //in word 3
#define MCI_CID_UNUSED_ID_WBMASK (0x01)
volatile uint32_t MCI_Block_End_Flag = 0;
volatile uint32_t CardRCA;
volatile en_Mci_CardType MCI_CardType;
// Terminal Counter flag, Error Counter flag for Channel 0
uint32_t dmaWrCh_TermianalCnt, dmaWrCh_ErrorCnt;
uint32_t dmaRdCh_TermianalCnt, dmaRdCh_ErrorCnt;
uint32_t MCI_ReadFifo(uint32_t * dest);
uint32_t MCI_WriteFifo(uint32_t * src);
volatile uint8_t* dataSrcBlock;
volatile uint8_t* dataDestBlock;
volatile uint32_t txBlockCnt=0, rxBlockCnt=0;
/******************************************************************************
** Function name: MCI_ReadFifo related
**
** Descriptions:
**
**
** parameters: None
** Returned value: None
**
******************************************************************************/
uint32_t MCI_ReadFifo(uint32_t * dest)
{
//copy 8 words (32 bytes) from FIFO
memcpy(dest, LPC_MCI->FIFO, 32);
return 0;
}
/******************************************************************************
** Function name: MCI_WriteFifo related
**
** Descriptions:
**
**
** parameters: None
** Returned value: None
**
******************************************************************************/
uint32_t MCI_WriteFifo(uint32_t * src)
{
//copy 8 words (32 bytes) from FIFO
memcpy(LPC_MCI->FIFO, src, 32);
return 0;
}
/******************************************************************************
** Function name: MCI_Interrupt related
**
** Descriptions: MCI interrupt handler and related APIs
**
**
** parameters: None
** Returned value: None
**
******************************************************************************/
void MCI_TXEnable( void )
{
#if MCI_DMA_ENABLED
LPC_MCI->MASK0 |= ((DATA_END_INT_MASK)|(ERR_TX_INT_MASK)); /* Enable TX interrupts only */
#else
LPC_MCI->MASK0 |= ((FIFO_TX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_TX_INT_MASK)); /* FIFO TX interrupts only */
#endif
return;
}
/*****************************************************************/
void MCI_TXDisable( void )
{
#if MCI_DMA_ENABLED
LPC_MCI->MASK0 &= ~((DATA_END_INT_MASK)|(ERR_TX_INT_MASK)); /* Enable TX interrupts only */
#else
LPC_MCI->MASK0 &= ~((FIFO_TX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_TX_INT_MASK)); /* FIFO TX interrupts only */
#endif
return;
}
/*****************************************************************/
void MCI_RXEnable( void )
{
#if MCI_DMA_ENABLED
LPC_MCI->MASK0 |= ((DATA_END_INT_MASK)|(ERR_RX_INT_MASK)); /* Enable RX interrupts only */
#else
LPC_MCI->MASK0 |= ((FIFO_RX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_RX_INT_MASK)); /* FIFO RX interrupts only */
#endif
return;
}
/*****************************************************************/
void MCI_RXDisable( void )
{
#if MCI_DMA_ENABLED
LPC_MCI->MASK0 &= ~((DATA_END_INT_MASK)|(ERR_RX_INT_MASK)); /* Enable TX interrupts only */
#else
LPC_MCI->MASK0 &= ~((FIFO_RX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_RX_INT_MASK)); /* FIFO TX interrupts only */
#endif
return;
}
/******************************************************************************
** Function name: MCI_CheckStatus
**
** Descriptions: MCI Check status before and after the block read and
** write. Right after the block read and write, this routine
** is important that, even the FIFO is empty, complete
** block has been sent, but, data is still being written
** to the card, this routine is to ensure that the data
** has been written based on the state of the card, not
** by the length being set.
**
** parameters: None
** Returned value: TRUE or FALSE
**
******************************************************************************/
uint32_t MCI_CheckStatus(void)
{
uint32_t respValue, retval = MCI_FUNC_FAILED;
while (1)
{
if (MCI_GetCardStatus(&respValue) != MCI_FUNC_OK)
{
break;
}
else
{
/* The only valid state is TRANS per MMC and SD state diagram.
RCV state may be seen, but, it happens only when TX_ACTIVE or
RX_ACTIVE occurs before the WRITE_BLOCK and READ_BLOCK cmds are
being sent, which is not a valid sequence. */
if(!(respValue & _SHIFT(MCI_CARDSTATUS_READYFORDATA_P0S)))
{
retval = MCI_FUNC_NOT_READY;
}
else if(CARDSTATEOF(respValue) != MCI_CARDSTATE_TRAN)
{
/* Should be in STANDBY state now and ready */
retval = MCI_FUNC_ERR_STATE;
}
else
{
return MCI_FUNC_OK;
}
}
}
return retval;
}
/******************************************************************************
** Function name: MCI_CmdProcess
**
** Descriptions: Called by MCI interrupt handler
** To simplify the process, for card initialization, the
** CMD interrupts are disabled.
**
**
** parameters: None
** Returned value: None
**
******************************************************************************/
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;
}
/******************************************************************************
** Function name: MCI_DataErrorProcess
**
** Descriptions: Called by MCI interrupt handler
** Process data error.
**
** parameters: None
** Returned value: 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;
}
return;
}
/******************************************************************************
** Function name: MCI_DATA_END_InterruptService
**
** Descriptions: Called by MCI interrupt handler
** This is the last interrupt module processing
** the block write and read to and from the MM card.
**
** FIFO interrupts are also used when DMA is disabled
** This routine simply clears the
** MCI_Block_End_Flag, and increments counters for debug
**
** parameters: None
** Returned value: 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;
return;
}
if ( MCIStatus & MCI_DATA_BLK_END )
{
LPC_MCI->CLEAR = MCI_DATA_BLK_END;
MCI_TXDisable();
MCI_Block_End_Flag = 0;
return;
}
/* Tx active */
if ( MCIStatus & MCI_TX_ACTIVE )
{
}
/* Rx active */
if ( MCIStatus & MCI_RX_ACTIVE )
{
}
return;
}
/******************************************************************************
** Function name: MCI_FIFOInterruptService
**
** Descriptions: Called by MCI interrupt handler when using FIFO
** interrupts and DMA is disabled
**
**
** parameters: None
** Returned value: None
**
******************************************************************************/
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 */
{
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)
{
rxBlockCnt = 0;
}
}
#endif
return;
}
/*********************************************************************//**
* @brief GPDMA interrupt handler sub-routine
* @param[in] None
* @return None
**********************************************************************/
void DMA_IRQHandler (void)
{
// check GPDMA interrupt on channel 0
if (GPDMA_IntGetStatus(GPDMA_STAT_INT, MCI_DMA_WRITE_CHANNEL))
{
//check interrupt status on channel 0
// Check counter terminal status
if(GPDMA_IntGetStatus(GPDMA_STAT_INTTC, MCI_DMA_WRITE_CHANNEL))
{
// Clear terminate counter Interrupt pending
GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, MCI_DMA_WRITE_CHANNEL);
dmaWrCh_TermianalCnt++;
}
if (GPDMA_IntGetStatus(GPDMA_STAT_INTERR, MCI_DMA_WRITE_CHANNEL))
{
// Clear error counter Interrupt pending
GPDMA_ClearIntPending (GPDMA_STATCLR_INTERR, MCI_DMA_WRITE_CHANNEL);
dmaWrCh_ErrorCnt++;
}
}
else if (GPDMA_IntGetStatus(GPDMA_STAT_INT, MCI_DMA_READ_CHANNEL))
{
//check interrupt status on channel 0
// Check counter terminal status
if(GPDMA_IntGetStatus(GPDMA_STAT_INTTC, MCI_DMA_READ_CHANNEL))
{
// Clear terminate counter Interrupt pending
GPDMA_ClearIntPending (GPDMA_STATCLR_INTTC, MCI_DMA_READ_CHANNEL);
dmaRdCh_TermianalCnt++;
}
if (GPDMA_IntGetStatus(GPDMA_STAT_INTERR, MCI_DMA_READ_CHANNEL))
{
// Clear error counter Interrupt pending
GPDMA_ClearIntPending (GPDMA_STATCLR_INTERR, MCI_DMA_READ_CHANNEL);
dmaRdCh_ErrorCnt++;
}
}
}
/******************************************************************************
** Function name: SDMMC_IRQHandler
**
** Descriptions: MCI interrupt handler
** The handler to handle the block data write and read
** not for the commands.
**
** parameters: None
** Returned value: None
**
******************************************************************************/
void MCI_IRQHandler (void)
{
uint32_t MCI_Status;
MCI_Status = LPC_MCI->STATUS;
/* handle MCI_STATUS interrupt */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -