最近在研究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的例程,开发板的例程,我们完全可以拿来稍加修改就可以使用。我们完全可以不明就里的拿来就用,好用就行,能交差就行,但是不明不白的拿来就用使我心里很不舒服,必须简单的弄明白原理,弄清楚结构,这样除了问题也能更快的定位。上面写了那么多,我也还是没有完全弄明白,随用随学吧!