SD卡(SecureDigital MemoryCard)即:安全数码卡,它是在MMC的基础上发展而来,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制。SD卡按容量分类,可以分为3类:SD卡、SDHC卡、SDXC卡。
一、SD卡内部结构-内部寄存器
名称 | bit宽度 | 描述 |
OCR | 32 | OCR记录了电压范围、卡的工作模式(如是否支持高容量模式)以及卡是否准备好进行数据传输。 |
CID | 128 | 通常用于获取卡的制造商ID和产品型号等。 |
RCA | 16 | 用于标识SD卡的相对地址。在初始化阶段,SD卡会通过RCA与主机系统建立连接。 |
DSR | 16 | 用于SD卡驱动阶段的控制,主要控制SD卡的电气特性和速率。 |
CSD | 128 | 包含有关SD卡具体规格的详细信息,包括卡的容量、访问模式、速度等级等。 |
SCR | 64 | 包含SD卡的配置和特性,如支持的功能、卡的速度等级等。 |
SSR | 512 | 它包含卡的工作状态、错误状态、命令结果等信息。 |
CSR | 32 | 显示SD卡当前的状态,包括是否准备好进行读写操作、卡的健康状态等。 |
二、SD卡硬件接线
为了驱动SD卡,首先的第一步就是观察SD卡引脚接线情况,通常我们在画原理图时,都是使用的SD卡卡槽与MCU进行接线。SD卡可以使用SDIO协议和SPI协议进行通信,这里我们主要介绍SDIO协议。下图中的TF卡只是容量小一点的SD卡。
引脚号 | SD卡 | TF卡 |
1 | data3 | data2 |
2 | cmd | data3 |
3 | vss | cmd |
4 | vdd | vdd |
5 | clk | clk |
6 | vss | vss |
7 | data0 | data0 |
8 | data1 | data1 |
9 | data2 |
SD卡硬件接线图:
其中
TF卡硬件接线图:
以F1C100S为例,接线图如下所示:
SDIO总线和USB总线类似,SDIO总线也有两端,其中一端是主机(HOST)端,另一端是设备端(DEVICE),采用HOST- DEVICE这样的设计是为了简化DEVICE的设计,所有的通信都是由HOST端发出命令开始的。在DEVICE端只要能解析HOST的命令,就可以同HOST进行通信了,SDIO的HOST可以连接多个DEVICE。
我们发现上图中的TF卡使用的协议为SDIO协议,主要有4根数据线,1根命令线,1根时钟线组合而成。为了驱动这个SD/TF卡我们就需要去了解SDIO协议的时序。
三、SD卡命令及其配置流程
1. 常用CMD命令
命令类型 | 命令 | 命令号 | 响应类型 | 功能描述 |
基本命令(class0) | CMD0 | 0x00 | - | 复位所有卡的状态为空闲状态。 |
CMD2 | 0x02 | R2 | 获取卡的CID。 | |
CMD3 | 0x03 | R6 | 获取卡的相对地址(RCA)。 | |
CMD7 | 0x07 | R1b | 选择卡并切换到传输状态。(OCR) | |
CMD8 | 0x08 | R7 | 询问卡是否支持主机支持电压。 | |
CMD9 | 0x09 | R2 | 获取卡的CSD。 | |
CMD12 | 0x0C | R1b | 停止传输命令(用于终止数据传输)。 | |
CMD13 | 0x0D | R1 | 读取 SD 卡的 Card Status Register(卡状态寄存器)。 | |
CMD15 | 0x0F | - | 释放卡的访问控制,解除卡锁定。 | |
CMD16 | 0x10 | R1 | 用于指定卡的数据块大小,通常是512字节或者更大的块。 | |
读取命令(class2) | CMD17 | 0x11 | R1 | 读取单个数据块。标准 SD读取数据块长度受 CMD16 控制。对于 SDHC、SDXC卡,读取数据块为固定的 512字节,不受CMD16 控制 |
CMD18 | 0x12 | R1 | 读取多个数据块。块大小由 CMD16 控制。 | |
擦除命令(class3) | CMD32 | 0x20 | R1 | 设置要擦除的第一个块的地址(擦除起始地址)。 |
CMD33 | 0x21 | R1 | 设置要擦除的最后一个块的地址(擦除结束地址)。 | |
CMD38 | 0x26 | R1b | 从块的起始位置到结束位置执行擦除操作的命令。 | |
写入命令(class4) | CMD24 | 0x18 | R1 | 写入单块数据。块大小由 CMD16 控制。 |
CMD25 | 0x19 | R1 | 写入多个数据块。块大小由 CMD16 控制。 | |
特殊命令(class8) | CMD55 | 0x37 | R1 | 发送前置命令,告知卡后续要执行ACMD命令。 |
ACMD6 | 0x06 | R1b | 配置卡的总线宽度。 | |
ACMD23 | 0x17 | R1 | 告诉SD卡后续要写入多少个数据块。 | |
ACMD41 | 0x29 | R3 | 启动卡并查询OCR响应,卡上电完成。 | |
ACMD51 | 0x33 | R1 | 读取SD卡的SD 状态寄存器。 |
2. 响应类型
在SD卡命令中,响应类型是指SD卡在接收到命令后返回的响应格式,所有响应都是通过CMD信号线发送。不同命令会有不同的响应类型,这些响应类型决定了卡返回数据的结构。响应类型的关键是根据命令和数据位数来判断的。根据响应类型,可以知道要解析多少个字节,以及如何解读响应内容。
SDIO总共有7个响应类型(代号:R1~R7),其中SD卡没有R4、R5类型响应。特定的命令对应有特定的响应类型,比如当主机发送CMD3命令时,可以得到响应R6。
根据响应内容大小可以分为短响应和长响应。短响应是48bit长度,只有R2类型是长响应,其长度为136bit。
而有些响应后面会带有 ' b' 标志,表示 " 忙 "标志。用于命令执行期间卡可能需要一些时间来完成操作。响应中会有一个“忙”位,表示卡是否仍在执行某些操作。
(1)短响应
R1响应(正常响应命令):R1响应会返回32位的卡状态。
Bit位 47 46 [45:40] [39:8] [7:1] 0 位宽 1 1 6 32 7 1 值 "0" "0" x x x "1" 描述 开始位 传输位 命令号 卡状态 CRC7 结束位 R1b响应:和R1响应差不多,但是R1b响应在数据线上会有busy信号,主机在发送完数据后,应该检查 busy 信号。
Bit位 47 46 [45:40] [39:8] [7:1] 0 位宽 1 1 6 32 7 1 值 "0" "0" x x x "1" 描述 开始位 传输位 命令号 卡状态 CRC7 结束位 R3响应(OCR 寄存器):R3响应会返回32位的OCR寄存器的值作为ACMD41的响应。
Bit位 47 46 [45:40] [39:8] [7:1] 0 位宽 1 1 6 32 7 1 值 "0" "0" "111111" x "111111" "1" 描述 开始位 传输位 保留位 OCR寄存器 保留位 结束位 R6响应(CMD3专用响应):
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 [31:16]卡的RCA [15:0]卡的状态 CRC7 结束位 R7响应(CMD8专用响应):Bit[19:16]表明卡支持的电压范围。卡接受提供的电压范围就返回 R7 响应。卡会在响应的参数中返回电压范围和检查模式。
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 保留位 接受电压 检查模式 CRC7 结束位
(2)长响应
R2响应(CID,CSD 寄存器):R2响应会返回SD卡中CID或者CSD寄存器的值。其中CID寄存器的值用于CMD2和CMD10响应,CSD寄存器的值用于CMD9响应。
Bit位 135 134 [133:128] [127:1] 0 位宽 1 1 6 127 1 值 "0" "0" "111111" x "1" 描述 开始位 传输位 保留位 CID/CSD寄存器的值(内部CRC7) 结束位
(2)命令和响应使用举例
以F1C100s举例,该芯片中有4个响应寄存器,如下所示。当我们发送命令后需要接收响应时,要根据不同的响应类型来获取响应寄存器的值。
例如短响应通常只需要 1 个响应寄存器,响应数据会被放入响应寄存器0(通常是
SD0_RESP0
),因此,获取响应时只需要读取SD0_RESP0
即可。// 假设响应数据保存在 sd_command.response 数组中 sd_command.cmdidx = 3; //CMD3 sd_command.cmdarg = 0; // 根据具体命令的参数设置 sd_command.resp_type = SD_RESPONSE_CRC | SD_RESPONSE_PRESENT; //SD_RESPONSE_PRESENT:设置需要响应。 SD_RESPONSE_CRC :CRC校验。 result = sd_card_send_command(&sd_command, 0); // 读取四个响应寄存器的值 uint32 response= sd_command.response[0]; //获取响应寄存器0的值
对于长响应,通常需要读取 4 个响应寄存器(如
SD0_RESP0
,SD0_RESP1
,SD0_RESP2
,SD0_RESP3
),SD0_RESP0
存储高位部分。// 假设响应数据保存在 sd_command.response 数组中 sd_command.cmdidx = 2; //CMD2 sd_command.cmdarg = 0; // 根据具体命令的参数设置 sd_command.resp_type = SD_RESPONSE_CRC | SD_RESPONSE_PRESENT | SD_RESPONSE_136; //SD_RESPONSE_PRESENT:设置需要响应。 SD_RESPONSE_CRC :CRC校验。SD_RESPONSE_136:长响应。 result = sd_card_send_command(&sd_command, 0); // 读取四个响应寄存器的值 uint32 response0 = sd_command.response[0]; //获取响应寄存器0的值 uint32 response1 = sd_command.response[1]; //获取响应寄存器1的值 uint32 response2 = sd_command.response[2]; //获取响应寄存器2的值 uint32 response3 = sd_command.response[3]; //获取响应寄存器3的值
3. SD卡初始化流程
(1)初始化GPIO功能,SDIO时钟不超过400kHz。
(2)开启SDIO电源,为卡提供时钟,并延时两毫秒。
(3)发送CMD0复位命令,让卡到空闲状态。
(4)发送CMD8命令,询问卡是否支持主机支持电压。根据电压值判断SD卡支持版本。
(5)反复发送ACMD41(先发送CMD55,再发送ACMD41),等待OCR回应,卡上电完成和卡容量类型。如果正常则进入准备状态。
(6)发送CMD2,进入识别状态,获得卡信息(CID)。包含卡的制造商、产品ID等信息。
(7)发送CMD3,获得卡的相对地址(RCA)。这个地址用于区分不同的卡,并在后续的操作中标识当前使用的卡。进入待机状态(下一步就要进行数据传输)。
(8)发送CMD9,获得卡的数据(CSD)。包含卡的规格、容量、访问模式等信息。
(9)发送CMD7,选择卡,切换到传输状态。此时,SD卡已经准备好进行数据的读写操作。
(10)检查卡是否被锁定,卡被锁定时不能进行写操作,通常用于保护卡内的数据不被修改。我们在写操作时,SD卡要处于非锁定模式。
(11)通过读取SD卡的SCR寄存器,判断卡是否支持宽总线(4位数据线宽度)。如果支持宽总线,则可以提高数据传输速率。
(12)发送ACMD6(先发送CMD55,再发送ACMD6),修改总线宽度,(如从1位宽设置为4位宽)。
4. SD卡写操作流程
(1)发送
CMD7
命令选择SD卡,确保卡处于“传输状态”。(2)设置块大小,通过
CMD16
命令设置块大小(通常是512字节),如果不设置,则默认为512字节。(3)配置SDIO的数据路径状态机DPSM(这个通常是硬件配置步骤,不需要通过命令发送)。在配置块大小后,需要配置SDIO(SD卡接口)的数据路径状态机(DPSM)来处理数据的传输。DPSM 控制数据传输的流动,它会确保数据能够被正确地写入到SD卡中。这个步骤通常是在硬件层面配置的,与命令流程关系不大,但非常重要。
(3)SD卡使用
CMD24
(单块写命令)或CMD25
(多块写命令)来执行数据写操作。命令需要包含块地址和要写入的数据。(4)发送命令 CMD13轮询SDIO状态寄存器:监控传输过程,等待数据完成写入FIFO。
TXFIFO_EMPTY
:表示发送 FIFO(数据缓冲区)为空,意味着数据已经传输完成。
RXFIFO_READY
:表示接收 FIFO 准备好接收数据。
CMD_DONE
:表示命令已经执行完成。
ERROR
:表示传输过程中出现了错误。(5)发送停止传输命令(CMD12):当数据传输完成后,在需要停止传输时使用。
单块写:
多块写:
5. SD卡读操作流程
(1)发送
CMD16
设置块大小,并配置 SDIO 的数据路径状态机。(2)发送
CMD18
连续读取命令,读取多个数据块直到完成。如果是单块读取,发送CMD17
单块读取命令。(3)发送命令 CMD13 轮询 SDIO 状态寄存器,读取 FIFO 中的数据,直到数据接收完毕。
(4)数据传输结束后,发送
CMD12
强制停止传输命令。(5)检查 FIFO 是否为空,如果不为空,则继续读取剩余数据。
(6)检查错误状态,确保数据读取无误,如果出现错误则处理。
单块读:
多块读:
6. SD卡擦除流程
(1)SD状态检查,参数检査、命令支持检查、检查卡类型:在进行任何写入操作之前,需要检查 SD 卡的状态,以确保卡处于正常工作状态。这通常包括检查卡是否处于准备状态、卡是否支持擦除操作等。在擦除操作前,需要确保所选参数(如要擦除的起始块和结束块的地址)是有效的。确认 SD 卡是否支持擦除命令。
(2)发送
CMD32
设置要擦除的起始块的地址:在执行该命令后,卡会将起始地址加载到擦除缓冲区,并准备好擦除操作。(3)发送
CMD33
设置要擦除的最后一个块的地址:该命令告诉卡擦除的结束地址,范围包括从起始块到结束块。(4)发送 CMD38 擦除选定的块:
CMD38
命令会要求卡擦除从起始块到结束块之间的所有数据块。(5)擦除完成后的检查:发送命令 CMD13轮询 SDIO 状态寄存器,检查是否存在错误。如果没有错误,擦除操作成功;如果有错误,系统需要根据错误码采取适当的恢复措施。
四、SDIO协议数据包格式
1. 单线传输模式
单线模式下,只有一根数据线
DAT0
传输数据。所以必须要有传输方向位来明确数据的流向。传输方向位:1:主机传输到SD卡, 0:SD卡传输到主机。
2. 多线传输模式
在多线传输模式下,有4 条数据线(
DAT0
到DAT3
)并行完成的,传输方向由 命令类型 和 数据线的硬件状态 决定,不需要额外的传输方向位。主机通过命令明确告诉 SD 卡当前的操作是读还是写(例如CMD17
是读单块,CMD24
是写单块),因此数据的方向是由命令预先确定的。多线模式强调高效并行传输,省去了传输方向位这一单线模式中的冗余信息。
五、SD卡相关时序分析
1. SD卡识别和卡启动时序(CMD2/ACMD41命令时序)
CMD2 和 ACMD41 的时序如下。命令后跟着两个 Z bit(允许总线切换方向的时间),接着是响应卡发出的 P bit。卡响应主机命令的起始在 Nid 时钟周期后。
2. SD卡发送相对地址时序(CMD3命令时序)
3. SD卡两个命令发送间隔时序(命令时序)
SD卡两个命令发送之间的时序,通常称为命令间隔时序,用来确保主机和卡之间的通信稳定,同时为卡提供充足的时间完成当前命令的处理。
主机在接收到卡的响应后,必须等待 至少 8 个时钟周期,确保 CMD 线为高电平空闲状态,才可发送下一条命令。
4. SD卡读时序
在SD卡的操作中,数据读取(尤其是单块读取)需要通过特定的命令来控制和配置。
(1)单块读
主机通过 CMD7 来选择一个卡进行数据读取操作,通过 CMD16 来设置需要传送数据的有效块长度。读操作的基本总线时序见图4-18。序列以单块读命令(CMD17)开始,CMD17 在参数中指出了起始地址。响应也通过CMD 线发送。
(2)多块读
多块读模式中,在主机读命令之后,卡发送一个连续的数据块流。通过CMD12来中止。
5. 停止命令时序
数据传输在停止命令后的两个时钟周期停止。