- 积分
- 28
贡献65
飞刀0 FD
注册时间2013-9-20
在线时间7 小时
扫一扫,手机访问本帖
|
本帖最后由 dragonnk 于 2014-3-2 12:08 编辑
折腾了一个多月终于把SD卡的驱动写好了,用1G卡测试过了,实现了基本的块读和块写,没有对错误进行处理,请读者自行添加,相信写SD卡驱动的朋友对SD卡及SD卡控制器有了一定的了解,废话少说了,直接上程序,注意的地方我在程序中注明,供大家参考。如有疑问可加我QQ:270428231。
unsigned int card_cap; // 标记卡是标准卡还是大容量卡
void sd_delay(void) //延时程序
{
unsigned int i;
for(i=0;i<1000;i++);
}
//发送命令
void sd_send_com(unsigned int com_index,unsigned int arg,unsigned int com_type,unsigned int data_present)
//第一个参数为命令号,第二个参数为参数,第三个参数为手册里COMMAND REGISTER下面那
//个表中五行从上到下的编号,从0开始,第四个参数如命令使用DAT线则为1,否则为0
{
unsigned short int rcom=0;
while(CONTROL4_0&0x01); //-- 等待总线允许发送命令
while(PRNSTS0&0x01); //-- 等待CMD总线允许发送命令
while(PRNSTS0&0x02); //-- 等待DAT总线允许发送命令
if(data_present)
rcom|=0x20;
switch(com_type)
{
case 1:
rcom|=0x9;
break;
case 2:
rcom|=0x2;
break;
case 3:
rcom|=0x1A;
break;
case 4:
rcom|=0x1B;
break;
default:
break;
}
rcom|=(unsigned short int)(com_index<<8);
ARGUMENT0=arg;
CMDREG0=rcom;
sd_delay(); //必须延时,千百次试验的结果,呵呵
if(com_index==8) //CMD8可能有应答,可能没有,所以产生命令超时也返回
{
while(!((NORINTSTS0&0x01)||(ERRINTSTS0&0x01)));
NORINTSTS0=0x01; //等待命令完成并清除
ERRINTSTS0=0x01;
return;
}
if(com_type) //其它命令
{
while(!(NORINTSTS0&0x01));
NORINTSTS0=0x01; //等待命令完成并清除
return;
}
}
//初始化
void sd0_init()
{
unsigned int response=0;
GPGCON=0x2222222;
GPGPUD=0x0; //数据端口设置
SWRST0=0x01; //软件复位
while(SWRST0&0x01);
CLK_SRC|=(3<<18); //SMMC选用外部27M
SPCON|=(0x03<<26);
CONTROL4_0=(0x03<<16); //选择电流驱动能力位9mA :Clock
CONTROL2_0=(0x0<<15)|(0x0<<14)|(0x1<<8)|(2<<4)|3|(8<<24);
//CMD,DAT不要设为由PWRCON控制,SDCD# 不要设为由DAT3控制,原理图中SDCD始终为高
CONTROL3_0=(0<<31)|(0<<23)|(0<<15)|(0<<7); //时钟设置
CLKCON0=0x4001; //选择最低平率 并且开启中断时钟 约200K
while(!(CLKCON0&0x02)); //等待内部时钟稳定
CLKCON0=(CLKCON0|(1<<2)); //开启时钟
TIMEOUTCON0=(TIMEOUTCON0&(0xf<<4))|0xe; //超时时间设置为最大
HOSTCTL0=HOSTCTL0&(~(1<<2));
NORINTSTSEN0=0x7fff; //启动所有中断
sd_delay();
sd_send_com(0,0,0,0);
sd_delay(); //必须延时
sd_send_com(8,0x1aa,3,0);
while(!response)
{
sd_send_com(55,0,3,0);
sd_send_com(41,0x40FF8000,2,0);
response=(RSPREG0_0&(1<<31));
}
card_cap=(RSPREG0_0&(1<<30));
response=0;
sd_send_com(2,0,1,0);
while(response==0)
{
sd_send_com(3,0,3,0);
response=(RSPREG0_0&0xFFFF0000);
}
//sd_send_com(9,response,1,0);
//sd_send_com(4,0x8010000,0,0); //这两处命令根据需要写
sd_send_com(7,response,4,0);
CLKCON0=0x8000; //停止时钟
if(card_cap)
CLKCON0=0x001;
else
CLKCON0=0x101; //开启内部时钟
while(!(CLKCON0&0x02)); //等待内部时钟稳定
CLKCON0=(CLKCON0|(1<<2)); //开启时钟 13.5M
sd_send_com(16,512,3,0);
}
//单块512字节读
void sd_read_single(unsigned int sect_arg,unsigned int *p)
{ //第一个参数为扇区号
unsigned int i;
NORINTSTSEN0=0x33;
BLKSIZE0=0x200;
TRNMOD0=0x10;
if(card_cap)
sd_send_com(17,sect_arg,3,1);
else
sd_send_com(17,sect_arg*512,3,1);
while(!(NORINTSTS0&0x020)); //等待读准备好中断
NORINTSTS0=0x20;
for(i=0;i<128;i++)
{
*p=BDATA0;
p++;
}
while(!(NORINTSTS0&0x02)); //等待传输完成
NORINTSTS0=0x02;
}
//单块512字节写
void sd_write_single(unsigned int sect_arg,unsigned int *p)
{ //第一个参数为扇区号
unsigned int i;
NORINTSTSEN0=0x33;
BLKSIZE0=0x200;
TRNMOD0=0x00;
if(card_cap)
sd_send_com(24,sect_arg,3,1);
else
sd_send_com(24,sect_arg*512,3,1); //等待写准备好中断
while(!(NORINTSTS0&0x010));
NORINTSTS0=0x10;
for(i=0;i<128;i++)
{
BDATA0=*p;
p++;
}
while(!(NORINTSTS0&0x02)); //等待传输完成
NORINTSTS0=0x02;
}
|
|