4. eMMC初始化流程:上电、复位、识别卡、操作条件设置

要把eMMC用起来,第一步就是把它“唤醒”。 很多人觉得初始化简单——给电、发命令就行了。 可我在项目中见过太多次因为初始化时序没卡准,导致后面读ID都读不出来的情况。 说白了,初始化就像给设备“对暗号”,顺序、电平、时序,少一个都不行。

eMMC初始化流程 eMMC初始化流程 ① 上电(Power On) ② 复位(Reset) ③ 识别卡(CMD2/CMD3) ④ 设置操作条件(CMD1) ⑤ 进入数据传输模式 关键提醒 • 上电后需等待至少1ms • 复位后CKO需稳定 • 识别卡阶段用CMD2获取CID • CMD1协商电压与HCS • 成功后用CMD7选中设备

4.1 上电时序——别急着发命令

eMMC上电不能像按台灯开关那样“啪”一下就完事。 VCC和VCCQ必须同时上升,而且要在规定时间内达到稳定。 我记得有一次调试,电源纹波稍大,卡在初始化第一步就不动了。 后来加上去耦电容,才把问题解决。

参数最小值典型值最大值说明
VCC上电时间(T_POWER_ON)0.1ms1ms10ms从0V到稳定电压
VCCQ上电时间0.1ms1ms10ms需与VCC同时或稍晚
上电后等待(T_CMD)1ms2ms—发第一条命令前必须等待
时钟稳定时间—74个时钟周期—上电后CKO需连续74个周期
我曾经... 遇到一块eMMC在低温环境下上电瞬间掉电,导致CID读取错误。排查后发现是电源启动时斜率不够,加长上电延时后解决。上电时序千万不能“差不多就行”。

4.2 复位操作——软硬兼施

复位有两种:硬件复位和软件复位。 硬件复位拉低RST_n至少1μs,然后释放。 软件复位用CMD0发送参数0xF0F0F0F0(GO_IDLE_STATE)。 我个人习惯在硬件复位之后,再补一条CMD0,确保卡彻底回到空闲状态。

// 伪代码:eMMC复位流程
// 1. 拉低RST_n至少1μs
GPIO_Reset(RST_n);
delay_us(2);
GPIO_Set(RST_n);

// 2. 等待时钟稳定(至少74个时钟周期)
delay_cycles(80);

// 3. 发送CMD0进入空闲状态
uint32_t cmd0_arg = 0xF0F0F0F0;
emmc_send_cmd(CMD0, cmd0_arg);
// 卡应返回无响应(无回应),但需等待超时
小技巧: 如果硬件复位后卡依然挂死,可以尝试连续发送3次CMD0,每次间隔1ms。这在某些国产eMMC上特别有用。

4.3 识别卡——获取身份证

复位后卡处于空闲状态,主机需要识别总线上有哪些卡。 这一步分两步走:

  • CMD2(ALL_SEND_CID): 广播命令,所有卡同时回应自己的CID(卡片识别码)。如果总线只有一张卡,直接得到CID;多卡时需通过CMD3分配RCA。
  • CMD3(SET_RELATIVE_ADDR): 给每张卡分配一个相对地址(RCA)。通常主机发送CMD3,卡返回RCA,然后主机用CMD7选中该卡。

你可能问:为什么要先CMD2再CMD3? 嗯,因为CMD2是用来“喊人”的,喊完之后才知道有谁。 CMD3则是给每个人发编号。编号在后续读写操作里必须用。

实际项目中的坑: 某些eMMC在CMD2返回CID后,会短暂进入“忙碌”状态。如果主机立刻发CMD3,卡可能不响应。建议在CMD2之后等待至少8个时钟周期,或者读取状态寄存器确认空闲再发CMD3。

4.4 操作条件设置——电压与容量协商

接下来用CMD1(SEND_OP_COND)告诉卡:“我要用多大的电压,支不支持大容量?” 卡会返回自己的OCR寄存器,包含电压范围和HCS(主机容量支持)标志。 主机需要持续发送CMD1,直到卡返回busy位清0(表示初始化完成)。

OCR位域含义典型值
[31]上电完成状态(busy)1=完成
[30:15]支持电压范围0x00FF8000(2.7V~3.6V)
[14:8]保留—
[7]UHS-II支持0/1
[6]HCS(大容量支持)1=支持大于2GB
// CMD1协商流程(简化)
uint32_t ocr_arg = 0; // 主机请求电压范围,通常设为0x00FF8000
int retry = 100;
do {
    uint32_t response = emmc_send_cmd(CMD1, ocr_arg);
    if (response & (1 << 31)) {
        // busy位清零,初始化完成
        break;
    }
    delay_ms(10);
} while (--retry);

if (retry == 0) {
    // 初始化超时,需要复位重试
}
我曾经 在某个项目中,CMD1一直不返回busy=1。后来发现是VCCQ电压设置过低(1.8V的卡供电1.8V,但有些卡需要先以3.3V协商)。嗯,电压范围千万别写死,最好是先尝试全范围再降下来。

4.5 进入数据传输模式

操作条件设置成功后,卡处于“就绪”状态。 此时用CMD7(SELECT/DESELECT_CARD)选中刚才分配的RCA,卡就会进入传输模式。 之后才能发送读写命令(CMD18/CMD24等)。

对了,还有个细节:CMD7的参数是RCA左移16位。 选中的卡会切换为“传输状态”,其他卡保持“待机”。 如果你要切换操作其他卡,可以先用CMD7注销当前卡(参数=0),再选另一张。

警告: 在多卡总线中,如果忘记先取消选中旧卡就直接选新卡,旧卡会进入“断开连接”状态,可能导致后续命令响应异常。我吃过这个亏,排查了整整一天才发现是RCA冲突。

初始化结束后,eMMC就准备好为你服务了。 不过别忘了,HS400模式需要在传输模式下切换,那部分我们后续再聊。 现在先把初始化流程走通,后面就顺了。