📄 mmc.c
字号:
/*************************************************************************
*
* 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 + -