免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3147 | 回复: 0
打印 上一主题 下一主题

基于ARM含SD控制器的SD卡的SDIO模式驱动解析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-12 09:57 |只看该作者 |倒序浏览

SD卡由日本
松下

东芝
及美国
SanDisk
公司于1999年8月共同开发研制。
SD卡的结构能保证数字文件传送的安全性,也很容易重新格式化,因此越来越多的被应用的嵌入式系统中。
SD卡的使用非常方便,常见的有两种工作模式:SPI和SDIO。SPI是串行的工作模式,速度相对较低,但是使用方便,只要MCU含有SPI接口均可使用。SDIO模式,可以最多4线传输,因此速度比较快,由于SD卡的普及,越来越多的MCU内部集成了SDIO控制器,简化了我们的工作。本文以三星s3c2410为例介绍。

1.    SD卡的接口电路




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:设置超时时间
   SDIBSIZE:block的大小
   SDIDCON:数据控制寄存器,配置是几线传输,数据发送方向,数据传送方式等。
   SDIDSTA: 数据状态寄存器,数据是否发送完,CRC效验,超时等
   SDIFSTA: FIFO状态积存器,DMA传输时否判断FIFO
   SDIMSK:中断屏蔽

4.    SD卡SDIO模式的驱动分析
4.1 SD卡的初始化
步骤是:1)配置时钟,慢速一般为400K,设置工作模式
        2)发送CMD0,进入空闲态,该指令没有反馈
        3)发送CMD55+ACMD41,判断SD卡的上电是否正确,短反馈
        4)发送CMD2,验证SD卡是否接入,长反馈
        5)发送CMD3,读取SD卡的RCA(地址),短反馈
        6)发送CMD7,使能SD卡
        7)配置高速时钟,准备数据传输,一般20M~25M
        8)发送CMD55+ACMD6配置为4bit数据传输模式

代码如下:
int SD_card_init(void)
{
    int i;
    char key;
    rSDIPRE=PCLK/(2*INICLK)-1;        //时钟 400KHz
    rSDICON=(1               // Type B, FIFO reset, clk enable
    rSDIBSIZE=0x200;                    // 512byte(128word)
    rSDIDTIMER=0xffff;                        // Set timeout count

    for(i=0;i                // Wait 74SDCLK for MMC card

    CMD0();                           //进入idle
                                      //-- Check SD card OCR
    if(Chk_SD_OCR())                  //发送AM41,判断电压正确否
        ;
    else
    {
      ;
        return 0;
    }

RECMD2:
rSDICARG=0x0;                     
// CMD2(stuff bit),判断连接
rSDICCON=(0x1  
//lng_resp, wait_resp, start, CMD2
    //-- Check end of CMD2
if(!Chk_CMDend(2, 1))                //查询反馈是否正确

goto RECMD2;
   
RECMD3:
    //--Send RCA,得到SD卡的地址
rSDICARG=MMC                        
// CMD3(MMC:Set RCA, SD:Ask RCA-->SBZ)
rSDICCON=(0x1           
// 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                          
      //Wide 0: 1bit, 1: 4bit
    rSDICCON=(0x1              
   //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          // FIFO reset
    rSDICARG=0x0;                      // CMD17/18(addr参数)
RERDCMD:
          pISR_DMA0=(unsigned)DMA_end;   //DMA的相关配置
          rINTMSK = ~(BIT_DMA0);
          rDISRC0=(int)(SDIDAT);               // SDIDAT
          rDISRCC0=(1             // APB, fix
          rDIDST0=(U32)(Rx_buffer);            // Rx_buffer
          rDIDSTC0=(0              // AHB, inc
          rDCON0=(1
  //handshake, sync PCLK, TC int, single tx, single service, SDI, H/W request,
//auto-reload off, word, 128blk*num
          rDMASKTRIG0=(0                  
//no-stop, DMA2 channel on, no-sw trigger

          rSDIDCON=(1
            // Rx after rsp, blk, 4bit bus, dma enable, Rx start, blk num
          if(block                                          // SINGLE_READ
          {
           rSDICCON=(0x1      
          // sht_resp, wait_resp, dat, start, CMD17
           if(!Chk_CMDend(17, 1))                        
     //-- Check end of CMD17
               goto RERDCMD;      
          }
          else                           // MULTI_READ
          {
           rSDICCON=(0x1               
  // 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                 //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=(0x14c;           
  //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;
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/49742/showart_1962481.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP