关于DJYOS下SD卡驱动开发详解

王建忠 2011/6/21

1      开发环境及说明

硬件平台:tq2440(CPU: s3c2440)

操作系统:DJYOS1.0.0

1.1    说明

Tq2440开发板用的cpu是S3C2440,由于s3c2440自带SD卡控制器,故我们选择操作SD卡的模式是SD卡模式。对SPI模式的SD卡驱动,这里我就不说明了。等以后在djyos下有移植spi模式的SD卡驱动,我就再写一篇技术文章。

网上关于SD卡得文章非常多,在这里关于SD卡协议等等细节的,我就不介绍了。大家去网上搜索几篇看看,在这里,我就简单介绍一点以及主要还是讲DJYOS下的SD卡驱动。

注意:这文档附带的sd卡驱动,不支持sdv2.0以上的sd卡(即2G以上sd卡不支持)

1.2    SD卡电路图

下面是tq2440开发板上面的SD卡模块电路图。

2      SD卡简介

2.1    SD卡引脚解析

2.2    SD卡命令解析

2.2.1  SD卡的命令格式:

SD卡的指令由6字节(Byte)组成,如下:

Byte1:0 1 x x x x x x(命令号,由指令标志定义,如CMD39为100111即16进制0x27,那么完整的CMD39第一字节为01100111,即0x27+0x40)

Byte2-5:Command Arguments,命令参数,有些命令没有参数

Byte6:前7位为CRC(CyclicRedundacy Check,循环冗余校验)校验位,最后一位为停止位0

2.2.2  SD卡的命令

SD卡命令共分为12类,分别为class0到class11,

不同的SDd卡,主控根据其功能,支持不同的命令集 如下:

Class0 :(卡的识别、初始化等基本命令集)

CMD0:复位SD 卡.

CMD1:读OCR寄存器.

CMD9:读CSD寄存器.

CMD10:读CID寄存器.

CMD12:停止读多块时的数据传输

CMD13:读 Card_Status 寄存器

Class2 (读卡命令集):

CMD16:设置块的长度

CMD17:读单块.

CMD18:读多块,直至主机发送CMD12为止 .

Class4(写卡命令集) :

CMD24:写单块.

CMD25:写多块.

CMD27:写CSD寄存器 .

Class5 (擦除卡命令集):

CMD32:设置擦除块的起始地址.

CMD33:设置擦除块的终止地址.

CMD38: 擦除所选择的块.

Class6(写保护命令集):

CMD28:设置写保护块的地址.

CMD29:擦除写保护块的地址.

CMD30: Ask the card for the status of thewrite protection bits

class7:卡的锁定,解锁功能命令集

class8:申请特定命令集。

class10 -11 :保留

3      Djyos下开发SD卡驱动

Tq2440,自带的sd卡程序。只是从0地址开始。简单的测试,可以读写就行。整个代码比较乱,sd卡驱动接口没有规范好。我在这里,根据DJYOS的需求,将tq2440自带的代码进行修改,变成只支持SD卡驱动,不支持MMC卡驱动。并且提供可以供上层使用的SD卡读写接口。

3.1    SD卡初始化

3.1.1  SD卡初始化流程图

图3-1,是SD卡初始化的流程图。

图3-1 SD卡初始化流程图

3.1.2  Sd卡初始化函数module_init_SD

module_init_SD(),是SD卡模块初始化函数。本函数,在djyos源码main.c文件djy_main()函数中调用。只要被调用了,这个时候上层就可以调用SD卡的读写函数了。

module_init_SD的源码,在3.1.1节的流程图介绍的已经比较清楚了。下面的代码里,也带有详细的注释。就不做很多解释了。下面代码中,有些带有MMC的代码,是因为MMC和SD卡类似,为了以后兼容MMC卡。

int module_init_SD(void)

