最近在研究STM32F4的SD卡Fatfs文件系统,官方和开发板提供的例程完全可以使用,但是缺少了理论的支持,完全看不懂。所以在网上以及《零死角玩转STM32》上整理了一些SD卡相关的基础知识。
SD卡的分类
目前常用的存储卡按照尺寸可分为SD卡和micro SD卡(TF卡)(其实种类繁多,我只接触过这两种),按照容量可分为标准容量SD(不大于2GB)、高容量SDHC(大于2GB,不大于32GB)和超大容量SDXC(大于32GB,不大于2TB),还可以按照传输速度进行划分,SD2.0规范中分为Class2,Class4,Class6和Class10,SD3.01规范中分为USH-I和USH-II。
其实,了解了SD卡的分类,不同速度等级的应用场景,看懂SD卡上的标识,足可以应付在生活中使用SD卡,例如:行车记录仪要求SD卡的速度等级为Class10。
容量等级 | 容量范围 | 磁盘格式 |
---|---|---|
SD | 上限至2GB | FAT12、FAT16 |
SDHC | 2GB至32GB | FAT32 |
SDXC | 32GB至2TB | exFAT |
速度等级 | 速度(MB/S) | 应用范围 |
---|---|---|
Class 0 | — | 低于Class 2和未标注Speed Class的情况 |
Class 2 | 最低写入2.0 MB/S | 观看普通清晰度电视,数码相机连拍 |
Class 4 | 最低写入4.0 MB/S | 流畅播放高清电视(HDTV),数码相机连拍 |
Class 6 | 最低写入6.0 MB/S | 单反相机连拍,以及专业设备的使用 |
Class 10 | 最低写入10 MB/S | 全高清电视的录制和播放 |
UHS-I | 写入50 MB/S以内,读取104 MB/S以内 | 专业全高清电视实时录制 |
UHS-II | 写入156 MB/S以内,读取312 MB/S以内 | 未来世界 |
SD上常见的标识
SD卡引脚
SD卡有9个引脚,TF卡有8个引脚,引脚顺序是面向卡的引脚,左侧第一个是引脚1,依次类推。
CMD:命令控制线,主机通过该线发送控制命令,SD卡也是通过该线传输应答信息。通过管脚的名称可以看出它的功能,下面简单介绍了一下CMD。
SD分为卡识别阶段和数据传输阶段,两个阶段的时钟是有区别的:
- 识别阶段时钟频率FOD,最高400KHz。
- 数据传输模式时钟频率FPP,默认最高25MHz
SD卡忙状态通过把D0拉低来表示。
SD卡寄存器
SD卡内部共有8个寄存器,必须通过命令来进行访问,SDIO定义了64个访问SD卡的命令。
名称 | Bit宽度 | 描述 |
---|---|---|
CID | 128 | 卡识别号(Card Identification) |
RCA | 16 | 相对卡地址(Relative Card Address) |
DSR | 16 | 驱动级寄存器(Driver Stage Register) |
CSD | 128 | 卡的特定数据(Card Specific Data) |
SCR | 64 | SD配置寄存器(SD Configuration Register) |
OCR | 32 | 操作条件寄存器(Operation Conditions Register) |
SSR | 512 | SD状态寄存器(SD Status) |
CSR | 32 | 卡状态寄存器(Card Status) |
SD卡数据包格式
SD卡有常规数据(8bit)和宽位数据(512bit)两种格式的数据包。它先发低字节再发高字节,而每
个字节则是先发高位再发低位。
SD卡命令
SD命令格式,共计48位。依次为:起始位、传输标志、命令+地址信息/参数、CRC7校验和终止位。
0 | 1 | CONTENT | CRC | 1 |
1 | 1 | 6+32 | 7 | 1 |
SD卡命令类型有四种:
- 无响应广播命令(bc),发送到所有卡,不返回任务响应;
- 带响应广播命令(bcr),发送到所有卡,同时接收来自所有卡响应;
- 寻址命令(ac),发送到选定卡,DAT线无数据传输;
- 寻址数据传输命令(adtc),发送到选定卡,DAT线有数据传输;
在标准中定义了两种类型的通用命令:特定应用命令(ACMD)和常规命令(GEN_CMD)
命令序号 | 类型 | 参数 | 响应 | 缩写 | 描述 |
基本命令(Class 0) | |||||
CMD0 | bc | [31:0]填充位 | — | GO_IDEL_STATE | 复位所有的卡到idle状态 |
CMD2 | bcr | [31:0]填充位 | R2 | ALL_SEND_CID | 通知所有的卡通过CMD线返回CID值。 |
CMD3 | bcr | [31:0]填充位 | R6 | SEND_RELATIVE_ADDR | 通知所有卡发布新RCA。 |
CMD4 | bc | [31:16]DSR[15:0]填充位 | — | SET_DSR | 编程所有卡的DSR。 |
CMD7 | ac | [31:16]RCA[15:0]填充位 | R1b | SELECT/DESELECT_CARD | 选择/取消选择RCA地址卡。 |
CMD8 | bcr | [31:12]保留位 [11:8]VHS [7:0]检查模式 | R7 | SEND_IF_COND | 发送SD卡接口条件,包含主机支持的电压信息,并询问卡是否支持。 |
CMD9 | ac | [31:16]RCA[15:0]填充位 | R2 | SEND_CSD | 选定卡通过CMD线发送CSD内容。 |
CMD10 | ac | [31:16]RCA[15:0]填充位 | R2 | SEND_CID | 选定卡通过CMD线发送CID内容。 |
CMD12 | ac | [31:0]填充位 | R1b | STOP_TRANSMISSION | 强制卡停止传输。 |
CMD13 | ac | [31:16]RCA[15:0]填充位 | R1 | SEND_STATUS | 选定卡通过CMD线发送它状态寄存器 |
CMD15 | ac | [31:16]RCA[15:0]填充位 | — | GO_INACTIVE_STATE | 使选定卡进入“inactive”状态 |
面向块的读操作(Class 2) | |||||
CMD16 | ac | [31:0]块长度 | R1 | SET_BLOCK_LEN | 对于标准SD卡,设置块命令的长度,对于SDHC卡块命令长度固定为512字节。 |
CMD17 | adtc | [31:0]数据地址 | R1 | READ_SINGLE_BLOCK | 对于标准SD卡,读取SET_BLOCK_LEN长度字节的块,对于SDHC卡,读取512字节的块。 |
CMD18 | adtc | [31:0]数据地址 | R1 | READ_MULTIPLE_BLOCK | 连续从SD卡读取数据块,直到被CMD12中断。块长度同CMD17。 |
面向块的写操作(Class 4) | |||||
CMD24 | adtc | [31:0] 数据地址 | R1 | WRITE_BLOCK | 对于标准SD卡,写入SET_BLOCK_LEN长度字节的块,对于SDHC卡,写入512字节的块。 |
CMD25 | adtc | [31:0]数据地址 | R1 | WRITE _ MULTIPLE _BLOCK | 连续向SD卡写入数据块,直到被CMD12中断。块长度同CMD17。 |
CMD27 | adtc | [31:0] 填充位 | R1 | PROGRAM_CSD | 对CSD的可编程位进行编程。 |
擦除命令(Class 5) | |||||
CMD32 | ac | [31:0] 数据地址 | R1 | ERASE_WR_BLK_START | 设置擦除的起始块地址。 |
CMD33 | ac | [31:0]数据地址 | R1 | ERASE_WR_BLK_END | 设置擦除的结束块地址。 |
CMD38 | ac | [31:0] 填充位 | R1b | ERASE | 擦除预先选定的块。 |
加锁命令(Class 7) | |||||
CMD42 | adtc | [31:0]保留 | R1 | LOCK_UNLOCK | 加锁/解锁SD卡。 |
特定应用命令(Class 8) | |||||
CMD55 | ac | [31:16]RCA[15:0]填充位 | R1 | APP_CMD | 指定下个命令为特定应用命令,不是标准命令。 |
CMD56 | adtc | [31:1] 填充位 [0] 读/写 | R1 | GEN_CMD | 通用命令,或者特定应用命令中,用于传输一个数据块,最低位1表示读数据,为0表示写数据。 |
SD卡特定应用命令 | |||||
ACMD6 | ac | [31:2] 填充位 [1:0] 总线宽度 | R1 | SET_BUS_WIDTH | 定义数据总线宽度(‘00’=1bit,‘10’=4bit)。 |
ACMD13 | adtc | [31:0] 填充位 | R1 | SD_STATUS | 发送SD状态. |
ACMD41 | bcr | [31] 保留位 [30] HCS(OCR[30])[29:24] 保留位[23:0]VDD电压(OCR[23:0]) | R3 | SD_SEND_OP_COND | 主机要求卡发送它的支持信息(HCS)和OCR寄存器内容。 |
ACMD51 | adtc | [31:0] 填充位 | R1 | SEND_SCR | 读取配置寄存器SCR. |
响应类型
SD卡有R1、R2、R3、R6、R7这几种响应类型,不同的命令对应的响应类型是不一样的。
R1(正常响应命令) | |||||||||||
描述 | 起始位 | 传输位 | 命令号 | 卡状态 | CRC7 | 终止位 | |||||
Bit | 47 | 46 | [45:40] | [39:8] | [7:1] | 0 | |||||
位宽 | 1 | 1 | 6 | 32 | 7 | 1 | |||||
值 | “0” | “0” | X | X | X | “1” | |||||
备注 | 如果有传输到卡的数据,那么在数据线可能有busy信号。 | ||||||||||
R2(CID、CSD寄存器) | |||||||||||
描述 | 起始位 | 传输位 | 保留 | [127:1] | 终止位 | ||||||
Bit | 135 | 134 | [133:128] | 127 | 0 | ||||||
位宽 | 1 | 1 | 6 | X | 1 | ||||||
值 | “0” | “0” | “111111” | CID或者CSD寄存器[127:1]位的值 | “1” | ||||||
备注 | CID寄存器内容作为CMD2和CMD10响应,CSD寄存器内容作为CMD9响应。 | ||||||||||
R3(OCR寄存器) | |||||||||||
描述 | 起始位 | 传输位 | 保留 | OCR寄存器 | 保留 | 终止位 | |||||
Bit | 47 | 46 | [45:40] | [39:8] | [7:1] | 0 | |||||
位宽 | 1 | 1 | 6 | 32 | 7 | 1 | |||||
值 | “0” | “0” | “111111” | X | “1111111” | “1” | |||||
备注 | OCR寄存器的值作为ACMD41的响应。 | ||||||||||
R6(发布的RCA寄存器响应) | |||||||||||
描述 | 起始位 | 传输位 | CMD3 | RCA寄存器 | 卡状态位 | CRC7 | 终止位 | ||||
Bit | 47 | 46 | [45:40] | [39:8] | [7:1] | 0 | |||||
位宽 | 1 | 1 | 6 | 16 | 16 | 7 | 1 | ||||
值 | “0” | “0” | “000011” | X | X | X | “1” | ||||
备注 | 专用于命令CMD3的响应。 | ||||||||||
R7(发布的RCA寄存器响应) | |||||||||||
描述 | 起始位 | 传输位 | CMD8 | 保留 | 接收电压 | 检测模式 | CRC7 | 终止位 | |||
Bit | 47 | 46 | [45:40] | [39:20] | [19:16] | [15:8] | [7:1] | 0 | |||
位宽 | 1 | 1 | 6 | 20 | 4 | 8 | 7 | 1 | |||
值 | “0” | “0” | “001000” | “00000h” | X | X | X | “1” | |||
备注 | 专用于命令CMD8的响应,返回卡支持电压范围和检测模式。 |
SD卡状态
SD卡的操作模式和状态如下表所示。接下来的两张图片也卡模式和数据传输模式下的状态切换。
操作模式 | SD卡状态 |
---|---|
无效模式(Inactive) | 无效状态(Inactive State) |
卡识别模式(Card identification mode) | 空闲状态(Idle State) |
准备状态(Ready State) | |
识别状态(Identification State) | |
数据传输模式(Data transfer mode) | 待机状态(Stand-by State) |
传输状态(Transfer State) | |
发送数据状态(Sending-data State) | |
接收数据状态(Receive-data State) | |
编程状态(Programming State) | |
断开连接状态(Disconnect State) |
现在就可以通过SD卡的状态、模式、命令、响应等信息来仔细阅读STM32的sdio.c文件了。由于我也不太懂所以,还没有具体的内容来提供。接下来我们去看看SD卡是如何Fatfs关联上的。
文件系统Fatfs
在Fatfs下面有diskio.c这个文件,这个文件中定义了五个接口,被ff.c文件调用,ff.c文件提供了open(),close(),write(),read()等等文件系统常用的接口。Fatfs的移植就是主要是更改diskio.c这个文件,通过五个接口来适配不同的存储介质,如SD卡、U盘、Flash等。
- DSTATUS disk_status (BYTE pdrv);
- DSTATUS disk_initialize ( BYTE pdrv );
- DRESULT disk_read (BYTE pdrv, BYTE *buff,DWORD sector, UINT count );
- DRESULT disk_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
- DRESULT disk_ioctl (BYTE pdrv, BYTE cmd,void *buff );
在这5个接口中,有一个共同的形参pdrv,他就是不同的存储介质SD卡、U盘、Flash。
结语
ST的例程,开发板的例程,我们完全可以拿来稍加修改就可以使用。我们完全可以不明就里的拿来就用,好用就行,能交差就行,但是不明不白的拿来就用使我心里很不舒服,必须简单的弄明白原理,弄清楚结构,这样除了问题也能更快的定位。上面写了那么多,我也还是没有完全弄明白,随用随学吧!