欢迎光临
我们一直在努力

芯参谋(27):EMMC 软件设计规范

面向嵌入式系统 eMMC(embedded MultiMediaCard,JESD84 / eMMC 5.1)主机侧驱动的设计约束与推荐实现: 覆盖 初始化状态机、EXT_CSD 寄存器体系、分区与启动、读写擦命令序列、 Cache 与掉电保护、BKOPS / HPI 与 健康寿命管理,逐条给出可落地的命令序列、判据与超时预算。

18章节

5附录

512 B扇区访问粒度

CMD6EXT_CSD 唯一写入口

文档编号

版本 / 状态

适用器件

基准器件

参考标准

配套文档

EMMC-SW-SPEC-001
V1.0 · 正式发布
JEDEC eMMC 4.5 / 5.0 / 5.1 器件(BGA-153 / BGA-169 / BGA-100 / BGA-221),容量 4 GB ~ 256 GB
XTX TLC eMMC 5.1(HS400)XT28EG32GA2YUECGA(32 GB)/ XT28EG64GA2YUECGA(64 GB),FBGA-153 11.5×13×1.0 mm,VCC=3.3 V / VCCQ=1.8 V;文中标注「本器件」的数值均取自该手册 版本号 V1.0
JEDEC JESD84-B51(eMMC 5.1)· JESD84-B50(5.0)· JESD84-A441(4.41)· XTX eMMC Spec Rev 1.0
eMMC_电路设计指南.html(原理图 / 双电源 / BGA 扇出 / HS400 布线 / 焊接与生产)

0. 目的与范围

本规范约束 eMMC 器件在嵌入式固件中的主机侧软件行为:初始化状态机、EXT_CSD 配置、分区切换、 读写擦命令序列、Cache 与掉电保护、后台操作与健康管理。凡本文与器件 datasheet 冲突,以 datasheet 为准。

  • 统一初始化路径:CMD0 → CMD1 → CMD2 → CMD3 → CMD7 → CMD8 固化为唯一标准流程,提速必须「先宽度、后时序、切完必验」。
  • 统一配置入口:所有器件配置只走 CMD6 写 EXT_CSD,禁止裸写、禁止批量改字节。
  • 统一 busy 判据:以 DAT0 释放 + CMD13 状态位为准,禁止用固定延时代替。
  • 统一掉电语义:明确哪些操作是原子的、哪些必须 flush、哪些必须提前通知器件。
  • 统一健康策略:寿命字段读什么、读到什么值做什么动作,形成可运维的闭环。

不在本规范范围:硬件原理图、电源设计、PCB 布线与焊接(见《eMMC 电路设计指南》); 文件系统与 FTL 算法选型(eMMC 的 FTL 在器件内部,主机不可干预);RPMB 的密码学协议细节与密钥托管方案。

一句话结论:eMMC 是「把麻烦事都封进 BGA 里的 Managed NAND」—— 坏块、ECC、磨损均衡、映射表全部由器件内部完成,主机只面对 512 B 扇区的块设备接口。 代价是主机必须自己管好三件事:Cache 什么时候 flush、掉电前怎么通知器件、后台操作什么时候让器件做。 这三件事没做好,是 eMMC 项目里 90% 的丢数据与掉速事故的根因。

文档使用说明

  • 本文是《eMMC 电路设计指南》的软件配套篇:硬件篇解决「怎么接、怎么供电、怎么走线」,本文解决「驱动怎么写、协议怎么等、错误怎么救」。
  • 命令码、EXT_CSD 偏移、时序值取自 JESD84-B51。不同厂商、不同固件版本的器件在可选特性上存在差异,移植前必须逐条核对 datasheet。
  • 文中 C 代码为协议骨架伪代码,演示命令序列与判断条件,非特定平台可直接编译的完整实现;mmc_send_cmd()、now_ms() 等为平台相关底层。
  • EXT_CSD 偏移量统一写作 EXT_CSD[179] 形式,方括号内为字节偏移(0~511),不是 bit 位。

贯穿全文的四条铁律

① 绝不用固定延时替代 busy 判断——编程/擦除/GC 时间受磨损、温度、随机性影响,波动可达数量级; ② 每个 CMD6 都当成一次「写操作」——它返回 R1b,必须等 DAT0 释放并检查 SWITCH_ERROR; ③ 提速前先确认双方能力——读 DEVICE_TYPE 再决定切哪一档,切完必须读写回环验证并保留回退路径; ④ Cache 是性能开关,也是风险开关——开启前先想清楚掉电时有没有时间 flush,想不清楚就别开。

1 · 器件定位与系统架构

