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

📄 mci.c

📁 NXP的LPC2468开发板光盘
💻 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 <nxp/iolpc2468.h>
#include <intrinsics.h>
#include "type.h"
#include "irq.h"
#include "timer.h"
#include "mci.h"
#include "dma.h"

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 DataTxActiveCount = 0;
volatile DWORD DataRxActiveCount = 0;

volatile DWORD DataFIFOCount = 0;

volatile DWORD CardRCA;
volatile DWORD CardType;

#if MCI_DMA_ENABLED
extern DWORD *src_addr;
extern DWORD *dest_addr;
#else
extern volatile BYTE WriteBlock[BLOCK_LENGTH], ReadBlock[BLOCK_LENGTH];
extern volatile DWORD TXBlockCounter, RXBlockCounter;
#endif

/******************************************************************************
** Function name:   MCI_Interrupt related
**
** Descriptions:    MCI interrupt handler and related APIs
**
**
** parameters:      None
** Returned value:    None
**
******************************************************************************/
void MCI_TXEnable( void )
{
  MCIMASK0 |= DATA_TX_INT_MASK; /* Enable TX interrupts only */
  MCIMASK1 = MCIMASK0;
}

void MCI_TXDisable( void )
{
  MCIMASK0 &= ~DATA_TX_INT_MASK;  /* Disable TX interrupts only */
  MCIMASK1 = MCIMASK0;
}

/*****************************************************************/
void MCI_RXEnable( void )
{
  MCIMASK0 |= DATA_RX_INT_MASK; /* Enable RX interrupts only */
  MCIMASK1 = MCIMASK0;
}

void MCI_RXDisable( void )
{
  MCIMASK0 &= ~DATA_RX_INT_MASK;  /* Disable RX interrupts only */
  MCIMASK1 = MCIMASK0;
}

/******************************************************************************
** 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 disable.
**
**
** parameters:      None
** Returned value:    None
**
******************************************************************************/
void MCI_CmdProcess( void )
{
  DWORD MCIStatus;

  MCIStatus = MCISTATUS;
  if ( MCIStatus &  MCI_CMD_CRC_FAIL )
  {
    CmdCRCErrCount++;
    MCICLEAR = MCIStatus | MCI_CMD_CRC_FAIL;
  }
  if ( MCIStatus &  MCI_CMD_TIMEOUT )
  {
    CmdTimeoutErrCount++;
    MCICLEAR = MCIStatus | MCI_CMD_TIMEOUT;
  }
  /* Cmd Resp End or Cmd Sent */
  if ( MCIStatus &  MCI_CMD_RESP_END )
  {
    CmdRespEndCount++;
    MCICLEAR = MCIStatus | MCI_CMD_RESP_END;
  }
  if ( MCIStatus &  MCI_CMD_SENT )
  {
    CmdSentCount++;
    MCICLEAR = MCIStatus | MCI_CMD_SENT;
  }
  if ( MCIStatus &  MCI_CMD_ACTIVE )
  {
    CmdActiveCount++;
    MCICLEAR = MCIStatus | 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 = MCISTATUS;
    if ( MCIStatus &  MCI_DATA_CRC_FAIL )
  {
    DataCRCErrCount++;
    MCICLEAR = MCIStatus | MCI_DATA_CRC_FAIL;
  }
  if ( MCIStatus &  MCI_DATA_TIMEOUT )
  {
    DataTimeoutErrCount++;
    MCICLEAR = MCIStatus | MCI_DATA_TIMEOUT;
  }

  /* Underrun or overrun */
  if ( MCIStatus &  MCI_TX_UNDERRUN )
  {
    DataTxUnderrunErrCount++;
    MCICLEAR = MCIStatus | MCI_TX_UNDERRUN;
  }
  if ( MCIStatus &  MCI_RX_OVERRUN )
  {
    DataRxOverrunErrCount++;
    MCICLEAR = MCIStatus | MCI_RX_OVERRUN;
  }
  /* Start bit error on data signal */
  if ( MCIStatus &  MCI_START_BIT_ERR )
  {
    DataStartbitErrCount++;
    MCICLEAR = MCIStatus | MCI_START_BIT_ERR;
  }
  return;
}

/******************************************************************************
** Function name:   MCI_DataInterruptProcess
**
** Descriptions:    Called by MCI interrupt handler
**            This is the key module processing the block write
**            read to from the card. The FIFO interrupts are not
**            handled, the routine mainly use TX_ACTIVE and RX_ACTIVE
**            interrupts to handle a block write and read.
**            There is an ugly polling right after the block write
**            and read to handle the situation that, the block has
**            been sent, but the prograamming to the card is still
**            in progress. This needs to be done when TX_ACTIVE or
**            RX_ACTIVE is still set. In the real application, during
**            the card programming, a semiphone like signaling will be
**            needed.
**
** parameters:      None
** Returned value:    None
**
******************************************************************************/
void MCI_DataInterruptProcess( void )
{
  DWORD MCIStatus;
#if !MCI_DMA_ENABLED
  DWORD i, blockSize, DataWord;
#endif

  MCIStatus = MCISTATUS;
  if ( MCIStatus &  MCI_DATA_END )    /* Data end, and Data block end  */
  {
    DataEndCount++;
    MCICLEAR = MCIStatus | MCI_DATA_END;
  }
  if ( MCIStatus &  MCI_DATA_BLK_END )
  {
    DataBlockEndCount++;
    MCICLEAR = MCIStatus | MCI_DATA_BLK_END;
  }

  /* Tx active, and Rx active  */
  if ( MCISTATUS & MCI_TX_ACTIVE )
  {
    DataTxActiveCount++;
#if MCI_DMA_ENABLED
    while ( !(DMACRAWINTTCSTATUS & 0x01) );
    DMACINTTCCLEAR = 0x01;
#else
    while ( TXBlockCounter < BLOCK_LENGTH )
    {
      blockSize = 0;
      if ( MCISTATUS & MCI_TX_FIFO_EMPTY )
      {
        blockSize = FIFO_SIZE * 4;
      }
      else if ( MCISTATUS & MCI_TX_HALF_EMPTY )
      {
        blockSize = (FIFO_SIZE/2) * 4;
      }
      else if ( !(MCISTATUS & MCI_TX_FIFO_FULL) )
      {
        blockSize = 1 * 4;
      }

      for ( i = 0; i < blockSize; i += 4 )
      {
        DataWord = (DWORD)(WriteBlock[TXBlockCounter]) | (DWORD)(WriteBlock[TXBlockCounter+1] << 8)
          | (DWORD)(WriteBlock[TXBlockCounter+2] << 16) | (DWORD)(WriteBlock[TXBlockCounter+3] << 24);
        MCIFIFO0 = DataWord;
        TXBlockCounter += 4;
      }
    }
#endif
    /* Data has been written, but has not been programmed into the card yet. */
    /* Even it's a dead while loop inside the ISR, but, during the
    flash writing, there is not much else you should do. If it's not in the
    TRAN state, per MMC/SD state diagram, send STOP to bail out. */

    // wait transfer complete
    while(MCISTATUS_bit.TXACTIVE);
    MCIDATACTRL = 0;

    if ( MCI_CheckStatus() != TRUE )
    {
      MCI_Send_Stop();
    }
  }

  if ( MCISTATUS & MCI_RX_ACTIVE )
  {
    DataRxActiveCount++;
#if MCI_DMA_ENABLED
    while ( !(DMACRAWINTTCSTATUS & 0x02) );
    DMACINTTCCLEAR = 0x02;
#else
    while ( RXBlockCounter < BLOCK_LENGTH )
    {
      if ( !(MCISTATUS & MCI_RX_FIFO_FULL) )
      {
        blockSize = FIFO_SIZE * 4;
      }
      else if ( MCISTATUS & MCI_RX_HALF_FULL )
      {
        blockSize = (FIFO_SIZE/2) * 4;
      }
      else if ( MCISTATUS & MCI_RX_FIFO_EMPTY )
      {
        blockSize = 1 * 4;
      }
      else
      {
        blockSize = 0;
      }

      for ( i = 0; i < blockSize; i += 4 )
      {
        while ( !(MCISTATUS & MCI_RX_DATA_AVAIL) );
        DataWord = MCIFIFO0;
        ReadBlock[RXBlockCounter] = DataWord & 0xFF;
        ReadBlock[RXBlockCounter+1] = (DataWord >> 8) & 0xFF;
        ReadBlock[RXBlockCounter+2] = (DataWord >> 16) & 0xFF;
        ReadBlock[RXBlockCounter+3] = (DataWord >> 24) & 0xFF;
        RXBlockCounter += 4;
      }
    }
#endif

    // wait receive complete
    while(MCISTATUS_bit.RXACTIVE);

    MCIDATACTRL = 0;
    if ( MCI_CheckStatus() != TRUE )
    {
      MCI_Send_Stop();
    }
  }
  return;
}

/******************************************************************************
** Function name:   MCI_FIFOProcess
**
** Descriptions:    Called by MCI interrupt handler
**            FIFO interrupts are disabled.
**
** parameters:      None
** Returned value:    None
**
******************************************************************************/
void MCI_FIFOProcess( void )
{
volatile DWORD MCIStatus;

  MCIStatus = MCISTATUS;
  DataFIFOCount++;
  return;
}

/******************************************************************************
** Function name:   MCI_Handler
**
** 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_Handler (void)
{

  /* handle MCI_STATUS interrupt */
  if ( MCISTATUS & CMD_INT_MASK )
  {
    MCI_CmdProcess();
  }
  else if ( MCISTATUS & DATA_ERR_INT_MASK )
  {
    MCI_DataErrorProcess();
  }
  else if ( MCISTATUS & DATA_INT_MASK )
  {
    MCI_DataInterruptProcess();
  }
    else if ( MCISTATUS & FIFO_INT_MASK )
  {
    MCI_FIFOProcess();
  }
  VICADDRESS = 0;   /* Acknowledge Interrupt */
}

/******************************************************************************
** Function name:   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 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 */
  }
  MCICLOCK |= (1 << 8) | (1 << 9) | ClkValue;
  for ( i = 0; i < 0x10; i++ ); /* delay 3MCLK + 2PCLK before next write */
  return;
}

/******************************************************************************
** 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
**
******************************************************************************/
DWORD MCI_Init( void )
{
DWORD i;
  MCICLOCK = 0;

⌨️ 快捷键说明

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