📄 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 2.0
* @date 29. 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.
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors'
* relevant copyright in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
**********************************************************************/
#ifdef __BUILD_WITH_EXAMPLE__
#include "lpc177x_8x_libcfg.h"
#else
#include "lpc177x_8x_libcfg_default.h"
#endif /* __BUILD_WITH_EXAMPLE__ */
#ifdef _MCI
#include "LPC177x_8x.h"
#include "lpc_types.h"
#include "lpc177x_8x_mci.h"
#include "lpc177x_8x_gpdma.h"
#include "lpc177x_8x_clkpwr.h"
#include "lpc177x_8x_pinsel.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_PWRCTRL_BMASK (0xC3)
#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_Data_Xfer_End = 0;
volatile uint32_t Mci_Data_Xfer_ERR = 0;
volatile uint8_t fifo_plane = 0;
volatile uint32_t CardRCA;
volatile uint8_t CCS;
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_SettingDma(uint8_t* memBuf, uint32_t ChannelNum, uint32_t DMAMode );
int32_t MCI_ReadFifo(uint32_t * dest);
int32_t MCI_WriteFifo(uint32_t * src);
void MCI_TXEnable( void );
void MCI_RXEnable( void );
void MCI_TXDisable( void );
void MCI_RXDisable( void );
void MCI_CmdProcess( void );
void MCI_DataErrorProcess( void );
void MCI_DataErrorProcess( void );
void MCI_DATA_END_InterruptService( void );
void MCI_FIFOInterruptService( void );
int32_t MCI_CheckStatus(void);
volatile uint8_t* dataSrcBlock = (uint8_t *) MCI_DMA_SRC_ADDR;
volatile uint8_t* dataDestBlock = (uint8_t *) MCI_DMA_DST_ADDR;;
volatile uint32_t txBlockCnt=0, rxBlockCnt=0;
/** @addtogroup MCI_Private_Functions MCI Private Function
* @ingroup MCI
* @{
*/
#if MCI_DMA_ENABLED
/*********************************************************************//**
* @brief Do setting GPDMA for MCI working
*
* @param[in] DMAMode set for the Type of DMA Transfer. It may be memory
* to peripheral (M2P) or peripheral to memory (P2M)
* in MCI working
*
* @param[in] ChannelNum which channel is used for current transfer with
* DMA compent
*
* @param[in] memBuf point to a UINT8 buffer. In 2 cases of DMAMode
* seperated:
* - M2P: it is the source address that hold the
* expected buffer to transfer
* - P2M: it is the destination address that will store
* data that retrieved from the peripheral (the Card in slot)
*
* @return None
*
* @note This is only required if DMA support is enabled
**********************************************************************/
uint32_t MCI_SettingDma(uint8_t* memBuf, uint32_t ChannelNum, uint32_t DMAMode )
{
GPDMA_Channel_CFG_Type GPDMACfg;
// Transfer size
GPDMACfg.TransferSize = DMA_MCI_SIZE;
// Transfer width
GPDMACfg.TransferWidth = GPDMA_WIDTH_WORD;
// Transfer type
GPDMACfg.TransferType = DMAMode;
// Linker List Item - unused
GPDMACfg.DMALLI = 0;
/* USB RAM is used for test.
Please note, Ethernet has its own SRAM, but GPDMA can't access
that. GPDMA can access USB SRAM and IRAM. Ethernet DMA controller can
access both IRAM and Ethernet SRAM. */
GPDMACfg.ChannelNum = ChannelNum;
if ( DMAMode == GPDMA_TRANSFERTYPE_M2P_DEST_CTRL )
{
/* Ch0 set for M2P transfer from mempry to MCI FIFO. */
// Source memory
GPDMACfg.SrcMemAddr = (uint32_t)memBuf;
// Destination memory
GPDMACfg.DstMemAddr = (uint32_t)LPC_MCI->FIFO;
// Source connection
GPDMACfg.SrcConn = 0;
// Destination connection
GPDMACfg.DstConn = GPDMA_CONN_MCI;
}
else if ( DMAMode == GPDMA_TRANSFERTYPE_P2M_SRC_CTRL )
{
/* Ch0 set for P2M transfer from MCI FIFO to memory. */
// Source memory
GPDMACfg.SrcMemAddr = (uint32_t)LPC_MCI->FIFO;
// Destination memory
GPDMACfg.DstMemAddr = (uint32_t)memBuf;
// Source connection
GPDMACfg.SrcConn = GPDMA_CONN_MCI;
// Destination connection
GPDMACfg.DstConn = 0;
}
else
{
return ( FALSE );
}
// Setup channel with given parameter
GPDMA_Setup(&GPDMACfg);
// Enable GPDMA channel
GPDMA_ChannelCmd(ChannelNum, ENABLE);
/* Enable GPDMA interrupt */
NVIC_EnableIRQ(DMA_IRQn);
return (TRUE);
}
/*********************************************************************//**
* @brief GPDMA interrupt handler sub-routine
*
* @param None
*
* @return None
*
* @note This is only executed if DMA support is enabled
**********************************************************************/
void MCI_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++;
}
}
}
#endif
/*********************************************************************//**
* @brief Read data from FIFO (after a transmission with card) to
* a destination buffer
*
* @param[in] *dest The buffer to store the data that read from card
*
* @return MCI_FUNC_OK
*************************************************************************/
int32_t MCI_ReadFifo(uint32_t * dest)
{
uint8_t i;
uint8_t start, end;
if(fifo_plane == 0)
{
start = 0;
end = 7;
}
else
{
start = 8;
end = 15;
}
fifo_plane = (fifo_plane) ? 0:1;
for (i = start; i <= end; i++)
{
*dest = LPC_MCI->FIFO[i];
dest++;
}
return MCI_FUNC_OK;
}
/*********************************************************************//**
* @brief Write data from a source buffer to FIFO for transmission
*
* @param[in] *src The buffer hold the data need to write to card
*
* @return MCI_FUNC_OK
*************************************************************************/
int32_t MCI_WriteFifo(uint32_t * src)
{
uint8_t i;
uint8_t start, end;
if(fifo_plane == 0)
{
start = 0;
end = 7;
}
else
{
start = 8;
end = 15;
}
fifo_plane = (fifo_plane) ? 0:1;
for (i = start; i <= end; i++)
{
LPC_MCI->FIFO[i] = *src;
src++;
}
return MCI_FUNC_OK;
}
/*********************************************************************//**
* @brief Enable Transmit data interrupt
*
* @param None
*
* @return 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;
}
/*********************************************************************//**
* @brief Disable Transmit data interrupt
*
* @param None
*
* @return None
*************************************************************************/
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;
}
/*********************************************************************//**
* @brief Enable Receive data interrupt
*
* @param None
*
* @return None
*************************************************************************/
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;
}
/*********************************************************************//**
* @brief Disable Receive data interrupt
*
* @param None
*
* @return None
*************************************************************************/
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;
}
/*********************************************************************//**
* @brief Check status when working with data-block transfer
*
* @details 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.
*
* @param None
*
* @return MCI_FUNC_OK if all success
*************************************************************************/
int32_t MCI_CheckStatus(void)
{
int32_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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -