I3C 设备角色与寻址:主控制器、目标设备、广播地址与动态地址
说实话,搞 I3C 之前我做了好几年 I2C,总觉得设备角色就那么回事——一个主控带着一堆从机,地址写死就完事了。但 I3C 这套东西刚接触时我也有点懵:动态地址?广播地址?目标设备不叫从机了?
别急,咱一个一个捋清楚。这章我把 设备角色 和 寻址体系 拆开讲,你学完就能明白整个地址怎么来的、怎么用的,后面做 CRC 校验时才不会糊。
1. 主控制器——谁是老大
I3C 总线上可以有一个或多个 主控制器。但在任何时刻,只有一个主控制器能发起传输。这个设计和 I2C 多主模式有点像,但仲裁方式完全不同——I3C 靠 “发起方决定”,不靠地址逐位仲裁。
我个人习惯把主控制器想象成 “会议主持人”。它能发起读写、能分配动态地址、能发起广播。我记得第一次在 FPGA 上搭建 I3C 主控时,最头疼的就是时序控制——因为这货比 I2C 快太多,得好好注意边沿对齐。
2. 目标设备——被指挥的干活
I3C 把原来的 “从机” 改叫 目标设备(Target)。为什么改名?因为 I3C 里目标设备也能主动发送数据——称为 “带内中断” 或 “副发起者”。这已经不是传统主从关系了。
目标设备分两类:
- I3C 原生目标:天然支持 I3C 协议,动态地址、带内中断、CCC(公共命令码)全会。
- I2C 旧设备(Legacy Device):只能工作在 I2C 模式,不能参与动态地址分配,得用静态地址。
你想想看,一个总线上混着两种设备,地址管理就复杂了。我在实际布局时,通常会先把 Legacy 设备的静态地址规划好,再留给 I3C 设备动态地址空间。
3. 广播地址——0000000 还是 0x7E?
I3C 的广播地址是 0x7E(7 位地址),而不是 I2C 通用的 0x00。为什么?因为 I3C 用 0x7E 来发送通用命令代码(CCC)给所有目标设备。
举个例子:主控制器要发起一次 “动态地址分配”,会先发一个广播头 + CCC 命令,所有处于待分配状态的目标设备都要响应。我在第一次调试这个流程时,自己写了个广播命令,结果只收到一半设备响应——后来发现有个设备的 PID(带内标识符)没配置好,直接忽略了广播。
4. 动态地址——I3C 的看家本领
I2C 地址靠硬件引脚或 EEPROM 配置,一旦定死就改不了。I3C 相反,它通过 动态地址分配(DAA) 给每个目标设备临时分配一个 7 位地址(通常从 0x01 到 0x7F 之间,避开 0x7E 广播地址)。
为什么要动态?
- 地址冲突避免:相同型号的传感器可以共用硬件设计,启动后主控逐个分配唯一地址。
- 热插拔支持:新设备加入总线时,主控可自动给它分配地址。
- 节省引脚:不用再为设备设计地址选择引脚了。
动态地址分配过程说白了就三步:
- 主控制器发出 ENTDAA(进入动态地址分配)CCC,携带广播地址 0x7E。
- 目标设备响应:每个未分配地址的设备通过 “位裁决” 逐步上报自己的临时标识(48 位或 64 位),胜出的设备获得主控分配的地址。
- 主控发送 SETDASA 或 RSTDAA:确认分配或重置。分配完成后,该设备就拥有自己的动态地址了。
这里有个关键点:动态地址分配过程中,CRC 校验 是必不可少的——后面我们会专门讲怎么算。我现在只提醒:如果你在 DAA 阶段发现设备分配失败,八成是 CRC 算错了或者地址被占用。
| 地址类型 | 地址值 | 用途 | 可否动态修改 |
|---|---|---|---|
| 广播地址 | 0x7E | CCC 命令、DAA 触发 | 否 |
| 动态地址 | 0x01 ~ 0x7F(除 0x7E) | 普通数据读写 | 是,可由主控重新分配 |
| 静态地址(Legacy) | 0x08 ~ 0x77(推荐范围) | I2C 兼容设备的固定地址 | 否 |
| 保留地址 | 0x00、0x7F | 系统保留 | 不可用 |
5. 寻址流程全景图
我画了张图,把主控制器、目标设备、广播地址、动态地址之间的关系串起来。你一看就明白。
6. 避坑指南——我踩过的几个坑
讲真,I3C 寻址的坑不少。我挑几个最常见的说说:
- 地址重叠:动态地址分配时,如果主控程序没处理好地址池,很可能把已分配设备的地址又给新设备。我曾在一个项目中把两个传感器分配成同一个地址,结果读出来数据全是乱的。后来我在主控里建了个已分配地址列表,每次分配前检查一下。
- 广播地址误解:有人以为广播地址 0x7E 和 I2C 的广播一样,可以用来写配置。错!I3C 广播只用于 CCC 命令,不能直接写寄存器。我之前在调试时试着用广播写寄存器,所有设备都 ACK 但没有一个接收数据——白忙活一场。
- 热加入处理:当一个新设备热加入时,主控需要暂停当前传输去处理。如果不及时处理,新设备会超时并影响后续地址分配。我在一个实时性要求高的系统里吃了这个亏,后来专门开了个高优先级任务来响应热加入请求。