SD卡是嵌入式设备中很常用的一种存储设备,体积小,容量大,通讯简单,电路简单所以受到很多设备厂商的欢迎,主要用来记录设备运行过程中的各种信息,以及程序的各种配置信息,很是方便,有这样几点是需要知道的
SD 卡是基于 flash 的存储卡。
SD 卡和 MMC 卡的区别在于初始化过程不同。SD卡并不是我们通常意义上的手机扩展卡,那种卡叫做TF卡,但是通讯以及驱动模式是类似的.
SD 卡的通信协议包括 SD 和 SPI 两类,SD卡上电之后默认处于SD状态。
SD 卡使用卡内智能控制模块进行 FLASH 操作控制,包括协议、安全算法、
数据存取、ECC 算法、缺陷处理和分析、电源管理、时钟管理。这些都不需要用户关系,这是SD卡厂商做的事情
驱动SD卡主要要实现读扇区,写扇区,初始化,获取SD卡相关配置信息这几个就可以了,
另外.SD卡本身只是一种数据介质,它不含有文件系统,文件系统是一种文件的组织格式,是独立于存储介质的一种规范
标准SD卡引脚序列
SD卡引脚功能表
TF卡引脚排序
TF卡引脚功能表
由此可见,TF卡比SD卡少了一个VSS引脚,也就是少了一个供电引脚
另外电路设计时若SD卡使用SPI模式,那么不用的几根数据线应加上上拉电阻,否者会因为这几根数据线的电流震荡引起电流损耗,造成电路上的不稳定
SD卡电路SPI驱动模式
SD卡内部有五个我们可以读取的寄存器,分别如下
要读取这些信息就需要与卡通讯,SD通讯是用命令+数据的形式进行的,命令格式如下
也就是说,一次SD卡命令发送一共要发送6个字节,对于SPI通讯而言,就是SPI总线上传送六个字节
字节 1 的最高 2 位固定为 01,低 6 位为命令号(比如 CMD16,
为 10000 即 16 进制的 0X10,完整的 CMD16,第一个字节为 01010000,即 0X10+0X40)。
字节 2~5 为命令参数,有些命令是没有参数的。对于没有参数的命令默认发送0即可
字节 6 的高七位为 CRC 值,最低位恒定为 1,crc计算遵循以下规律
GX为生成多项式,具体计算方法请查看CRC计算相关,不过有一点好处就是,在SPI驱动模式下,不需要CRC校验(默认SD卡在SPI模式下不开启CRC校验,在SD模式下默认开始CRC校验),所以我们只需要对CMD0进行CRC就可以了,后面的CRC都可以不管(因为在CMD0之前是SD模式,所以第一个命令需要,切换之后就不用了),而CMD0的CRC为0x95(加上了之后的一位1)
注:SPI模式下打开crc校验需要用到CMD59的保留命令,请查阅相关资料
SD卡的命令表如下所示(以下仅写出SPI模式的CMD)
CMD0 复位SD卡, 重置所有卡到 Idle状态,参数为0
CMD1 设置SD卡到ACTIVATE模式,也就是推出IDLE模式
CMD8 发送接口状态命令
CMD9 读取CSD寄存器
CMD10 读取CID寄存器
CMD12 在多块读取的时候请求停止读取
CMD13读取SD卡状态寄存器
CMD16 设置单个扇区的大小一般都设置为512字节一个扇区
CMD17 读取扇区命令
CMD18 读取多个扇区知道发送停止命令
CMD24 写扇区命令
CMD25 写多个扇区命令
CMD27 编辑CSD位
CMD28设置地址组保护位。写保护由卡配置数据的WP_GRP_SIZE 指定
CMD29清除保护位
CMD30 要求卡发送写保护状态,参数中有要查询的地址
CMD32 设置要擦除的第一个写数据块地址
CMD33 设置要擦除的最后一个写数据块地址
CMD38 擦除所有选中的块
CMD42 设置SD卡的解锁或者上锁
CMD55 告诉SD卡下一个命令式卡应用命令,不是标准命令
CMD56 应用相关的数据块读写命令
CMD58 读取OCR信息
CMD59 设置crc校验的使能与关闭(前面说到过)
ACMD13 发送SD卡状态
ACMD18保留作为 SD 安全应用(也就是这命令没用)
ACMD22发送写数据块的数目。响应为 32 位+CRC
ACMD23设置写前预擦除的数据块数目(用来加速多数据块写操作)。“1”=默认(一个块)(1)
不管是否使用 ACMD23,在多数据块写操作中都需要 STOP_TRAN(CMD12)命令
ACMD25 26 38 保留作为安全应用
ACMD41要求访问的卡发送它的操作条件寄存器(OCR)内容
ACMD42连接[1]/断开[0]卡上CD/DAT3(pin 1]的 50K 欧姆上拉电阻。上拉电阻可用来检测卡
ACMD43-49保留作为安全应用
ACMD51读取 SD 配置寄存器 SCR
ACMD命令,全称应该是application CMD,所以使用ACMD都需要在发送CMD55之后
发出命令后会收到相应的响应, 所有响应通过 CMD 线传输,响应以 MSB 开始,不同类型的响应长度根据类型不同而不同。
响应以起始位开始(通常为“0”),接着这是传输方向的位(卡为 0)。除了 R3 外其他
响应都有 CRC。每个响应都以结束位(通常为“1”)结束。,SD卡响应格式有多种
1. R1响应
2. R1b响应
多了一个忙数据
3. R2响应
4. R3响应(针对于read ocr的响应 CMD58)
5. 响应R4和R5都是正对于SD mode的响应
6. 针对CMD8命令的响应R7
SD卡的初始化以及识别过程(为了方便起见,我们只检测响应的R1状态)
1. 初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置,IO 口配置);
2. 上电延时(>74 个 CLK)(为了让卡正常启动)
3. 复位卡(CMD0),进入 IDLE 状态,检测R1的最低位,是否为闲置状态
4. 发送 CMD8,检查是否支持 2.0 协议,因为这个命令是在2.0的协议里面才添加的
5. 根据不同协议检查 SD 卡(命令包括:CMD55、CMD41、CMD58 和 CMD1 等);
6. 取消片选,发多 8 个 CLK,结束初始化
具体请查看下图
以下是网络上找到的一份经我修改之后的SD卡驱动,不完全符合SD卡标准驱动,但是我用着一直还蛮正常,大家有兴趣可以看看改改
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(Cyclic Redundacy Check,循环冗余校验)校验位,最后一位为停止位0
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 the write protection bits
class7:卡的锁定,解锁功能命令集
class8:申请特定命令集 。
class10 -11 :保留
有关sd卡驱动和fat fs的实现用了3个文件来实现。sdboot.c为sd的驱动(可理解为pdd)层,主要实现一些对sd控制器的配置以及一些基本sd命令的实现和对sd 卡的操作。sdmmc.c实现了从sd卡读取nk并跳到内存去运行的代码(基本可以理解为sd驱动的mdd层)。sdfat.c文件就是实现fat fs的。mdd层通过fatfs来对pdd层操作以实现读取文件。
在整个过程中遇到了很多问题,现在列举如下:
1)sd卡初始化问题
配置gpio有关sd的功能:SDCMD, SDDAT[3:0]。
使能CLKCON中的SDI位。
时钟以及计算公式:SDIPRE = PCLK/(CLK)-1;INICLK=300000;SDCLK=24000000; MMCCLK= 15000000
cmd0-cmd55-cmd41-cmd2-cmd3-cmd7-cmd6-cmd17
2)对sd卡操作问题
SD卡包括:一个标识寄存器CID,一个相应地址寄存器RCA,一个其他参数寄存器
CSD。
对sd卡的操作是驱动通过sd controller来发相应的命令以达到读写等操作的:发送命令通过SDICmdCon[7:0]的除了开始2bit:CmdIndex放置要发送的命令号;SDICmdCon[8]开始发送命令来完成的。
检测卡的插入,直接用中断引脚的电平来判断。
判断插入的卡是否是sd卡,用命令cmd55和cmd41,因为mmc卡对cmd55不做回应。
命令9就是获取sd卡中csd寄存器的值的,该值包括很多sd卡的信息,其中就有sd卡的容量。这个值在sd卡接收到cmd9之后会以response的 形式存放在sd控制器的SDI Response Register[0,1,2,3]中。在执行cmd9,cmd10等这样的命令的时候,卡的状态应该是不选中的,或直接在执行它们之前发送 cmd7(0)不选中卡,不然的话会timeout。
用cmd17来读取单个block的数据,该命令要带地址参数(该参数通过cmd3命令来获取),然后根据SDIDSTA和SDIFSTA状态值来从sd 控制器的SDIDAT寄存器中读出要读的数据。该命令与cmd9相反,在执行它之前要选中卡。读完一个block之后要做一些善后工作,为下次读取做好准 备,不然的话checkcmdend就要一直循环了。因为用的是每次都读一个block,并地址要以block对齐,这样就要考虑要读取的地址是否是 block对齐的,长度是否够一个block。
SDIDCON这个数据控制寄存器也很重要,一些对数据的操作形式就是在这里设置的。
3)fat文件系统问题
根据MBR找到分区表,根据分区表找到该分区MBR[446B+4个分区表(每个16B)+2B结束符)
分区表中的第9-12字节为该分区的启始地址(单位没sector),第13-16字节为分区的长度(单位也是sector)
转自http://hjx5548.blog.163.com/blog/static/563676392009111704249875/