您的位置:首页 > 其它

OK6410裸机SD卡驱动程序

2014-03-02 11:20 211 查看
      本人正在学习ARM,采用的是飞凌OK6410开发板,一直在写裸机程序。折腾了一个多月终于把SD卡的驱动写好了,用1G卡测试过了,实现了基本的块读和块写,没有对错误进行处理,请读者自行添加,相信写SD卡驱动的朋友对SD卡及SD卡控制器有了一定的了解,废话少说了,直接上程序,注意的地方我在程序中注明,供大家参考,不对之处还请批评指正,参考了一点三星提供的测试程序,主要是前面控制器配置的内容。

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ARM SD驱动 S3C6410