📄 mmc.c
字号:
#DEFINE mmcCardDetect() !input(MMC_CD) // Check for Card Detect (CD)
#DEFINE mmcWrite spi_write
#DEFINE mmcRead spi_read
#DEFINE mmcIdle() spi_read(0xFF)
BOOL mmcDetect() {
int i;
if(!mmcCardDetect())
return FALSE;
else {
output_high(MMC_CS);
input(MMC_CD);
output_high(MMC_SCLK);
input(MMC_DO);
output_high(MMC_DI);
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H | SPI_SAMPLE_AT_END);
// MMC requires at least 74 clock cycles before starting bus operation.
for(i=0;i<10;i++) {
mmcIdle();
}
}
}
#SEPARATE
BOOL mmcInit() {
int i;
BYTE response;
debug("\n\r[COMMAND] GO_IDLE_STATE");
response=mmcSendCmd(MMC_CMD_GO_IDLE_STATE,0x00000000,0x95);
debug("\n\rResponse=%X\n\r",response);
response=0xFF;
for(i=0;i<10;i++) {
debug("\n\r[COMMAND] SEND_OP_COND");
response=mmcSendCmd(MMC_CMD_SEND_OP_COND,0x00000000,0x01);
debug("\n\rResponse=%X\n\r",response);
if(!response) {
debug("\n\r*** MMC initialisation successful! ***\n\n\r");
mmcIdle();
return TRUE;
}
}
debug("\n\rMMC failed to initialise ...\n\r");
mmcIdle();
return FALSE;
}
int16 mmcGetSector(DWORD address) {
return (address>>9);
}
#SEPARATE
BYTE mmcSendCmd(BYTE cmd,DWORD arg,BYTE crc) {
int i;
BYTE response;
BYTE command[6];
command[5]=cmd;
command[4]=make8(arg,3);
command[3]=make8(arg,2);
command[2]=make8(arg,1);
command[1]=make8(arg,0);
command[0]=crc;
startcmd:
mmcIdle();
output_low(MMC_CS);
for(i=5;i!=0xFF;i--) {
mmcWrite(command[i]);
}
for(i=0;i<8;i++) { // Response time may range from one to 8 byte shifts.
response=spi_read(0xFF);
if((response==0x00) | (response==0x01))
break;
else if(response==0x40) {
debug("\n\rParameter error ...");
//for(i=0;i<50;i++)
// debug("\n\rNext byte : %X",mmcRead(0xFF));
break;
}
else if(response!=0xFF){
debug("\n\rError Dectected ...",response);
mmcDumpResponse(response);
// Ugly way of recovery
for(i=0;i<250;i++)
mmcWrite(0xFF);
output_high(MMC_CS);
goto startcmd;
}
}
if(response==0xFF) {
debug("\n\rResponse Timeout ... \n\r");
output_high(MMC_CS);
return FALSE;
}
switch(cmd) {
case MMC_CMD_GO_IDLE_STATE:
case MMC_CMD_SEND_OP_COND:
case MMC_CMD_SET_BLOCKLEN:
output_high(MMC_CS);
return response;
break;
case MMC_CMD_SEND_CSD:
case MMC_CMD_SEND_CID:
for(i=0;i<8;i++) {
response=mmcRead(0xFF);
if(response!=0xFF)
break;
}
if(response==0xFF) {
debug("\n\rData Timeout ... \n\r");
output_high(MMC_CS);
return FALSE;
}
if(response!=MMCSTARTSINGLEREAD) {
debug("\n\rInvalid Data START Token : %X ...\n\r",response);
output_high(MMC_CS);
return FALSE;
}
return 0;
break;
case MMC_CMD_SEND_STATUS :
response=mmcRead(0xFF);
output_high(MMC_CS);
return response;
break;
case MMC_CMD_READ_SINGLE_BLOCK :
for(i=0;i<250;i++) {
delay_us(100);
response=mmcRead(0xFF);
if(response!=0xFF)
break;
}
if(response==0xFF) {
debug("\n\rData Timeout ... \n\r");
output_high(MMC_CS);
return FALSE;
}
if(response!=MMCSTARTSINGLEREAD) {
debug("\n\rInvalid Data START Token : %X ...\n\r",response);
// Ugly way of recovery
for(i=0;i<250;i++)
mmcWrite(0xFF);
output_high(MMC_CS);
goto startcmd;
}
break;
case MMC_CMD_WRITE_BLOCK :
mmcWrite(0xFF);
mmcWrite(0xFF);
mmcWrite(MMCSTARTSINGLEWRITE);
break;
}
}
void mmcStartSingleRead(DWORD address,DWORD length) {
mmcSetBlockLength(length);
mmcSendCmd(MMC_CMD_READ_SINGLE_BLOCK,address,0x01);
}
void mmcEndSingleRead() {
mmcRead(0xFF); // 16-bit CRC ignored.
mmcRead(0xFF);
output_high(MMC_CS);
}
void mmcStartSingleWrite(WORD sector,BOOL useBuffer) {
int16 i;
DWORD address;
address=(int32)sector*512;
if(useBuffer) {
mmcStartSingleRead(address,512);
for(i=0;i<512;i++)
mmcWriteBuffer[i]=mmcRead(0xFF);
mmcEndSingleRead();
}
else
mmcSetBlockLength(512);
mmcSendCmd(MMC_CMD_WRITE_BLOCK,address,0x01);
}
void mmcEndSingleWrite(BOOL useBuffer) {
int16 i;
BYTE response;
if(useBuffer) {
for(i=0;i<512;i++)
mmcWrite(mmcWriteBuffer[i]);
}
mmcWrite(0x00); // 16-bit CRC ignored.
mmcWrite(0x00);
response=mmcRead(0xFF) & 0x0E;
if(response!=MMCDATAOK) {
debug("\n\rErroroneous Data Response -> ");
if(response==MMCCRCERROR)
debug("CRC Error ...");
else if (response==MMCWRITEERROR)
debug("MMC Write Error ...");
else
debug("Unexpected Data Response : %X",response);
}
while(!mmcRead(0xFF)); // Loop till MMC no longer returns busy signal
output_high(MMC_CS);
delay_us(100);
}
void mmcSetBlockLength(DWORD length) {
mmcSendCmd(MMC_CMD_SET_BLOCKLEN,length,0x01);
}
void mmcWriteSingleByte(DWORD address,BYTE data) {
mmcStartSingleWrite(mmcGetSector(address),TRUE);
mmcWriteBuffer[address & 0x000001FF]=data;
mmcEndSingleWrite(TRUE);
}
BYTE mmcReadSingleByte(DWORD address) {
BYTE data;
mmcSetBlockLength(1);
mmcSendCmd(MMC_CMD_READ_SINGLE_BLOCK,address,0x01);
data=mmcRead(0xFF);
mmcRead(0xFF); // 16-bit CRC ignored.
mmcRead(0xFF);
output_high(MMC_CS);
return data;
}
void mmcDumpResponse(BYTE response) {
debug("\n\rDumping R1 Response");
debug("\n\r===================");
debug("\n\rReserved : %D",bit_test(response,7));
debug("\n\rParameter Error : %D",bit_test(response,6));
debug("\n\rAddress Error : %D",bit_test(response,5));
debug("\n\rErase_Seq_Error : %D",bit_test(response,4));
debug("\n\rCom CRC Error : %D",bit_test(response,3));
debug("\n\rIllegal Command : %D",bit_test(response,2));
debug("\n\rErase Reset : %D",bit_test(response,1));
debug("\n\rIn Idle State : %D",bit_test(response,0));
}
#SEPARATE
void mmcDumpCSD() {
int i;
BYTE reg[16];
debug("\n\r[COMMAND] SEND_CSD");
mmcSendCmd(MMC_CMD_SEND_CSD,0x00000000,0x01);
for(i=15;i!=0xFF;i--)
reg[i]=mmcRead(0xFF);
output_high(MMC_CS);
debug("\n\rCard Specific Data (CSD) Register");
debug("\n\r=================================");
debug("\n\rCSD_STRUCTURE : %X",(reg[15]&0xC0)>>6);
debug("\n\rSPEC_VERS : %X",(reg[15]&0x3C)>>2);
debug("\n\rReserved : %X",reg[15]&0x03);
debug("\n\rTAAC : %X",reg[14]);
debug("\n\rNSAC : %X",reg[13]);
debug("\n\rTRAN_SPEED : %X",reg[12]);
debug("\n\rCCC : %X%X",(reg[11]&0xF0)>>4,((reg[11]&0x0F)<<4)+((reg[10]&0xF0)>>4));
debug("\n\rREAD_BL_LEN : %X",reg[10]&0x0F);
debug("\n\rREAD_BL_PARTIAL : %X",(reg[9]&0x80)>>7);
debug("\n\rWRITE_BLK_MISALIGN : %X",(reg[9]&0x40)>>6);
debug("\n\rREAD_BLK_MISALIGN : %X",(reg[9]&0x20)>>5);
debug("\n\rDSR_IMP : %X",(reg[9]&0x10)>>4);
debug("\n\rReserved : %X",(reg[9]&0x0C)>>2);
debug("\n\rC_SIZE : %X%X",((reg[9]&0x03)<<2)+((reg[8]&0xC0)>>6),((reg[8]&0x3F)<<2)+((reg[7]&0xC0)>>6));
debug("\n\rVDD_R_CURR_MIN : %X",(reg[7]&0x38)>>3);
debug("\n\rVDD_R_CURR_MAX : %X",reg[7]&0x07);
debug("\n\rVDD_W_CURR_MIN : %X",(reg[6]&0xE0)>>5);
debug("\n\rVDD_W_CURR_MAX : %X",(reg[6]&0x1C)>>2);
debug("\n\rC_SIZE_MULT : %X",((reg[6]&0x03)<<1)+((reg[5]&0x80)>>7));
debug("\n\rSECTOR_SIZE : %X",(reg[5]&0x7C)>>2);
debug("\n\rERASE_GRP_SIZE : %X",((reg[5]&0x03)<<3)+((reg[4]&0xE0)>>5));
debug("\n\rWP_GRP_SIZE : %X",reg[4]&0x1F);
debug("\n\rWP_GRP_ENABLE : %X",(reg[3]&0x80)>>7);
debug("\n\rDEFAULT_ECC : %X",(reg[3]&0x60)>>5);
debug("\n\rR2W_FACTOR : %X",(reg[3]&0x1C)>>2);
debug("\n\rWRITE_BL_LEN : %X",((reg[3]&0x03)<<2)+((reg[2]&0xC0)>>6));
debug("\n\rWRITE_BL_PARTIAL : %X",(reg[2]&0x20)>>5);
debug("\n\rReserved : %X",reg[2]&0x1F);
debug("\n\rFILE_FORMAT_GROUP : %X",(reg[1]&0x80)>>7);
debug("\n\rCOPY : %X",(reg[1]&0x40)>>6);
debug("\n\rPERM_WRITE_PROTECT : %X",(reg[1]&0x20)>>5);
debug("\n\rTMP_WRITE_PROTECT : %X",(reg[1]&0x10)>>4);
debug("\n\rFILE_FORMAT : %X",(reg[1]&0x0C)>>2);
debug("\n\rECC : %X",reg[1]&0x03);
debug("\n\rCRC : %X",(reg[0]&0xFE)>>1);
debug("\n\rReserved : %X",reg[0]&0x01);
debug("\n\r");
}
#SEPARATE
void mmcDumpCID() {
int i;
BYTE reg[16];
debug("\n\r[COMMAND] SEND_CID");
mmcSendCmd(MMC_CMD_SEND_CID,0x00000000,0x01);
for(i=15;i!=0xFF;i--)
reg[i]=mmcRead(0xFF);
output_high(MMC_CS);
debug("\n\rCard Identification Register(CID)");
debug("\n\r=================================");
debug("\n\rManuafacturer ID (MID) : %X%X%X",reg[15],reg[14],reg[13]);
debug("\n\rProduct Name (PNM) : %C%C%C%C%C%C%C",reg[12],reg[11],reg[10],reg[9],reg[8],reg[7],reg[6]);
debug("\n\rProduct Revision (PRV) : %D.%D",(reg[5]&0xF0)>>4,reg[5]&0x0F);
debug("\n\rSerial number (PSN) : %X%X%X",reg[4],reg[3],reg[2]);
debug("\n\rManufacturing Date Code (MDT) : %D/%D",(reg[1]&0xF0)>>4,reg[1]&0x0F);
debug("\n\rCRC7 checksum (CRC7) : %X",(reg[0]&0xFE)>>1);
debug("\n\rReserved : %X",reg[0]&0x01);
debug("\n\r");
}
BYTE mmcGetStatus() {
BYTE status;
debug("\n\r[COMMAND] SEND_STATUS");
status=mmcSendCmd(MMC_CMD_SEND_STATUS,0x00000000,0x01);
debug("\n\rSTATUS Register");
debug("\n\r===============");
debug("\n\rOut of Range, CSD_Overwrite : %D",bit_test(status,7));
debug("\n\rErase Param : %D",bit_test(status,6));
debug("\n\rWP Violation : %D",bit_test(status,5));
debug("\n\rCard ECC Failed : %D",bit_test(status,4));
debug("\n\rCC Error : %D",bit_test(status,3));
debug("\n\rError : %D",bit_test(status,2));
debug("\n\rWP Erase Skip, Lock/Unlock Cmd Failed : %D",bit_test(status,1));
debug("\n\rCard is Locked : %D",bit_test(status,0));
debug("\n\r");
return status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -