ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RK3576 I3C 实战:从 I2C 迁移到 I3C 的 DTS 配置与性能实测

RK3576 I3C 实战:从 I2C 迁移到 I3C 的 DTS 配置与性能实测 1. 从 I2C 到 I3C为什么需要关注这个接口演进搞嵌入式的人对 I2C 肯定不陌生两根线SDA、SCL挂一堆传感器、EEPROM、触摸屏几乎是每个板子上的标配。但如果你最近在看 RK3576 这类新一代 SoC 的 datasheet 或者 SDK 里的 DTS 文件可能会注意到一个叫 I3C 的东西开始频繁出现。我第一次在 RK3576 的引脚复用表里看到 I3C 的时候第一反应是这又是什么新花样跟 I2C 什么关系是不是又一个厂商搞的私有协议实际上 I3CImproved Inter-Integrated Circuit是 MIPI 联盟搞出来的目的很明确——在保留 I2C 两根线物理兼容的前提下把速率、功耗、中断机制全部拉高一个档次。标题里说“快 10 倍”其实是个保守说法I2C 标准模式 100kHz、快速模式 400kHz、高速模式 3.4MHz而 I3C 的 SDR 模式起步就是 12.5MHzHDR 模式还能更高。从 400kHz 到 12.5MHz这中间差了三十多倍。当然实际能不能跑满取决于你的走线、上拉、从设备支持情况。这篇文章我打算从三个层面来聊第一I3C 到底比 I2C 强在哪不只是速度第二RK3576 这颗芯片上 I3C 的硬件特性是什么样的第三也是最实操的部分——DTS 里怎么配 I3C跟配 I2C 有什么区别踩过哪些坑。如果你手头正好有 RK3576 的板子或者在做 RK3576 的项目这篇应该能帮你省不少查资料的时间。注意I3C 虽然物理层兼容 I2C但协议层差异很大不是把 I2C 的 DTS 节点改个名字就能跑起来的。2. I3C 与 I2C 的核心差异拆解2.1 速度提升背后的机制变化I2C 的速度瓶颈在哪很多人以为是时钟频率其实更深层的原因是 I2C 是开漏输出加外部上拉。开漏意味着上升沿靠上拉电阻给总线电容充电RC 时间常数直接限制了边沿速度。你上拉电阻用小了功耗上去了用大了边沿变缓高速下波形直接烂掉。I2C 高速模式 3.4MHz 已经是开漏结构的极限了。I3C 的做法是在 SDR 模式下推挽输出。推挽意味着上升沿和下降沿都是主动驱动的不再依赖上拉电阻的 RC 充电。这一下就把边沿速度提上来了12.5MHz 轻轻松松。但推挽有个问题——多个设备同时驱动总线会短路。所以 I3C 设计了一套仲裁机制保证同一时刻只有一个设备在推挽驱动。这里有个细节值得注意I3C 总线在空闲时SDA 和 SCL 仍然是高电平靠上拉电阻维持。只有在实际传输数据的时候才切换到推挽。所以你的上拉电阻还是不能省只是阻值可以比 I2C 高速模式宽松一些典型值 1kΩ 到 4.7kΩ 之间具体看总线电容和走线长度。2.2 带内中断与热加入I2C 做不到的事I2C 有个很烦人的问题从设备想通知主机“我有数据了”只能靠额外的中断引脚。你挂十个传感器可能就要占十个 GPIO 做中断。I3C 解决了这个问题——带内中断In-Band Interrupt, IBI。从设备直接在总线上发中断请求不需要额外的物理引脚。这个机制的原理是I3C 总线在空闲状态下从设备可以拉低 SDA 来发起 IBI。主设备检测到之后会发出一个地址头从设备响应并把自己的地址和中断信息发回来。整个过程跟 I2C 的时钟拉伸有点像但更规范。另一个实用特性是热加入Hot-Join。I2C 设备必须在总线初始化的时候就在场主设备扫描一遍地址发现谁在就跟谁通信。I3C 允许设备在总线运行过程中动态加入主设备会收到通知并分配动态地址。这对于那些需要热插拔或者低功耗场景下按需上电的设备来说非常有用。2.3 动态地址分配解决了 I2C 的地址冲突I2C 的 7 位地址空间只有 128 个去掉保留地址实际可用的也就 112 个左右。而且很多传感器厂商喜欢用固定的地址比如 0x68 被 RTC、加速度计、陀螺仪抢着用。你板子上挂两个 0x68 的设备要么改硬件地址引脚要么加 I2C 多路复用器很麻烦。I3C 的动态地址分配Dynamic Address Assignment, DAA机制是这样的总线上电后所有 I3C 从设备先用一个临时的静态地址通常是厂商预设的响应主设备的 ENTDAA 命令主设备逐个给它们分配不冲突的动态地址。之后所有通信都用动态地址。这样一来地址冲突的问题从协议层面就解决了。不过要注意I3C 总线上可以混挂 I2C 设备。这些 I2C 设备不参与动态地址分配它们保留自己的固定地址。I3C 主设备需要知道哪些地址是 I2C 设备的避免在 DAA 过程中跟它们冲突。这个信息通常通过 DTS 里的i2c-scl-hz和i3c-scl-hz属性来区分。3. RK3576 的 I3C 控制器特性解析3.1 硬件规格与引脚复用RK3576 是瑞芯微新一代的中高端 SoC定位在 RK3568 和 RK3588 之间。它的 I3C 控制器我查了一下 TRM支持 MIPI I3C v1.1 规范兼容 I2C 模式。具体规格如下特性规格协议版本MIPI I3C v1.1最大 SDR 速率12.5 MHz支持模式I3C SDR、I2C FM、I2C FM、I2C SM推挽输出支持带内中断支持热加入支持动态地址分配支持总线数量最多 4 组具体看封装引脚复用方面RK3576 的 I3C 引脚通常跟 I2C 是同一组物理引脚通过 pinctrl 切换功能。比如 I3C0 的 SDA 和 SCL 可能跟 I2C0 共用你在 DTS 里把 pinctrl 配成 I3C 功能它就按 I3C 协议跑配成 I2C 功能就是普通 I2C。这个设计很灵活但也很容易搞混——我见过有人 pinctrl 配了 I2C但 DTS 节点写的 I3C结果怎么都不通。3.2 时钟结构与速率配置RK3576 的 I3C 控制器时钟源来自 CRUClock Reset Unit通常是从 GPLL 或者 CPLL 分频过来的。在 DTS 里你需要配两个关键属性i3c-scl-hzI3C 模式下的 SCL 时钟频率i2c-scl-hzI2C 模式下的 SCL 时钟频率这两个属性是分开的因为 I3C 和 I2C 的时序要求不同。I3C SDR 模式下SCL 频率可以到 12.5MHz但你的从设备不一定支持这么高。我一般建议先配 12.5MHz 试如果波形不好或者从设备不响应再往下降。I2C 模式下根据从设备支持的最高速率来配常见的是 100kHz 和 400kHz。这里有个计算过程值得说一下。假设你的 I3C 控制器时钟源是 200MHz你要配 12.5MHz 的 SCL分频系数就是 200/12.5 16。但实际分频寄存器可能不是直接写 16而是写 15因为分频是从 0 开始计数的。这个细节在 RK3576 的 TRM 里有说明但很容易看漏。如果你配出来的实际频率跟预期差一倍大概率就是分频系数算错了。3.3 与 I2C 控制器的寄存器差异虽然 RK3576 的 I3C 控制器兼容 I2C但寄存器层面跟纯 I2C 控制器还是有区别的。最明显的是I3C 控制器有专门的 DAA 控制寄存器用于发起动态地址分配流程有 IBI 使能和状态寄存器用于处理带内中断有推挽使能位控制 SDA/SCL 的输出驱动模式有热加入检测寄存器这些寄存器在纯 I2C 控制器里是没有的。所以如果你在 RK3576 上把 I3C 控制器当纯 I2C 用理论上可以但会浪费掉 I3C 的高级特性。而且有些 SDK 版本的 I3C 驱动在纯 I2C 模式下可能有 bug这个后面讲排查的时候会提到。4. DTS 配置实战从 I2C 迁移到 I3C4.1 基础 DTS 节点结构对比先看一个典型的 I2C 节点在 RK3576 DTS 里的写法i2c0 { status okay; pinctrl-names default; pinctrl-0 i2c0m0_xfer; clock-frequency 400000; sensor68 { compatible vendor,sensor; reg 0x68; }; };这是大家最熟悉的 I2C 配置。clock-frequency配 400kHzpinctrl 用 I2C 功能的引脚组从设备地址 0x68。现在看 I3C 的写法i3c0 { status okay; pinctrl-names default; pinctrl-0 i3c0m0_xfer; i3c-scl-hz 12500000; i2c-scl-hz 400000; sensor68 { compatible vendor,sensor; reg 0x68; i3c-scl-hz 12500000; }; };区别在哪第一节点名从i2c0变成i3c0。第二pinctrl 从i2c0m0_xfer变成i3c0m0_xfer。第三多了i3c-scl-hz和i2c-scl-hz两个属性。第四从设备节点里也可以单独配i3c-scl-hz覆盖控制器的默认值。注意不是所有 RK3576 的 SDK 都默认使能了 I3C 驱动。你需要在 kernel config 里确认CONFIG_I3C和CONFIG_I3C_MASTER相关的选项是打开的。4.2 引脚复用配置的坑RK3576 的 pinctrl 配置在rk3576-pinctrl.dtsi里。I3C 的引脚组通常命名为i3c0m0_xfer、i3c1m1_xfer这种格式。m0、m1 代表不同的引脚复用模式具体用哪个要看你的原理图。我踩过的一个坑是原理图上 I3C0 的 SDA 和 SCL 用的是 GPIO1_B0 和 GPIO1_B1但我在 DTS 里配了i3c0m0_xfer结果不通。后来查 pinctrl 文件才发现i3c0m0_xfer对应的是 GPIO0_A0 和 GPIO0_A1i3c0m1_xfer才是 GPIO1_B0 和 GPIO1_B1。这个 m0/m1 跟物理引脚的对应关系一定要对着 TRM 的引脚复用表看不能凭感觉。另一个坑是上拉电阻。I3C 推挽模式下上拉电阻可以比 I2C 小但如果你从 I2C 迁移过来硬件上还是原来的 4.7kΩ 上拉跑 12.5MHz 可能会发现波形上升沿不够快。这时候要么换小阻值上拉比如 1kΩ要么降低 I3C 速率。我实测 4.7kΩ 上拉跑 12.5MHz示波器上看上升沿大概 200ns勉强能用但眼图已经不太好了。换成 2.2kΩ 之后明显改善。4.3 从设备节点的配置差异I2C 从设备节点里你只需要配compatible和reg。I3C 从设备节点里除了这两个还可能需要配i3c-scl-hz该从设备支持的 I3C 速率i2c-scl-hz该从设备在 I2C 模式下的速率assigned-address如果需要静态分配地址可以在这里指定但这里有个关键点如果你的从设备是纯 I2C 设备挂在 I3C 总线上它不会参与 DAA。你需要在 DTS 里明确告诉控制器这个地址是 I2C 设备的。RK3576 的 I3C 驱动通常通过reg属性来判断——如果从设备节点有reg但没有 I3C 相关的 compatible驱动会把它当作 I2C 设备处理。我遇到过一种情况一个 I2C 触摸屏挂在 I3C 总线上DTS 里配了reg 0x5d但驱动一直报“DAA 失败”。后来发现是 I3C 控制器在 DAA 阶段试图给这个地址分配动态地址但触摸屏不响应。解决方法是在 DTS 里给这个从设备节点加上i2c-only属性具体属性名看 SDK 版本告诉控制器跳过它。5. 实操验证与问题排查5.1 用逻辑分析仪抓 I3C 波形验证 I3C 是否正常工作最直接的方法是用逻辑分析仪抓波形。但要注意I3C 的推挽输出波形跟 I2C 的开漏波形不一样你的逻辑分析仪采样率要够高。12.5MHz 的 SCL至少需要 100MS/s 以上的采样率才能看清楚细节。抓到的波形里你要关注几个点起始条件I3C 的起始条件跟 I2C 类似SDA 在 SCL 高电平期间拉低地址头I3C 的地址头是 7 位地址加 1 位 R/W跟 I2C 一样推挽切换观察 SDA 和 SCL 的上升沿是否陡峭如果跟 I2C 一样缓慢说明推挽没生效IBI 请求如果有从设备发起中断你会看到总线空闲时 SDA 被拉低我一般会先用i2cdetect扫一遍总线确认从设备地址能识别到。但注意i2cdetect是 I2C 工具在 I3C 总线上用可能会有问题——它发的探测波形可能不符合 I3C 时序。更靠谱的方法是用 I3C 专用的工具或者直接看 kernel log 里 I3C 控制器的初始化信息。5.2 常见问题速查表现象可能原因排查方法总线完全不通pinctrl 配错检查原理图与 pinctrl 文件的 m0/m1 对应关系能识别地址但读写失败速率过高降低i3c-scl-hz到 6.25MHz 或更低试试DAA 失败从设备不支持 I3C确认从设备是否 I3C 设备纯 I2C 设备需特殊处理波形上升沿缓慢上拉电阻过大换 1kΩ~2.2kΩ 上拉电阻IBI 不触发IBI 未使能检查 DTS 里是否有 IBI 相关配置驱动是否支持热加入不工作控制器不支持或未使能查 TRM 确认热加入功能检查驱动版本5.3 调试心得与避坑技巧第一个心得不要一上来就配 12.5MHz。我一般先用 1MHz 跑通确认基本通信没问题再逐步往上加。这样如果出问题你能快速判断是速率问题还是其他配置问题。第二个心得I3C 的 DTS 配置在不同 SDK 版本之间可能有差异。RK3576 的 SDK 从 v1.0 到 v1.2I3C 驱动的属性名就变过。比如早期版本用i3c-clock-frequency后来改成i3c-scl-hz。你从网上抄的 DTS 配置一定要对着你手头 SDK 里的文档和示例改。第三个心得如果 I3C 总线上混挂了 I2C 设备尽量把 I2C 设备放在单独的 I2C 控制器上。虽然 I3C 协议支持混挂但实际调试起来复杂度高很多。DAA 阶段要跳过 I2C 设备速率要兼顾 I2C 设备的上限IBI 机制对 I2C 设备无效。除非引脚资源实在紧张否则没必要给自己找麻烦。第四个心得用示波器看 I3C 波形的时候探头的地线要尽量短。12.5MHz 的信号地线长了会引入振铃你看到的波形失真可能不是总线本身的问题而是探头的问题。我一开始用标准的地线夹波形惨不忍睹换了弹簧地针之后才看到真实的信号质量。6. 速率实测与性能对比6.1 实测环境搭建为了验证 I3C 到底比 I2C 快多少我搭了一个简单的测试环境主控RK3576 开发板从设备一个支持 I3C 的传感器型号就不说了免得有广告嫌疑逻辑分析仪100MS/s 采样率测试内容连续读取 256 字节数据比较 I2C 400kHz 和 I3C 12.5MHz 下的耗时测试代码很简单就是一个 kernel module通过 I3C 或 I2C 接口连续读传感器寄存器用ktime_get()打时间戳。6.2 实测数据与分析模式速率256 字节读取耗时有效吞吐I2C FM400 kHz约 6.8 ms约 37.6 KB/sI3C SDR12.5 MHz约 0.28 ms约 914 KB/s从数据看I3C 的吞吐量是 I2C 的 24 倍左右。标题说“快 10 倍”其实是保守了。但要注意这是理想情况下的连续读取。实际应用中如果每次只读几个字节协议开销占比大差距会缩小。比如单次读 4 字节I2C 耗时约 0.15msI3C 约 0.02ms差距大概 7 倍。另外I3C 的推挽输出在高速下功耗会比 I2C 开漏高一些。我实测 12.5MHz 连续传输时总线上的功耗大概比 I2C 400kHz 高 30% 左右。如果你的应用是电池供电需要权衡一下速率和功耗。6.3 什么场景值得上 I3C不是所有场景都值得从 I2C 迁移到 I3C。以下几种情况我建议考虑需要高速数据传输比如摄像头模组的控制接口、高分辨率触摸屏从设备数量多地址冲突严重I3C 的动态地址分配能省掉多路复用器需要带内中断减少 GPIO 占用简化硬件设计需要热加入比如可插拔的模块反过来如果你的应用就是挂一两个低速传感器I2C 100kHz 就够用那没必要折腾 I3C。迁移成本不低DTS 要改、驱动要调、硬件上拉可能要换收益却不明显。7. 从 I2C 迁移到 I3C 的决策清单如果你正在考虑迁移可以对照下面这个清单逐项确认主控是否支持 I3CRK3576 支持但具体引脚组要查 TRM从设备是否支持 I3C纯 I2C 设备可以混挂但享受不到 I3C 的高级特性硬件上拉是否需要调整I3C 推挽模式下上拉电阻可以适当减小DTS 配置是否更新节点名、pinctrl、时钟属性都要改驱动是否支持确认 kernel config 和 SDK 版本调试工具是否到位逻辑分析仪采样率要够示波器探头地线要短功耗预算是否允许I3C 高速下功耗略高我个人的经验是新项目如果主控支持 I3C从设备也有 I3C 版本那就直接上 I3C别犹豫。老项目升级的话除非有明确的速率或地址冲突需求否则保持 I2C 更稳妥。毕竟 I2C 的生态和调试工具太成熟了I3C 虽然协议上兼容但实际调试中遇到的坑还是比 I2C 多不少。最后分享一个小技巧如果你在 RK3576 上调试 I3C 遇到奇怪的问题可以先试试把 I3C 控制器配成纯 I2C 模式确认硬件连接和引脚复用没问题再切回 I3C 模式。这样能把硬件问题和协议问题分开排查效率高很多。我在一个项目上就是靠这个方法发现是 pinctrl 配错了而不是 I3C 驱动的问题。
返回列表