[牛人杂谈] SD卡操作

[复制链接]
1444|24
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:25 | 显示全部楼层 |阅读模式
SD 卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪**器的新一代**设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。SD 卡由日本松下、东芝及美国 SanDisk公司于 1999 年 8 月共同开发研制。大小犹如一张邮票的 SD **卡,重量只有 2 克,但却拥有高**容量、快速数据传输率、极大的移动灵活性以及很好的安全性。SD 卡 在 24mm×32mm×2.1mm 的 体 积 内 结 合 了 快 闪 记 忆 卡 控 制 器 与 MLC(Multilevel Cell)技术和 Toshiba(东芝)NAND 芯片技术,通过 9 针的接口界面与专门的驱动器相连接,不需要额外的电源来保持其上**的信息。而且它是一体化固体介质,没有任何移动部分,所以不用担心机械运动的损坏。 248525dadb1d3a96b7.png

 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:26 | 显示全部楼层
内部单元
SD 卡上所有单元(如图 28.1.2)由内部时钟发生器提供时钟。接口驱动单元同步外部时钟的 DAT 和 CMD 信号到内部所用时钟。
卡有自己的电源开通检测单元,无需附加的主复位信号来在电源开启后安装卡。它防短路,在带电插入或移出卡时,无需外部编程电压,编程电压在卡内生成。
SD 卡接口控制包括:CMD,CLK,DAT0~DAT3 等引脚,SD 卡支持 SD 模式与 SPI 模式,不同模式下,各引脚不尽相同,如下表。在多张 SD 卡连接的设备中,为了标识单独的 SD 卡,其内部的卡标识寄存器(CID:Card Identification)和相应地址寄存器(RCA:Relative Card Address)预先准备好。 一个附加的寄存器包括不同类型操作参数,这个寄存器叫做 CSD(Card Specific Data),使用 SD 卡线访问存储器还是寄存器的通信由 SD 卡标准定义如下表
411765dadb1f9d7a40.png

 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:26 | 显示全部楼层
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:26 | 显示全部楼层
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:27 | 显示全部楼层
SD 卡的指令由 6 个字节组成,字节 1 的最高 2 位固定为 01,低 6 位命令号(比如 CMD16 为 10000 即 16 进制数的 0x10,完整的 CMD16,第一个字节为 01010000,即 0x10+0x40)。
字节 2~5 为命令参数,有些命令没有参数。
字节 6 的高七位为 CRC 值,最低位恒定为 1。
SD 卡的命令总共有 12 类,分为 Class0~Class11,本章,我们仅介绍几个重要的命令。
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:27 | 显示全部楼层
718045dadb23ce82ae.png
431785dadb248256b9.png
上表中,大部分的命令是初始化的时候用到的,表中的 R1、R3、R7 等是 SD 卡的回应,SD 卡和单片机的通信采用发送应答机制。
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:28 | 显示全部楼层
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:28 | 显示全部楼层
每发送一个命令,SD 卡都会发出一个应答,以告知主机该命令的执行情况,或是主机需要获取的数据。SPI 模式下,SD 卡针对不同的命令,应答可以是 R1~R7,R1 的应答,各位描述如下表所示:
551465dadb27b98d22.png
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:28 | 显示全部楼层
R2~R7 的响应,我们就不介绍了,大家可以参考 SD 卡 2.0 的协议,接下来,我们看看 SD 卡初始化过程。因为我们使用的是 SPI 模式,所以先得让 SD 卡进入 SPI 模式。方法如下:在 SD 卡收到复位命令(CMD0)时,CS 为有效电平(低电平)则 SPI 模式被启用。不过在发送 CMD0 之前,要发送至少 74 个时钟信号,这是因为 SD 卡内部有个供电电压上升时间,大概为 64 个时钟,剩下的10 个时钟用于 SD 卡同步,之后才能开始 CMD0 的操作,在卡初始化的时候,CLK 时钟最大不能超过 400Khz!
接着我们看看 SD 卡的初始化,SD 卡的典型初始化过程如下:
1、初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置,IO 口配置);
2、上电延时(>74 个时钟);
3、复位卡(CMD0),进入 IDLE 状态,设置为 SPI 模式,无须 CRC 校验;
4、发送 CMD8,检查是否支持 2.0 协议;
5、根据不同协议检查 SD 卡(命令包括:CMD55、CMD41、CMD58 和 CMD1 等);
6、取消片选,发 8 个时钟,结束初始化
这样我们就完成了对 SD 卡的初始化,注意末尾发送的 8 个时钟是提供 SD 卡额外的时钟,完成某些操作。通过 SD 卡初始化,我们可以知道 SD 卡的类型(V1、V2、V2HC 或者 MMC),在完成了初始化之后,就可以开始读写数据了。
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:29 | 显示全部楼层
SD 卡读取数据,通过 CMD17 来实现,具体过程如下:
1、发送 CMD17;
2、接收卡响应 R1;
3、接收数据起始令牌 0XFE;
4、接收数据;
5、接收 2 个字节的 CRC,如果不使用 CRC,这两个字节在读取后可以丢掉。
6、禁止片选之后,额外发 8 个时钟;
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:29 | 显示全部楼层
SD 卡写入数据,通过 CMD24 来实现,具体过程如下:
1、发送 CMD24;
2、接收卡响应 R1;
3、发送写数据起始令牌 0XFE;
4、发送数据;
5、发送 2 字节的伪 CRC;
6、禁止片选之后,发多 8 个 CLK;
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:29 | 显示全部楼层
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:30 | 显示全部楼层
[1]SD 卡既支持 SDIO 接口,也支持 SPI 接口,M451 只支持 SPI 接口,因此,实验当中只能采用 SPI 接口,SPI 通信我们用回之前学习到的 SPI 接口就可以了。
[2]获取 CID(卡标识别寄存器)时,需要发送指令 10,那么发送命令必需遵循 SD 卡命令传输机制,且每次发送的是 48 位命令,数据格式如下:
479355dadb2e767ab8.png
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:31 | 显示全部楼层
向 SD 卡发送命令时,起始位必须为’0’,第二位为’1’,紧接着就是命令的内容,最后发送的一个字节由 7 位的 CRC 和结束位’1’ 组成。有一点要注意的是,SD 上电后默认为 SD 模式,必须要使用带 CRC 校验的命令,CMD0 让其进入 SPI 模式,进入 SPI 模式之后就无需再用任何带 CRC 校验的命令了,好的,那么现在我们编写简单的发送 SD 卡命令函数,代码如下:
  1. UINT8 SD_SendCmd(UINT8 cmd, UINT32 arg, UINT8 crc)
  2. {
  3. UINT8 r1;
  4. UINT8 Retry=0;
  5. /* 取消上次片选 */
  6. SD_DisSelect();
  7. if(SD_Select())
  8. {
  9. /* 片选失效 */
  10. return 0XFF;
  11. }
  12. /* 分别写入命令 */
  13. SD_SPI_ReadWriteByte(cmd | 0x40); //发送命令,位或 0x40 表示起始位为 0,紧接着发送 1
  14. SD_SPI_ReadWriteByte(arg >> 24); //发送命令内容
  15. SD_SPI_ReadWriteByte(arg >> 16);
  16. SD_SPI_ReadWriteByte(arg >> 8);
  17. SD_SPI_ReadWriteByte(arg);
  18. SD_SPI_ReadWriteByte(crc); //发送 7 位 crc,结束位为 1
  19. /* 等待响应,或超时退出 */
  20. Retry=0X1F;
  21. do
  22. {
  23. r1=SD_SPI_ReadWriteByte(0xFF);
  24. }while((r1&0X80) && Retry--);
  25. /* 返回状态值 */
  26. return r1;
  27. }
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:42 | 显示全部楼层
[3]然后接着如何初始化 SD 卡,流程如下:
 初始化与 SD 卡连接的硬件条件(MCU 的 SPI 配置,IO 口配置);
 上电延时(>74 个 CLK);
 复位卡(CMD0),进入 IDLE 状态,设置为 SPI 模式,无须 CRC 校验;
 发送 CMD8,检查是否支持 2.0 协议;
 根据不同协议检查 SD 卡(命令包括:CMD55、CMD41、CMD58 和 CMD1 等);
 取消片选,额外发送 8 个 CLK,结束初始化
详细流程图如下:
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:42 | 显示全部楼层
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:43 | 显示全部楼层
  1. /****************************************
  2. *函数名称:SD_Initialize
  3. *输 入:无
  4. *输 出:0 -成功
  5. 其他 -失败
  6. *功 能:SD 卡初始化
  7. ******************************************/
  8. UINT8 SD_Initialize(VOID)
  9. {
  10. UINT8 r1; // 存放 SD 卡的返回值
  11. UINT16 retry; // 用来进行超时计数
  12. UINT8 buf[4];
  13. UINT32 i;
  14. /* 初始化 IO */
  15. SD_SPI_Init();
  16. /* 设置到低速模式 */
  17. SD_SPI_SpeedLow();
  18. for(i=0;i<10;i++)
  19. {
  20. /* 发送最少 74 个时钟 */
  21. SD_SPI_ReadWriteByte(0XFF);
  22. }
  23. retry=20;
  24. do
  25. {
  26. /* 进入 IDLE 状态 */
  27. r1=SD_SendCmd(CMD0,0,0x95);
  28. }while((r1!=0X01) && retry--);
  29. /* 默认无卡 */
  30. SD_Type=0;
  31. if(r1==0X01)
  32. {
  33. if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
  34. {
  35. for(i=0;i<4;i++)
  36. {
  37. /* 等待应答 */
  38. buf[i]=SD_SPI_ReadWriteByte(0XFF);
  39. }
  40. /* 卡是否支持 2.7~3.6V */
  41. if(buf[2]==0X01&&buf[3]==0XAA)
  42. {
  43. retry=0XFFFE;
  44. do
  45. {
  46. /* 发送 CMD55 */
  47. SD_SendCmd(CMD55,0,0X01);
  48. /* 发送 CMD41 */
  49. r1=SD_SendCmd(CMD41,0x40000000,0X01);
  50. }while(r1&&retry--);
  51. /* 鉴别 SD2.0 卡版本开始 */
  52. if(retry&&SD_SendCmd(CMD58,0,0X01)==0)
  53. {
  54. for(i=0;i<4;i++)
  55. {
  56. /* 得到 OCR 值 */
  57. buf[i]=SD_SPI_ReadWriteByte(0XFF);
  58. }
  59. /* 检查 CCS */
  60. if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;
  61. else SD_Type=SD_TYPE_V2;
  62. }
  63. }
  64. }
  65. else//SD V1.x/ MMC V3
  66. {
  67. /* 发送 CMD55 */
  68. SD_SendCmd(CMD55,0,0X01);
  69. /* 发送 CMD41 */
  70. r1=SD_SendCmd(CMD41,0,0X01);
  71. if(r1<=1)
  72. {
  73. SD_Type=SD_TYPE_V1;
  74. retry=0XFFFE;
  75. do //等待退出 IDLE 模式
  76. {
  77. /* 发送 CMD55 */
  78. SD_SendCmd(CMD55,0,0X01);
  79. /* 发送 CMD41 */
  80. r1=SD_SendCmd(CMD41,0,0X01);
  81. }while(r1&&retry--);
  82. }
  83. else//MMC 卡不支持 CMD55+CMD41 识别
  84. {
  85. /* MMC V3 */
  86. SD_Type=SD_TYPE_MMC;
  87. retry=0XFFFE;
  88. /* 等待退出 IDLE 模式 */
  89. do
  90. {
  91. /* 发送 CMD1 */
  92. r1=SD_SendCmd(CMD1,0,0X01);
  93. }while(r1&&retry--);
  94. }
  95. if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)
  96. {
  97. /* 错误的卡 */
  98. SD_Type=SD_TYPE_ERR;
  99. }
  100. }
  101. }
  102. /* 取消片选 */
  103. SD_DisSelect();
  104. /* 高速 */
  105. SD_SPI_SpeedHigh();
  106. if(SD_Type)return 0;
  107. if(r1) return r1;
  108. /* 其他错误 */
  109. return 0xAA;
  110. }
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:44 | 显示全部楼层
[4]读取数据
发送命令后向 SD 卡获取数据,SD 卡会自动地向主机端发送令牌 0xFE,当主机验证为 0xFE 过后,同时传入 len 的参数比较固定,例如读取 CSD 寄存器时,len 为 16;若然对某一扇区进行读时,len 为 512,最后发送两个伪 CRC 值表示当前的数据结束,因此函数可以编写如下:
  1. /****************************************
  2. *函数名称:SD_RecvData
  3. *输 入: buf 数据缓存区
  4. len 要读取的数据长度
  5. *输 出: 0 成功;
  6. 其他 失败;
  7. *功 能:从 sd 卡读取一个数据包的内容
  8. ******************************************/
  9. UINT8 SD_RecvData(UINT8*buf,UINT16 len)
  10. {
  11. /* 等待 SD 卡发回数据起始令牌 0xFE */
  12. if(SD_GetResponse(0xFE))
  13. {
  14. return 1;
  15. }
  16. /* 开始接收数据 */
  17. while(len--)
  18. {
  19. *buf=Spi0WriteRead(0xFF);
  20. buf++;
  21. }
  22. /* 下面是 2 个伪 CRC(dummy CRC)*/
  23. SD_SPI_ReadWriteByte(0xFF);
  24. SD_SPI_ReadWriteByte(0xFF);
  25. /* 读取成功 */
  26. return 0;
  27. }

 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:44 | 显示全部楼层