eMMC 不是一颗裸 NAND,而是「NAND 阵列 + 控制器 + FTL + MMC 接口」的完整子系统。 软件设计的第一件事,是认清主机到底能管什么、管不了什么——把器件内部的事当成自己的事,是新手最常见的过度设计。

1.1 器件定位与关键参数

512 B

访问粒度

读写擦一律按扇区(Sector)寻址

6 类

可寻址分区

Boot1/2 · RPMB · GPP1~4 · User

400 MB/s

HS400 峰值

8-bit DDR 200 MHz + DS 选通

4~256 GB

容量范围

典型 8 / 16 / 32 / 64 GB

1.8 V

VCCQ(HS 模式)

本器件仅支持 1.8 V 档(DEVICE_TYPE=57h)

370 ms

通用 CMD6 超时

本器件 GENERIC_CMD6_TIME = 0x25

2550 ms

掉电通知超时

本器件 POWER_OFF_LONG_TIME = 0xFF

≤ 80%

建议容量使用率

给 FTL 留足 GC 与磨损均衡空间

参数取自 JESD84-B51 与主流器件 datasheet;具体数值(Cache 容量、Erase Group 大小、P/E 次数)以所用料号 datasheet 为准。

1.2 系统分层与器件内部架构

eMMC 对外只暴露一组 MMC 总线(CLK / CMD / DAT0~7 / DS / RST_n),且是点对点连接—— 一条总线上只能挂一颗 eMMC,不支持多设备并联(这与 SD 卡的多卡总线是本质区别)。

eMMC 系统分层:主机 / 总线 / 器件内部三层主机 SoC:eMMC Host 控制器块设备层 → MMC 协议层 → 主机控制器驱动(HAL)MMC 总线(点对点,只允许挂一颗器件)CLK · CMD · DAT0~7 · DS(HS400 选通) · RST_neMMC 器件(BGA 封装)MMC 接口 + 协议引擎(命令解析 / 数据 FIFO / CRC)Flash 控制器:FTL 映射 · ECC · 磨损均衡 · 坏块替换 · 垃圾回收NAND 阵列:MLC / TLC + OP 预留空间(对主机完全不可见)主机只看到「512 B 扇区块设备」,坏块 / ECC / 磨损均衡全部由器件内部完成

图 1-1 eMMC 系统分层与内部架构(主机只面对块设备接口)

主机能管的 vs 器件自己管的

主机负责:初始化与提速、分区切换、读写擦命令序列、Cache 开关与 flush、掉电通知、BKOPS 调度、寿命监控、写保护策略。

器件内部负责(主机不可见也不可干预):坏块管理与替换、ECC 纠错、磨损均衡、逻辑到物理地址映射、垃圾回收、OP 预留空间管理。

这意味着:不要再在主机侧实现一套坏块表或磨损均衡——那既无效又浪费 RAM。主机真正要做的是「给器件留出做这些事的时间与空间」。

1.3 地址空间与访问粒度

eMMC 把复杂的 NAND 几何全部藏了起来,主机看到的是一个连续的 32 bit 扇区地址空间。 但有三种粒度在软件里迟早要碰到:

eMMC 地址空间与三种访问粒度主机可见:User Data Area / Boot1 / Boot2 / RPMB / GPP1~4全部按 32 bit 扇区地址(Sector,512 B)线性寻址器件内部(主机不可见)Erase Group擦除粒度 = HC_ERASE_GRP_SIZE × 512 KB;Erase 命令按它对齐Write Protect Group写保护粒度 = HC_WP_GRP_SIZE × Erase Group;写保护按它对齐NAND Page / Block真正的读写擦物理单元,由 FTL 自行映射,主机无从干预软件结论:读写按 512 B 对齐即可,Trim / Erase / 写保护才需要关心内部粒度

图 1-2 eMMC 地址空间与三种访问粒度

  • Sector(512 B):读写的最小单位,也是所有地址参数的单位(容量 > 2 GB 的器件)。读写必须 512 B 对齐。
  • Erase Group:擦除粒度 = HC_ERASE_GRP_SIZE × 512 KB(本器件 = 1 → 512 KB)。CMD35/CMD36 的地址会被器件向下取整到 Erase Group 边界。
  • Write Protect Group:写保护粒度 = HC_WP_GRP_SIZE × HC_ERASE_GRP_SIZE × 512 KB(本器件 = 16 × 512 KB = 8 MB)。写保护只能按它整块施加。

本器件实测粒度(EXT_CSD)

HC_ERASE_GRP_SIZE[224] = 1 → Erase Group = 512 KB; HC_WP_GRP_SIZE[221] = 0x10 → Write Protect Group = 8 MB; SEC_COUNT[215:212] = 07480000h(64 GB 版)→ 用户区扇区总数;BOOT_SIZE_MULT[226] = 0x20 → Boot1/Boot2 各 4096 KB;RPMB_SIZE_MULT[168] = 0x20 → RPMB 4096 KB。 这些值必须运行时从 EXT_CSD 读出,不要按「典型 eMMC」硬编码——换料、换固件版本都可能变。

Erase 的地址会被「悄悄对齐」

给 CMD35 一个未对齐的地址,器件不会报错,而是忽略低于 Erase Group 大小的低位、向下取整。 后果是多擦了相邻区域——如果那里放着有效数据,就静默丢了。正确做法:擦除前自己把起止地址按 Erase Group 大小对齐,并确认范围内的所有数据都不再需要。

1.4 与 SD NAND / SPI NAND / SPI NOR 的关键差异(移植必读)

维度SPI NORSPI NANDSD NANDeMMC
主机接口 SPI(1/2/4 线) SPI(1/2/4 线) SDIO / SPI MMC 总线(1/4/8 bit + DS)
访问粒度 字节 页(2048 B + 备用区) 块(512 B) 扇区(512 B)
坏块管理 无 主机必须做(BBT) 器件内部 器件内部(主机无需参与)
ECC 无 片内 / 主机侧,须判读 器件内部 器件内部,主机不可见
擦除 Sector/Block 擦 Block 擦(64 页) 器件内部 Erase Group(器件内部调度)
可寻址分区 无 无 无 Boot1/2 · RPMB · GPP1~4 · UDA
掉电通知 无 无 无 POWER_OFF_NOTIFICATION(独有)
寿命查询 无 靠自己统计 P/E 无 DEVICE_LIFE_TIME_EST / PRE_EOL_INFO
Cache 无 页 Cache 寄存器 无 写 Cache(需显式 flush)
封装 / 可焊性 SOP/WSON,易 WSON/LGA,易 LGA/WSON,易 BGA,需 HDI + X 光检测

从 SPI NAND / SD NAND 移植过来最危险的三个假设

  • 假设「写完就落盘」:裸 NAND 里 10h 后轮询 OIP 结束就是写完了;eMMC 开了 Cache 后,DAT0 释放只代表数据进了 Cache。
  • 假设「要自己管坏块」:SPI NAND 必须有 BBT;eMMC 完全没有坏块概念,实现一套是纯粹的浪费。
  • 假设「掉电就掉电」:eMMC 提供了标准掉电通知机制,不用它就是放弃了一个免费的可靠性提升。

2 · 术语与缩写

本章统一术语口径。eMMC 的术语体系与 NAND 系(页/块/备用区)完全不同,混用会导致文档与代码对不上。

2.1 接口与协议术语

缩写 / 术语全称本文中的含义
eMMC embedded MultiMediaCard 板载 Managed NAND 子系统;本文默认 JESD84-B51(5.1)
CMD / Resp Command / Response 48 bit 命令帧与响应;R1/R1b/R2/R3 等响应类型
RCA Relative Card Address 器件相对地址,由 CMD3 分配(常用 0x0001)
OCR Operating Conditions Register 电压窗口与上电完成标志;CMD1 响应 bit31 = 就绪
CID Card IDentification 128 bit 器件标识:厂商 ID、产品名、序列号、生产日期
CSD Card Specific Data 器件基础参数(CMD9 读取)
EXT_CSD Extended CSD 512 字节扩展寄存器(CMD8 读 / CMD6 写),eMMC 的核心管理面
R1 / R1b — 32 bit 状态响应;R1b 附带 busy 信号(DAT0 拉低)
SWITCH_ERROR — R1 bit7;CMD6 写 EXT_CSD 失败标志

2.2 存储与分区术语

缩写 / 术语全称本文中的含义
Sector — 512 B,读写与寻址的最小单位
Erase Group — 擦除粒度 = HC_ERASE_GRP_SIZE × 512 KB
Write Protect Group — 写保护粒度,通常远大于 Erase Group
UDA User Data Area 用户数据区,默认承载全部容量,文件系统主要用这里
Boot 1 / Boot 2 Boot Area Partition 启动分区,容量 = 128 KB × BOOT_SIZE_MULT
RPMB Replay Protected Memory Block 带 HMAC-SHA256 认证与防重放的分区;密钥 / 计数器放这里
GPP 1~4 General Purpose Partition 通用分区,可做增强属性与独立写保护,用于系统 / 数据 / 日志隔离
Enhanced / pSLC Enhanced User Data Area 把部分区域配置为 pseudo-SLC:容量换寿命、性能与数据保持
OP Over-Provisioning 器件内部预留空间(主机不可见)+ 用户主动留出的空闲容量
FTL Flash Translation Layer 器件内部的逻辑→物理映射层,主机不可干预

2.3 特性与机制术语

缩写 / 术语全称本文中的含义
HS200 / HS400 — 高速时序档位;HS200 = SDR 200 MHz,HS400 = DDR 200 MHz + DS 选通
DS Data Strobe HS400 模式下由器件输出的选通信号,用于主机采样
Tuning — HS200/HS400 下用 CMD21 找最佳采样相位的过程
Cache — 器件内部写缓存;开则快、掉电则丢,需 FLUSH_CACHE 落盘
Reliable Write — CMD23 bit31;要求该次写入原子完成(要么新要么旧)
Forced Programming — CMD23 bit24;仅 Cache 开启时有效,强制立即写入 NAND
BKOPS Background Operations 器件内部垃圾回收与磨损均衡等后台任务
HPI High Priority Interrupt 高优先级中断;打断器件长时间操作(CMD12/CMD13 带 HPI 标志)
Trim / Discard — 标记数据无效;Trim 读出值确定,Discard 不确定
Sanitize — 物理清除所有未映射数据,用于出厂恢复与报废清密
FFU Field Firmware Update 器件固件在线升级;过程掉电可能变砖
POWER_OFF_NOTIFICATION — EXT_CSD[34];主机断电前通知器件的标准机制

2.4 本文书写约定

  • 命令写作 CMD13 形式(不加 h 后缀),与 JEDEC 文本一致。
  • EXT_CSD 字段写作 EXT_CSD[179],方括号内为字节偏移;位域写作 EXT_CSD[179][2:0]。
  • 数值:十六进制用 0x 前缀;位序 bit0 为最低位。
  • 时序:「典型值 / 最大值」成对给出时,软件超时一律按最大值预算;typ 值只用于安排轮询节奏。
  • 代码示例为 C 伪代码,省略主机控制器寄存器细节,只表达命令序列与判据。

3 · 驱动架构与初始化

eMMC 的初始化是一条不能跳步的状态机:每一步都把器件推到下一个状态,跳步的直接后果是「命令发出去没响应」。 提速则是初始化之后单独的一段,必须「先慢后快、切完必验」。

3.1 分层职责

层职责禁止做的事
文件系统 / 块设备层 提交 bio / request;下发 flush、discard 语义 直接拼 MMC 命令、直接算扇区边界之外的地址
MMC 核心协议层 初始化状态机、EXT_CSD 解析、分区切换、BKOPS 调度 绕过状态检查直接发读写命令
命令封装层 CMD17/18/24/25、CMD23、CMD13、CMD6、CMD35/36/38 省略 busy 等待、忽略 SWITCH_ERROR
主机控制器驱动(HAL) 时钟、总线宽度、DMA、CRC、tuning 引擎、超时 在数据传输中途改时钟频率或总线宽度

3.2 上电初始化流程

完整的识别流程只有一条标准路径,六步缺一不可:

上电初始化:MMC 协议状态机推进顺序CMD0GO_IDLE_STATE→ IdleCMD1SEND_OP_COND轮询 OCR bit31→ ReadyCMD2ALL_SEND_CID→ IdentCMD3SET_RELATIVE_ADDR→ StbyCMD7SELECT_CARDRCA ≪ 16→ TranCMD8SEND_EXT_CSD读回 512 B→ Tran① CMD1 必须循环重发并设超时(典型 1 s),不可用固定延时代替轮询② CMD8 只能在 Transfer 态发送;EXT_CSD 未读到则无从判断能力提速:必须「先慢后快、先宽度后时序」,切完必验配总线宽度CMD6 → BUS_WIDTH[183]1→4→8 bit切时序CMD6 → HS_TIMING[185]HS / HS200HS200 TuningCMD21 采样相位找到采样窗口切 HS400CMD6 → HS_TIMING=3DS 选通 + DDR⑤ 切换后必须做读写回环校验;失败要能逐级回退到低速模式HS400 不允许直接从 Legacy/HS 切入,必须先经 HS200 完成 tuning

图 3-1 上电初始化状态机与提速路径

int mmc_init(void)
{
uint32_t resp, rca = 0x0001;
uint8_t ext_csd[512];

/* ① 电源与复位就绪:VCC/VCCQ 稳定、RST_n 释放、输出 400 kHz 以下时钟 */
host_set_clock(400000); /* 识别阶段必须低速 */
host_set_width(1);

/* ② CMD0:复位到 Idle */
send_cmd(CMD0, 0x00000000, RSP_NONE); /* GO_IDLE_STATE → Idle(0xF0F0F0F0 是 GO_PRE_IDLE_STATE,用于复位后重引导 boot) */
delay_us(200);

/* ③ CMD1:电压协商 + 等待上电完成(bit31 = 1) */
if (wait_cmd1_ready(1000) != 0) /* 超时 1 s,循环重发 */
return -E_MMC_NO_RESPONSE;

/* ④ CMD2 / CMD3:读 CID、分配 RCA */
send_cmd(CMD2, 0, RSP_R2); /* 128 bit CID */
send_cmd(CMD3, rca << 16, RSP_R1); /* → Standby */

/* ⑤ CMD7:选中,进入 Transfer 态 */
send_cmd(CMD7, rca << 16, RSP_R1);

/* ⑥ CMD8:读 512 B EXT_CSD(只能在 Transfer 态发) */
if (mmc_send_ext_csd(ext_csd) != 0)
return -E_MMC_EXT_CSD;

return mmc_setup_from_ext_csd(ext_csd); /* 提速 + 分区(见 3.4 / 第 5 章) */
}

/* CMD1 必须循环重发并设超时 —— 固定延时必然在某些器件上翻车 */
static int wait_cmd1_ready(uint32_t timeout_ms)
{
uint32_t t0 = now_ms(), resp;
do {
send_cmd(CMD1, 0x40FF8080, RSP_R3);
resp = host_last_resp();
if (resp & 0x80000000u) /* bit31 = 上电完成 */
return 0;
delay_ms(10);
} while (now_ms() – t0 < timeout_ms);
return -E_TIMEOUT;
}

CMD1 用固定延时代替轮询,是「某些批次起不来」的经典原因

器件的上电就绪时间随容量、温度、内部初始化任务(尤其是掉电恢复)波动,可以从几十毫秒到几百毫秒。 写死一个 delay_ms(100) 在实验室样机上没问题,量产时换个批次或低温冷启动就起不来。

正确做法:循环发送 CMD1 并检查 OCR bit31,总超时设 1 s。这是 JEDEC 明确要求的做法,没有捷径。

3.3 器件识别与能力协商

初始化完成后,器件的全部能力都在 CID / CSD / EXT_CSD 里。驱动必须从寄存器读,不许硬编码:

信息来源关键字段软件用途
厂商 / 型号 / 序列号 CID(CMD2) MID、PNM、PSN 日志、追溯、产线记录
eMMC 版本 EXT_CSD[192] REV 0x07 = 5.0,0x08 = 5.1 决定可用特性集(5.1 才有 pSLC 增强等)
用户区容量 EXT_CSD[215:212] SEC_COUNT 容量 = SEC_COUNT × 512 B 唯一的容量来源,不要用 CSD 推算
支持的速度档位 EXT_CSD[196] DEVICE_TYPE 位域:HS200/HS400 及对应电压 决定能切到哪一档
Cache 容量 EXT_CSD[252:249] CACHE_SIZE 0 = 无 Cache;否则 × 1 KB 是否值得开 Cache
可靠写扇区数 EXT_CSD[222] REL_WR_SEC_C 单次可靠写的最大扇区数 Reliable Write 的分批依据
Erase / Trim 粒度 EXT_CSD[224] / [232] HC_ERASE_GRP_SIZE、TRIM_MULT 擦除对齐与超时预算
分区切换时间 EXT_CSD[199] PARTITION_SWITCH_TIME 切分区后的等待时间
寿命与预警 EXT_CSD[267..269] PRE_EOL_INFO、LIFE_TIME_A/B 健康管理(第 12 章)

/* 能力解析:全部从 EXT_CSD 取,禁止硬编码容量与几何 */
static int mmc_setup_from_ext_csd(const uint8_t *e)
{
uint32_t sec = le32(e + 212); /* SEC_COUNT[215:212] */
uint64_t cap = (uint64_t)sec * 512; /* 用户区字节容量 */
uint8_t rev = e[192]; /* EXT_CSD_REV */
uint8_t dtype = e[196]; /* DEVICE_TYPE */
uint32_t cache = le32(e + 249); /* CACHE_SIZE[252:249] */

mmc.capacity = cap;
mmc.rev = rev;
mmc.hs200_1v8 = !!(dtype & 0x02); /* HS200 @ 1.8 V */
mmc.hs400_1v8 = !!(dtype & 0x04); /* HS400 @ 1.8 V */
mmc.cache_kb = cache; /* 0 = 无 Cache */

log_i("eMMC rev=%d cap=%llu MB cache=%u KB hs400=%d",
rev, cap >> 20, cache, mmc.hs400_1v8);
return 0;
}

