4. SDIO命令集

说到SDIO协议,核心就是命令的交互。没有命令,主机和卡就是两个哑巴。我刚开始接触SDIO时,被那堆命令号搞得有点懵。其实没那么复杂。

所有SDIO命令都是48位宽。你想想看,这48位里包含了起始位、方向、命令索引、参数,再加上CRC校验和结束位。结构很规整。

命令格式(48位)

  • Bit 47: 起始位(总是0)
  • Bit 46: 方向位(1=主机→卡)
  • Bit [45:40]: 命令索引(6位,支持64个命令)
  • Bit [39:8]: 参数(32位,具体含义看命令)
  • Bit [7:1]: CRC7校验
  • Bit 0: 结束位(总是1)

4.1 基本命令:SDIO操作的基石

基本命令是所有SD/O/SDIO卡共用的。它们定义了卡的生命周期管理。从识别、初始化到状态切换,都靠这些命令。

我个人习惯把基本命令分成三组:控制类、状态类、配置类。

分类 命令 功能简述 我的使用心得
控制类 CMD0 (GO_IDLE_STATE) 复位卡到空闲状态 硬件复位后必须发,但注意CMD0后别急着发其他命令,给卡留点反应时间
控制类 CMD15 (GO_INACTIVE_STATE) 将指定卡置于非激活态 多卡应用时用它断掉不用的卡,省电
状态类 CMD13 (SEND_STATUS) 获取卡当前状态 我调试时最常用的命令,没有之一
配置类 CMD52 (IO_RW_DIRECT) 读写SDIO卡内部寄存器(1字节) SDIO的灵魂命令,后面细说

个人经验:CMD13这玩意儿太重要了。每次执行耗时的操作(比如擦除、切换电压)之后,我习惯先发CMD13确认卡的状态,再发下一步操作。卡没准备好你就发读写,结果就是超时。

4.2 读写命令:数据吞吐的关键

读写命令是Benchmark测试的核心。吞吐跑不上去,八成是读写命令配置有问题。

SDIO的读写命令分两种:单块读写和多块读写。单块用于小数据量,多块用于大数据量传输。

  • CMD53 (IO_RW_EXTENDED) — SDIO的扩展读写命令,支持多字节和多块传输。这个命令是SDIO吞吐测试的主角。
  • CMD17/CMD18 — 用于存储卡的单块/多块读取。
  • CMD24/CMD25 — 用于存储卡的单块/多块写入。

讲个例子。CMD53的参数结构是这样的:

Bit [31]: 读写方向(1=读,0=写)
Bit [30:28]: 功能号(0~6,对应SDIO卡的7个功能)
Bit [27]: 块模式(1=按块传输,0=按字节传输)
Bit [26]: 操作码(1=多块,0=单块)
Bit [25:9]: 寄存器地址(17位)
Bit [8:0]: 字节数或块数(9位)

注意!CMD53的数据长度上限是512字节(或512块)。如果单次传输超过这个限制,必须分多次进行。

我见过有人踩坑:一次CMD53想传2KB数据,结果卡直接返回超时。后来发现是因为没有理解块模式下的块数限制。

4.3 ACMD:隐藏在标准命令后的秘密

ACMD是什么?字面意思是Application-Specific Command。其实就是私有命令,但需要通过CMD55(APP_CMD)来引导。

为什么要这么设计?说白了,标准命令集只有64个,不够用。于是SD协会留了个后门:先用CMD55告诉卡“接下来我要发私有命令了”,然后再发ACMD。

ACMD的操作流程是这样的:

  1. 主机发送CMD55,带上目标卡RCA。
  2. 卡返回R1响应,如果响应中的APP_CMD位(bit 5)为1,表示卡准备好接收ACMD。
  3. 主机再发送ACMDx(注意ACMD的命令号映射到普通命令索引上)。
  4. 卡执行并返回响应。

我曾经踩过一个坑:发CMD55后,不等响应位就立刻发ACMD。结果卡报错。后来养成习惯:发完CMD55,一定要检查响应中的APP_CMD位,确认置1后再发ACMD。

常用的ACMD有:

  • ACMD6 (SET_BUS_WIDTH) — 设置总线宽度(1位或4位)。想跑高吞吐?记得设置成4位模式。
  • ACMD51 (SEND_SCR) — 读取卡的配置寄存器(SCR),获取卡支持的特性。
  • ACMD42 (SET_CLR_CARD_DETECT) — 控制卡检测引脚。

我这里有一个常用的ACMD结构图,帮你理清关系:

ACMD 调用流程 主机 CMD55 (APP_CMD) SDIO 卡 R1 响应 (APP_CMD=1) ACMDx (如ACMD6) 执行私有功能 注意事项 1. 必须先发CMD55,再发ACMD 2. 每发一次ACMD前都需要重新发CMD55

4.4 命令响应类型:主机知道卡在说什么

命令发出去,卡得回话。SDIO定义了5种响应类型:R1、R2、R3、R4、R5。但SDIO卡最常用的是R1和R5。

响应类型 长度 使用场景 关键位说明
R1 48位 大多数命令(CMD13、CMD55等) 包含卡当前状态和错误标志
R3 48位 CMD5(SDIO SEND_OP_COND) 返回OCR寄存器的内容
R5 48位 CMD52、CMD53(SDIO特定命令) 包含功能号、读写标志、数据位
R2 136位 CMD2、CMD9(CID、CSD读取) 长响应,包含128位寄存器数据

避坑:好多人在处理R5响应时会忽略最高两位。CMD52的R5响应在高位包含了读写标志和功能号。如果不校验这俩位,你可能会读到错误的数据而浑然不知。

我有个同事,就因为没检查R5的读写标志,把读出来的数据当寄存器内容分析了两天,才发现读反了。

4.5 实战建议:如何用命令集测吞吐

回到我们的主题——吞吐测试。基于上面的命令集知识,我一般会分几步走:

  1. 初始化阶段:发CMD0复位,CMD5获取OCR,CMD3获取RCA,CMD7选中卡。
  2. 功能选择:CMD52写入功能接口的I/O使能寄存器,唤醒具体的功能。
  3. 配置总线:CMD55 + ACMD6设置4位总线宽度。
  4. 吞吐测试:大量使用CMD53(扩展读写),选择合适的块大小和块数。
  5. 状态监控:每发一批数据,插几个CMD13看看卡的状态有没有异常。

你想想看,这一步一步下来,节奏就掌握在你手里了。吞吐测试不是蛮力发数据,而是精细控制的过程。

小技巧:我用CMD52读取卡的功能寄存器和中断状态寄存器,来判断卡是否准备好接受新数据。这样比单纯依赖超时机制靠谱得多。超时是最后一道防线,不是常规手段。