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

📄 mmc.c

📁 NXP LPC系列AMR7的开发程序源码(LCD
💻 C
📖 第 1 页 / 共 2 页
字号:
/*************************************************************************
 *
 *    Used with ICCARM and AARM.
 *
 *    (c) Copyright IAR Systems 2007
 *
 *    File name   : mmc.c
 *    Description : MMC module
 *
 *    History :
 *    1. Date        : February 6, 2007
 *       Author      : Stanimir Bonev
 *       Description : Create
 *
 *  When DMA is used I/O buffer must be in DMA RAM region
 * between 0x7FD0 0000 - 0x7FD0 1FFF (8kB)
 *
 *    $Revision: 1.4 $
 **************************************************************************/
#define MMC_GLOBAL
#include "mmc.h"

#define CSD_GET_TRAN_SPEED_EXP()      (MmcSdCsd[ 0]&0x07)
#define CSD_GET_TRAN_SPEED_MANT()    ((MmcSdCsd[ 0]&0xF8)>>3 )
#define CSD_GET_NSAC()                (MmcSdCsd[ 1]          )
#define CSD_GET_TAAC_EXP()            (MmcSdCsd[ 2]&0x7)
#define CSD_GET_TAAC_MANT()          ((MmcSdCsd[ 2]&0xF8)>>3 )
#define CSD_GET_R2W_FACTOR()         ((MmcSdCsd[15]&0x1C)>>2 )
#define CSD_GET_READ_BL_LEN()         (MmcSdCsd[ 6]&0x0F)
#define CSD_GET_C_SIZE()            (((MmcSdCsd[ 5]&0x03)<<10) + (MmcSdCsd[4]<<2) + ((MmcSdCsd[11]&0xc0)>>6))
#define CSD_GET_C_SIZE_MULT()       (((MmcSdCsd[10]&0x03)<<1 ) +((MmcSdCsd[9]&0x80)>>7))
#define CSD_GET_PERM_WRITE_PROTECT() ((MmcSdCsd[13]&0x20)>>5 )
#define CSD_GET_TMP_WRITE_PROTECT()  ((MmcSdCsd[13]&0x10)>>4 )

#define MCI_BUS_DLY() {\
                        for(volatile Int32U i = 10; i;--i);\
                      }\

const Int32U MmcTransfExp[] =
{
     10000UL,
    100000UL,
   1000000UL,
  10000000UL,
         0UL,
         0UL,
         0UL,
         0UL,
};

const Int32U MmmcAccessTime [] =
{
        1UL,
       10UL,
      100UL,
     1000UL,
    10000UL,
   100000UL,
  1000000UL,
 10000000UL,
};

const Int32U MmcCsdMant[] =
{
  0UL,10UL,12UL,13UL,15UL,
  20UL,25UL,
  30UL,35UL,
  40UL,45UL,
  50UL,55UL,
  60UL,
  70UL,
  80UL,
};

const MmcCommads_t MmcCmd[CMD_END] =
{
  // CMD0
  {0x00,MmcNoArg    ,MmcNoResp },
  // CMD1
  {0x01,MmcOcr      ,MmcR3 },
  // CMD2
  {0x02,MmcNoArg    ,MmcR2 },
  // CMD3
  {0x03,MmcRelAddr  ,MmcR1 },
  // CMD7
  {0x07,MmcRelAddr  ,MmcR1 },
  // CMD9
  {0x09,MmcRelAddr  ,MmcR2 },
  // CMD10
  {0x0A,MmcRelAddr  ,MmcR2 },
  // CMD12
  {0x0C,MmcNoArg    ,MmcR1b},
  // CMD13
  {0x0D,MmcRelAddr  ,MmcR1 },
  // CMD16
  {0x10,MmcBlockLen ,MmcR1 },
  // CMD17
  {0x11,MmcDataAdd  ,MmcR1 },
  // CMD18
  {0x12,MmcDataAdd  ,MmcR1 },
  // CMD24
  {0x18,MmcDataAdd  ,MmcR1 },
  // CMD25
  {0x19,MmcDataAdd  ,MmcR1 },
  // CMD27
  {0x1B,MmcOcr      ,MmcR1 },
  // CMD28
  {0x1C,MmcDataAdd  ,MmcR1b},
  // CMD29
  {0x1D,MmcDataAdd  ,MmcR1b},
  // CMD30
  {0x1E,MmcDataAdd  ,MmcR1 },
  // CMD32
  {0x20,MmcDataAdd  ,MmcR1 },
  // CMD33
  {0x21,MmcDataAdd  ,MmcR1 },
  // CMD34
  {0x22,MmcDataAdd  ,MmcR1 },
  // CMD35
  {0x23,MmcDataAdd  ,MmcR1 },
  // CMD36
  {0x24,MmcDataAdd  ,MmcR1 },
  // CMD37
  {0x25,MmcDataAdd  ,MmcR1 },
  // CMD38
  {0x26,MmcNoArg    ,MmcR1b},
  // CMD42
  {0x2A,MmcNoArg    ,MmcR1b},
  // CMD55
  {0x37,MmcRelAddr  ,MmcR1 },
  // CMD56
  {0x38,MmcNoArg    ,MmcR1 },
  // ACMD46
  {0x06,MmcDataAdd  ,MmcR1 },
  // ACMD41
  {0x29,MmcDataAdd  ,MmcR3 },
};

DiskCtrlBlk_t MmcDskCtrlBlk;
Int32U MmcLastError,Tnac,Twr;
Boolean bMmcChanged;
#pragma data_alignment = 4
Int8U MmcSdCsd[16];

static Int32U CardRCA;
static Boolean bMmcPermWriteProtect;

/*************************************************************************
 * Function Name: MmcPresent
 * Parameters: none
 * Return: Boolean - true cart present
 *                 - false cart no present
 *
 * Description: Mmc present check
 *
 *************************************************************************/
inline
Boolean MmcPresent (void)
{
  return(!(MMC_CP_FIO & MMC_CP_MASK));
}

/*************************************************************************
 * Function Name: MmcWriteProtect
 * Parameters: none
 * Return: Boolean - true cart is protected
 *                 - false cart no protected
 *
 * Description: SD write protect status
 *
 *************************************************************************/
inline
Boolean MmcWriteProtect (void)
{
  return((MMC_WP_FIO & MMC_WP_MASK) != 0);
}

/*************************************************************************
 * Function Name: MmcSetClockFreq
 * Parameters: Int32U Frequency
 * Return: Int32U
 *
 * Description: Set SPI ckl frequency
 *
 *************************************************************************/
static
Int32U MmcSetClockFreq (Int32U Frequency)
{
Int32U Pclk = SYS_GetFpclk(MCI_PCLK_OFFSET);
Int32U Div;
  Frequency <<= 1;

  for(Div = 4; Div <= 256; ++Div)
  {
    if((Frequency * Div) > Pclk)
    {
      break;
    }
  }
  // Set divider, clk enable and power save
  MCICLOCK_bit.CLKDIV = Div - 1;
  MCI_BUS_DLY();
  MCICLOCK_bit.ENABLE = 1;
  MCI_BUS_DLY();
  MCICLOCK_bit.PWRSAVE = 1;
  MCI_BUS_DLY();
  // Return real frequency
  return(Pclk/(Div<<1));
}

/*************************************************************************
 * Function Name: MmcInit
 * Parameters: none
 * Return: none
 *
 * Description: Init MCI module and Cart Present and Write Protect pins
 *
 *************************************************************************/
void MmcInit (void)
{
  // CP set to input
  MMC_CP_DIR &= ~MMC_CP_MASK;
  MMC_CP_MODE = 2;  // pin has neither pull-up nor pull-down
  // WP set to input
  MMC_WP_DIR &= ~MMC_WP_MASK;
  MMC_WP_MODE = 2;  // pin has neither pull-up nor pull-down

  PCLKSEL1_bit.PCLK_MCI = 1;  // set divider to /1
  PCONP_bit.PCSDC = 1;        // Enable MCI clk

  // Pins assign to MCI module (P0.19,20,21,22, P2.11,12,13)
  PINSEL1_bit.P0_19 = \
  PINSEL1_bit.P0_20 = \
  PINSEL1_bit.P0_21 = \
  PINSEL1_bit.P0_22 = \
  PINSEL4_bit.P2_11 = \
  PINSEL4_bit.P2_12 = \
  PINSEL4_bit.P2_13 = 2;

  PINMODE1_bit.P0_19 =\
  PINMODE1_bit.P0_20 =\
  PINMODE1_bit.P0_21 =\
  PINMODE1_bit.P0_22 = 0;

  MmcPowerDown();

  // enable DMA , little endian
  PCONP_bit.PCGPDMA = 1;
  DMACCONFIGURATION = 1;
  DMACSYNC = 0;           // DMA sync enable
  DMACINTERRCLR = 3;
  DMACINTTCCLEAR = 3;
  DMACC0CONFIGURATION = DMACC1CONFIGURATION = 0;

}

/*************************************************************************
 * Function Name: MmcPowerDown
 * Parameters: none
 * Return: none
 *
 * Description: Set power down state
 *
 *************************************************************************/
static
void MmcPowerDown (void)
{
  // Init power state
  SCS_bit.MCIPWR = 1;
  MCIPOWER    = 0;
  MCI_BUS_DLY();
  MCIMASK0    = 0;        // Disable all interrupts for now
  MCIMASK1    = MCIMASK0;
  MCICOMMAND  = 0;
  MCI_BUS_DLY();
  MCIDATACTRL = 0;
  MCI_BUS_DLY();
  MCICLEAR    = 0x7FF;    // clear all pending interrupts
  MCICLOCK_bit.WIDEBUS = 0;
  MCI_BUS_DLY();

  // Clock Freq. Identification Mode < 400kHz
  MmcSetClockFreq(IdentificationModeClock);
}
/*************************************************************************
 * Function Name: MmcSendCmd
 * Parameters: MmcSpiCmdInd_t ComdInd, Int32U Arg
 *
 * Return: Int32U
 *
 * Description: MMC commands implement
 *
 *************************************************************************/
static
MmcState_t MmcSendCmd(MmcSpiCmdInd_t ComdInd, pInt32U pArg)
{
Int32U Status;
union {
  Int32U Data;
  struct
  {
    Int32U CMDINDEX   : 6;
    Int32U RESPONSE   : 1;
    Int32U LONGRSP    : 1;
    Int32U INTERRUPT  : 1;
    Int32U PENDING    : 1;
    Int32U ENABLE     : 1;
    Int32U            :21;
  };
} Command;


  // the command engine must be disabled when we modify the argument or the
  // peripheral resends
  while (MCISTATUS_bit.CMDACTIVE )
  {
    // Command in progress.
    MCICOMMAND = 0;
    MCI_BUS_DLY();
  }
  Command.Data = 0;

  // Send command code
  Command.CMDINDEX = MmcCmd[ComdInd].TxData;
  if(pArg != NULL)
  {
    switch(MmcCmd[ComdInd].Resp)
    {
    case MmcR2:
      Command.LONGRSP = 1;
    case MmcR1:
    case MmcR1b:
    case MmcR3:
      Command.RESPONSE = 1;
    }
  }
  Command.ENABLE = 1;

  // Send command's arguments
  if(MmcCmd[ComdInd].Arg != MmcNoArg)
  {
    MCIARGUMENT = *pArg;
  }
  else
  {
    MCIARGUMENT = 0;
  }

  // Send command
  MCICOMMAND = Command.Data;
  MCI_BUS_DLY();

  // Wait command respond
  while((Status = MCISTATUS & 0x000000C5) == 0);

  MCICLEAR = Status;
  // Command timeout
  if(Status & (1UL << 2))
  {
    MCICOMMAND = 0;
    MCI_BUS_DLY();
    return(MmcNoResponse);
  }

  // Command CRC fault
  if(Status & (1UL << 0))
  {
    switch(MCICOMMAND_bit.CMDINDEX)
    {
    // Ignore CRC Error
    case  1: // CMD1
    case 41: // ACMD42
    case 12: // CMD12
      MCICOMMAND = 0;
      MCI_BUS_DLY();
      MCIARGUMENT = 0xFFFFFFFF;
      break;
    default:
      MCICOMMAND = 0;
      MCI_BUS_DLY();
      return(MmcCardError);
    }
  }

  if(pArg != NULL)
  {
    switch (MmcCmd[ComdInd].Resp)
    {
    case MmcNoResp:
      break;
    case MmcR3:
      *pArg = MCIRESPONSE0;
      break;
    case MmcR2:
      *pArg++ = MCIRESPONSE0;
      *pArg++ = MCIRESPONSE1;
      *pArg++ = MCIRESPONSE2;
      *pArg++ = MCIRESPONSE3;
      break;
    default:
      if(MmcCmd[ComdInd].TxData != MCIRESPCMD_bit.RESPCMD)
      {
        return(MmcCardError);
      }
      *pArg = MCIRESPONSE0;
    }
  }
  MCICOMMAND = 0;
  MCI_BUS_DLY();
  return(MmcOk);
}

/*************************************************************************
 * Function Name: MmcInitMedia
 * Parameters: none
 *
 * Return: MmcState_t
 *
 * Description: Mmc detect and initialize
 *
 *************************************************************************/
Int32U Status;
MmcState_t MmcInitMedia (void)
{
Int32U i,res;
volatile Int32U Dly;
Int8U MmcSdCid[16];

  Tnac = 1;
  if(!MmcPresent())
  {
    if(MCIPOWER_bit.CTRL)
    {
      // Set to power down state
      MmcPowerDown();
    }
    return(MmcNoPresent);
  }

  MmcPowerDown();
  MmcDly_1ms(100);

  MCIPOWER_bit.CTRL = 0x02;    // power up
  MCI_BUS_DLY();
  while ((MCIPOWER_bit.CTRL != 0x02));
  MmcDly_1ms(10);
  MCIPOWER_bit.CTRL = 0x01;   // power on
  MmcDly_1ms(100);

  // CMD0 (Go to IDLE) to put MMC in SPI mode
  MCIPOWER_bit.OPENDRAIN = 0;
  MCI_BUS_DLY();

  if(MmcSendCmd(CMD0,NULL) != MmcOk)
  {
    return(MmcNoResponse);
  }

  // Determinate Card type SD or MMC
  MmcDskCtrlBlk.DiskType = DiskMMC;
  for(i=100;i;--i)
  {
    MCIPOWER_bit.OPENDRAIN = 0;
    MCI_BUS_DLY();
    res = 0;
    if(((Status = MmcSendCmd(CMD55,&res)) == MmcOk) &&
       (res & 0x100))
    {
      res = OcrReg;
      if((MmcSendCmd(ACMD41,&res) == MmcOk) &&
         (res & 0x80000000))
      {
        // SD card is find
        MmcDskCtrlBlk.DiskType = DiskSD;
        break;
      }
    }
    else
    {
      MCIPOWER_bit.OPENDRAIN = 1;
      MCI_BUS_DLY();
      // CMD1 for MMC Init sequence
      // will be complete within 500ms
      res = OcrReg;
      if(MmcSendCmd(CMD1,&res) ==  MmcOk && (res & 0x80000000))
      {
        // MMC card is find
        break;
      }
    }

    MmcDly_1ms(50);
  }


  if(i == 0)
  {
    return(MmcNoResponse);
  }

  // Read CID
  if(MmcSendCmd(CMD2,(pInt32U)MmcSdCid) != MmcOk)
  {
    return(MmcNoResponse);
  }

  // Set address
  CardRCA = (MmcDskCtrlBlk.DiskType == DiskMMC)?0x00010000:0x00000000;
  if(MmcSendCmd(CMD3,&CardRCA) != MmcOk)
  {
    return(MmcNoResponse);
  }
  if(MmcDskCtrlBlk.DiskType == DiskSD)
  {
    CardRCA &= 0xFFFF0000;
  }
  else
  {
    CardRCA  = 0x00010000;
  }

  // Set Pushpull CMD output type
  MCIPOWER_bit.OPENDRAIN = 0;
  MCI_BUS_DLY();

  // Read CSD
  MmcSdCsd[0] = 0;
  MmcSdCsd[1] = 0;
  MmcSdCsd[2] = CardRCA >> 16;
  MmcSdCsd[3] = CardRCA >> 24;
  if(MmcSendCmd(CMD9,(pInt32U)MmcSdCsd) != MmcOk)
  {
    return(MmcNoResponse);
  }

  // Implement CSD data
  MmcCsdImplemet();

  // Enter in TRAN state
  res = CardRCA;
  if(MmcSendCmd(CMD7,&res) != MmcOk)
  {
    return(MmcNoResponse);
  }
  res = CardRCA;
  if(MmcOk != MmcSendCmd(CMD13,&res))
  {
    return(MmcNoResponse);
  }
  else if(!(res & READY_FOR_DATA) ||
          ((res & CURRENT_STATE) != CARD_TRAN))
  {
    return(MmcCardError);
  }

  // Set Block size
  res = MmcDskCtrlBlk.BlockSize;
  if(MmcSendCmd(CMD16,&res))
  {
    return(MmcNoResponse);
  }

  if(MmcDskCtrlBlk.DiskType == DiskSD)
  {
    // Use wide bus for SD
    MCICLOCK_bit.WIDEBUS = 1;
    MCI_BUS_DLY();
    res = CardRCA;
    if(((Status = MmcSendCmd(CMD55,&res)) != MmcOk) ||
       !(res & 0x100))
    {
      return(MmcCardError);
    }
    // Set bus width 4bits
    res = 2;
    if(MmcSendCmd(ACMD6,&res) != MmcOk)
    {
      return(MmcCardError);
    }
  }
  return(MmcOk);
}

/*************************************************************************
 * Function Name: MmcCsdImplemet
 * Parameters:  none
 *
 * Return: none
 *
 * Description: Implement data from CSD
 *
 *************************************************************************/
Int32U Tets;

⌨️ 快捷键说明

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