{

int i;

RCA=0;

MMC=0;

//GPIO初始化

rGPEUP  = 0xf83f;     // SDCMD, SDDAT[3:0] => PU En.

rGPECON = 0xaaaaaaaa;      //SDCMD, SDDAT[3:0]

//设置频率为400KHz

rSDIPRE=cn_pclk/(INICLK)-1;

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

rSDIFSTA=rSDIFSTA|(1<<16);   //YH 040223 FIFO reset

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

rSDIDTIMER=0x7fffff;              // Set timeout count

// Wait 74SDCLK for MMC card

for(i=0;i<0x1000;i++);

//发送命令0,使sd卡进入idle状态

cmd0();

//检查是否是MMC卡,并且设置目标工作电压

//设置MMC,为了以后兼容MMC

if(chk_MMC_OCR())

{

MMC=1;

goto RECMD2;

}

//检查是否是SD卡,并且设置目标工作电压

if(!chk_SD_OCR())

return 0;

RECMD2:

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

rSDICCON=(0x1<<10)|(0x1<<9)|(0x1<<8)|0x42; //lng_resp, wait_resp, start, CMD2

//发送CMD2,获取SD卡身份信息,并且使卡进入identification模式

if(!chk_cmd_end(2, 1))

goto RECMD2;

rSDICSTA=0xa00; // Clear cmd_end(with rsp)

RECMD3:

//--Send RCA

rSDICARG=MMC<<16;           // CMD3(MMC:Set RCA, SD:Ask RCA-->SBZ)

rSDICCON=(0x1<<9)|(0x1<<8)|0x43; // sht_resp, wait_resp, start, CMD3

//发送CMD3,SD卡获取RCA,进入stand_by状态

if(!chk_cmd_end(3, 1))

goto RECMD3;

rSDICSTA=0xa00; // Clear cmd_end(with rsp)

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

rSDIPRE=cn_pclk/(SDCLK)-1;    // Normal clock=25MHz

//--State(stand-by) check

if( rSDIRSP0 & 0x1e00!=0x600 )  // CURRENT_STATE check

goto RECMD3;

card_sel_desel(1);   // Select

set_4bit_bus();

return 1;

}

3.2    SD卡接口

SD卡接口,就是指SD卡得读写函数。在这里,我们将使用读写一扇区,作为对应用层的接口,所以读写SD卡,都是一次性一个扇区的读写。没有精确到某个地址读写。

Tq2440下的SD卡,是直接由CPU控制的。CPU,拥有自己的SD卡控制器。对SD卡读写接口,在这里涉及到一个比较重要的寄存器,对其配置比较多。就是SDI数据控制寄存器(rSDIDCON)。

SD卡读写,基本上都是在该寄存器进行配置,所以配置这个寄存器的时候要特别注意。下面是该寄存器每比特位代表的含义。想看其他更多有关于SD卡控制器的寄存器,请看S3C2440A的芯片资料。

保留 [31:25]

Burst4 enable   [24]    在DMA模式下使能Burst4。仅当数据大小是字时该位被

(Burst4)               置位。0:无效 1:Burst4使能

Data Size       [23:22] 指出用FIFO传输的大小,哪个类型,半字或字。00 = 字节

(DataSize)              传输,01 =半字传输 10 = 字传输, 11 = 保留

SDIO Interrupt  [21]    决定SDIO的中断周期是 2个周期还是外部更多周期,当数据块

Period Type(PrdType)    最后被发送(对SDIO)。0=正好两个周期 1=更多周期(像单周期)

Transmit After  [20]    决定数据传输在响应收到后开始或不开始。0= 在DatMode设置后直接

Response(TARSP)         1= 在响应收到后(假定设置DatMode设为 2b11)

Receive After   [19]    决定数据传输在命令发出后开始或不开始 0= 在DatMode设置后直接

Command(RACMD)          1= 在命令发出后(假定设置DatMode设为2b10)

Busy After      [18]    决定忙接收在命令发出后开始或不开始 0= 在DatMode设置后直接

Command(BACMD)          1= 在命令发出后(假定设置DatMode设为2b01)

Block mode      [17]    数据传输模式 0=流数据传输 1=模块数据传输

(BlkMode)

Wide bus        [16]    决定使能宽总线模式 0:标准总线模式(仅使用SDIDAT[0])

enable(WideBus)         1:宽总线模式(使用SDIDAT[3])

DMA Enable      [15]    使能DMA(当DMA操作完成时,该位应该无效)

(EnDMA)                 0:无效(查询) 1:DMA使能

Data Transfer   [14]    决定数据传输是否开始,该位自动清除。

Start(DTST)             0:数据准备好, 1:数据开始

Data Transfer   [13:12] 决定数据传输的方向 00 =无操作, 01 = 仅忙检测模式

Mode (DatMode)          10 =数据接收模式,11 =数据发送模式

BlkNum          [11:0] 模块数(0~4095),当流模式时不考虑

3.2.1  读一扇区read_one_sector

下面代码,是读一扇区的代码。其实整个代码的核心部分。是上面一开始就说的rSDIDCON寄存器的配置。现在我们就大概的讲一下读一个扇区的过程

