I3C 协议栈:命令、数据、响应、仲裁

如果你做过 I2C 项目,再看 I3C 协议栈,第一感觉就是——它还是那个熟悉的两线制框架,但里子已经彻底重构了。我个人习惯把 I3C 协议栈拆成四个核心环节:命令、数据、响应、仲裁。这四个环节环环相扣,你在 PCB 布线时遇到的大部分信号完整性问题,都能从这里面找到根因。

1. 命令阶段:CCC 与私有命令

I3C 的命令分两大类:通用命令代码(CCC) 和 私有命令。CCC 是协议规定的广播或定向指令,比如动态地址分配(ENTDAA)、设置 IBI 使能等。私有命令则是主设备和特定从设备之间的“私聊”。

命令的发送格式,说白了就是一个 8 位地址 + 读/写位 + ACK 位。但跟 I2C 有个巨大区别:I3C 的地址是 7 位,而且从设备地址可以在运行时动态改。这也是“动态地址分配”能玩起来的基础。

命令类型地址域数据方向典型场景
CCC 广播7’h7E写ENTDAA、RSTDAA
CCC 定向目标从地址写 / 读SETDASA、GETACCCR
私有命令目标从地址写 / 读传感器数据读取、寄存器配置
我的经验: 别被“动态地址”吓到。在实际调试中,主设备刚上电时发一个 ENTDAA,所有从设备自动拿到地址。我遇到过从设备因时序没对齐,导致 ENTDAA 过程中 NACK 反复出现。后来查出是 SCL 上升沿斜率太大,信号过冲触发了从设备的毛刺滤波。嗯,布线时把 SCL 串联电阻加上就解决了。

2. 数据阶段:SDR 与 HDR 的取舍

数据阶段是协议栈的“体力活”。I3C 支持两种数据传输模式:单倍数据率(SDR) 和 高倍数据率(HDR)。SDR 向后兼容 I2C 传统模式,每个 SCL 时钟传 1 位;HDR 则能在一个时钟内传 2 位甚至更多。

你可能会问:“那我全部用 HDR 不就好了?” 没那么简单。HDR 对布线要求高得多。我做过一个项目,为了赶速度把相机模块配成 HDR 模式,结果信号在 10cm 的 PCB 走线上就跑飞了。波形上冲下冲明显,数据校验总是出错。最后老老实实切回 SDR,虽然带宽降了一半,但稳如老狗。

避坑指南: 我曾经在 4 层板上走 400mm 长的 I3C 总线,还启用了 HDR 模式。结果从设备返回的数据全是随机值。示波器一抓,总线反射严重。从此我给自己定了个规矩:HDR 模式下,走线长度不要超过 100mm;超过就必须加终端匹配或降低负载电容。

3. 响应阶段:ACK/NACK 的黄金法则

命令和数据发出去之后,从设备必须给个回应——这就是响应阶段。每个字节传输结束后,接收方在第 9 个 SCL 时钟周期拉低 SDA 表示 ACK,保持高则表示 NACK。

I3C 有个巧妙的设计:NACK 不仅仅是“我不认”,它还能携带状态信息。比如从设备忙,就 NACK 主设备的后续读写;主设备在 CCC 过程中发现没有设备响应,也会 NACK 并结束本次传输。

核心逻辑:
- 收到 ACK → 继续传下一个字节
- 收到 NACK → 主设备发 STOP 或重复 START
- 广播命令的 NACK 处理:任何从设备都可以 NACK 来拒绝广播

我在调试一块温度传感器时,发现主设备读温度值总是读到 0xFF。示波器一看,从设备在第 9 时钟拉了 NACK,主设备没正确处理,直接把上一帧的残余数据当有效数据用了。那是我第一次意识到:NACK 后的收尾时序必须严格按协议走,否则数据会“串味”。

4. 仲裁阶段:谁抢到总线谁说话

仲裁是 I3C 协议栈里最有趣的部分。I2C 的仲裁是基于“线与”逻辑,谁拉低 SDA 谁赢。I3C 保留了这套机制,但增加了 主设备之间的主动仲裁。比如两个主设备同时想发命令,它们会在 START 之后的地址阶段角逐——地址更低的一方会获胜(因为 SDA 是开漏,拉低优先)。

但注意:I3C 的仲裁 只发生在 SDR 模式。HDR 模式下不允许多主争抢,必须由当前主设备主动交出控制权。这个细节很多人不知道,结果在 HDR 总线上一接两个主设备,直接就死锁了。

我个人的习惯: 在设计多主系统时,我会给每个主设备分配一个唯一的 7 位地址,并且把地址小的设备作为默认主设备。这样仲裁冲突的概率降到最低。另外,SPI 转 I3C 的桥接芯片,经常因为 SPAD 寄存器没配置对,导致仲裁时地址冲突。所以每次换桥接芯片型号,我都会先看它的地址仲裁时序图。
I3C协议栈:命令·数据·响应·仲裁 核心流程 I3C协议栈核心流程 主设备发起START 发送CCC/私有命令 从设备ACK/NACK响应 ACK → 进入数据阶段 NACK → 发出STOP SDR/HDR 数据传输 响应校验 & 奇偶位 仲裁冲突(多主) 注:仲裁只发生在SDR模式;HDR模式由主设备独占总线,不参与多主争抢。

5. 协议栈与布线的映射关系

学完这四个环节,你在画 PCB 时就要带着“场景”去布。比如:

  • 命令阶段:地址位的上升/下降时间要匹配 I3C 的时序容限(通常 SCL 频率 12.5MHz 时,tr/tf ≤ 20ns)。我的做法是在 SCL 和 SDA 上各串一个 22Ω 电阻,既能限流又能抑制过冲。
  • 数据阶段:HDR 模式要求走线阻抗控制在 50Ω ± 10%,差分对?不,I3C 是单端线,但你要把 SCL 和 SDA 的走线长度控制在 ±5% 以内。否则数据建立时间会出问题。
  • 响应阶段:从设备拉低 SDA 给出 ACK 的时刻,正是总线电平最低、噪声最敏感的时间点。旁边有 DC-DC 的话,容易把 ACK 误判成 NACK。我吃过这个亏,后来把 I3C 总线跟电源层用 GND 隔了一个完整的地平面。
  • 仲裁阶段:多主系统的 PCB 上,每个主设备的 SDA 脚要加独立的上拉电阻(通常 2.2kΩ 左右),否则仲裁时主设备之间的拉电流会打架,导致信号畸变。
再啰嗦一句: 我曾经在一个产品里用两颗 MCU 做主设备,PCB 上只放了一颗上拉电阻。结果两个 MCU 同时尝试发命令时,总线电平拖了很久才恢复,所有从设备都退出了总线。后来改成每个主设备独立上拉,而且上拉电阻分别接到各自的 VDDIO,问题解决了。嗯,细节决定成败。