4. eMMC初始化流程:上电、复位、识别卡、操作条件设置
要把eMMC用起来,第一步就是把它“唤醒”。 很多人觉得初始化简单——给电、发命令就行了。 可我在项目中见过太多次因为初始化时序没卡准,导致后面读ID都读不出来的情况。 说白了,初始化就像给设备“对暗号”,顺序、电平、时序,少一个都不行。
4.1 上电时序——别急着发命令
eMMC上电不能像按台灯开关那样“啪”一下就完事。 VCC和VCCQ必须同时上升,而且要在规定时间内达到稳定。 我记得有一次调试,电源纹波稍大,卡在初始化第一步就不动了。 后来加上去耦电容,才把问题解决。
| 参数 | 最小值 | 典型值 | 最大值 | 说明 |
|---|---|---|---|---|
| VCC上电时间(T_POWER_ON) | 0.1ms | 1ms | 10ms | 从0V到稳定电压 |
| VCCQ上电时间 | 0.1ms | 1ms | 10ms | 需与VCC同时或稍晚 |
| 上电后等待(T_CMD) | 1ms | 2ms | — | 发第一条命令前必须等待 |
| 时钟稳定时间 | — | 74个时钟周期 | — | 上电后CKO需连续74个周期 |
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);
// 卡应返回无响应(无回应),但需等待超时
4.3 识别卡——获取身份证
复位后卡处于空闲状态,主机需要识别总线上有哪些卡。 这一步分两步走:
- CMD2(ALL_SEND_CID): 广播命令,所有卡同时回应自己的CID(卡片识别码)。如果总线只有一张卡,直接得到CID;多卡时需通过CMD3分配RCA。
- CMD3(SET_RELATIVE_ADDR): 给每张卡分配一个相对地址(RCA)。通常主机发送CMD3,卡返回RCA,然后主机用CMD7选中该卡。
你可能问:为什么要先CMD2再CMD3? 嗯,因为CMD2是用来“喊人”的,喊完之后才知道有谁。 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) {
// 初始化超时,需要复位重试
}
4.5 进入数据传输模式
操作条件设置成功后,卡处于“就绪”状态。 此时用CMD7(SELECT/DESELECT_CARD)选中刚才分配的RCA,卡就会进入传输模式。 之后才能发送读写命令(CMD18/CMD24等)。
对了,还有个细节:CMD7的参数是RCA左移16位。 选中的卡会切换为“传输状态”,其他卡保持“待机”。 如果你要切换操作其他卡,可以先用CMD7注销当前卡(参数=0),再选另一张。
初始化结束后,eMMC就准备好为你服务了。 不过别忘了,HS400模式需要在传输模式下切换,那部分我们后续再聊。 现在先把初始化流程走通,后面就顺了。