原创 基于ARM含SD控制器的SD卡的SDIO模式驱动解析

2009-5-31 19:40 7890 11 14 分类: MCU/ 嵌入式

SD卡由日本松下东芝及美国SanDisk公司于19998月共同开发研制。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


SD卡的结构能保证数字文件传送的安全性,也很容易重新格式化,因此越来越多的被应用的嵌入式系统中。


SD卡的使用非常方便,常见的有两种工作模式:SPISDIOSPI是串行的工作模式,速度相对较低,但是使用方便,只要MCU含有SPI接口均可使用。SDIO模式,可以最多4线传输,因此速度比较快,由于SD卡的普及,越来越多的MCU内部集成了SDIO控制器,简化了我们的工作。本文以三星s<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />3c2410为例介绍。


 


1.    SD卡的接口电路


279b8108-2756-43af-bf54-aa45ee6ef701.JPG


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />


2.    SD卡的协议


SD卡的控制指令非常强大,支持SPI,SDIO模式,兼容MMC等。而且不同的


指令有不同的响应(3种),这在我们使用指令是要注意的。我在附件里面放了一个SD卡的中文协议,包括数据包介绍,指令索引介绍,反馈介绍等。


 


3.    S3C2410 SD卡控制器的介绍


SD卡控制器帮我们完成了协议上的很多工作,我们只需要按照协议配置寄存器


以及按照协议流程对SD卡操作就可以完成SD卡的功能了。


   SDICON:完成SD卡基础配置,包括大小端,中断允许,模式选择,时钟使能等。


   SDIPRE:对SDCLK的配置。


   SDICARG:指令的参数存放在这里


   SDICCON:控制指令形式的寄存器,配置SPI还是SDI指令,指令的反馈长度,是否等待反馈,是否运行指令,指令的索引等


   SDICSTA:指令状态寄存器,指令是否超时,传送,结束,CRC是否正确等


   SDIRSPO:反映SD的状态


   SDITIMER:设置超时时间


   SDIBSIZEblock的大小


   SDIDCON:数据控制寄存器,配置是几线传输,数据发送方向,数据传送方式等。


   SDIDSTA 数据状态寄存器,数据是否发送完,CRC效验,超时等


   SDIFSTA FIFO状态积存器,DMA传输时否判断FIFO


   SDIMSK:中断屏蔽


 


4.    SDSDIO模式的驱动分析


4.1 SD卡的初始化


步骤是:1)配置时钟,慢速一般为400K,设置工作模式


        2)发送CMD0,进入空闲态,该指令没有反馈


        3)发送CMD55+ACMD41,判断SD卡的上电是否正确,短反馈


        4)发送CMD2,验证SD卡是否接入,长反馈


        5)发送CMD3,读取SD卡的RCA(地址),短反馈


        6)发送CMD7,使能SD


        7)配置高速时钟,准备数据传输,一般20M25M


        8)发送CMD55+ACMD6配置为4bit数据传输模式


 


代码如下:


int SD_card_init(void)


{


    int i;


    char key;


    rSDIPRE=PCLK/(2*INICLK)-1;        //时钟 400KHz


    rSDICON=(1<<4)|(1<<1)|1;               // Type B, FIFO reset, clk enable


    rSDIBSIZE=0x200;                    // 512byte(128word)


    rSDIDTIMER=0xffff;                        // Set timeout count


 


    for(i=0;i<0x1000;i++);                // Wait 74SDCLK for MMC card


 


    CMD0();                           //进入idle


                                      //-- CheckSD card OCR


    if(Chk_SD_OCR())                  //发送AM41,判断电压正确否


        ;


    else


    {


      ;


        return 0;


    }


 


RECMD2:


rSDICARG=0x0;                     


 // CMD2(stuff bit),判断连接


rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42; 


//lng_resp, wait_resp, start, CMD2


    //-- Check end of CMD2


if(!Chk_CMDend(2, 1))                //查询反馈是否正确


 


goto RECMD2;


   


RECMD3:


    //--Send RCA,得到SD卡的地址


rSDICARG=MMC<<16;                        


// CMD3(MMC:Set RCA, SD:Ask RCA-->SBZ)


rSDICCON=(0x1<<9)|(0x1<<8)|0x43;          


// sht_resp, wait_resp, start, CMD3


 


    //-- Check end of CMD3


    if(!Chk_CMDend(3, 1))


goto RECMD3;


    //--Publish RCA


   


RCA=( rSDIRSP0 & 0xffff0000 )>>16;


   


    //--State(stand-by) check


if( rSDIRSP0 & 0x1e00!=0x600 )           


  // CURRENT_STATE check  验证反馈


goto RECMD3;


  


   


rSDIPRE=PCLK/(2*NORCLK)-1;                    


// 设置高速时钟Normal clock="25MHz"


    Card_sel_desel(1);              // Select SD


   Set_4bit_bus();             //设置为4bit模式


}


 


