1. 从 I2C 到 I3C为什么需要一条新总线1.1 I2C 的辉煌与瓶颈但凡搞过嵌入式或者驱动开发的人对 I2C 都不会陌生。两根线一根 SCL 时钟一根 SDA 数据挂上一堆传感器、EEPROM、PMIC、触摸屏控制器用地址来区分设备布线简单、协议成熟、生态庞大。从 STM32 到树莓派从 Arduino 到各种国产 SoCI2C 几乎是每个硬件工程师入门必学的总线之一。但 I2C 的问题也很明显。标准模式 100kHz快速模式 400kHz快速模式 1MHz高速模式 3.4MHz——听起来还行但实际用起来尤其是挂多个设备、需要频繁读写寄存器的时候那个速度真的让人着急。比如你用 I2C 读一个 6 轴 IMU 的 FIFO 数据或者从触摸屏控制器里轮询坐标400kHz 下每秒钟能传的有效数据量其实很有限。更别提 I2C 是开漏输出上升沿靠上拉电阻拉高边沿速率受总线电容影响很大线一长、设备一多波形就塌了。还有一个痛点I2C 没有带内中断机制。设备有数据要上报只能靠额外的 GPIO 中断线来通知主机这在引脚紧张的系统里很要命。另外 I2C 的功耗也不算低因为开漏结构加上拉电阻静态电流一直在消耗。1.2 I3C 到底解决了什么问题I3CImproved Inter-Integrated Circuit是 MIPI 联盟推出的下一代总线标准目标很明确在保留 I2C 两根线物理兼容性的前提下把速度、功耗、功能全部拉高一个档次。先说速度。I3C 的 SDRSingle Data Rate模式默认就能跑到 12.5MHzHDRHigh Data Rate模式下理论带宽可以到 33Mbps 甚至更高。对比 I2C 标准模式 100kHz说“快 10 倍”其实还是保守了——如果拿 I2C 快速模式 400kHz 来比I3C SDR 12.5MHz 是它的 30 多倍。当然实际有效吞吐要看协议开销和从机响应能力但量级上的提升是实打实的。再说功耗。I3C 用的是推挽输出不需要上拉电阻静态功耗大幅降低。而且 I3C 支持带内中断In-Band Interrupt, IBI从机可以直接在总线上发起中断请求不用额外的 GPIO。这对于那些引脚资源紧张、又需要低功耗待机的移动设备和 IoT 终端来说简直是救命稻草。还有几个 I2C 没有的能力I3C 支持动态地址分配DAA主机可以给从机重新分配地址避免地址冲突支持热加入Hot-Join设备可以在总线运行中接入支持多主机Multi-Master和二级主机Secondary Master还有 CCCCommon Command Code通用命令集用来统一管理总线上的设备。1.3 RK3576 上的 I3C为什么值得关注RK3576 是瑞芯微推出的一颗中高端应用处理器定位在 RK3568 和 RK3588 之间主打 AIoT、边缘计算、工业控制和多媒体终端。它集成了多路 I2C 和 I3C 控制器其中 I3C 控制器是这次我们要重点聊的。为什么拿 RK3576 举例因为它的 I3C 控制器设计比较典型DTS 配置也有代表性而且 RK3576 和 RK3588 在 I3C 部分的寄存器结构和驱动框架有很多相似之处搞懂一个另一个基本也能触类旁通。很多人在调试 RK3576 的 I3C 时会遇到从机不识别、速率上不去、IBI 不触发等问题这些问题往往不是硬件坏了而是 DTS 没配对、时钟没算对、或者对 I3C 的工作模式理解有偏差。这篇文章就从 I3C 的接口特性讲起然后落到 RK3576 的 DTS 配置实操把那些文档里不会写、但实际调试中一定会踩的坑一个一个掰开说清楚。2. I3C 接口特性深度拆解不只是“更快的 I2C”2.1 物理层两根线但电气特性完全不同I3C 在物理层上兼容 I2C都是 SCL SDA 两根线但电气特性有本质区别。I2C 是开漏输出SCL 和 SDA 都需要外接上拉电阻。总线空闲时上拉电阻把线拉高设备拉低线表示逻辑 0。这种结构的好处是支持多设备线与不会出现驱动冲突坏处是上升沿靠 RC 充电边沿速率受总线电容和上拉电阻影响。上拉电阻越小上升越快但静态功耗越大。典型 4.7kΩ 上拉在 400kHz 下勉强够用到了 1MHz 以上就得换 1kΩ 甚至更小功耗直接起飞。I3C 在推挽模式下SCL 和 SDA 由主机主动驱动高和低不需要上拉电阻或者只需要很弱的上拉用于总线空闲检测。推挽输出的边沿速率快得多功耗也低得多。这是 I3C 能跑到 12.5MHz 以上的物理基础。但这里有个关键点I3C 总线在初始阶段和 I2C 设备共存时仍然需要上拉电阻。因为 I2C 设备只懂开漏如果总线上混挂了 I2C 从机主机在跟 I2C 设备通信时必须切回开漏模式。所以实际设计中I3C 总线上通常还是会保留上拉电阻只是阻值可以比纯 I2C 场景大一些比如 2.2kΩ 到 10kΩ具体看总线电容和速率需求。注意如果你的 I3C 总线上只挂 I3C 设备理论上可以去掉上拉电阻但很多 SoC 的 I3C 控制器在初始化阶段仍然需要检测总线空闲状态没有上拉可能会导致初始化失败。稳妥起见保留弱上拉。2.2 协议层SDR、HDR 和 CCCI3C 的协议层比 I2C 复杂不少但核心概念不多搞懂几个关键词就行。SDRSingle Data Rate是 I3C 的默认模式所有 I3C 设备都必须支持。SDR 模式下数据在 SCL 的每个时钟周期传输一位速率取决于 SCL 频率。I3C SDR 的典型速率是 12.5MHz但具体能跑多高要看从机能力和总线负载。HDRHigh Data Rate模式是可选的高速模式包括 HDR-DDR、HDR-TSP、HDR-TSL 等子模式。HDR-DDR 在 SCL 的双边沿都传输数据所以有效速率是 SCL 频率的两倍。HDR-TSP 和 HDR-TSL 是纯数据模式没有传统的地址和命令阶段适合大批量数据传输。不过 HDR 模式需要从机支持而且协议切换比较复杂实际项目中用得不多大多数场景 SDR 12.5MHz 已经够用了。CCCCommon Command Code是 I3C 的通用命令机制。主机通过 CCC 来管理总线上的设备比如使能/禁用 IBI、分配动态地址、读取设备信息等。每个 CCC 命令有一个字节的编码后面可以跟参数。常见的 CCC 包括 ENECEnable Events Command、DISECDisable Events Command、SETDASASet Dynamic Address from Static Address、RSTDAAReset Dynamic Address Assignment等。CCC 是 I3C 比 I2C 更“智能”的关键。I2C 只能读写寄存器没有标准化的设备管理机制I3C 通过 CCC 实现了总线级别的设备发现、地址分配和事件管理。2.3 带内中断 IBI省掉一根 GPIO 线IBI 是 I3C 最实用的特性之一。在 I2C 系统里从机要通知主机“我有数据了”只能拉一根额外的 GPIO 中断线。主机收到中断后再通过 I2C 去读从机的状态寄存器确认是什么事件。这个过程慢而且占用宝贵的 GPIO 资源。I3C 的 IBI 机制允许从机直接在总线上发起中断。从机在总线空闲时拉低 SDA主机检测到后发起一个 IBI 读取过程从机把自己的地址和中断状态发回来。整个过程不需要额外的引脚而且速度比 GPIO 中断 I2C 轮询快得多。IBI 还支持带数据的中断IBI with Data Payload从机可以在发起中断的同时把一小段数据比如传感器读数直接传给主机主机不用再单独读寄存器。这在低功耗传感器场景里非常有用——传感器触发中断顺便把数据推上去主机处理完继续休眠。实操心得IBI 的配置在 DTS 里通常需要显式使能而且不同 SoC 的 I3C 控制器对 IBI 的支持程度不一样。有些控制器只支持从机发起 IBI有些还支持主机发起的二级主机中断。调试 IBI 时先用逻辑分析仪抓总线波形确认从机确实拉低了 SDA再检查控制器的 IBI 使能位和中断映射。2.4 动态地址分配告别地址冲突I2C 的地址是固定的由从机芯片的硬件引脚决定。这就带来一个问题如果你要挂两个同型号的传感器而它的地址引脚只能配两个值那就很容易冲突。I3C 的动态地址分配DAA解决了这个问题。DAA 的流程是这样的主机通过 CCC 命令SETDASA 或 ENTDAA给从机分配一个 7 位动态地址。从机在收到命令后用新地址响应。这样即使两个从机静态地址相同主机也可以给它们分配不同的动态地址和平共处。DAA 还支持热加入。一个新设备接入总线后可以主动发起 Hot-Join 请求主机会给它分配地址并纳入管理。这对于支持热插拔的系统比如某些模块化工业设备很有价值。不过 DAA 也有代价主机需要维护一张地址映射表驱动要处理地址分配和回收。而且不是所有 I3C 设备都支持 DAA有些简单设备只有静态地址。实际项目中如果总线上设备不多、地址不冲突用静态地址也能跑DAA 更多是解决复杂场景的问题。3. RK3576 I3C 控制器与 DTS 配置实操3.1 RK3576 I3C 控制器概览RK3576 的 I3C 控制器在硬件上支持 I3C SDR 和部分 HDR 模式兼容 I2C 设备。根据瑞芯微的文档和实际调试经验RK3576 的 I3C 控制器有以下几个特点支持 I3C SDR 最高 12.5MHz具体速率取决于时钟源和分频配置。支持 I2C 标准模式、快速模式、快速模式方便兼容旧设备。支持 IBI 带内中断但需要从机支持并在 DTS 中使能。支持 DAA 动态地址分配但驱动层需要相应配置。寄存器接口和 RK3588 的 I3C 控制器高度相似驱动可以复用。在 RK3576 的 TRM技术参考手册里I3C 控制器的时钟树通常是这样的PLL 提供高频时钟经过分频器产生 I3C 控制器的工作时钟再经过 SCL 分频产生总线时钟。DTS 里的clock-frequency属性就是用来配置总线时钟的。3.2 DTS 节点配置从零开始写一个 I3C 设备假设我们要在 RK3576 的 I3C1 总线上挂一个 I3C 传感器地址是 0x6A需要 IBI 功能。DTS 配置大概长这样i3c1 { status okay; pinctrl-names default; pinctrl-0 i3c1m0_xfer; clock-frequency 12500000; i3c-scl-hz 12500000; i3c-sda-hz 12500000; sensor6a { compatible vendor,sensor-i3c; reg 0x6a; i3c-ibi-enabled; i3c-ibi-payload 4; vdd-supply vcc_1v8_s3; status okay; }; };逐项解释一下status okay是使能控制器这个不用多说。pinctrl-0指定引脚复用。RK3576 的 I3C 引脚通常和 I2C 引脚复用需要确认 pinctrl 配置里把引脚功能设成了 I3C 而不是 I2C。如果 pinctrl 配错总线可能完全没波形或者波形异常。clock-frequency是控制器的工作时钟频率不是总线频率。这个值需要根据 SoC 的时钟树来填通常填 PLL 分频后的频率。RK3576 的 I3C 控制器工作时钟一般在 50MHz 到 200MHz 之间具体看时钟树设计。i3c-scl-hz和i3c-sda-hz是总线时钟频率这里填 12.5MHz。注意这两个属性不是所有内核版本都支持有些驱动用clock-frequency同时表示控制器时钟和总线时钟需要看具体驱动实现。从机节点的compatible要和驱动里的 of_match_table 匹配否则驱动不会 probe。reg是从机地址I3C 用 7 位地址这里填 0x6A。i3c-ibi-enabled是使能 IBI 的属性具体属性名要看驱动实现。有些驱动用ibi-enabled有些用i3c-ibi-enabled还有的用interrupts来映射 IBI 中断。这个一定要对照内核里实际驱动的文档来写。i3c-ibi-payload指定 IBI 带数据的字节数这里填 4 字节。如果从机不支持带数据 IBI这个属性可以省略。vdd-supply是电源域确保从机供电正常。如果从机没供电I3C 扫描时可能识别不到。3.3 时钟配置算清楚每一个分频I3C 的时钟配置是调试中最容易出问题的地方。很多人 DTS 里写了 12.5MHz结果实际波形只有 6MHz 或者干脆没有波形多半是时钟没算对。RK3576 的 I3C 时钟路径大致是PLL - CLK_I3C1 - 分频器 - I3C 控制器工作时钟 - SCL 分频 - 总线时钟假设 PLL 输出 1188MHzCLK_I3C1 的分频系数是 6那么控制器工作时钟是 198MHz。SCL 分频系数如果是 16总线时钟就是 198/16 ≈ 12.375MHz接近 12.5MHz。在 DTS 里clock-frequency通常填控制器工作时钟而不是总线时钟。但有些驱动会自动计算分频你填总线时钟它也能算。关键是要看驱动代码里怎么解析这个属性。踩坑记录我曾经在一个项目里把clock-frequency填成了 12.5MHz以为就是总线频率结果驱动把它当成控制器时钟算出来的分频系数是 1总线时钟变成了 12.5MHz 的控制器时钟除以 1实际波形完全不对。后来查驱动源码才发现驱动期望的是控制器工作时钟总线时钟是通过i3c-scl-hz单独指定的。所以一定要看驱动文档和源码不要想当然。3.4 引脚复用与电气配置RK3576 的 I3C 引脚通常和 I2C、GPIO 复用。在 pinctrl 里需要把引脚功能设为 I3C。以 I3C1 为例pinctrl { i3c1m0_xfer: i3c1m0-xfer { rockchip,pins 1 RK_PB0 3 pcfg_pull_none_smt, 1 RK_PB1 3 pcfg_pull_none_smt; }; };这里的3是引脚功能编号具体值要看 RK3576 的 pinctrl 文档。pcfg_pull_none_smt表示不上拉、带施密特触发器。I3C 推挽模式下不需要上拉但施密特触发器可以改善信号质量。如果总线上混挂了 I2C 设备或者需要总线空闲检测可以改成pcfg_pull_up但阻值要选大一点比如 10kΩ避免推挽模式下功耗过大。电气配置还包括驱动能力。I3C 高速模式下引脚驱动能力要足够否则边沿会变缓。RK3576 的 pinctrl 通常支持多档驱动能力配置高速场景下建议选高驱动档位。3.5 内核驱动与设备树匹配RK3576 的 I3C 驱动在内核里通常是drivers/i3c/master/下的某个文件比如dw-i3c-master.c或者瑞芯微自己维护的驱动。设备树匹配是通过compatible属性完成的。控制器节点的compatible通常是rockchip,rk3576-i3c或类似的字符串。从机节点的compatible要和从机驱动匹配。如果从机驱动是标准 I3C 驱动比如mipi-i3c-sensor那就要确保内核里编译了对应的驱动。调试时可以用以下命令检查 I3C 总线是否注册成功ls /sys/bus/i3c/devices/如果看到类似i3c-1和1-6a的目录说明控制器和从机都注册了。如果只有控制器没有从机说明从机没被识别可能是地址不对、供电不对、或者 IBI 配置有问题。还可以用i3cdetect工具如果内核支持扫描总线i3cdetect -d /dev/i3c-1这个工具会尝试用 CCC 命令发现总线上的设备并打印设备信息。如果扫描不到先用逻辑分析仪看总线波形确认 SCL 和 SDA 有正常电平变化。4. 常见问题与排查技巧实录4.1 I3C 从机识别不到怎么办这是最常见的问题。现象是 DTS 配了驱动也加载了但/sys/bus/i3c/devices/下只有控制器没有从机。排查思路按优先级来第一检查供电。用万用表量从机的 VDD 和 VDDIO确认电压正常。很多 I3C 传感器有多个电源域少一个都不工作。第二检查引脚复用。用cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinmux查看引脚当前功能确认是 I3C 而不是 I2C 或 GPIO。第三检查总线波形。用逻辑分析仪抓 SCL 和 SDA看主机有没有发出 CCC 扫描命令。如果完全没有波形说明控制器没工作检查status和时钟配置。如果有波形但从机没响应检查从机地址和 I3C 使能位。第四检查从机是否支持 I3C。有些芯片标称支持 I3C但默认上电是 I2C 模式需要通过寄存器切换到 I3C 模式。这种情况下主机先用 I2C 模式跟它通信发命令切到 I3C然后再重新扫描。第五检查 DTS 里的reg地址。I3C 用 7 位地址但有些驱动期望的是 8 位地址左移一位。如果地址填错从机不会响应。4.2 总线速率上不去DTS 里写了 12.5MHz实际测出来只有 6MHz 或者更低。先确认时钟源。用clk_summary查看 I3C 控制器的实际工作时钟cat /sys/kernel/debug/clk/clk_summary | grep i3c如果工作时钟本身就不够高SCL 分频后自然达不到目标。比如工作时钟只有 50MHz分频系数最小是 4那总线最高只能到 12.5MHz。如果分频系数最小是 8那就只能到 6.25MHz。再确认从机能力。不是所有 I3C 设备都能跑 12.5MHz。有些传感器标称支持 I3C但最高 SCL 只有 4MHz 或 8MHz。这种情况下主机需要根据从机能力调整总线速率或者用 CCC 命令查询从机的最大速率。还要看总线负载。总线电容越大边沿越缓高速下波形质量越差。如果总线上挂了多个设备或者走线很长可能需要降低速率或者加缓冲器。4.3 IBI 不触发从机配置了 IBI但主机收不到中断。先确认从机是否真的发起了 IBI。用逻辑分析仪抓总线看从机有没有在空闲时拉低 SDA。如果没有检查从机的 IBI 使能寄存器是否配置正确。再确认主机的 IBI 中断映射。RK3576 的 I3C 控制器通常有一个中断输出连接到 GIC。在 DTS 里控制器的interrupts属性要正确配置。如果中断号不对或者中断被屏蔽主机就收不到 IBI。还要检查驱动里的 IBI 处理。有些驱动需要显式注册 IBI 回调如果回调没注册即使硬件收到 IBI驱动也不会处理。可以看内核日志里有没有 IBI 相关的打印。实操心得IBI 调试时先在从机侧用寄存器操作手动触发一次 IBI确认硬件通路没问题。然后在主机侧用cat /proc/interrupts看 I3C 中断计数有没有增加。如果计数增加但驱动没反应就是驱动回调的问题如果计数不增加就是硬件或中断映射的问题。4.4 I2C 和 I3C 混挂时的注意事项很多项目里I3C 总线上会混挂 I2C 设备比如一个 I3C 传感器加一个 I2C EEPROM。这种情况下有几个坑第一总线速率要兼容。I2C 设备通常最高 400kHz 或 1MHz如果主机用 12.5MHz 跟 I3C 设备通信切到 I2C 设备时必须降速。驱动通常会自动处理但 DTS 里要确保 I2C 设备的clock-frequency属性正确。第二上拉电阻要保留。I2C 设备需要上拉所以总线上不能去掉上拉电阻。但推挽模式下上拉电阻会消耗额外功耗选大一点比如 4.7kΩ 到 10kΩ。第三地址分配要小心。I2C 设备只有静态地址I3C 设备可以用动态地址。如果 I2C 设备的静态地址和 I3C 设备的动态地址冲突主机会分配失败。规划地址时要把 I2C 设备的地址预留出来。第四协议切换有开销。主机在 I3C 和 I2C 模式之间切换需要时间频繁切换会降低有效吞吐。如果总线上 I2C 设备很多考虑把 I2C 设备挪到单独的 I2C 总线上。4.5 常见问题速查表问题现象可能原因排查方法解决思路从机识别不到供电异常万用表量 VDD/VDDIO检查电源域和 LDO从机识别不到引脚复用错误查看 pinctrl debugfs修正 pinctrl 配置从机识别不到地址填错对比从机手册确认 7 位/8 位地址从机识别不到从机默认 I2C 模式逻辑分析仪抓波形先用 I2C 切换模式速率上不去时钟源频率不足clk_summary 查看调整 PLL 或分频速率上不去从机能力限制查从机手册降低总线速率速率上不去总线负载过大测波形边沿减少设备或加缓冲IBI 不触发从机未使能 IBI读从机寄存器配置 IBI 使能位IBI 不触发主机中断未映射/proc/interrupts修正 interrupts 属性IBI 不触发驱动回调未注册内核日志检查驱动 IBI 支持I2C 设备不工作上拉电阻被去掉量总线空闲电平保留弱上拉I2C 设备不工作速率不兼容抓 I2C 波形降速到 400kHz5. 调试工具与实战建议5.1 逻辑分析仪I3C 调试的必备工具调 I3C 没有逻辑分析仪基本寸步难行。I3C 的协议比 I2C 复杂光看内核日志很难判断问题出在硬件还是软件。逻辑分析仪可以抓 SCL 和 SDA 的原始波形解码 I3C 协议看到底是主机没发命令、从机没响应、还是响应了但数据不对。选逻辑分析仪时注意几点采样率要足够高I3C 12.5MHz 的 SCL采样率至少 100MS/s 才能看清边沿要支持 I3C 协议解码有些便宜的分析仪只支持 I2C 解码I3C 的 CCC 命令和 IBI 过程解不出来通道数至少 2 路如果要同时抓 IBI 中断线需要 3 路。抓波形时建议同时抓 SCL、SDA 和从机的电源。有时候从机响应异常是因为电源跌落光看总线波形看不出来。5.2 内核调试接口除了逻辑分析仪内核里也有一些有用的调试接口。/sys/bus/i3c/devices/可以看到总线上注册了哪些设备。每个设备目录下有modalias、name、dynamic_address等属性可以确认设备是否被正确识别。/sys/kernel/debug/clk/clk_summary可以看 I3C 控制器的实际时钟频率确认时钟配置是否符合预期。/proc/interrupts可以看 I3C 中断的触发次数判断 IBI 是否被硬件接收。内核日志里I3C 驱动通常会打印设备发现、地址分配、IBI 处理等信息。把loglevel调到 8可以看到更详细的调试信息。5.3 从机侧调试寄存器读写与状态确认主机侧调不通时从机侧也要查。很多 I3C 传感器有状态寄存器可以读出当前的工作模式、IBI 使能状态、错误标志等。如果从机支持 I2C 模式可以先用 I2C 工具比如i2cget/i2cset读写从机寄存器确认从机本身工作正常。然后再切到 I3C 模式对比行为差异。从机的 I3C 使能位通常在某个配置寄存器里上电默认可能是 I2C 模式。需要先通过 I2C 写寄存器切到 I3C然后主机重新扫描。这个过程在 DTS 里不好描述通常需要在驱动里加一段初始化代码。5.4 实战建议从低速开始逐步提速新项目调试 I3C 时不要一上来就配 12.5MHz。先用低速比如 1MHz 或 3.4MHz把设备识别和基本读写跑通确认硬件连接、电源、引脚都没问题再逐步提高速率。提速过程中每提一档就用逻辑分析仪看波形确认边沿质量、时序余量。如果波形开始变差或者出现偶发错误就退回上一档。不要盲目追求最高速率稳定可靠比快更重要。IBI 调试也是类似思路。先不用 IBI用轮询方式读数据确认数据通路正常。然后再使能 IBI用逻辑分析仪抓 IBI 过程确认从机发起、主机响应的时序都对。最后再测带数据 IBI确认数据内容正确。最后分享一个小技巧RK3576 的 I3C 和 I2C 引脚复用有时候内核启动时引脚默认是 I2C 功能I3C 驱动 probe 时才会切到 I3C。如果 probe 失败引脚可能停留在 I2C 功能导致后续操作异常。可以在 DTS 里把 pinctrl 的 default 状态配成 I3C确保上电就是正确功能。另外如果 I3C 总线上挂了 I2C 设备内核启动阶段 I2C 驱动可能会先 probe 并占用引脚导致 I3C 驱动 probe 失败。这种情况下需要调整驱动加载顺序或者把 I2C 设备挪到其他总线。
