I3C 总线基础
大家好,我是你们的硬件工程师老张。做了十几年总线接口,从 I²C 到 SPI 再到现在的 I3C,踩过的坑能填满一个 PCB 厂。今天咱们聊 I3C 总线基础,这部分是后面 ENTDAA 时序排查的基石,不急于跑通,先搞明白它是谁、从哪来、到哪去。
I3C 协议概述
I3C 的全称是 Improved Inter-Integrated Circuit,由 MIPI 联盟在 2014 年左右推出。说白了,它就是 I²C 的全面升级版——保留了 I²C 的两线制优点,但速度更快、功耗更低、功能更灵活。我个人习惯把它称作“智能传感器总线”,因为最初就是为了替代 I²C 连接大量传感器而设计的。
核心特性我列一下:
- 两线制:还是 SDA 和 SCL,和 I²C 硬件几乎兼容,但协议层完全不同。
- 多主多从:支持多个控制器(主)在同一总线仲裁,不需要额外的片选线。
- 动态地址分配:这是我重点想说的,ENTDAA 时序异常就常出现在这步。设备上电后控制器会为每个从设备分配一个唯一的 7 位地址,避免了 I²C 那种老式地址冲突问题。
- 高速能力:典型速率 12.5 MHz(SDR 模式),HDR 模式能到 25 MHz 以上。我记得第一次测 I3C 眼图时,看到那么干净的波形还以为是仿真没跑对(笑)。
- 带内中断:从设备可以直接在总线空闲时发送中断请求,不需要额外中断引脚。
- 热插拔支持:设备可以随时加入或离开总线,控制器能自动发现。
重要概念:I3C 不是对 I²C 的简单提速,它的物理层虽然用了类似的开漏+推挽组合,但协议层引入了 START/STOP 条件、CCC(通用命令代码)、动态地址(Dynamic Address)等全新机制。如果你拿 I²C 的时序分析方法去套 I3C,嗯,会出大问题。我吃过这个亏,后面 ETDAA 章节会详细讲。
与传统 I²C / SPI 对比
很多工程师刚接触 I3C 时,会问:它到底比 I²C 和 SPI 强在哪?咱们直接拉一张对比表,清晰明了。
| 特性 | I²C | SPI | I3C |
|---|---|---|---|
| 引脚数 | 2(SDA+SCL) | 4+(SCLK/MOSI/MISO/CS) | 2(SDA+SCL) |
| 最大设备数 | 受限于地址(7位=127,但实际少见超过10个) | 受限于片选线(每设备多一根CS) | 可挂 127 个(通过动态地址分配) |
| 典型速率 | 100 kHz ~ 3.4 MHz | 10 MHz ~ 100 MHz(甚至更高) | 12.5 MHz(SDR)~ 25 MHz(HDR) |
| 功耗 | 中等(上拉电阻持续耗电) | 较高(持续驱动) | 低(推挽驱动,空闲时高阻) |
| 中断支持 | 需额外引脚或轮询 | 需额外引脚或轮询 | 带内中断(内置) |
| 多主能力 | 支持(但复杂) | 不支持(一主多从架构) | 原生支持(自动仲裁) |
| 热插拔 | 不友好(地址冲突、总线挂死) | 需额外机制 | 原生支持(动态加入) |
| 协议复杂度 | 低 | 低 | 中等(状态机较复杂) |
我的经验:如果你设计的产品只需要接一两个传感器,且速率要求不高,I²C 依然够用。但一旦传感器数量超过 5 个、需要频繁中断上报、或者对功耗和布线有严格限制,I3C 的优势立竿见影。我去年做过一个智能手表项目,12 个传感器 + 1 个触控屏,一条 I3C 总线全搞定,省了 10 多个 GPIO 和 8 条走线。
I3C 总线拓扑
I3C 的拓扑结构看起来和 I²C 很像——一条 SDA 线、一条 SCL 线,所有设备并联其上。但它的实际工作方式有本质区别。咱们直接看这张图(下面是我手绘的拓扑示意):
注意图中的虚线连接:第二主控制器是可选的,但在同一总线上必须通过仲裁机制避免冲突。我遇到过客户把两个控制器直接并联,SCL 没有做开漏处理,结果烧了 IO 口。为了避免重蹈覆辙,我建议在设计初期就确定好主从关系,如果确实需要多主,务必检查开漏和上拉电阻配置。
在拓扑上,有几个关键点需要记住:
- 所有设备的 SDA 和 SCL 都是开漏结构,总线上要有上拉电阻(通常 4.7 kΩ 左右,速率高时可能需要 1 kΩ)。
- 控制器在推挽模式下驱动时钟和数据,但也要能够进入高阻态让从设备驱动(比如中断请求)。
- 动态地址分配发生在总线初始化阶段:控制器发送 ENTDAA(Enter Dynamic Address Assignment)CCC,然后通过一系列时序交互给每个从设备分配地址。这个过程非常依赖严格的时序窗口,也是我们这门课的核心。
- 总线上的设备分为 主控制器(Master)、从目标(Target,I3C 原生) 和 I²C 兼容设备(Legacy Device)。I²C 设备使用静态地址,不参与动态分配。这其实是个过渡方案,但是很实用。