void Set_4bit_bus(void)


{


    Wide=1;


    SetBus();


}


void SetBus(void)


{


SET_BUS:


    CMD55();                                        


// Make ACMD


    //-- CMD6 implement


    rSDICARG=Wide<<1;                         


      //Wide 0: 1bit, 1: 4bit


    rSDICCON=(0x1<<9)|(0x1<<8)|0x46;             


   //sht_resp, wait_resp, start, CMD55


    if(!Chk_CMDend(6, 1))                   // ACMD6


     goto SET_BUS;


   


}


 


4.2SD卡的读与写


读写就是正反向的问题,这里只分析读


步骤:1)读单block CMD17 block CMD18


       (写单block CMD24 block CMD25


      2)发送CMD12,终止数据传输


 


程序如下:采用DMA模式


void Rd_Block(void)


{


    int status;


    rd_cnt=0;   


    rSDICON |= rSDICON|(1<<1);          // FIFO reset


    rSDICARG=0x0;                      // CMD17/18(addr参数)


RERDCMD:


          pISR_DMA0=(unsigned)DMA_end;   //DMA的相关配置


          rINTMSK = ~(BIT_DMA0);


          rDISRC0=(int)(SDIDAT);               // SDIDAT


          rDISRCC0=(1<<1)+(1<<0);             // APB, fix


          rDIDST0=(U32)(Rx_buffer);            // Rx_buffer


          rDIDSTC0=(0<<1)+(0<<0);              // AHB, inc


          rDCON0=(1<<31)+(0<<30)+(1<<29)+(0<<28)+(0<<27)+(2<<24)+(1<<23)+(1<<22)+(2<<20)+128*block;


  //handshake, sync PCLK, TC int, single tx, single service, SDI, H/W request,


//auto-reload off, word, 128blk*num


          rDMASKTRIG0=(0<<2)+(1<<1)+0;                  


//no-stop, DMA2 channel on, no-sw trigger


 


          rSDIDCON=(1<<19)|(1<<17)|(Wide<<16)|(1<<15)|(2<<12)|(block<<0);


            // Rx after rsp, blk, 4bit bus, dma enable, Rx start, blk num


          if(block<2)                                          // SINGLE_READ


          {


           rSDICCON=(0x1<<9)|(0x1<<8)|0x51;      


          // sht_resp, wait_resp, dat, start, CMD17


           if(!Chk_CMDend(17, 1))                        


     //-- Check end of CMD17


               goto RERDCMD;      


          }


          else                           // MULTI_READ


          {


           rSDICCON=(0x1<<9)|(0x1<<8)|0x52;              


  // sht_resp, wait_resp, dat, start, CMD18


           if(!Chk_CMDend(18, 1))                           


      //-- Check end of CMD18


               goto RERDCMD;


          }


          while(!TR_end);


           rINTMSK |= (BIT_DMA0);


          TR_end=0;


          rDMASKTRIG0=(1<<2);                 //DMA0 stop


          break;


      default:


          break;


    }


    //-- Check end of DATA


    if(!Chk_DATend())


      ;


    rSDIDSTA=0x10;                     // Clear data Tx/Rx end


 


    if(block>1)


    {


RERCMD12:   


      //--Stop cmd(CMD12)


      rSDICARG=0x0;                           //CMD12(stuff bit)


      rSDICCON=(0x1<<9)|(0x1<<8)|0x4c;          


  //sht_resp, wait_resp, start, CMD12


      //-- Check end of CMD12


      if(!Chk_CMDend(12, 1))


          goto RERCMD12;


          }


}


 


4.3上面用到的响应判断函数


 


主要完成对反馈状态的分析。


