4. SDIO数据传输模式(块传输、字节传输)
这一章我们聊聊SDIO的数据传输模式。说白了,就是Host和Card之间怎么把数据搬过去。SDIO协议主要定义了两种传输方式:块传输(Block Transfer)和字节传输(Byte Transfer)。这两种模式在总线占有率、数据吞吐量、以及应用场景上差别挺大。
核心要点:块传输以固定长度的“块”为单位,适合大数据量、高效率的场景;字节传输则按每个字节独立控制,适合小数据量、需要低延迟的交互。
4.1 块传输模式
块传输是SDIO最常用的数据传输模式。每个块有固定大小,协议里常见的是512字节。传输时,Host发一个CMD,告诉Card“我要读/写一块数据”,Card收到后就准备好,然后开始搬。
我刚开始做SDIO测试时,踩过一个坑。当时觉得块大小只要设对了就行,结果发现总线速度上去后,CRC校验总是失败。后来查出来是块对齐的问题——Host发送的数据块必须严格与Card的块起始地址对齐,差一个字节都不行。
避坑指南: 我曾经在验证某款IoT模块时,发现块传输模式下连续读多块时,Card会偶尔返回CRC错误。排查发现是Host端的FIFO深度不够,导致数据断流。记住:块传输要求整个块连续发送,中间不能有停顿。
块传输的典型流程:
- Host发送CMD(如CMD17读单块、CMD18读多块)
- Card回应R1响应
- 数据线开始发送/接收数据块
- 每个块后面跟着16位CRC校验
- 如果是多块传输,最后需要Host发CMD12来终止传输
4.2 字节传输模式
字节传输就灵活多了。它不要求固定块长度,每个字节都可以单独控制。SDIO协议里专门定义了CMD52(读写单个寄存器)和CMD53(读写多个寄存器)。字节模式主要用于访问Card内部的寄存器,比如配置功能、读取状态等。
个人习惯,在调试阶段优先用字节模式。为什么呢?因为它每一字节都能拿到即时反馈,出了问题更容易定位。块模式一旦出问题,你得等整个块传完才知道对错,debug效率太低。
字节传输的关键特征:
- 数据线宽度可配置:1-bit、4-bit均可
- 每次传输的字节数由参数决定(CMD53支持最多512字节)
- 每个字节传输后,Card可以插入等待周期(通过数据线拉低)
- 适用于小数据量、低延迟的控制类操作
个人经验: 我曾在某个项目中用字节模式读Card的FIFO状态寄存器,发现Card总是返回0x00。后来用逻辑分析仪抓波形才明白——Host发完地址后,Card需要至少8个时钟周期才能准备好数据。字节模式允许Card通过数据线插入等待状态,但很多Host控制器不自动处理这个。
4.3 两种模式的对比
| 维度 | 块传输 | 字节传输 |
|---|---|---|
| 数据单元 | 固定长度块(通常512字节) | 单字节或多字节(可自行设定) |
| 总线效率 | 高,适合大数据量 | 低,每字节都有握手开销 |
| 灵活性 | 低,块对齐要求严格 | 高,可随时中断/等待 |
| 典型应用 | 读卡数据、文件系统 | 寄存器配置、状态读取 |
| CRC校验 | 每块16位CRC | 可选,多字节时也有CRC |
为什么块传输效率高?你想想看,块模式下总线一旦开始传输,数据线几乎每拍都在传有效数据。字节模式每传一个字节都要确认Card是否准备好,总线上有很多空闲周期。
4.4 多块传输与传输终止
实际项目中,我们很少只传一块数据。多块传输(Multiple Block Transfer)通过一个CMD就能连续传多个块,效率极高。但有个关键点:终止机制。
- 预定义块数:CMD23配合CMD18/CMD25,提前告诉Card要传多少块。这是我推荐的做法,稳定可靠。
- 开放结束:CMD18/CMD25不指定块数,Host发CMD12强制终止。我遇到过某些Card在不停发数据时对CMD12响应很慢,容易超时。
曾经的教训: 我测试一块WLAN SDIO卡时,用开放结束模式读大数据,结果Card在收到CMD12后并没有立即停止,而是又发了一个完整块才停,导致Host收到多余数据,缓冲区溢出。后来只能改用预定义块数,才解决问题。
4.5 知识结构图
下图把块传输和字节传输的核心要素整理在一起,方便整体理解。
4.6 测试验证要点
最后,总结几个我在测试中重点关注的检查点:
- 块对齐: 确保Host发送的块起始地址是块大小的整数倍。
- CRC校验: 块传输必须检查每块的CRC;字节模式虽然可选,但我建议打开,能尽早发现总线错误。
- 多块终止: 用逻辑分析仪抓一下CMD12之后的波形,确认Card是否立即停止发送。
- 等待周期: 字节模式下,测试Card拉低数据线时Host是否支持等待。
- 总线宽度切换: 验证从1-bit切到4-bit后,两种模式是否仍能正常工作。
一个小技巧: 我通常用CMD52读写一个已知值的寄存器,确认字节模式正确;再用CMD53批量读,验证多字节。确认没问题后再切到块模式跑吞吐量。这样分层验证,效率高,也容易定位问题。