1、 复位FIFO

2、 配置rSDIDCON寄存器

(2<<22)|(1<<19)|(1<<17)|(1<<16)|(1<<14)|(2<<12)|(1<<0)

分别代表:使用一字传输、数据传输在命令开始后、使用模块数据传输、使用宽总线模式(使用4个数据地址线引脚)、数据开始,该位自动清零、启动数据接收模式(用户读取SD卡的意思)、模块数为1。

3、 设置sector_addr,这里左移9位。代表的是扇区的意思,扇区是512字节大小(1左移9位,是512)。

4、 通过配置rSDICCON寄存器,开始读取数据。数据是一个字一个字的读。所以512字节,读取128次。

5、 通过chk_dat_end,检查数据是否结束

6、 一些清除操作,见代码

void read_one_sector(u32 sector_addr,unsigned int *buf)

{

unsigned int value;

int status;

rd_cnt=0;

rSDIFSTA=rSDIFSTA|(1<<16);   // FIFO reset

=(2<<22)|(1<<19)|(1<<17)|(1<<16)|(1<<14)|(2<<12)|(1<<0);   //YH 040220

//rSDIDCON,[11:0] 我设置是1,所以这里block_addr,必须是地址,而不是扇区号

//移动9位,512字节。这样,block_addr就变成了"扇区号"了

rSDICARG= sector_addr <<9;      // CMD17/18(addr)

//开始准备读取数据

rSDICCON=(0x1<<9)|(0x1<<8)|0x51;    // sht_resp, wait_resp, dat, start, CMD17

if(!chk_cmd_end(17, 1))       //-- Check end of CMD17

return ;

rSDICSTA=0xa00; // Clear cmd_end(with rsp)

while(rd_cnt<128)  // 128word=512byte

{

if((rSDIDSTA&0x20)==0x20) // Check timeout

{

rSDIDSTA=(0x1<<0x5);  // Clear timeout flag

break;

}

status=rSDIFSTA;

if((status&0x1000)==0x1000)      // Is Rx data?

{

value = rSDIDAT;

byte_conversion(&value,buf);

*buf++;

rd_cnt++;

}

}

//-- Check end of DATA

if(!chk_dat_end())

return ;

rSDIDCON=rSDIDCON&~(7<<12);

rSDIFSTA=rSDIFSTA&0x200;    //Clear Rx FIFO Last data Ready

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

}

3.2.2  写一扇区write_one_sector

下面代码,是写一扇区的代码。写一个扇区的大概过程如下:

1、 复位FIFO

2、 配置rSDIDCON寄存器

(2<<22)|(1<<20)|(1<<17)|(1<<16)|(1<<14)|(3<<12)|(1<<0)

分别代表:使用一字传输、数据传输在命令开始后、使用模块数据传输、使用宽总线模式(使用4个数据地址线引脚)、数据开始,该位自动清零、启动数据发送模式(用户写入SD卡的意思)、模块数为1。

3、 设置sector_addr,这里左移9位。代表的是扇区的意思,扇区是512字节大小(1左移9位,是512)。

4、 通过配置rSDICCON寄存器,开始写入数据。数据是一个字一个字的写入。所以512字节,写入128次。

5、 通过chk_dat_end,检查数据是否结束

6、 一些清除操作,见代码

void write_one_sector(u32 sector_addr,unsigned int *buf)

{

u32 value;

int status;

buf=(u32*)buf;//由于FAT是是以u8传入。不知道上面是否强制转换了

wt_cnt=0;

rSDIFSTA=rSDIFSTA|(1<<16);   // FIFO reset

rSDIDCON=(2<<22)|(1<<20)|(1<<17)|(1<<16)|(1<<14)|(3<<12)|(1<<0);       //YH 040220

//扇区号转为地址,移动9位,是512字节的意思

rSDICARG= sector_addr <<9;          // CMD24/25(addr)

rSDICCON=(0x1<<9)|(0x1<<8)|0x58; //sht_resp, wait_resp, dat, start, CMD24

if(!chk_cmd_end(24, 1))       //-- Check end of CMD24

return;

rSDICSTA=0xa00; // Clear cmd_end(with rsp)

while(wt_cnt<128)

{

status=rSDIFSTA;

if((status&0x2000)==0x2000)

{

byte_conversion(buf,&value);

rSDIDAT=value;

*buf++;

wt_cnt++;

}

}

if(!chk_dat_end())

return;

// Clear Data Transfer mode => no operation,Cleata

//Data Transfer start

rSDIDCON=rSDIDCON&~(7<<12);

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

}

【SD卡】关于DJYOS下SD卡驱动开发详解相关推荐

  1. Linux下Android ADB驱动安装详解

    Developing with cocos2d-x for android on Linux http://blog.plicatibu.com/developing-with-cocos2d-x-f ...

  2. 《Linux设备驱动开发详解 A》一一2.3 接口与总线

    本节书摘来华章计算机出版社<Linux设备驱动开发详解 A>一书中的第2章,第2.3节,作者:宋宝华 更多章节内容可以访问云栖社区"华章计算机"公众号查看.1 2.3 ...

  3. 《Linux设备驱动开发详解(第2版)》隆重出版

    Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图     基本信息 * 作者: 宋宝华       * 出版社:人民邮电出版社     * ISBN:97 ...

  4. linux设备驱动总结,《Linux设备驱动开发详解(第3版)》海量更新总结

    本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 2015.2.26 几乎完成初稿. [F]是修正或升级:[N]是新增知识点:[D]是删除的内容 第1章 <Linux ...

  5. linux设备驱动开发详解 第三版,《Linux设备驱动开发详解(第3版)》进展同步更新...

    2014.8.25 目前初步完成2-11章以及第22章 <Linux设备驱动的调试>,相对于第2版,这几章主要的变更. 本博实时更新<Linux设备驱动开发详解(第3版)>的最 ...

  6. 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)进展同步更新

    本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 目前已经完成稿件. 2015年8月9日,china-pub开始上线预售: http://product.china-pub ...

  7. Linux设备驱动开发详解 第3版 (即 Linux设备驱动开发详解 基于最新的Linux 4 0内核 )前言

    Linux从未停歇脚步.Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核.做技术,从来没有终南捷径,拼的就是坐冷板凳的 ...

  8. linux 设备驱动 ppt,linux设备驱动开发详解讲座ppt

    PPT内容 这是linux设备驱动开发详解讲座ppt下载,主要介绍了设备驱动简介:建立和运行模块:字符驱动:调试技术:并发和竞争:分配内存:硬件通讯:中断处理:块设备驱动,欢迎点击下载. 嵌入式Lin ...

  9. 《linux设备驱动开发详解》笔记——15 linux i2c驱动

    <linux设备驱动开发详解>笔记--15 linux i2c驱动 15.1 总体结构 如下图,i2c驱动分为如下几个重要模块 核心层core,完成i2c总线.设备.驱动模型,对用户提供s ...

最新文章

  1. 大厂技术文档:Redis+Nginx+Spring全家桶+Dubbo精选
  2. Execute permission missing on User-Defined table Type
  3. Linux vim开启/关闭代码着色(高亮显示)
  4. 【AI超级美发师】深度学习算法打造染发特效(附代码)
  5. 牛客网 在线编程 局部最小值位置
  6. 用rollback()VS不用rollback()
  7. 【计算机网络】—— 差错控制(检错编码)
  8. (二十三)Java工具类ToStringBuilder方法详解
  9. python键值对储存数据_python 存储键值对
  10. 宝利通视频会议常见故障
  11. 液晶VGH、 VGL电路解析
  12. Apache Rewrite详细配置与使用说明
  13. 输入法公司Kika完成2.2亿B+轮融资 猎豹移动领投
  14. java muti实现图片上传_MutiFileUpload.java 多文件上传
  15. win10激活错误,软件授权服务报告无法激活计算机怎么办?
  16. 如何使用uni-app做一个音乐播放器
  17. windows IDT
  18. VS2008运行过程中出现regsvr32问题解决方法记录
  19. LED显示按键控制 CT1642、PT6964(1)
  20. 批量部署stg Pool到生产脚本

热门文章

  1. 清华博导的“好学生”自述:我为什么逃离科研,选择去中学当老师!
  2. 「后台列表页设计原则和技巧」
  3. python变量前面加星(*)含义
  4. dz index.php 编写,Thinkphp5.0.24框架开发仿DZ应用平台资源站源码
  5. vxWorks7.0下基于zynq的boot启动程序
  6. Macbook Pro黑屏和装双系统后开机一直卡在加载界面解决方案
  7. pythonppt_python操作ppt下载
  8. BILSTM模型介绍
  9. OO Design Principles(OO设计原则): SOLID
  10. 一个年轻人开始废掉时的三个表现,请保持警惕!!!