函数如下:


 


int Chk_CMDend(int cmd, int be_resp)         //指令反馈判断函数


{


    int finish0;


    if(!be_resp)                              // No response


    {


        finish0=rSDICSTA;


      while((finish0&0x800)!=0x800)             // 验证指令是不是发送


          finish0=rSDICSTA;


      rSDICSTA=finish0;                        // Clear cmd end state


      return 1;


    }


    else                                     // With response


    {


        finish0=rSDICSTA;


  while( !( ((finish0&0x200)==0x200) | ((finish0&0x400)==0x400) ))       


   // 验证反馈响应完成


            finish0=rSDICSTA;


 


      if(cmd==1 | cmd==9 | cmd==41)                 // CRC no check


      {


          if( (finish0&0xf00) != 0xa00 )            // CRC是否错误


          {


           rSDICSTA=finish0;                    // Clear error state


 


           if(((finish0&0x400)==0x400))          // 验证超时


 


               return 0;                                 }


          rSDICSTA=finish0;                        


 // Clear cmd & rsp end state


      }


      else                                        // CRC check


      {


          if( (finish0&0x1f00) != 0xa00 )            // Check error


          {


           ;


           rSDICSTA=finish0;                   // Clear error state


 


           if(((finish0&0x400)==0x400))


               return 0;                        // Timeout error


            }


          rSDICSTA=finish0;


      }


      return 1;


    }


}


 


int Chk_DATend(void)


{


    int finish;


 


    finish=rSDIDSTA;


    while( !( ((finish&0x10)==0x10) | ((finish&0x20)==0x20) ))    


                                                      // Chek timeout or data end


      finish=rSDIDSTA;


 


    if( (finish&0xfc) != 0x10 )


    {


       


        rSDIDSTA=0xec;                              // Clear error state


        return 0;


    }


    return 1;


}


 


int Chk_BUSYend(void)              //数据反馈判断函数


{


    int finish;


    finish=rSDIDSTA;


    while( !( ((finish&0x08)==0x08) | ((finish&0x20)==0x20) ))


      finish=rSDIDSTA;             //等待数据发送完成或超时


 


    if( (finish&0xfc) != 0x08 )


    {


        rSD


IDSTA=0xf4;         //clear error state


        return 0;


    }


    return 1;


}


 


 


 


rar


 
PARTNER CONTENT

文章评论3条评论)

登录后参与讨论

用户401565 2012-10-20 17:00

很好

用户539229 2009-6-7 19:36

我改不过来啊。。。。 试了各种颜色,都是这么显示。。。 怎么该啊?

用户789309 2009-6-5 21:25

颜色不好
相关推荐阅读
用户539229 2010-01-23 22:52
vmware下debian5的安装配置以及vmtools的安装使用
一.安装vmware6.5.21.下载vmware6.5.2http://4.scdx3.crsky.com/software/vmware_652.rar2.下载vmware6.5.2汉化包http...
用户539229 2009-12-29 12:57
最新诺基亚Qt4.6的上下位机移植手记,触摸屏支持
一.PC for Winxp下的开发环境的搭建诺基亚收购Qt以后,开发了自己的集成开发环境Qt Creater。这是一个非常强大的工具,上手也很快。登陆:http://qt.nokia.com/dow...
用户539229 2009-12-11 20:14
Omap3evm下android开发第一例hello下位机运行实践
1.       驱动的安装<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 1.1...
用户539229 2009-12-09 19:01
android的windows下开发环境的搭建与hello第一例
Android的SDK的官方网址如下官方网址:http://androidappdocs.appspot.com/sdk/index.html<?xml:namespace prefix = o...
用户539229 2009-11-28 13:21
Omap3下Goole的Android操作系统的实现 相当于山寨智能机啦
首先要有一个:OMAP3EVM平台的开发板 我用的是OMAP35x的TI的评估板还要有一个SD卡 TI花了很大的功夫打造了OMAP3智能手机开发平台,给用户提供了SDK包,GDK包,以及双核的Davi...
用户539229 2009-11-08 19:50
OMAP35x下OneNand的分析以及x-loader的介绍
OMAP35x下OneNand的分析以及x-loader的介绍<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:...
EE直播间
更多
我要评论
3
11
关闭 站长推荐上一条 /3 下一条