3.4 提速:先宽度、后时序、切完必验

上电后器件默认1-bit + Legacy(最高 26 MHz),所有高速档位都要主机主动切换。顺序错了会直接通信失败。

  • 确认 VCCQ 已切到 1.8 V:HS200/HS400 只在低电压档位下保证,3.3 V 下不许切(本器件 DEVICE_TYPE=0x57 只开放 1.8 V 档的 HS200/HS400,不支持 1.2 V)。
  • 先配总线宽度:CMD6 写 EXT_CSD[183] BUS_WIDTH —— 0 = 1-bit,1 = 4-bit,2 = 8-bit,5 = 4-bit DDR,6 = 8-bit DDR。
  • 再切时序:CMD6 写 EXT_CSD[185] HS_TIMING —— 0 = Legacy,1 = High Speed,2 = HS200,3 = HS400,4 = HS400ES。
  • HS200 必须 tuning:反复发 CMD21,主机在不同采样相位上采集并选出有效窗口。
  • HS400 必须先经 HS200:完成 HS200 tuning 后,写 HS_TIMING = 3 并启用 DS 选通。
  • 切完必验:做一次已知数据的写入 → 读回 → 比对,失败则逐级回退(HS400 → HS200 → HS → Legacy)。
  • /* 提速:每一步都等 busy、每一步都检查 SWITCH_ERROR */
    static int mmc_switch(uint8_t index, uint8_t value, uint32_t timeout_ms)
    {
    uint32_t arg = (0x03u << 24) /* Access = Write Byte */
    | ((uint32_t)index << 16)
    | ((uint32_t)value << 8)
    | 0x00u; /* CmdSet = 标准命令集 */
    uint32_t st;

    send_cmd(CMD6, arg, RSP_R1b);
    if (wait_dat0_release(timeout_ms)) /* 关键:CMD6 也带 busy */
    return -E_TIMEOUT;
    send_cmd(CMD13, mmc.rca << 16, RSP_R1);
    st = host_last_resp();
    if (st & (1u << 7)) /* SWITCH_ERROR */
    return -E_SWITCH_ERR;
    return 0;
    }

    int mmc_upgrade_to_hs400(void)
    {
    mmc_switch(183, 2, 500); /* BUS_WIDTH = 8-bit */
    mmc_switch(185, 2, 500); /* HS_TIMING = HS200 */
    if (host_hs200_tuning()) /* CMD21 采样相位调谐 */
    return -E_TUNING;
    mmc_switch(183, 6, 500); /* 8-bit DDR */
    mmc_switch(185, 3, 500); /* HS_TIMING = HS400 */
    return mmc_speed_verify(); /* 读写回环校验,失败即回退 */
    }

    超时别写 100 ms:本器件通用 CMD6 超时是 370 ms

    JEDEC 给的通用默认 GENERIC_CMD6_TIME = 0x0A(10 × 10 ms = 100 ms),但本器件实测为 0x25 = 37 → 370 ms。 按 100 ms 判超时,在 Cache 回收、GC 撞车、分区切换等场景下会误判失败,进而触发本不必要的复位与回退。

    正确做法:超时值从 GENERIC_CMD6_TIME 读出再乘单位(10 ms)算出来,再加 30% 余量;只有那些自带更长超时字段的操作(Sanitize、掉电通知、分区切换、初始化后第一次分区生效)才改用对应字段。

    跳过 tuning 的后果是「偶发数据错误」,不是「连不上」

    HS200/HS400 下如果不做 tuning,器件能连上、能跑、大部分时间也对, 只在特定温度、电压、老化程度下偶尔出现 CRC 错误或数据位错。这类问题在实验室几乎抓不到,量产时才爆发。

    另一类常见错误是HS400 直接从 Legacy 切入:协议要求先到 HS200 完成 tuning,跳过这一步的器件行为未定义。

    3.5 初始化自检清单

    • 上电时钟 ≤ 400 kHz,CMD1 循环轮询 bit31 且超时 ≥ 1 s
    • CMD8 在 Transfer 态发送,已成功读回 512 B EXT_CSD
    • 容量从 SEC_COUNT 计算,未硬编码;已与预期容量对账
    • 提速前已确认 DEVICE_TYPE 与 VCCQ 电压档位匹配
    • 总线宽度与 HS_TIMING 的写入顺序正确(宽度在前)
    • HS200/HS400 已完成 tuning,并有读写回环验证
    • 提速失败有逐级回退路径,且回退后功能可用
    • 初始化日志记录了 REV、容量、速度档位、Cache 容量,便于现场追溯

    4 · EXT_CSD 寄存器体系

    EXT_CSD 是 eMMC 的管理面:512 字节,包罗万象。 所有配置只有一个入口——CMD6。理解它的分段、写入规则与生效时机,是写对 eMMC 驱动的前提。

    4.1 512 字节的分段

    EXT_CSD:512 字节,CMD8 读 / CMD6 写Properties Segment [0..191]只读:容量(SEC_COUNT)、版本(REV)、能力(DEVICE_TYPE)、寿命、时序Mode Segment [192..511]可读写:总线宽度、HS_TIMING、分区配置、Cache、BKOPS、写保护访问方式:CMD8 读整块(512 B) / CMD6 改单个字节写后一律返回 R1b:必须等 DAT0 释放,并检查 SWITCH_ERROR(R1 bit7)常见误解:EXT_CSD 不是「寄存器数组」,每次 CMD6 只能改一个字节,且部分字段要断电/复位才生效

    图 4-1 EXT_CSD 512 字节分段与访问方式

    • Properties Segment(0~191):只读。容量、版本、能力、时序、寿命都在这里。
    • Mode Segment(192~511):可读写。总线宽度、时序、分区、Cache、BKOPS、写保护都在这里。

    4.2 CMD6:唯一的写入口

    CMD6(SWITCH)32 bit 参数位域31:26置 025:24Access23:16Index15:8Value7:3置 02:0CmdSetAccess:00 = 命令集切换 01 = 置位 10 = 清位 11(0x3) = 写字节(最常用)Index = EXT_CSD 字节偏移(0~511) Value = 写入值 CmdSet = 0(标准命令集)例:切 HS400 → arg = (0x03≪24) | (185≪16) | (0x03≪8) | 0x00例:开 Cache → arg = (0x03≪24) | (33≪16) | (0x01≪8) | 0x00

    图 4-2 CMD6(SWITCH)32 bit 参数位域

    CMD6 是 R1b 命令,自带 busy

    这一点最容易被忽略:CMD6 不是「写个寄存器就完事」,它可能触发器件内部的重新配置、分区重算甚至内部擦除。 返回类型是 R1b,器件会把 DAT0 拉低直到操作结束。不等 busy 就发下一条命令,会得到不可预期的结果。

    超时由 GENERIC_CMD6_TIME 给出,单位 10 ms:本器件 = 0x25 → 370 ms(JEDEC 通用默认 0x0A → 100 ms,切勿照抄); 个别操作(Sanitize、掉电通知、分区切换、初始化后第一次分区生效)有自己的更长超时字段,见附录 C 与附录 F。

    4.3 写 EXT_CSD 六步准则

  • 先读后写:用本地缓存的 512 B EXT_CSD 确认当前值,避免无意义的改写。
  • 一次只改一个字节:CMD6 的 Index 是单字节偏移,没有批量写。
  • 用 Write Byte 模式:Access = 0x3(写字节);置位/清位模式只在少数场景需要。
  • 等 busy 释放:轮询 DAT0 或用主机控制器的 R1b 完成中断,超时按 GENERIC_CMD6_TIME 预算。
  • 检查 SWITCH_ERROR:发 CMD13 读状态,R1 bit7 = 1 表示这次写入被拒绝。
  • 回读确认:关键配置(总线宽度、时序、分区)写完后重新 CMD8 读回比对。
  • 4.4 生效时机:三种,别搞混

    生效时机典型字段软件要注意什么
    立即生效 HS_TIMING、BUS_WIDTH、CACHE_CTRL、PARTITION_ACCESS 写完等 busy 结束即可使用新配置
    复位后生效 PARTITION_CONFIG 的 BOOT 相关位、部分写保护设置 写完需 CMD0 或 RST_n 才生效
    断电 / 硬件复位后生效 BOOT_SIZE_MULT、RPMB_SIZE_MULT、GP_SIZE_MULT、ENH_SIZE_MULT 分区容量类配置必须 power cycle,只复位不一定够,以 datasheet 为准

    分区容量配置写完没断电,是「分区大小不对」的头号原因

    典型事故:主机写完 GP_SIZE_MULT 后只做了软件复位,然后立刻按新分区大小去读写—— 器件还停留在旧的分区布局上,轻则读不到数据,重则写到错误的分区(比如把文件系统镜像写进了 Boot 区)。

    产线流程必须把「配置分区 → 断电 → 重新上电 → 校验分区布局」做成不可跳过的固定步骤。

    4.5 高频字段速查

    偏移字段R/W取值与含义用途
    34 POWER_OFF_NOTIFICATION R/W 0x00 不支持 / 0x01 POWERED_ON / 0x02 SHORT / 0x03 LONG / 0x04 SLEEP 掉电通知(第 10 章)
    32 FLUSH_CACHE W bit0 FLUSH = 1 触发回写 Cache 落盘(第 7 章)
    33 CACHE_CTRL R/W bit0 Cache_EN:0 关 / 1 开 Cache 开关
    161 HPI_MGMT R/W bit0 HPI_EN 使能 HPI(第 11 章)
    163 BKOPS_EN R/W bit0 MANUAL_EN,bit1 AUTO_EN 一次性可编程,不可回退
    164 BKOPS_START W 0x01 手动触发一次后台操作 空闲时主动 GC
    165 SANITIZE_START W 0x01 启动物理清除 出厂恢复 / 报废清密
    175 ERASE_GROUP_DEF R/W 0 = 用 CSD 定义 / 1 = 用 EXT_CSD 定义 高密度器件必须置 1
    179 PARTITION_CONFIG R/W [7] BOOT_ACK / [5:3] BOOT_PARTITION_ENABLE / [2:0] PARTITION_ACCESS 分区切换与启动配置
    183 BUS_WIDTH R/W 0/1/2 = 1/4/8-bit;5/6 = 4/8-bit DDR 总线宽度
    185 HS_TIMING R/W 0/1/2/3/4 = Legacy/HS/HS200/HS400/HS400ES 速度档位
    192 REV R 0x08 = eMMC 5.1 版本判断
    196 DEVICE_TYPE R 位域:HS200 / HS400 及各电压档 能力协商
    212 SEC_COUNT R 4 字节小端;容量 = SEC_COUNT × 512 B 容量唯一来源
    246 BKOPS_STATUS R 0 = 无需求;1~3 = 需求等级递增 是否该让器件做 GC
    267 PRE_EOL_INFO R 0 Normal / 1 Warning / 2 Urgent 寿命终期预警
    268 DEVICE_LIFE_TIME_EST_A R 0x01 0–10% … 0x0A 90–100%,0x0B 超期 常规模式寿命
    269 DEVICE_LIFE_TIME_EST_B R 同 A 的分档规则 pSLC / SLC 模式寿命

    完整字段定义见 JESD84-B51 第 7 章;厂商自定义字段以器件 datasheet 为准。本器件(XT28EG32/64GA2YUECGA)上电默认实测值见附录 F.1——其中 RST_n_FUNCTION[162] = 0(硬件复位默认未使能)、HPI_MGMT[161] = 0、BKOPS_EN[163] = 0、CACHE_CTRL[33] = 0、CMQ_MODE_EN[15] = 0 都是「支持但默认关」,必须由主机显式打开。

    4.6 常见陷阱

    陷阱现象对策
    不等 CMD6 的 busy 后续命令无响应或返回错乱状态 把 CMD6 一律当 R1b 处理,等 DAT0 释放
    不查 SWITCH_ERROR 配置静默失败,实际仍在旧档位 每次 CMD6 后 CMD13 查 bit7
    用 3.3 V VCCQ 切 HS400 高速下大量 CRC 错误 切高速前先把 VCCQ 切到 1.8 V(本器件不支持 1.2 V 档)
    照抄 JEDEC 默认超时 Cache 回收 / GC 撞车时误判 CMD6 失败 超时一律从 GENERIC_CMD6_TIME 读出算,本器件 370 ms
    分区配置后未断电 分区大小不对,甚至写错分区 配置 → 断电 → 上电 → 校验,固化为产线步骤
    把 BKOPS_EN 当普通开关 写入后无法回退(一次性可编程) 只在确认需要时写入,并留记录
    改 ERASE_GROUP_DEF 后不重算几何 擦除范围算错 置 1 后从 EXT_CSD 重新读取所有几何参数

    后续章节请下载「芯参谋」查看

    ……(篇幅原因, 还有20章· 详见芯参谋→方案设计)

    当前分享仅开放前 5 章正文。详细资料请在芯参谋客户端中打开完整文档。

    打开路径:🔧解决方案&应用市场分析 -> 原理方案设计 -> eMMC_软件设计规范

    📥 下载芯参谋客户端

    赞(0)
    未经允许不得转载:171主机测评 » 芯参谋(27):EMMC 软件设计规范
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址