【SD卡】关于DJYOS下SD卡驱动开发详解
关于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卡驱动开发详解相关推荐
- Linux下Android ADB驱动安装详解
Developing with cocos2d-x for android on Linux http://blog.plicatibu.com/developing-with-cocos2d-x-f ...
- 《Linux设备驱动开发详解 A》一一2.3 接口与总线
本节书摘来华章计算机出版社<Linux设备驱动开发详解 A>一书中的第2章,第2.3节,作者:宋宝华 更多章节内容可以访问云栖社区"华章计算机"公众号查看.1 2.3 ...
- 《Linux设备驱动开发详解(第2版)》隆重出版
Linux设备驱动开发详解(第2版)(前一版狂销3万册,畅销书最新升级) [新品] 点击看大图 基本信息 * 作者: 宋宝华 * 出版社:人民邮电出版社 * ISBN:97 ...
- linux设备驱动总结,《Linux设备驱动开发详解(第3版)》海量更新总结
本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 2015.2.26 几乎完成初稿. [F]是修正或升级:[N]是新增知识点:[D]是删除的内容 第1章 <Linux ...
- linux设备驱动开发详解 第三版,《Linux设备驱动开发详解(第3版)》进展同步更新...
2014.8.25 目前初步完成2-11章以及第22章 <Linux设备驱动的调试>,相对于第2版,这几章主要的变更. 本博实时更新<Linux设备驱动开发详解(第3版)>的最 ...
- 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)进展同步更新
本博实时更新<Linux设备驱动开发详解(第3版)>的最新进展. 目前已经完成稿件. 2015年8月9日,china-pub开始上线预售: http://product.china-pub ...
- Linux设备驱动开发详解 第3版 (即 Linux设备驱动开发详解 基于最新的Linux 4 0内核 )前言
Linux从未停歇脚步.Linus Torvalds,世界上最伟大的程序员之一,Linux内核的创始人,Git的缔造者,仍然在没日没夜的合并补丁,升级内核.做技术,从来没有终南捷径,拼的就是坐冷板凳的 ...
- linux 设备驱动 ppt,linux设备驱动开发详解讲座ppt
PPT内容 这是linux设备驱动开发详解讲座ppt下载,主要介绍了设备驱动简介:建立和运行模块:字符驱动:调试技术:并发和竞争:分配内存:硬件通讯:中断处理:块设备驱动,欢迎点击下载. 嵌入式Lin ...
- 《linux设备驱动开发详解》笔记——15 linux i2c驱动
<linux设备驱动开发详解>笔记--15 linux i2c驱动 15.1 总体结构 如下图,i2c驱动分为如下几个重要模块 核心层core,完成i2c总线.设备.驱动模型,对用户提供s ...
最新文章
- 大厂技术文档:Redis+Nginx+Spring全家桶+Dubbo精选
- Execute permission missing on User-Defined table Type
- Linux vim开启/关闭代码着色(高亮显示)
- 【AI超级美发师】深度学习算法打造染发特效(附代码)
- 牛客网 在线编程 局部最小值位置
- 用rollback()VS不用rollback()
- 【计算机网络】—— 差错控制(检错编码)
- (二十三)Java工具类ToStringBuilder方法详解
- python键值对储存数据_python 存储键值对
- 宝利通视频会议常见故障
- 液晶VGH、 VGL电路解析
- Apache Rewrite详细配置与使用说明
- 输入法公司Kika完成2.2亿B+轮融资 猎豹移动领投
- java muti实现图片上传_MutiFileUpload.java 多文件上传
- win10激活错误,软件授权服务报告无法激活计算机怎么办?
- 如何使用uni-app做一个音乐播放器
- windows IDT
- VS2008运行过程中出现regsvr32问题解决方法记录
- LED显示按键控制 CT1642、PT6964(1)
- 批量部署stg Pool到生产脚本
热门文章
- 清华博导的“好学生”自述:我为什么逃离科研,选择去中学当老师!
- 「后台列表页设计原则和技巧」
- python变量前面加星(*)含义
- dz index.php 编写,Thinkphp5.0.24框架开发仿DZ应用平台资源站源码
- vxWorks7.0下基于zynq的boot启动程序
- Macbook Pro黑屏和装双系统后开机一直卡在加载界面解决方案
- pythonppt_python操作ppt下载
- BILSTM模型介绍
- OO Design Principles(OO设计原则): SOLID
- 一个年轻人开始废掉时的三个表现,请保持警惕!!!