3、I3C协议基础:帧格式、命令码、起始/停止条件归纳总结
协议玩了这么多年,每次看到新总线协议,我第一反应就是去翻它的帧格式和命令码。
为什么?因为帧格式决定了你怎么把数据塞进去,命令码决定了对方怎么理解你的意图。
I3C的帧结构其实并不复杂,但和I2C有不少差别。你想想看,一个总线既要向后兼容I2C,又要跑出更高效率,必然得在帧头尾做文章。下面我把这块掰开揉碎了讲。
3.1 起始条件与停止条件
先说最基础的——总线状态的切换。
I3C的起始条件和停止条件,形式上跟I2C一模一样:
- 起始条件(Start):SCL为高电平时,SDA从高电平跳变为低电平。
- 停止条件(Stop):SCL为高电平时,SDA从低电平跳变为高电平。
但这里有个坑——I3C的多主场景下,仲裁逻辑比I2C更复杂。
我曾经在一款传感器项目中,因为起始条件建立时间不够,导致主机切换时总线卡死。后来查协议规范才发现,I3C对起始条件的保持时间有更严格的要求,特别是从I2C切换到I3C模式的瞬间。
注意:I3C允许在同一个传输序列中连续发送多个起始条件(重复起始),但不允许中途插入停止条件后再重新启动。如果你要做多命令合并,务必用重复起始,不要发Stop。
3.2 I3C帧格式解析
帧格式是协议的核心。I3C的帧结构分为两种:私有数据帧和公共命令帧(CCC)。先看图,再细讲。
上面这幅图展示的是最基本的私有数据帧。如果是CCC帧(公共命令帧),结构会稍有不同:地址阶段后紧接着一个命令码字节,而不是数据字节。命令码由I3C协议规范统一规定。
3.3 命令码汇总
命令码(CCC)是I3C区别于I2C的核心。说白了,I2C里你想让从机做什么,得自定义寄存器;I3C则通过公共命令码让总线做标准操作。
我个人习惯把常用CCC分成三类:地址分配类、配置控制类、状态读取类。下面这张表列出了我在项目中反复用到的几个:
| 命令码(十六进制) | 名称 | 用途 | 方向 |
|---|---|---|---|
| 0x07 | ENTDAA | 进入动态地址分配模式 | 主机→所有从机 |
| 0x15 | SETDASA | 设置静态地址 | 主机→指定从机 |
| 0x00 | ENEC | 启用事件检测(中断) | 主机→所有从机 |
| 0x01 | DISEC | 禁用事件检测 | 主机→所有从机 |
| 0x02 | ENTAS0 | 进入挂起模式(低功耗) | 主机→所有从机 |
| 0x06 | RSTDAA | 重置动态地址 | 主机→所有从机 |
| 0x08 | GETMXDS | 读取最大数据速率 | 主机→指定从机 |
实战提醒:ENTDAA是地址分配的第一步。你用逻辑分析仪抓CCC时,注意看从机回复的Ack。如果从机没出现,很大概率是地址冲突或时序不满足。我记得第一次调I3C,愣是花了一个下午才发现是停止条件后的总线空闲时间不够。
3.4 避坑总结
最后,把我在I3C协议基础这块遇到过的坑攒一攒,送给你:
- 起始条件前必须保证总线空闲——I3C要求停止条件后至少等待一个tBUF时间才能发起始。我曾经用I2C那套习惯,连续传输间只留了几个时钟,结果从机直接罢工。
- 地址7位还是8位?I3C地址是7位,但和I2C一样,发送时左移一位,低位放R/W。别搞错了,否则地址对不上。
- CCC帧的应答响应:有些命令(如ENTDAA)需要所有从机同时应答,此时如果某个从机没准备好,总线上的应答位可能是多个从机信号叠加——你看到的可能是“奇怪的电平”。
- 停止条件后SDA释放:主机必须释放SDA为高阻,否则从机无法拉高。我见过硬件设计把SDA上拉电阻选太小,导致停止后SDA拉不到高电平,总线直接死锁。
建议新手从最简单的私有写帧开始调:发起始→地址+写→数据字节→停止。先把这条路径跑通,再玩CCC命令。你想想看,如果连最简单的数据都传不对,哪还有心思去管动态地址分配呢?
好了,帧格式、起始停止、命令码这三块就是I3C协议的基础骨架。把这个骨架搭稳了,后面做地址分配、事件检测、高速模式都会顺很多。