EMMC协议之CMD请求与应答格式详解

深入解析eMMC总线命令的48位请求格式与应答格式,逐字段讲解起始位、传输位、命令索引、参数、CRC7的作用,并给出常见命令Argument参数的含义

1. 概述

eMMC(embedded Multi Media Card)是 JEDEC 制定的嵌入式存储标准(JESD84 系列,目前常见 eMMC 5.1)。主机与 eMMC 之间通过以下信号通信:

信号 方向 说明
CLK 主机 → 设备 时钟信号,命令和数据都在其上升沿被采样
CMD 双向(半双工) 用于传输命令和应答,同一时刻只能有一个方向发送
DAT0 ~ DAT7 双向 数据线,可工作于 x1 / x4 / x8 模式

所有命令与应答都通过 CMD 线以位流形式传输:主机发命令(主机 → 设备),设备回应答(设备 → 主机)。命令格式和应答格式本质上都是 48 位的一帧,唯一的方向标志就是传输位。下面逐一拆解每一帧里每一位的作用。

2. 命令请求格式(48 位)

主机发往设备的命令固定为 48 位,高位先发(MSB first),位布局如下:

1
2
3
4
5
6
bit47      bit46      bit45            bit40   bit39                        bit8  bit7      bit1  bit0
┌─────────┬─────────┬─────────────────┬─────────────────────────────────────────┬──────────────┬──────┐
│ Start   │  Trans  │  Command Index  │                Argument                 │     CRC7     │ End  │
│ Bit     │  Bit    │      [5:0]      │                [31:0]                   │     [6:0]    │ Bit  │
└─────────┴─────────┴─────────────────┴─────────────────────────────────────────┴──────────────┴──────┘
    0          1          6 bits                      32 bits                       7 bits        1

各字段作用:

字段 宽度 作用
起始位 Start Bit bit47 1 固定为 0,标志一帧的开始,接收方靠它识别帧边界
传输位 Transmission Bit bit46 1 1 表示主机 → 设备(命令方向);应答时此位为 0
命令索引 Command Index bit45 ~ bit40 6 命令号,范围 0 ~ 63(6 位可表示 64 个命令,如 CMD8 的二进制为 001000
参数 Argument bit39 ~ bit8 32 命令携带的参数,具体含义随命令而定(见第 7 节)
CRC7 bit7 ~ bit1 7 对"命令索引 + 参数"共 38 位计算的 CRC 校验值(见第 8 节)
结束位 End Bit bit0 1 固定为 1,标志一帧的结束

3. 应答格式(48 位)

设备对大部分命令会返回 48 位应答,其结构与命令格式几乎一样,唯一区别是传输位为 0(设备 → 主机),且 bit39 ~ bit8 不再是参数,而是应答内容(随应答类型解释,如 Card Status、OCR、RCA 等):

1
2
3
4
5
6
bit47      bit46      bit45            bit40   bit39                        bit8  bit7      bit1  bit0
┌─────────┬─────────┬─────────────────┬─────────────────────────────────────────┬──────────────┬──────┐
│ Start   │  Trans  │  Command Index  │            Card Status /                │     CRC7     │ End  │
│ Bit     │  Bit    │      [5:0]      │       OCR / RCA / 其他内容 [31:0]        │     [6:0]    │ Bit  │
└─────────┴─────────┴─────────────────┴─────────────────────────────────────────┴──────────────┴──────┘
    0          0          6 bits                      32 bits                       7 bits        1
字段 作用
起始位 bit47 固定 0
传输位 bit46 0 = 设备 → 主机(应答方向)
命令索引 bit45 ~ bit40 回显本次应答对应的是哪条命令
应答内容 bit39 ~ bit8 32 位,按应答类型解释(R1/R3/R6/R7 等)
CRC7 bit7 ~ bit1 对"索引 + 应答内容"38 位的校验值
结束位 bit0 固定 1

4. R2 长应答(136 位)

CID(CMD2 / CMD10 返回)和 CSD(CMD9 返回)寄存器本身是 128 位,装不进 48 位应答,因此 R2 应答是 136 位的长格式:

1
2
3
4
5
6
bit135   bit134  bit133         bit128  bit127                           bit8  bit7      bit1  bit0
┌────────┬────────┬──────────────────┬──────────────────────────────────────────┬──────────────┬──────┐
│ Start  │ Trans  │     Reserved     │      CID / CSD 内容 [127:8]               │     CRC7     │ End  │
│ Bit    │ Bit    │     (6 bits)     │            120 bits                      │     [6:0]    │ Bit  │
└────────┴────────┴──────────────────┴──────────────────────────────────────────┴──────────────┴──────┘
   0        0          全 0                                                           7 bits        1
字段 说明
起始位 + 传输位 bit135 ~ bit134 00
保留位 bit133 ~ bit128 6 位,全部为 0
CID / CSD 内容 bit127 ~ bit8 120 位。寄存器低 8 位(bit7 ~ bit0)是寄存器自身的 CRC7 和结束位,不随应答传出,所以只传 [127:8]
CRC7 bit7 ~ bit1 对上面 120 位内容计算的校验值
结束位 bit0 固定 1

5. 响应类型(R1 ~ R7)

类型 长度 应答内容 典型命令
R1 48 位 32 位 Card Status(卡状态寄存器) CMD13、CMD55 等
R1b 48 位 + busy 同 R1,应答后 DAT0 拉低表示忙 CMD6、CMD12、CMD38
R2 136 位 CID 或 CSD 寄存器内容 CMD2、CMD9、CMD10
R3 48 位 OCR 寄存器(操作条件) CMD1
R6 48 位 RCA[31:16] + 卡状态[15:0] CMD3
R7 48 位 回显接口条件(电压 + 校验模式) CMD8

关于 R1b 的忙信号:R1b 应答之后,设备会在 DAT0 上持续输出低电平表示"忙",主机必须等待忙信号结束才能发起下一条命令。实际驱动中常用 CMD13(SEND_STATUS)轮询设备状态,直到 READY_FOR_DATA 置位或设备进入目标状态。

6. R1 应答:Card Status 字段详解

R1 应答的 32 位内容就是卡的状态寄存器,是调试时最常解析的字段:

名称 类型 作用
31 OUT_OF_RANGE R 命令参数超出设备支持范围(如地址越界)
30 ADDRESS_ERROR R 地址未对齐(例如不是块边界对齐)
29 BLOCK_LEN_ERROR R 块长度不支持
28 ERASE_SEQ_ERROR R 擦除序列错误
27 ERASE_PARAM R 擦除参数无效
26 WP_VIOLATION R 尝试写入写保护区域
25 CARD_IS_LOCKED R 卡处于锁定状态
24 LOCK_UNLOCK_FAILED R 锁定/解锁操作失败
23 COM_CRC_ERROR E 上一次命令 CRC 校验失败(总线传输错误)
22 ILLEGAL_COMMAND E 命令非法(设备不支持或当前状态下不允许)
21 DEVICE_ECC_FAILED E 设备内部 ECC 纠错失败
20 CC_ERROR E 内部控制电路错误
19 ERROR E 一般性错误
18 UNDERRUN E 数据下溢(多块读时数据供应不及时)
17 OVERRUN E 数据上溢(多块写时数据接收不及时)
16 CID/CSD_OVERWRITE E CID/CSD 寄存器被改写
15 WP_ERASE_SKIP E 因写保护跳过部分擦除区域
14 CARD_ECC_DISABLED E ECC 被禁用
13 ERASE_RESET E 擦除序列被重置
12:9 CURRENT_STATE X 设备当前状态(见下表)
8 READY_FOR_DATA X 1 表示设备可收发数据
7 SWITCH_ERROR E 模式切换(CMD6)失败
6 EXCEPTION_EVENT X 异常事件标志,配合 EXT_CSD 的 EXCEPTION_EVENTS_STATUS 使用
5 APP_CMD X 1 表示下一条命令将按 ACMD(应用命令)解释
4:0 Reserved 保留

类型说明:R 类错误位在命令执行时更新;E 类错误位在主机读取后清除;X 类为状态位,实时反映当前状态。

CURRENT_STATE(bit12:9)取值:

状态 说明
0 idle 空闲(上电或 CMD0 复位后)
1 ready 就绪,等待识别
2 ident 识别中(CMD2/CMD3 阶段)
3 stby 待机,已分配 RCA
4 tran 数据传输状态(读写命令都在此状态下发出)
5 data 数据接收中
6 rcv 数据发送中
7 prg 编程中(写入/擦除进行中)
8 dis 断开(CMD7 取消选中)
9 ~ 15 保留

驱动调试时最常见的场景:发完 CMD24(写)后卡停留在 prg 状态,说明上一次写操作还没完成;发命令后返回 ILLEGAL_COMMAND,则要检查命令是否在正确状态下发出(例如未完成初始化就发读写命令)。

7. 常见命令 Argument 参数作用

命令 名称 Argument 作用 应答
CMD0 GO_IDLE_STATE 无参数(全 0),复位设备到 idle 状态
CMD1 SEND_OP_COND 主机 OCR:bit30 = HCS(高容量支持),bit29:24 = 电压窗口;设备在 R3 应答中回传自己的 OCR R3
CMD2 ALL_SEND_CID 无参数 R2(CID)
CMD3 SEND_RELATIVE_ADDR 无参数;设备在 R6 应答中分配并返回自己的 RCA R6
CMD6 SWITCH 模式切换 / EXT_CSD 字节读写(见下方展开) R1b
CMD7 SELECT_CARD RCA[15:0]:选中该 RCA 的设备进入 tran 状态;RCA 为 0 表示取消选中 R1b
CMD8 SEND_EXT_CSD 无参数;应答后 DAT 上再传输 512 字节 EXT_CSD R1 + 数据
CMD9 SEND_CSD RCA[15:0]:指定要读 CSD 的设备 R2(CSD)
CMD10 SEND_CID RCA[15:0]:指定要读 CID 的设备 R2(CID)
CMD12 STOP_TRANSMISSION 无参数,中止正在进行的多块读写 R1b
CMD13 SEND_STATUS RCA[15:0]:查询指定设备的状态 R1(Card Status)
CMD16 SET_BLOCKLEN 块长度(如 512) R1
CMD17 READ_SINGLE_BLOCK 数据起始字节地址[31:0](须块对齐) R1 + 数据
CMD18 READ_MULTIPLE_BLOCK 数据起始字节地址[31:0] R1 + 数据
CMD23 SET_BLOCK_COUNT 块数[31:0](bit31 必须为 0),限定后续 CMD18/CMD25 传输的块数 R1
CMD24 WRITE_BLOCK 数据起始字节地址[31:0] R1 + 数据
CMD25 WRITE_MULTIPLE_BLOCK 数据起始字节地址[31:0] R1 + 数据
CMD38 ERASE 无参数(擦除范围由 CMD35/CMD36 的起始/结束地址设定) R1b
CMD55 APP_CMD RCA[15:0];执行成功后设备状态寄存器 APP_CMD 位置 1,下一条命令按 ACMD 解释 R1
CMD56 GEN_CMD bit0:1 = 读、0 = 写;bit25:1 = 块偏移(块内传输,不经过地址映射) R1 + 数据

几个需要展开的关键参数:

CMD1 的 OCR 参数:bit30 = HCS(Host Capacity Support,高容量支持,1 表示主机支持块寻址);bit29:24 = 电压窗口(如 110000 表示支持 2.7V ~ 3.6V)。设备在 R3 应答中返回自己的 OCR,其中 bit31 表示设备是否完成上电(busy 标志),初始化代码通常循环发 CMD1 直到该位置 1 且电压窗口匹配。

CMD6 的 SWITCH 参数(eMMC 5.1,Linux 内核 mmc_switch() 即按此编码):

1
2
3
4
5
bit31      bit26  bit25    bit24  bit23         bit16  bit15        bit8  bit7  bit3  bit2      bit0
┌──────────┬──────┬─────────┬──────┬─────────────────┬──────────────────┬───────────┬──────────────┐
│  Reserved │      │ Access  │      │      Index      │      Value       │ Reserved  │   Cmd Set    │
│ (全 0)    │      │ [25:24] │      │     [23:16]     │     [15:8]       │ (全 0)    │    [2:0]     │
└──────────┴──────┴─────────┴──────┴─────────────────┴──────────────────┴───────────┴──────────────┘
字段 作用
Access(访问模式) bit25:24 00 = Command Set(按 Cmd Set 切换命令集);01 = Set Bits(按 Value 中为 1 的位置位);10 = Clear Bits(按 Value 中为 1 的位清零);11 = Write Byte(把 Value 写入指定字节)
Index bit23:16 EXT_CSD 字节偏移(0 ~ 191 有效;192 ~ 255 非法,设备不改写并置 SWITCH_ERROR)
Value bit15:8 要写入/设置的 8 位值
Cmd Set bit2:0 命令集编号,默认 0

例如切换 HS400 模式(写 EXT_CSD byte 197)就是:arg = (0b11 << 24) | (197 << 16) | (value << 8),即 Write Byte 模式写偏移 197 的字节。CMD6 的应答是 R1b,写完后需等待忙结束,再用 CMD13 轮询确认 SWITCH_ERROR 没有置位。

CMD55 与 ACMD 机制:eMMC 很多功能命令(如 CMD6 的扩展、CMD22 等)以 ACMD 形式出现。发送 CMD55 后,设备状态寄存器的 APP_CMD 位置 1,此时紧接着发的下一条命令就按 ACMD 解释,并且这条命令的索引可以大于 63(因为 ACMD 用 CMD6/CMD56 等通道复用)。ACMD 结束后 APP_CMD 位自动清零。

RCA(相对卡地址):CMD3 应答(R6)的 bit31:16 就是设备被分配的 RCA(1 ~ 65535 范围内的某个值,0 表示未分配/取消)。之后 CMD7/CMD9/CMD13 等命令都靠 RCA[15:0] 指定目标设备——eMMC 是单设备总线,但规范保留了多设备编址能力。

8. CRC7 校验

命令与应答帧中的 CRC7 字段用于检测总线传输错误:

  • 多项式:x⁷ + x³ + 1(即 0x89),初始值为 0,MSB 先出
  • 覆盖范围:命令帧覆盖"索引 + 参数"共 38 位;R2 长应答覆盖 120 位 CID/CSD 内容
  • 校验失败:设备认为命令无效并丢弃;主机侧则由控制器硬件校验应答,若失败会在状态寄存器置 COM_CRC_ERROR(bit23)

需要注意的是,这个 CRC7 只保护 CMD 线上的命令/应答帧,不保护 DAT 线上的数据——数据块的完整性由数据 CRC16 单独保证(x16 + x12 + x5 + 1,即 0x1021)。

9. 参考

  • JEDEC JESD84-B51(eMMC 5.1 规范),命令格式见 §6.10,响应格式与 Card Status 见 §6.12/§6.13
  • Linux 内核:include/linux/mmc/mmc.h(R1 状态位定义)、drivers/mmc/core/mmc_ops.c(CMD6 参数编码 mmc_switch()
  • SD/MMC 协议相关参考手册(如 GD32、NXP 系列控制器手册中的命令定义表)
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计