4. MMC/SD/eMMC协议详解:命令、响应、数据传输与总线速度模式

MMC、SD与eMMC协议虽然分属不同代际与市场定位,但其底层通信模型高度一致:主机(Host)通过命令线(CMD)发送命令,从设备(Card/Device)在指定窗口内返回响应(Response),数据线(DAT0-DAT7)按约定的时序传输块数据,所有信号线均受CRC校验保护。理解这套协议体系,是驱动开发中正确初始化设备、配置总线时序、实现高效读写以及排查通信故障的前提。本章将从命令格式与分类、响应类型、数据线传输模式、CRC算法以及总线速度模式五个维度展开,并结合实际驱动代码与调试案例进行深度拆解。

Host Controller SD/MMC主机控制器 CMD/DAT/CLK驱动 CMD线(双向) 命令/响应复用 DAT0-DAT7(双向) 1/4/8位并行数据 CLK(主机→设备) 最高200MHz(HS400) eMMC/SD设备 CMD接口逻辑 数据FIFO CRC生成/校验 电源管理单元 命令格式(48位) 起始位(1) + 方向位(1) + 命令索引(6) + 参数(32) + CRC7(7) + 结束位(1) CMD0: 参数=0x00000000 CMD8: 参数=0x000001AA 响应类型 R1: 状态(32位) + CRC7 R2: CID/CSD(120位) R3: OCR(32位) R6: RCA(16位) + 状态 R7: 回声(参数) 总线速度模式演进 DS: 25MHz, 1/4/8bit, 12.5/25/50MB/s HS: 50MHz, 1/4/8bit, 25/50/100MB/s SDR104: 208MHz, 4bit, 104MB/s DDR50: 50MHz DDR, 4bit, 50MB/s HS200: 200MHz, 8bit, 200MB/s HS400: 200MHz DDR, 8bit, 400MB/s 注:HS400需切换至1.8V信号电平并启用CRC

4.1 命令格式与分类

MMC/SD/eMMC协议中,所有命令均为48位长度,由主机通过CMD线发送。命令格式固定为:1位起始位(恒为0)、1位方向位(主机发送为1)、6位命令索引(CMD0-CMD63)、32位命令参数(内容因命令而异)、7位CRC校验码(覆盖命令索引与参数)以及1位结束位(恒为1)。驱动开发中,命令索引与参数的正确构造是基础,而CRC7的硬件自动生成通常由控制器完成,软件层只需关注命令语义。

命令按功能可分为四大类:广播命令(如CMD0、CMD2),不指定特定设备,所有设备同时接收;点对点命令(如CMD7、CMD17),通过RCA(相对设备地址)或地址参数指定目标设备;带数据命令(如CMD24、CMD18),命令本身仅触发数据传输,实际数据在DAT线上完成;应用特定命令(ACMD),需先发送CMD55告知设备后续命令为应用命令。例如,SD卡初始化时,ACMD41用于查询/设置工作电压,而eMMC则使用CMD1完成类似功能。

实战要点:在Linux内核的mmc核心层中,mmc_wait_for_cmd()函数负责发送命令并等待响应。驱动开发者需注意,CMD0(复位)与CMD15(中断)等命令不要求设备返回响应,而CMD6(切换功能)在eMMC中用于模式切换,其参数需按位域精确构造,错误位将导致设备无响应或进入未知状态。

4.2 响应类型详解:R1/R2/R3/R6/R7

设备对命令的响应同样通过CMD线返回,长度分为48位(R1/R3/R6/R7)和136位(R2)两种。响应类型由命令规范决定,驱动需根据命令索引解析对应响应结构。

响应类型长度关键字段典型命令驱动关注点
R148位32位设备状态CMD7, CMD17, CMD24检查错误位(如ADDRESS_ERROR、WP_VIOLATION)
R2136位CID或CSD寄存器(120位)CMD2, CMD9, CMD10解析设备容量、最大时钟频率、读写块长度
R348位OCR寄存器(32位)CMD1, ACMD41检查电压窗口与忙标志(BUSY)
R648位RCA(16位)+ 状态位CMD3获取设备地址,用于后续点对点命令
R748位回声字段(参数原样返回)CMD8验证SD卡版本与电压匹配

R1响应是驱动中最常处理的类型,其32位状态字段包含23个状态位,涵盖设备当前状态(如tran、data)、错误标志(如ECC错误、CCRC错误)以及锁定状态等。驱动在每次命令后应检查关键错误位,避免在设备异常时继续后续操作。R2响应用于读取CID(设备ID)和CSD(设备特定数据),其中CSD中的c_size、c_size_mult和read_bl_len字段共同决定设备容量,驱动需按规范进行移位计算。

经验提醒:CMD8的R7响应是SD卡初始化中区分SDSC与SDHC/SDXC的关键。主机发送参数0x000001AA(表示支持2.7-3.6V电压),若设备返回相同参数,则为SDHC/SDXC;若返回0x00000000或无响应,则为SDSC或MMC设备。eMMC不支持CMD8,驱动需通过CMD1的OCR响应判断电压范围。

4.3 数据线传输模式与CRC校验

数据在DAT0-DAT7线上传输,支持1位、4位和8位(仅eMMC)三种模式。数据传输以块为单位,块长度由CSD或CMD16设定,常见为512字节。读操作(CMD17/CMD18)中,设备在命令响应后拉低DAT0表示忙,随后在CLK上升沿输出数据块;写操作(CMD24/CMD25)中,主机在命令响应后直接发送数据,设备通过CRC状态令牌(在DAT0上返回)告知写入结果。

CRC校验覆盖命令、响应和数据三个层面:命令与响应使用CRC7多项式x^7+x^3+1,数据块使用CRC16多项式x^16+x^12+x^5+1。硬件控制器通常自动完成CRC生成与校验,但驱动需理解CRC失败时的处理流程:若命令响应CRC错误,主机应重发命令;若数据CRC错误,读操作应重读,写操作需查询设备状态并可能重写。

// 数据块CRC校验示例(伪代码)
uint16_t crc16_data(const uint8_t *data, size_t len) {
    uint16_t crc = 0;
    for (size_t i = 0; i < len; i++) {
        crc ^= (data[i] << 8);
        for (int j = 0; j < 8; j++) {
            if (crc & 0x8000) crc = (crc << 1) ^ 0x1021;
            else crc <<= 1;
        }
    }
    return crc;
}
风险提示:在HS400模式下,数据线在DDR时钟沿采样,CRC校验的时序裕量极小。若PCB布线不等长或信号完整性不佳,CRC错误率会显著上升。驱动应实现CRC错误计数与重试机制,连续多次失败后应降速至HS200或HS模式。

4.4 总线速度模式:DS/HS/SDR/DDR/HS200/HS400

总线速度模式决定了CLK频率、数据线宽度和信号电平,直接影响吞吐量。驱动需在初始化阶段通过命令序列逐步提升速度模式,每一步都需验证设备能力与稳定性。

模式CLK频率数据线宽度信号电平理论带宽适用设备
DS (Default Speed)25MHz1/4/8位3.3V12.5/25/50 MB/s所有MMC/SD/eMMC
HS (High Speed)50MHz1/4/8位3.3V25/50/100 MB/sSD 2.0+, eMMC 4.x
SDR104208MHz4位1.8V104 MB/sSD 3.0+
DDR5050MHz DDR4位1.8V50 MB/sSD 3.0+
HS200200MHz8位1.8V200 MB/seMMC 5.0+
HS400200MHz DDR8位1.8V400 MB/seMMC 5.1+

速度模式切换流程遵循“先配置设备,再切换主机”的原则。以eMMC从HS切换至HS200为例:首先通过CMD6将设备切换到HS模式并验证;然后通过CMD6的HS_TIMING字段选择HS200,同时将信号电平切换至1.8V(通过CMD6的VOLTAGE_SWITCH字段);最后主机侧将CLK频率提升至200MHz,并将数据线宽度配置为8位。整个过程需在设备返回的忙信号结束后进行,否则可能导致设备状态错乱。

案例拆解:某嵌入式平台eMMC HS400初始化失败
背景:基于i.MX8M Plus平台,eMMC为三星KLMBG4JETD-B041,设计目标为HS400模式。
现象:初始化过程中,CMD6切换至HS400后,设备无响应,CMD线卡死。
分析:通过逻辑分析仪抓取波形,发现主机在发送CMD6后立即提升CLK频率至200MHz,但设备仍在处理内部切换,DAT0忙信号尚未释放。进一步检查代码,发现驱动未等待设备忙信号结束。
解决:在CMD6响应后增加忙信号轮询,等待DAT0拉高后再提升CLK频率。同时,将信号电平切换与HS200模式切换分离,先切电平再切模式,避免时序竞争。
结果:修改后HS400模式稳定运行,顺序读速度从HS200的180MB/s提升至350MB/s。
复盘:高速模式切换必须严格遵循设备规范中的时序要求,尤其是忙信号等待和电平切换顺序,驱动中应增加超时保护与重试机制。

4.5 常见误区与总结复盘

  • 误区一:认为所有设备都支持最高速度模式。实际需通过CSD/EXT_CSD寄存器读取设备能力,如eMMC的EXT_CSD第196字节(DEVICE_TYPE)指示支持的HS200/HS400模式。
  • 误区二:忽略CRC错误的重试策略。在高速模式下,偶发CRC错误是正常的,驱动应具备重试机制,而非直接报错。
  • 误区三:混淆SD与eMMC的初始化流程。SD卡使用ACMD41与CMD8,eMMC使用CMD1与CMD6,两者不兼容。
  • 误区四:在DDR模式下未正确配置数据选通(DS)信号。HS400模式依赖DS信号进行数据采样,若未启用或时序错误,将导致数据错位。

总结而言,MMC/SD/eMMC协议的命令-响应-数据模型是驱动开发的核心骨架。驱动开发者需熟练掌握命令构造、响应解析、CRC校验逻辑以及速度模式切换的完整流程。在实际项目中,建议使用逻辑分析仪或协议分析仪验证初始化时序,并建立完善的错误处理与降速机制,以确保在各种硬件环境下稳定运行。