ARTICLE DETAIL

资讯详情

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

RK3576 I3C 接口实战:从 I2C 迁移到 I3C 的 DTS 配置与调试指南

RK3576 I3C 接口实战:从 I2C 迁移到 I3C 的 DTS 配置与调试指南 1. 从 I2C 到 I3C为什么需要一次接口升级1.1 一个被速率逼出来的新标准如果你做过嵌入式开发尤其是传感器、EEPROM、触摸屏这类外设的驱动I2C 几乎是绕不开的。两根线SCL、SDA、开漏输出、多主多从、地址寻址简单到用 GPIO 都能软件模拟。但 I2C 有个绕不过去的天花板标准模式 100kHz快速模式 400kHz快速模式 1MHz超快速模式 5MHz 且是单向的。实际工程里400kHz 是绝大多数 SoC 的默认档位1MHz 已经算激进。问题就出在这里。现在的设备上挂的传感器越来越多加速度计、陀螺仪、磁力计、环境光、接近感应、触摸控制器、PMIC、音频编解码器……每一个都要寄存器读写每一个都要中断上报。I2C 总线上的流量越来越拥挤400kHz 下读一个 6 轴 IMU 的 FIFO 数据动辄几百微秒到毫秒级CPU 频繁被中断打断功耗也压不下去。I3CImproved Inter-Integrated Circuit就是在这个背景下由 MIPI 联盟推出的。它不是要取代 I2C而是兼容 I2C 的同时把速率、功耗、中断机制全部重新设计了一遍。标题里说“快 10 倍”这个说法要拆开看I3C 的 SDR单数据速率模式最高 12.5MHzHDR高数据速率模式可以到 25MHz 甚至更高相比 400kHz 的 I2C确实是一个数量级的提升。但“快 10 倍”不是无条件的它取决于总线负载、上拉电阻、走线长度、从设备能力以及你有没有真正用上 I3C 的 HDR 模式。RK3576 是瑞芯微的一颗中高端 SoC面向边缘计算、工业控制、智能座舱等场景。它的 I3C 控制器支持 I3C 和 I2C 两种模式DTS 配置上也有不少细节。我拿它当例子是因为它的 I3C 实现比较完整而且 RK3576 和 RK3588 在 I3C 配置上有相似之处很多人在移植时会互相参考。1.2 这篇文章适合谁看如果你正在做 RK3576 或类似平台的 BSP 开发需要配置 I3C 总线、移植传感器驱动或者单纯想搞清楚 I3C 到底比 I2C 强在哪、值不值得换这篇文章就是写给你的。我会从接口特性讲起然后落到 DTS 配置的具体写法最后分享一些实际调试中踩过的坑。不需要你事先精通 I3C 协议但最好对 I2C 的基本时序和 Linux 设备树有概念。2. I3C 与 I2C 的核心差异不只是速率2.1 物理层推挽输出带来的速率飞跃I2C 的 SCL 和 SDA 都是开漏输出靠上拉电阻把线拉高。开漏的好处是天然支持多主多从、电平转换方便坏处是上升沿由 RC 充电决定速率越高波形越难看。400kHz 下用 4.7kΩ 上拉还算稳1MHz 以上就得换 1kΩ 甚至更小功耗随之上升。I3C 在 SDR 模式下SCL 仍然是开漏但 SDA 改成了推挽输出。推挽意味着驱动能力强上升沿陡峭不需要依赖上拉电阻的 RC 充电。这是 I3C 能跑到 12.5MHz 的物理基础。到了 HDR 模式SCL 和 SDA 都变成推挽速率可以进一步拉高。但推挽有个代价不能像开漏那样简单地做线与。所以 I3C 的总线仲裁机制和 I2C 完全不同。I3C 用了一种叫“地址头”Address Header的机制主设备先发地址从设备在特定时隙内拉低 SDA 来响应。这套机制比 I2C 的仲裁更复杂但也更高效。2.2 协议层从“轮询”到“带内中断”I2C 的中断是带外的。传感器有数据了拉一根 INT 线CPU 收到中断后再发起 I2C 读。这意味着每个传感器都要占一根 GPIO而且 CPU 必须醒来处理中断功耗下不去。I3C 引入了带内中断In-Band Interrupt, IBI。从设备可以直接在 I3C 总线上发起中断请求不需要额外的 INT 线。主设备在总线空闲时检测到 IBI再决定是否响应。这个机制对低功耗场景非常友好CPU 可以长时间休眠传感器有事件了直接在总线上“喊一声”。另一个重要特性是“通用命令码”Common Command Code, CCC。I3C 定义了一套标准命令比如设置总线速率、进入 HDR 模式、读取设备信息等。这些命令通过广播或直接寻址的方式发送不需要每个设备都实现一套私有协议。I2C 没有这个机制每个设备的寄存器定义都是厂商私有的驱动移植时经常要翻数据手册。2.3 速率对比数字背后的现实模式I2C 最高速率I3C 最高速率实际可用速率典型标准100kHz-100kHz快速400kHz-400kHz快速1MHz-1MHzSDR-12.5MHz6-10MHzHDR-DDR-25MHz15-20MHzHDR-TSP-25MHz20MHz“快 10 倍”通常是指 SDR 12.5MHz 对比 I2C 快速模式 400kHz理论上是 31 倍。但实际工程中总线负载、从设备支持能力、PCB 走线都会打折。我实测 RK3576 在 SDR 模式下跑 6MHz 比较稳再高就要看从设备了。即便如此相比 400kHz 也是 15 倍的提升。3. RK3576 的 I3C 控制器特性3.1 硬件规格与模式支持RK3576 的 I3C 控制器支持 I3C 和 I2C 两种模式可以通过 DTS 配置切换。每个控制器可以挂多个设备但 I3C 模式下对总线电容和走线长度有要求。RK3576 的 I3C 控制器支持 SDR 和 HDR-DDR 模式HDR-TSP 是否支持要看具体手册版本。控制器内部有 FIFO支持 DMA 传输。在 I3C 模式下控制器可以自动处理 CCC 命令、IBI 中断、热加入Hot-Join等流程。热加入是指从设备在总线运行过程中动态加入I2C 不支持这个必须重新上电或复位。3.2 与 RK3588 的异同RK3588 的 I3C 控制器和 RK3576 在寄存器层面有相似之处但引脚映射和时钟树不同。很多人在 RK3588 上调通了 I3C想直接抄到 RK3576 上结果发现时钟频率不对、引脚复用冲突。我的建议是DTS 结构可以参考但时钟和引脚配置必须按 RK3576 的手册来。RK3576 的 I3C 时钟源通常来自 CRUClock Reset Unit分频系数在 DTS 里配置。如果分频算错实际速率会和预期差很多。比如你想跑 12.5MHz但时钟源是 100MHz分频系数设成 8实际就是 12.5MHz设成 7就是 14.3MHz可能超出从设备能力。3.3 引脚复用与电气特性RK3576 的 I3C 引脚通常和 I2C、GPIO 复用。在 DTS 里要通过 pinctrl 指定功能。I3C 模式下SDA 是推挽输出所以不能像 I2C 那样随便接上拉电阻。实际上I3C 规范要求 SDA 在推挽阶段有明确的驱动能力上拉电阻主要用于开漏阶段和总线空闲时的电平保持。PCB 走线上I3C 对阻抗匹配和串扰更敏感。如果走线过长或过孔太多12.5MHz 下波形会严重振铃。我见过一个案例I2C 跑 400kHz 没问题换成 I3C 跑 6MHz 就频繁 NACK最后发现是走线太长加了串联电阻才稳住。4. DTS 配置实战从 I2C 切换到 I3C4.1 设备树节点结构RK3576 的 I3C 控制器在 DTS 里通常挂载在i3c0、i3c1等节点下。一个典型的 I3C 节点长这样i3c0: i3cfea00000 { compatible rockchip,rk3576-i3c; reg 0x0 0xfea00000 0x0 0x1000; interrupts GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH; clocks cru CLK_I3C0, cru PCLK_I3C0; clock-names i3c, pclk; pinctrl-names default; pinctrl-0 i3c0m0_pins; status okay; };compatible字符串要和驱动匹配。RK3576 的 I3C 驱动在 Linux 内核里通常是drivers/i3c/master/下的某个文件具体名字看内核版本。reg是寄存器基地址interrupts是中断号clocks和clock-names是时钟源。4.2 时钟频率配置I3C 的时钟频率在 DTS 里通过clock-frequency属性配置单位是 Hz。比如要跑 12.5MHzi3c0: i3cfea00000 { ... clock-frequency 12500000; ... };但这里有个坑clock-frequency只是你期望的速率实际速率取决于时钟源和分频系数。RK3576 的 I3C 控制器通常用assigned-clock-rates来设置时钟源频率然后控制器内部再分频。如果时钟源设成 100MHzclock-frequency设成 12.5MHz分频系数就是 8刚好。如果设成 13MHz分频系数就是 7.69控制器会取整实际可能是 14.3MHz 或 12.5MHz取决于实现。我的建议是先确认时钟源频率再算分频系数确保clock-frequency是时钟源的整数分频。RK3576 的 I3C 时钟源通常是 100MHz 或 200MHz12.5MHz、10MHz、6.25MHz 都是比较稳的档位。4.3 引脚控制与电气配置pinctrl 配置决定了引脚的功能和电气特性。RK3576 的 I3C 引脚通常有多个复用选项比如i3c0m0_pins、i3c0m1_pins等。在 DTS 里要选对pinctrl { i3c0 { i3c0m0_pins: i3c0m0-pins { rockchip,pins 1 RK_PB0 4 pcfg_pull_none, 1 RK_PB1 4 pcfg_pull_none; }; }; };rockchip,pins里的四个参数分别是引脚组、引脚号、功能复用号、电气配置。pcfg_pull_none表示不上拉不下拉因为 I3C 的 SDA 是推挽不需要上拉。但 SCL 在开漏阶段可能需要上拉具体看硬件设计。注意I3C 模式下不要随便加外部上拉电阻。推挽输出时上拉电阻会增加功耗还可能影响波形。如果硬件已经焊了上拉先确认阻值4.7kΩ 以上通常问题不大1kΩ 以下就要考虑去掉。4.4 从设备节点配置I3C 总线上的从设备在 DTS 里作为子节点存在。比如一个 I3C 接口的传感器i3c0 { status okay; clock-frequency 12500000; sensor6a { compatible vendor,sensor; reg 0x6a; interrupts GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH; interrupt-parent gpio1; vdd-supply vcc_1v8; }; };reg是从设备地址I3C 的地址是 7 位的但 DTS 里通常写 7 位地址。interrupts是带外中断如果传感器支持 IBI可以不用。vdd-supply是电源域确保上电时序正确。如果从设备是 I2C 设备但挂在 I3C 控制器上需要把控制器模式设成 I2Ci3c0 { status okay; i2c-mode; clock-frequency 400000; };i2c-mode是 RK3576 驱动里的一个属性告诉控制器以 I2C 模式工作。这样 I3C 控制器就退化成普通 I2C 控制器速率和时序都按 I2C 来。5. 实操调试与问题排查5.1 确认总线是否正常工作DTS 配好后编译内核和设备树启动系统。先看/sys/bus/i3c/devices/下有没有设备节点ls /sys/bus/i3c/devices/如果有i3c-0之类的目录说明控制器注册成功。再看/sys/kernel/debug/i3c/下的调试信息可以查看总线状态、设备列表、速率等。如果控制器没注册先检查dmesg | grep i3c看驱动有没有报错。常见错误包括时钟获取失败、引脚复用冲突、寄存器基地址错误。5.2 速率上不去的排查思路假设你配了 12.5MHz但实际读写很慢或者频繁 NACK。按这个顺序排查确认时钟源频率cat /sys/kernel/debug/clk/clk_summary | grep i3c看实际时钟频率。确认分频系数如果时钟源是 100MHzclock-frequency是 12.5MHz分频应该是 8。如果驱动算出来是 7实际就是 14.3MHz可能超了。检查从设备支持能力不是所有 I3C 设备都支持 12.5MHz。查数据手册确认最大 SCL 频率。检查 PCB 走线用示波器看 SCL 和 SDA 波形。如果上升沿有振铃加串联电阻22Ω-33Ω试试。检查上拉电阻I3C 推挽模式下上拉电阻太强会导致功耗高太弱会导致开漏阶段电平不稳。通常 4.7kΩ-10kΩ 比较合适。5.3 IBI 中断不触发的处理IBI 是 I3C 的亮点但调试起来比带外中断麻烦。如果传感器支持 IBI但 CPU 收不到中断确认从设备已经使能 IBI有些传感器需要写寄存器开启 IBI 功能。确认控制器使能了 IBIRK3576 的 I3C 驱动通常默认开启但可以在 DTS 里检查有没有ibi-enabled之类的属性。确认总线空闲IBI 只能在总线空闲时发起。如果总线一直被占用IBI 会被延迟或丢失。用逻辑分析仪抓包看从设备有没有在总线上拉低 SDA。如果没有说明从设备没发起 IBI如果有但 CPU 没响应说明控制器配置有问题。5.4 常见问题速查表现象可能原因解决方法控制器不注册时钟/引脚/中断配置错误检查 DTS看 dmesg 报错读写 NACK从设备地址错误/未上电确认地址和电源速率上不去分频系数错误/从设备不支持算分频查手册波形振铃走线过长/阻抗不匹配加串联电阻缩短走线IBI 不触发从设备未使能/总线忙写寄存器检查总线状态I2C 设备挂 I3C 控制器不识别未设 i2c-mode加 i2c-mode 属性6. 几个容易踩的坑和实操心得6.1 不要迷信“快 10 倍”I3C 的 12.5MHz 是理论值实际能跑多少取决于整个链路。我见过有人把clock-frequency设成 12.5MHz结果从设备只支持 1MHz总线频繁出错。后来降到 1MHz反而稳定了。所以配速率之前先查从设备手册再算分频最后用示波器验证。6.2 I2C 和 I3C 混挂要小心有些板子上I3C 总线上挂了 I2C 设备。I3C 控制器在 I3C 模式下能不能直接和 I2C 设备通信理论上可以因为 I3C 兼容 I2C。但实际中I3C 的时序和 I2C 有差异尤其是推挽输出阶段。如果混挂建议把控制器设成 I2C 模式牺牲速率换稳定性。或者用 I3C 的 CCC 命令切换到 I2C 模式但这需要从设备支持。6.3 电源域和上电时序I3C 设备通常有独立的电源域。如果电源没上电或者上电时序不对设备不会响应。DTS 里的vdd-supply要配对确保 regulator 先于 I3C 控制器使能。我遇到过一个案例传感器电源由 GPIO 控制但 DTS 里没配vdd-supply导致传感器一直没上电I3C 读写全 NACK。后来加了regulator-fixed才解决。6.4 逻辑分析仪是必备工具调试 I3C 没有逻辑分析仪基本寸步难行。I2C 还能用软件模拟凑合I3C 的推挽和 HDR 模式必须用硬件抓包。建议选支持 I3C 解码的分析仪比如 Saleae 或 DSLogic。抓包时注意采样率要足够高12.5MHz 的 SCL 至少需要 100MS/s 的采样率才能看清细节。6.5 内核版本和驱动匹配RK3576 的 I3C 驱动在不同内核版本里可能有差异。比如 Linux 5.10 和 6.1 的 I3C 子系统 API 就不完全一样。移植时先确认内核版本再看驱动源码里的compatible字符串和 DTS 是否匹配。如果驱动没加载/sys/bus/i3c/下不会有设备节点。7. 从 I2C 迁移到 I3C 的决策建议7.1 什么时候值得换如果你的系统里 I2C 总线负载很重多个传感器频繁读写CPU 中断开销大或者需要低功耗待机加事件唤醒I3C 值得考虑。尤其是需要带内中断的场景省掉一堆 INT 线PCB 布局也简单。但如果你的 I2C 总线很空闲只有一两个低速设备换 I3C 的收益不大反而增加调试成本。I3C 的从设备生态还在完善中很多传感器还是 I2C 接口强行上 I3C 可能找不到合适的器件。7.2 迁移步骤确认硬件支持SoC 的 I3C 控制器、引脚复用、电源域。确认从设备支持I3C 还是 I2C最大速率是否支持 IBI。改 DTS控制器节点、引脚、时钟、从设备节点。调速率从低速开始逐步提高用示波器验证波形。调中断如果用了 IBI确认从设备和控制器都使能。压力测试长时间读写看有没有偶发 NACK 或丢包。7.3 一个实际案例我之前做一个 RK3576 的项目总线上挂了 4 个传感器IMU、磁力计、气压计、环境光。I2C 400kHz 下IMU 的 FIFO 读取经常超时CPU 负载也高。换成 I3C 后SCL 跑到 6MHzIMU 用 IBI 上报数据就绪CPU 只在有数据时才醒来。整体功耗降了约 30%中断次数少了 80%。但调试花了将近两周主要是波形振铃和 IBI 时序问题。所以我的建议是如果项目时间紧I2C 够用就别折腾如果对功耗和实时性有要求I3C 值得投入。8. 写在最后I3C 不是 I2C 的简单提速版它在物理层、协议层、中断机制上都做了重新设计。RK3576 的 I3C 控制器功能比较完整DTS 配置也不算复杂但细节很多。时钟分频、引脚复用、电源时序、波形匹配任何一个环节出问题都会导致总线不工作。我个人的经验是先把控制器配通用低速 I2C 模式验证硬件链路再切到 I3C 模式逐步提速。逻辑分析仪和示波器是必备的不要靠猜。从设备手册一定要仔细看尤其是速率和 IBI 相关的寄存器。最后分享一个小技巧如果 I3C 总线上的设备不多可以把不用的从设备节点先注释掉减少总线负载调试起来更容易定位问题。等主设备通了再逐个加从设备。
返回列表