[5]当一切准备就绪后,就是研究如何获取 SD 卡的 CID 和 CSD 信息。CID 寄存器存储了 SD 卡的标识码。每一个卡都有唯一的标识码。CID 寄存器长度为 128 位。主要是获得厂商信息、产品版本等,它的寄存器结构如下:
533305dadb647d90f8.png
 楼主| 天灵灵地灵灵 发表于 2019-10-21 21:45 | 显示全部楼层
MID
8bit 的二进制数,表示卡的制造商。MID 号,由 SD-3C、LLC 组织来控制、定义、以及分配给 SD 卡制造商。这个程序是用来保证 CID 寄存器的唯一性。
OID
2 个字符的 ASCII 码,表明卡的 OEM 和/或者卡的内容(当用于分发媒体的时候)。OID 同样是由 SD-3C、LLC 组织来控制、定义和分配的。也是为了保证 CID 的唯一性注:SD-3C、LLC 授权给厂家来生产或者销售 SD 卡,包含但不限于 Flash 存储,ROM,OTP,RAM 和 SDIO 卡。
SD-3C 是由松下电子工业,SanDisk 公司和东芝公司成立的有限责任公司。
PNM
产品名称,5 个字符的 ASCII 码。
PRV
产品版本,由两个十进制数组成,每个数 4 个 bit,“n.m” ,n 表示大版本号,m 表示小版本号。比如,产品版本号是“6.2”,
那么 PRV =“0110 0010b”。
PSN
序列号,32 位二进制数。
MDT
制造日期由两个 16 进制数组成,一个是 8bit 的年(y),一个是 4bit 的月(m)。
m=bit[11:8],1= 1 月。
n=bit[19:12],0=2000
比如 2001 年 4 月,MDT=“0000 0001 0100”
CRC
7 位 CRC 校验码,CID 内容的校验码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

183

主题

3475

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部