📄 mmc.c
字号:
#include<stdio.h>
#include<reg52.h>
#include<intrins.h>
#include<stdlib.h>
#include<ctype.h>
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
#define HIGH 0
#define LOW 1
#define TRUE 1
#define FALSE 0
sbit MCS=P3^4;
sbit MI=P3^3;
sbit MSCK=P1^3;
sbit MO=P1^1;
sbit MGND=P1^2;
void gen_crc7_syndrome_table (void);
void insert_crc7 (unsigned char *path_trace_message);
int crc7_OK (const unsigned char *path_trace_message);
uchar Response(uchar index);
void M_8clock(void);
void clock(void);
bit M_init(void);
bit ReadSec(ulong add);
bit WriteSec(ulong add);
uchar SendCmd(void);
uchar GetResp(void);
uchar GetByte(void);
uchar SendByte(uchar ch);
void M_delay(void);
void putch(uchar ch);
/*SPI常量定义*/
#define GO_IDLE_STATE 0 /*复位*/
#define SEND_OP_COND 1 /*激活卡的初始化过程*/
#define SEND_CSD 9 /*请求被选择的卡以便发送卡特征数据CSD*/
#define SEND_CID 10 /*请求被选择的卡以便发送卡ID*/
#define STOP_TRANSMISSION 12 /*多块读时停止传输*/
#define SEND_STATUS 13 /*请求被选卡发送状态寄存器的内容*/
#define SEND_BLOCKLEN 16 /*选择块长度,以便随后的块命令(读和写)*/
#define READ_SINGLE_BLOCK 17 /*读一块,长度由SEND_BLOCKLEN决定*/
#define READ_MULTIPLE_BLOCK 18 /*从卡连续传输数据块到主机,直到停止命令中断或被请求的数据块数*/
#define WRITE_BLOCK 24 /*写一块,长度由SEND_BLOCKLEN决定*/
#define WRITE_MULTIPLE_BLOCK 25 /*从主机连续传输数据块到卡,直到停止命令中断或被请求的数据块数*/
#define PROGRAM_CSD 27 /*编程CSD的可编程位*/
#define SET_WRITE_PROT 28 /*如果卡有写保护特性,此命令用来设置地址组的写保护位,该特性在CSD中编码(WP_GRP_SIZE)*/
#define CLR_WRITE_PROT 29 /*如果卡有写保护特性,此命令用来清除地址组的写保护位*/
#define SEND_WRITE_PROT 30 /*如果卡有写保护特性,此命令用来请求卡发送写保护位的状态*/
#define TAG_SECTOR_START 32 /*设置擦除组的首扇区的地址*/
#define TAG_SECTOR_END 33 /*设置擦除组的连续范围末扇区的地址,或单扇区的地址*/
#define UNTAG_SECTOR 34 /*从擦除组除去先前被选择的扇区*/
#define TAG_ERASE_GROUP_START 35 /*设置在擦除组内的首扇区的地址*/
#define TAG_ERASE_GROUP_END 36 /*设置在擦除组内的末扇区的地址*/
#define UNTAG_ERASE_GROUP 37 /*除去先前被选择的擦除组*/
#define ERASE 38 /*擦除先前被选的扇区*/
#define LOCK_UNLOCK 42 /*用来设置或复位密码,锁/开锁卡,数据块的长度由SEND_BLOCKLEN定义*/
#define READ_OCR 58 /*读卡中OCR寄存器*/
#define CRC_ON_OFF 59 /*开关CRC参数,1开,0关*/
/*CRC变量定义*/
#define CRC7_POLYNOMIAL 0x89 /* x^7 + x^3 + 1 */
static unsigned char path_trace_message[] = "\200123456789ABCDEF";
static unsigned char crc7_syndrome_table[3];
uchar xdata SecBuf[624]="This is the MMC test!This is the MMC test!This is the MMC test!";
uchar xdata pccommand[6]="";
bit flag=0;
/*硬盘文件分配表*/
//typedef struct
// {uchar boot=0;
// }
/*MMC变量定义*/
typedef struct
{uchar Index;
ulong Address;
uchar Crc;
}type1;
union u1{type1 CmdFormat;
uchar CmdBuf[6];
};
union u1 data Cmd;
int main (void)
{ uchar i,ch;
uint m,n;
ulong address;
bit errorflag=0;
MCS=HIGH;MI=HIGH;MSCK=HIGH;
for (m=0;m<1000;m++)
for (n=0;n<50;n++);
SCON=0x52;
TMOD=0x20;
TH1=0xf3; /*12M 2400*/
TL1=0xf3;
TR1=1;
for (m=0;m<512;m++)
SecBuf[m]=0x23;
putch(1);
errorflag=M_init();
putch(2);
WriteSec(0x100);
putch(3);
// if (errorflag==1)
// {putch(1);
// goto tt;
// }
// errorflag=1; //WriteSec(10);
// if (errorflag==1)
// {putch(2);
// goto tt;
// }
for (m=0;m<512;m++)
SecBuf[m]=0;
//goto scan;
address=0xea00; //0xea00为文件分配表位置;
n=0;
while(n<62720){
mv:goto mz;
for (i=0;i<6;i++) pccommand[i]=i;
address=0;
for (i=6;i>0;i--) {RI=0;while(RI==0);RI=0;
address=address+(ulong)(toint(SBUF));
if (i!=1) address=address<<4;
}
goto mz;
TI=0;
SBUF=(uchar)((address>>24)&0xff);
while(TI==0);TI=0;
TI=0;
TI=0;
SBUF=(uchar)((address>>16)&0xff);
while(TI==0);TI=0;
TI=0;
TI=0;
SBUF=(uchar)((address>>8)&0xff);
while(TI==0);TI=0;
TI=0;
TI=0;
SBUF=(uchar)((address)&0xff);
while(TI==0);TI=0;
TI=0;
goto mv;
mz:
errorflag=ReadSec(address); /*bit31--bit9:为扇区地址,bit8--bit0:为扇区内字节首地址*/
for (m=0;m<208;m++)
{TI=0;
SBUF=SecBuf[m];
while(TI==0);TI=0;}
i=0;
while(i!=0xd0)
{RI=0;
while(RI==0);
RI=0;i=SBUF;}
for (m=208;m<416;m++)
{TI=0;
SBUF=SecBuf[m];
while(TI==0);TI=0;}
i=0;
while(i!=0xd0)
{RI=0;
while(RI==0);
RI=0;i=SBUF;}
for (m=416;m<624;m++)
{TI=0;
SBUF=SecBuf[m];
while(TI==0);TI=0;}
// RI=0;
// while(RI==0);
// RI=0;
address=address+0x200;
n++;
goto mv;
scan:
/* address=0x27000; n=0x381是时找到led.bin*/
address=0x97200;
n=0;
while(1){
putch((uchar)(n>>8)&0xff);
putch((uchar)(n)&0xff);
errorflag=ReadSec(address);
address=address+0x200;
n++;
for (m=0;m<512;m++)
{if ((SecBuf[m]==0xc2)&&(SecBuf[m+1]==0x91)&&(SecBuf[m+2]==0x12))
{ for (m=0;m<180;m++)
{TI=0;
SBUF=SecBuf[m];
while(TI==0);TI=0;}
RI=0;
while(RI==0);
RI=0;
for (m=181;m<360;m++)
{TI=0;
SBUF=SecBuf[m];
while(TI==0);TI=0;}
RI=0;
while(RI==0);
RI=0;
for (m=361;m<512;m++)
{TI=0;
SBUF=SecBuf[m];
while(TI==0);TI=0;}
RI=0;
while(RI==0);
RI=0;goto lxx;
}
}
lxx:_nop_();
}
}
tt:goto tt;
}
void putch(uchar ch)
{
TI=0;
SBUF=ch;
while(TI==0);TI=0;
}
/*SPI操作程序*/
bit M_init(void)
{uchar i,Res;
bit flaginit=0;
//// MCS=HIGH; /*MCS上升沿*/
for (i=0;i<10;i++) /*发至少74clock*/
//M_8clock();
GetByte(); /*发10个虚拟字节*/
//// MCS=LOW; /*MCS低*/
flaginit=1;
Cmd.CmdFormat.Index=0; /*发送命令0使MMC卡进入SPI模式*/
Cmd.CmdFormat.Address=0;
Cmd.CmdFormat.Crc=0x95 ;
SendCmd();
/* if (SendCmd()==0x01) goto M_initEnd; /*如果响应不等于01则退出!*/
/* if (SendCmd()!=0x01) goto M_initEnd; /*如果响应不等于01则退出!*/
M_init1:
GetByte(); /*8clock*/
Cmd.CmdFormat.Index=1; /*发送命令1(argument 和 CRC 无关紧要)*/
Cmd.CmdFormat.Address=0; /*(OCR电压描绘在SPI模式中不用)*/
Cmd.CmdFormat.Crc=0x95;
Res=(SendCmd())&0x01;
if (Res==1) goto M_init1; /*循环直到响应不等于01*/
/* if (Res==0x01) goto M_init1; /*循环直到响应不等于01*/
//if (Res!=0) flaginit=1;
/* else flaginit=0; /*如果响应不为0则标志位置1*/
flaginit=0;
M_initEnd:
//// MCS=HIGH; /*取消选择 */
GetByte(); /*8colck*/
return(flaginit);
}
bit ReadSec(ulong add)
{uint i;
bit flagread=0;
//// MCS=LOW; /*MCS低 */
Cmd.CmdFormat.Index=16; /*发送命令16选择数据块长度*/
Cmd.CmdFormat.Address=512;
Cmd.CmdFormat.Crc=0;
SendCmd();
Cmd.CmdFormat.Index=17; /*发送读命令17*/
Cmd.CmdFormat.Address=0xEA00; //add;
Cmd.CmdFormat.Crc=0; /*虚拟CRC(在SPI模式中不正常使用)*/
SendCmd();
// if (SendCmd()!=0)
// {flagread=1;goto ReadSecEnd;}
/* else flagread=0; /*如果响应不等于0则标志位置1*/
GetByte(); /*读开始字节0XFE*/
GetResp();
for (i=0;i<512;i++) /*从MMC卡读512字节到缓冲区地址*/
SecBuf[i]=GetByte();
GetByte(); /*读16位校验和并忽略它*/
GetByte();
flagread=0; /*成功操作标志*/
ReadSecEnd: /*退出*/
//// MCS=HIGH;
GetByte();
return(flagread);
}
bit WriteSec(ulong add)
{uint i;
bit flagwrite=0;
//// MCS=LOW; /*MCS低 */
Cmd.CmdFormat.Index=16; /*发送命令16选择数据块长度*/
Cmd.CmdFormat.Address=512;
Cmd.CmdFormat.Crc=0;
SendCmd();
Cmd.CmdFormat.Index=29; /*取消写保护*/
Cmd.CmdFormat.Address=0xEA00;
Cmd.CmdFormat.Crc=0; /*虚拟CRC,在SPI模式中不正常使用*/
SendCmd();
Cmd.CmdFormat.Index=24; /*写数据*/
Cmd.CmdFormat.Address=0xEA00;
Cmd.CmdFormat.Crc=0; /*虚拟CRC,在SPI模式中不正常使用*/
SendCmd();
// if (SendCmd()!=0)
// {flagwrite=1;goto WriteSecEnd;}
/* else flagwrite=0; /*如果响应不等于0则标志位置1*/
SendByte(0xfe); /*开始字节*/
for (i=0;i<512;i++) /*发512字节到MMC卡*/
SendByte(0x33); //SecBuf[i]);
GetByte(); /*发送虚拟16位校验和=FFFFH*/
GetByte();
GetByte(); /*读数据响应字节=xxx00101b,只校验CRC,它不用*/
while (GetByte()==0); /*循环直到不忙,完成一个块写操作需要一些时间*/
flagwrite=0; /*成功操作标志*/
WriteSecEnd:
//// MCS=HIGH;
GetByte();
return(flagwrite);
}
uchar SendCmd(void)
{uchar result;
Cmd.CmdFormat.Index=Cmd.CmdFormat.Index|0x40;
SendByte(Cmd.CmdFormat.Index); /*command index*/
SendByte(Cmd.CmdBuf[1]); /*arg0*/
SendByte(Cmd.CmdBuf[2]); /*arg1*/
SendByte(Cmd.CmdBuf[3]); /*arg2*/
SendByte(Cmd.CmdBuf[4]); /*arg3*/
SendByte(Cmd.CmdFormat.Crc|0x01); /*低位一定要置1,但无关紧要*/
result=GetResp(); /*响应*/
return(result);
}
uchar GetResp(void)
{uchar i,RespData;
i=0;
while (i<64) /*循环至少最大次数64次,8次不够*/
{RespData=GetByte();
if (RespData!=0xff) goto GetRestEnd; /*读响应字节 */
i++; /*当计数未到或响应数据=FFH是循环*/
}
GetRestEnd:
return(RespData);
}
uchar GetByte(void)
{uchar x;
x=SendByte(0xff);
return(x);
}
uchar SendByte(uchar ch)
{uchar i,M_data=0;
MCS=LOW;
ch=~ch;
for (i=0;i<8;i++)
{MSCK=LOW;
MI=(bit)(ch&0x80);
ch=ch<<1;
MSCK=HIGH;
M_data*=2;
if (MO==1) M_data++;
}
MCS=HIGH;
return(M_data);
}
void M_delay(void)
{
_nop_();
}
void M_8clock(void)
{uchar i;
for (i=0;i<8;i++)
{MSCK=HIGH;
M_delay();
MSCK=LOW;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -