⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mci.c

📁 lpc2478开发板基于IAR编译器移植ucos实验例程
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
 *   mci.c:  SD/MMC module file for NXP LPC23xx/24xx Family Microprocessors
 *
 *   Copyright(C) 2006, NXP Semiconductor
 *   All rights reserved.
 *
 *   History
 *   2006.07.20  ver 1.00    Prelimnary version, first Release
 *
******************************************************************************/
#include "LPC2468.h"                        /* LPC23xx/24xx definitions */
#include "type.h"
#include "irq.h"
#include "mci.h"
#include "dma.h"

volatile DWORD MCI_DataErrorProcess_count = 0;
volatile DWORD MCI_DATA_END_InterruptService_count = 0;
volatile DWORD MCI_FIFOInterruptService_count = 0;
volatile DWORD MCI_CmdProcess_count = 0;

volatile DWORD CmdCRCErrCount = 0;
volatile DWORD CmdTimeoutErrCount = 0;
volatile DWORD CmdRespEndCount = 0;
volatile DWORD CmdSentCount = 0;
volatile DWORD CmdActiveCount = 0;

volatile DWORD DataCRCErrCount = 0;
volatile DWORD DataTimeoutErrCount = 0;
volatile DWORD DataTxUnderrunErrCount = 0;
volatile DWORD DataRxOverrunErrCount = 0;
volatile DWORD DataStartbitErrCount = 0;

volatile DWORD DataEndCount = 0;
volatile DWORD DataBlockEndCount = 0;
volatile DWORD MCI_Block_End_Flag = 0;

volatile DWORD DataTxActiveCount = 0;
volatile DWORD DataRxActiveCount = 0;

volatile DWORD DataFIFOCount = 0;
volatile DWORD DataRxFIFOCount = 0;
volatile DWORD DataTxFIFOCount = 0;

volatile DWORD CardRCA;
volatile DWORD MCI_CardType;

/* Assembly modules using the ARM block transfer instruction in readfifo.s. */
extern  DWORD MCI_ReadFifo(DWORD * dest);
extern  DWORD MCI_WriteFifo(DWORD * src);

volatile BYTE *WriteBlock = (BYTE *)(DMA_SRC); /* treat WriteBlock as a constant address */
volatile BYTE *ReadBlock  = (BYTE *)(DMA_DST); /* treat ReadBlock as a constant address */

volatile DWORD TXBlockCounter=0, RXBlockCounter=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
  MCI_MASK0 |= ((DATA_END_INT_MASK)|(ERR_TX_INT_MASK));	/* Enable TX interrupts only */
  MCI_MASK1 |= ((DATA_END_INT_MASK)|(ERR_TX_INT_MASK));	/* Enable TX interrupts only */
#else
  MCI_MASK0 |= ((FIFO_TX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_TX_INT_MASK));	/* FIFO TX interrupts only */
  MCI_MASK1 |= ((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
  MCI_MASK0 &= ~((DATA_END_INT_MASK)|(ERR_TX_INT_MASK));	/* Enable TX interrupts only */
  MCI_MASK1 &= ~((DATA_END_INT_MASK)|(ERR_TX_INT_MASK));	/* Enable TX interrupts only */
#else
  MCI_MASK0 &= ~((FIFO_TX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_TX_INT_MASK));	/* FIFO TX interrupts only */
  MCI_MASK1 &= ~((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
  MCI_MASK0 |= ((DATA_END_INT_MASK)|(ERR_RX_INT_MASK));	/* Enable RX interrupts only */
  MCI_MASK1 |= ((DATA_END_INT_MASK)|(ERR_RX_INT_MASK));	/* Enable RX interrupts only */
#else
  MCI_MASK0 |= ((FIFO_RX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_RX_INT_MASK));	/* FIFO RX interrupts only */
  MCI_MASK1 |= ((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
  MCI_MASK0 &= ~((DATA_END_INT_MASK)|(ERR_RX_INT_MASK));	/* Enable TX interrupts only */
  MCI_MASK1 &= ~((DATA_END_INT_MASK)|(ERR_RX_INT_MASK));	/* Enable TX interrupts only */
#else
  MCI_MASK0 &= ~((FIFO_RX_INT_MASK)|(DATA_END_INT_MASK)|(ERR_RX_INT_MASK));	/* FIFO TX interrupts only */
  MCI_MASK1 &= ~((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
**
******************************************************************************/
DWORD MCI_CheckStatus( void )
{
  DWORD respValue;
  while ( 1 )
  {
	if ( (respValue = MCI_Send_Status()) == INVALID_RESPONSE )
	{
	  break;
	}
	else
	{
	  /* The only valid state is TRANS per MMC and SD state diagram.
	  RCV state may be seen, but, I have found that 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 & (0x0F << 8)) == 0x0900 )
	  {
		return ( TRUE );
	  }
	}
  }
  return ( FALSE );
}

/******************************************************************************
** 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 )
{
  DWORD MCIStatus;

  MCIStatus = MCI_STATUS;
  if ( MCIStatus &  MCI_CMD_CRC_FAIL )
  {
	CmdCRCErrCount++;
	MCI_CLEAR =  MCI_CMD_CRC_FAIL;
  }
  if ( MCIStatus &  MCI_CMD_TIMEOUT )
  {
	CmdTimeoutErrCount++;
	MCI_CLEAR =  MCI_CMD_TIMEOUT;
  }
  /* Cmd Resp End or Cmd Sent */
  if ( MCIStatus &  MCI_CMD_RESP_END )
  {
	CmdRespEndCount++;
	MCI_CLEAR =  MCI_CMD_RESP_END;
  }
  if ( MCIStatus &  MCI_CMD_SENT )
  {
	CmdSentCount++;
	MCI_CLEAR =  MCI_CMD_SENT;
  }
  if ( MCIStatus &  MCI_CMD_ACTIVE )
  {
	CmdActiveCount++;
	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 )
{
  DWORD MCIStatus;

  MCIStatus = MCI_STATUS;
  if ( MCIStatus &  MCI_DATA_CRC_FAIL )
  {
	DataCRCErrCount++;
	MCI_CLEAR = MCI_DATA_CRC_FAIL;
  }
  if ( MCIStatus &  MCI_DATA_TIMEOUT )
  {
	DataTimeoutErrCount++;
	MCI_CLEAR =  MCI_DATA_TIMEOUT;
  }
  /* Underrun or overrun */
  if ( MCIStatus &  MCI_TX_UNDERRUN )
  {
	DataTxUnderrunErrCount++;
	MCI_CLEAR = MCI_TX_UNDERRUN;
  }
  if ( MCIStatus &  MCI_RX_OVERRUN )
  {
	DataRxOverrunErrCount++;
	MCI_CLEAR =  MCI_RX_OVERRUN;
  }
  /* Start bit error on data signal */
  if ( MCIStatus &  MCI_START_BIT_ERR )
  {
	DataStartbitErrCount++;
	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 )
{
  DWORD MCIStatus;

  MCIStatus = MCI_STATUS;
  if ( MCIStatus &  MCI_DATA_END )		/* Data end, and Data block end  */
  {
	DataEndCount++;
	MCI_CLEAR = MCI_DATA_END;
	return;
  }
  if ( MCIStatus &  MCI_DATA_BLK_END )
  {
	DataBlockEndCount++;
	MCI_CLEAR =  MCI_DATA_BLK_END;
	MCI_TXDisable();
	MCI_Block_End_Flag = 0;
	return;
  }
	
  /* Tx active  */
  if ( MCIStatus & MCI_TX_ACTIVE )
  {
	DataTxActiveCount++;
  }
  /* Rx active  */
  if ( MCIStatus & MCI_RX_ACTIVE )
  {
	DataRxActiveCount++;
  }
  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
  DWORD MCIStatus;

  MCIStatus = MCI_STATUS;
  if ( MCIStatus & (FIFO_TX_INT_MASK ) )
  {
	DataTxFIFOCount++;			 /* if using TX_HALF_EMPTY remove one WriteFifo below */
	if ( MCIStatus & MCI_TX_HALF_EMPTY ) /* empty is multiple of 512 block size */
	{
	  MCI_WriteFifo((DWORD *)&WriteBlock[TXBlockCounter]); /* write 8 words to fifo */
	  TXBlockCounter += 32;
	}
	if (TXBlockCounter == BLOCK_LENGTH)	/* block complete */
	{
	  TXBlockCounter = 0;
	  MCI_MASK0 &= ~(FIFO_TX_INT_MASK);  /* disable FIFO int until next block write */
	  MCI_MASK1 &= ~(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) )
  {
	DataRxFIFOCount++;
	if ( MCIStatus & MCI_RX_HALF_FULL )	/* if using RX_HALF_FULL remove one ReadFIFO below */
	{
	  MCI_ReadFifo((DWORD *)&ReadBlock[RXBlockCounter]); /* read 8 words from fifo */
	  RXBlockCounter += 32;
	}
	if (RXBlockCounter == BLOCK_LENGTH)	/* block complete */
	{
	  RXBlockCounter = 0;
	}
  }
#endif
  DataFIFOCount++;
  return;
}

/******************************************************************************
** Function name:		MCI_IRQHandler
**
** Descriptions:		MCI interrupt handler
**						The handler to handle the block data write and read
**						not for the commands.
**
** parameters:			None
** Returned value:		None
**
******************************************************************************/
__irq __arm void MCI_IRQHandler (void)
{
  DWORD MCI_Status;

  MCI_Status = MCI_STATUS;	
  /* handle MCI_STATUS interrupt */
  if ( MCI_Status & DATA_ERR_INT_MASK )
  {
	MCI_DataErrorProcess();
	MCI_DataErrorProcess_count++;
	VICVectAddr = 0;		/* Acknowledge Interrupt */
	return;
  }
  if ( MCI_Status & DATA_END_INT_MASK )
  {
	MCI_DATA_END_InterruptService();
	MCI_DATA_END_InterruptService_count++;
	VICVectAddr = 0;		/* Acknowledge Interrupt */
	return;
  }
  else if ( MCI_Status & FIFO_INT_MASK )
  {
	MCI_FIFOInterruptService();
	MCI_FIFOInterruptService_count++;
	VICVectAddr = 0;		/* Acknowledge Interrupt */
	return;
  }
  else if ( MCI_Status & CMD_INT_MASK )
  {
	MCI_CmdProcess();
	MCI_CmdProcess_count++;
	VICVectAddr = 0;		/* Acknowledge Interrupt */
	return;
  }
  VICVectAddr = 0;		/* Acknowledge Interrupt */
}

/******************************************************************************
** 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( DWORD ClockRate )
{
  DWORD i, ClkValue = 0;

  if ( ClockRate == SLOW_RATE )
	ClkValue |= MCLKDIV_SLOW;	/* slow clock */
  else if ( ClockRate == NORMAL_RATE )
	ClkValue |= MCLKDIV_NORMAL;/* normal clock */

  MCI_CLOCK &= ~(0xFF); /* clear clock divider */
  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
**
******************************************************************************/
DWORD SD_Set_BusWidth( DWORD width )
{
  DWORD i;

  for ( i = 0; i < 0x10; i++ );	/* delay 3MCLK + 2PCLK  */
  if ( width == SD_1_BIT )
  {
	MCI_CLOCK &=  ~(1 << 11);	/* 1 bit bus */
  }
  else if ( width == SD_4_BIT )
  {
	MCI_CLOCK |=  (1 << 11);/* 4 bit bus */
  }
	
  if ( MCI_Send_ACMD_Bus_Width( BUS_WIDTH_4BITS ) == FALSE )
  {
	return( FALSE );
  }
  return TRUE;
}

/******************************************************************************
** Function name:		MCI_Init
**
** Descriptions:		Set MCI clock and power registers, setup VIC for
**						data interrupt.		
**
** parameters:			None
** Returned value:		true or fase, if VIC table is full, return false
**
******************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -