📄 mmc.c
字号:
/*************************************************************************
*
* Used with ICCARM and AARM.
*
* (c) Copyright IAR Systems 2005
*
* File name : mmc.c
* Description : MMC
*
* History :
* 1. Data : July 1, 2005
* Author : Stanimir Bonev
* Description : Create
*
* $Revision: 1.2.2.1 $
**************************************************************************/
#define MMC_GLOBAL
#include "mmc.h"
#include "mmc_ll_SPI1.c"
#define MMC_RET_ERROR(Res) MmcLastError = Res;return(MmcCardError)
#define MMC_RET_DATA_ERR(Res) MmcLastError = Res;return(MmcDataError)
#define CSD_GET_TRAN_SPEED_EXP() (MmcSdCsd[ 3]&0x07)
#define CSD_GET_TRAN_SPEED_MANT() ((MmcSdCsd[ 3]&0xF8)>>3)
#define CSD_GET_NSAC() (MmcSdCsd[ 2] )
#define CSD_GET_TAAC_EXP() (MmcSdCsd[ 1]&0x7)
#define CSD_GET_TAAC_MANT() ((MmcSdCsd[ 1]&0xF8)>>3)
#define CSD_GET_R2W_FACTOR() ((MmcSdCsd[12]&0x1C)>>2)
#define CSD_GET_READ_BL_LEN() (MmcSdCsd[ 5]&0x0F)
#define CSD_GET_C_SIZE() (((MmcSdCsd[ 6]&0x03)<<10) + (MmcSdCsd[7]<<2) + ((MmcSdCsd[8]&0xc0)>>6))
#define CSD_GET_C_SIZE_MULT() (((MmcSdCsd[ 9]&0x03)<<1 ) +((MmcSdCsd[10]&0x80)>>7))
#define CSD_GET_PERM_WRITE_PROTECT() ((MmcSdCsd[14]&0x20)>>5)
#define CSD_GET_TMP_WRITE_PROTECT() ((MmcSdCsd[14]&0x10)>>4)
const Int32U MmcTransfExp[] =
{
10000UL,
100000UL,
1000000UL,
10000000UL,
0UL,
0UL,
0UL,
0UL,
};
const Int32U MmmcAccessTime [] =
{
10000000UL,
1000000UL,
100000UL,
10000UL,
1000UL,
100UL,
10UL,
1UL,
};
const Int32U MmcCsdMant[] =
{
0UL,10UL,12UL,13UL,15UL,
20UL,25UL,
30UL,35UL,
40UL,45UL,
50UL,55UL,
60UL,
70UL,
80UL,
};
const Int32U MmcAccessTimeMant[] =
{
0UL,100UL,83UL,77UL,67UL,
50UL,40UL,
33UL,29UL,
25UL,22UL,
20UL,18UL,
17UL,
14UL,
13UL,
};
const MmcCommads_t MmcCmd[CMD_END] =
{
// CMD0
{0x40,MmcNoArg ,MmcR1 },
// CMD1
{0x41,MmcNoArg ,MmcR1 },
// CMD9
{0x49,MmcNoArg ,MmcR1 },
// CMD10
{0x4A,MmcNoArg ,MmcR1 },
// CMD12
{0x4C,MmcNoArg ,MmcR1 },
// CMD13
{0x4D,MmcNoArg ,MmcR2 },
// CMD16
{0x50,MmcBlockLen ,MmcR1 },
// CMD17
{0x51,MmcDataAdd ,MmcR1 },
// CMD18
{0x52,MmcDataAdd ,MmcR1 },
// CMD24
{0x58,MmcDataAdd ,MmcR1 },
// CMD25
{0x59,MmcDataAdd ,MmcR1 },
// CMD27
{0x5B,MmcNoArg ,MmcR1 },
// CMD28
{0x5C,MmcDataAdd ,MmcR1b},
// CMD29
{0x5D,MmcDataAdd ,MmcR1b},
// CMD30
{0x5E,MmcDataAdd ,MmcR1 },
// CMD32
{0x60,MmcDataAdd ,MmcR1 },
// CMD33
{0x61,MmcDataAdd ,MmcR1 },
// CMD34
{0x62,MmcDataAdd ,MmcR1 },
// CMD35
{0x63,MmcDataAdd ,MmcR1 },
// CMD36
{0x64,MmcDataAdd ,MmcR1 },
// CMD37
{0x65,MmcDataAdd ,MmcR1 },
// CMD38
{0x66,MmcDummyWord,MmcR1b},
// CMD42
{0x6A,MmcDummyWord,MmcR1b},
// CMD55
{0x77,MmcNoArg ,MmcR1 },
// CMD56
{0x78,MmcNoArg ,MmcR1 },
// CMD58
{0x7A,MmcNoArg ,MmcR3 },
// CMD59
{0x7B,MmcDummyWord,MmcR1 },
// ACMD41
{0x69,MmcNoArg ,MmcR1 }
};
DiskStatus_t MmcDskStatus;
Int32U MmcLastError,Tnac,Twr;
Int8U MmcSdCsd[16];
Boolean bMmcChanged;
/*************************************************************************
* Function Name: MmcSendCmd
* Parameters: MmcSpiCmdInd_t ComdInd,Int32U Arg
*
* Return: Int32U
*
* Description: MMC commands implemet
*
*************************************************************************/
Int32U MmcSendCmd(MmcSpiCmdInd_t ComdInd,Int32U Arg)
{
Int32U ch = 0xFF;
Int32U i;
// Chip Select
MmcChipSelect(1);
// Send command code
MmcTranserByte(MmcCmd[ComdInd].TxData);
// Send command's argulents
if(MmcCmd[ComdInd].Arg == MmcNoArg)
{
MmcTranserByte(0x00);
MmcTranserByte(0x00);
MmcTranserByte(0x00);
MmcTranserByte(0x00);
}
else
{
MmcTranserByte(Arg >> 24);
MmcTranserByte(Arg >> 16);
MmcTranserByte(Arg >> 8 );
MmcTranserByte(Arg );
}
// Send CRC
if(ComdInd == CMD0)
{
MmcTranserByte(0x95);
}
else
{
MmcTranserByte(0xFF);
}
for(i = 9; i && (ch == 0xFF); --i) ch = MmcTranserByte(0xFF);
if (i == 0)
{
MmcChipSelect(0);
return((Int32U)-1);
}
switch (MmcCmd[ComdInd].Resp)
{
case MmcR1b:
for (Int32U Busy = 0,i = Twr; i && (Busy != 0xFF); --i)
{
Busy = MmcTranserByte(0xFF);
}
case MmcR1:
return(ch);
case MmcR2:
Arg = ((Int32U)ch << 8) & 0x0000FF00;
Arg |= MmcTranserByte(0xFF) & 0xFF;
return(Arg);
case MmcR3:
default:
Arg = ((Int32U)ch << 24) & 0xFF000000;
Arg |= ((Int32U)MmcTranserByte(0xFF) << 16) & 0x00FF0000;
Arg |= ((Int32U)MmcTranserByte(0xFF) << 8 ) & 0x0000FF00;
Arg |= MmcTranserByte(0xFF) & 0xFF;
return(Arg);
}
}
/*************************************************************************
* Function Name: MmcSetBlockLen
* Parameters: Int32U Length
*
* Return: Int32U
*
* Description: Set Block length Return command's result
*
*************************************************************************/
Int32U MmcSetBlockLen(Int32U length)
{
Int32U res = MmcSendCmd(CMD16,length);
MmcChipSelect(0);
return(res);
}
/*************************************************************************
* Function Name: MmcInitMedia
* Parameters: none
*
* Return: MmcState_t
*
* Description: Mmc detect and initialize
*
*************************************************************************/
MmcState_t MmcInitMedia (void)
{
Int32U i,res;
Tnac = 1;
if(!MmcPresent())
{
return(MmcNoPresent);
}
// Clock Freq. Identification Mode < 400kHz
MmcSetClockFreq(IdentificationModeClock);
// Set maximum time out
Tnac = IdentificationModeClock/SD_READ_TIME_OUT;
// Power up cycles
for(i = 0; i<2; i++)
{
// After power up at least 74 clock cycles are required prior to
// starting bus communication
MmcChipSelect(0);
for(res = 10; res; --res)
{
MmcTranserByte(0xFF);
}
// CMD0 (Go to IDLE) to put MMC in SPI mode
res = MmcSendCmd(CMD0,0);
MmcChipSelect(0);
if(res == MMC_ILDE_STATE)
{
break;
}
}
if(res != MMC_ILDE_STATE)
{
return(MmcNoResponse);
}
// Determinate Card type SD or MMC
MmcDskStatus.DiskType = DiskMMC;
for(i=100;i;--i)
{
MmcChipSelect(0);
MmcTranserByte(0xFF);
res = MmcSendCmd(CMD55,0);
MmcChipSelect(0);
MmcChipSelect(0);
MmcTranserByte(0xFF);
res = MmcSendCmd(ACMD41,0);
MmcChipSelect(0);
if(res & MMC_ILLEGAL_CMD)
{
// MMC card may be
// CMD1 for MMC Init sequence
// will be complete within 500ms
for (i = 100; i;--i)
{
MmcChipSelect(0);
MmcTranserByte(0xFF);
res = MmcSendCmd(CMD1,0);
MmcChipSelect(0);
if(res == MMC_OK)
{
// Init complete
break;
}
MmcDly_1ms(50);
}
break;
}
if(res == MMC_OK)
{
// SD card is find
MmcDskStatus.DiskType = DiskSD;
break;
}
MmcDly_1ms(50);
}
if(i == 0)
{
return(MmcNoResponse);
}
// Read CSD
res = MmcReadCardInfo(MmcSdCsd,CMD9);
if(res != MmcOk)
{
// CSD must be always valid
return(MmcNoResponse);
}
// Implement CSD data
MmcCsdImplemet();
// Set Block size
MmcSetBlockLen(MmcDskStatus.BlockSize);
return(MmcOk);
}
/*************************************************************************
* Function Name: MmcReadCardInfo
* Parameters: pInt8U pData,
* MmcSpiCmdInd_t Command - CMD9, CMD10 are only allowed
*
* Return: MmcState_t
*
* Description: Read CSD or CID registers depend of commoand
*
*************************************************************************/
MmcState_t MmcReadCardInfo(pInt8U pData, MmcSpiCmdInd_t Command)
{
Int32U i;
Int32U res;
switch(Command)
{
case CMD9:
case CMD10:
break;
default:
return(MmmcParameterError);
}
MmcChipSelect(0);
MmcTranserByte(0xFF);
res = MmcSendCmd(Command,0);
if (res == MMC_OK)
{
for(i = 8; i ; --i)
{
res = MmcTranserByte(0xFF);
if((res | MMC_DATA_ERR_TOLKEN) == MMC_DATA_ERR_TOLKEN)
{
MMC_RET_DATA_ERR(res);
}
else if (res == MMC_DATA_TOLKEN)
{
for(i = 0; i <16 ; ++i)
{
*pData++ = MmcTranserByte(0xFF);
}
// CRC receive
MmcTranserByte(0xFF);
MmcTranserByte(0xFF);
MmcChipSelect(0);
return(MmcOk);
}
}
}
MmcChipSelect(0);
MMC_RET_ERROR(res);
}
/*************************************************************************
* Function Name: MmcCsdImplemet
* Parameters: none
*
* Return: none
*
* Description: Implemet data from CSD
*
*************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -