嵌入式爱好者

查看: 9473|回复: 5

[裸机程序] 裸机SD卡驱动程序

[复制链接]

7

主题

15

帖子

28

积分

扫一扫,手机访问本帖
发表于 2014-3-1 21:28:08 | 显示全部楼层 |阅读模式
本帖最后由 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;
}



回复

使用道具 举报

4

主题

36

帖子

71

积分

发表于 2014-3-2 15:14:48 | 显示全部楼层
谢谢分享。楼主辛苦了。
点评回复 支持 反对

使用道具 举报

qm3234 该用户已被删除
发表于 2014-3-3 20:01:31 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
点评回复 支持 反对

使用道具 举报

7

主题

15

帖子

28

积分

 楼主| 发表于 2014-3-3 21:15:51 | 显示全部楼层
不客气,不对之处还请指正!
点评回复 支持 反对

使用道具 举报

110

主题

1358

帖子

1443

积分

A40i/T3/T507/T527通行证i.MX6Q通行证i.MX6UL通行证i.MX8MM通行证i.MX8MP通行证RK3568通行证RK3588通行证RK3399通行证LS1028A通行证G2L通行证LS1012A通行证LS1043A\46A通行证TCU通行证FDU产品通行证FCU1401通行证FCU1301通行证FCU11xx通行证FCU1201通行证FCU2201通行证FCU2301/FCU2302通行证FCU2401通行证5G转接卡通行证FCU3001通行证AM5718通行证Hi3519A通信证AM335x通行证i.MX RT通行证XX18通行证AM62x资料下载FDU070K02\FDU101K02通行证i.MX9352通行证

发表于 2014-3-4 08:37:49 | 显示全部楼层
感谢楼主的分享!!辛苦了!!!
该会员没有填写今日想说内容.
点评回复 支持 反对

使用道具 举报

0

主题

0

帖子

3

积分

发表于 2014-7-3 23:09:50 | 显示全部楼层
楼主,您辛苦了,我想和您了解一下winCE下底层驱动程序的操作流程,和如何去验证驱动.:)
点评回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋| 飞凌嵌入式 ( 冀ICP备12004394号-1 )

GMT+8, 2024-12-21 12:38

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表