RK3576 android14 I2C总线,硬件I2C 与 GPIO模拟I2C 比对

在嵌入式 Linux 板级开发里,接一颗带 I2C 接口的外设时,常常会遇到两种做法:一是走 SoC 自带的 硬件 I2C 控制器,二是用两个 GPIO 软件模拟 成一条 I2C 总线。表面上看,二者在设备树里都能挂出同样的 i2c_client,驱动层也往往无感;但在 速率、波形质量、EMI、休眠与 IO 供电域、以及量产后的稳定性上有所差别。

一,两种方案参数对比

硬件i2c(soc外设控制器) gpio模拟i2c(i2c-gpio)
CRU 提供时钟,内核 i2c-designware 等驱动控制 SCL/SDA 时序 用两个 GPIO 在软件里 bit-bang,每比特多次 GPIO 翻转
易做 100k / 400k / 1M(受 clock-frequency 与从设备能力限制) 实际有效速率明显低于硬件 I2C,且与 delay-us、CPU 负载强相关
需占用 一组复用为 I2C 功能 的管脚(pinctrl 切到 i2cX xfer) 占用 任意 GPIO,功能保持为 GPIO 模式即可
硬件时序规整,上升沿/占空比由控制器与 IO 驱动能力保证 依赖 GPIO 驱动强度、走线、外部上拉;delay-us 过小易误码
控制器可随时钟门控;管脚电平与 IO 电压域(VCCIO)、休眠策略相关 同样受 VCCIO 保持 / 掉电 影响;无独立控制器时钟,但 GPIO 域掉电会直接"哑火"
标准 &i2cN { ... };,子节点 reg 为从机地址 compatible = "i2c-gpio",子设备写法与硬件 I2C 相同(对上层驱动透明)

总结:能走硬件 I2C、且管脚和复用都允许时,优先硬件 I2C;只有布线/复用冲突、或必须"任意脚"接从设备时,再用 GPIO 模拟,并接受速率、可靠性与休眠场景上的额外工程成本。


二,硬件 I2C

典型硬件 I2C:使能控制器、pinctrl 切到 I2C 复用、下面挂 reg = <0x**> 等子设备。

举个例子:

bash 复制代码
&i2c6 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&i2c6m3_xfer>;

	sgm41542: sgm41542@3b {
		compatible = "sgm,sgm41542";
		status = "okay";
		reg = <0x3b>;
		extcon = <&u2phy0>, <&usbc0>;
		pinctrl-names = "default";
		pinctrl-0 = <&charger_ok>;
		interrupt-parent = <&gpio0>;
		interrupts = <RK_PD2 IRQ_TYPE_EDGE_FALLING>;
		otg-mode-en-gpios = <&gpio2 RK_PC7 GPIO_ACTIVE_HIGH>;
		input-voltage-limit-microvolt = <4500000>;
		input-current-limit-microamp = <3000000>;
		monitored-battery = <&bat>;
		regulators {
			vbus5v0_typec: vbus5v0-typec {
				regulator-compatible = "otg-vbus";
				regulator-name = "vbus5v0_typec";
			};
		};
	};

pinctrl-0 = <&i2c6m3_xfer> ; 表示 SCL/SDA 在 芯片复用功能 上,由 I2C 控制器驱动,而不是软件 toggling。
clock-frequency; 直接约束总线速率;与 i2c-gpio,delay-us 的调参逻辑完全不同。


三、GPIO 模拟 I2C

当硬件I2C控制器资源不足或需要特殊引脚配置时,GPIO模拟方案提供了灵活的替代选择。GPIO子系统支持开漏(OD)模式,可直接模拟I2C总线所需的线"与"特性。

举个例子:

bash 复制代码
/* GPIO 模拟 I2C 控制器节点:对内核表现为一个 i2c_adapter */
i2c_nfc: i2c-nfc {
	compatible = "i2c-gpio";

	/* SDA/SCL 必须为开漏语义:ACTIVE_HIGH | OPEN_DRAIN */
	sda-gpios = <&gpio2 RK_PD1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
	scl-gpios = <&gpio2 RK_PD0 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;

	/*
	 * 每步 GPIO 操作之间的延时;过小易在长线/大电容总线上 NACK/丢包,
	 * 过大则降低有效速率。需结合示波器与 NFC 芯片手册在板级微调。
	 */
	i2c-gpio,delay-us = <20>;

	#address-cells = <1>;
	#size-cells = <0>;

	pinctrl-names = "default";
	/* 将相关脚固定为 GPIO 功能及 IRQ 脚上下拉 */
	pinctrl-0 = <&i2c_nfc_gpio &nfc_int_gpio>;
	status = "okay";

	/* 下游子设备写法与硬件 I2C 总线上一致 */
	nfc@38 {
		compatible = "nxp,nxpnfc";
		reg = <0x38>;
		interrupt-parent = <&gpio2>;
		interrupts = <RK_PC6 IRQ_TYPE_LEVEL_HIGH>;
		nxp,nxpnfc-irq = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>;
	};
};

aliases 里把 i2c10 指到 i2c_nfc,方便用户空间或文档用「逻辑编号」指代这条模拟总线:

bash 复制代码
		i2c8 = &i2c8;
		i2c9 = &i2c9;
		i2c10 = &i2c_nfc;
		i3c0 = &i3c0;

硬件 I2C 与 GPIO 模拟 I2C 都可能受 IO 电压域、休眠漏电策略影响;但 GPIO 模拟完全依赖 两根数据线处于合法空闲态(通常靠外部上拉 + 软件释放总线),一旦休眠路径上 IO 断电或态丢失,从设备可能锁死、需要掉电复位。


四,如何「抉择」?

  1. 优先选择硬件I2C控制器的场景:

高速数据传输(>100kHz)

多设备总线拓扑

实时性要求高的系统

需要DMA支持的批量传输

产品量产方案

  1. GPIO模拟I2C更合适的场景:

引脚资源紧张时的临时方案

特殊时序要求的设备

原型开发阶段的快速验证

低频(<10kHz)单设备通信

需要动态切换引脚的功能

实际项目里:只要原理图能把从设备的 SCL/SDA 接到 SoC 上可用的硬件 I2C 复用脚、且速率与可靠性有要求,就优先用硬件 I2C;只有在管脚/复用/布线已定型无法改线、或必须用普通 GPIO 才能接到从设备时,再接受 GPIO 模拟 I2C,并预留好上拉、位时序(如 delay-us)和休眠/供电域相关的联调成本。

相关推荐
小+不通文墨1 小时前
树莓派4b-wiringpi库的安装和使用
驱动开发·经验分享·笔记·嵌入式硬件·学习
小麦嵌入式2 小时前
FPGA入门(三):3-8 译码器 仿真波形解读
stm32·单片机·嵌入式硬件·mcu·fpga开发·硬件工程
xuhaoyu_cpp_java2 小时前
SpringMVC学习(三)
java·经验分享·笔记·学习·spring
Teacher.chenchong2 小时前
SWMM模型深度技术与案例精讲高级实践应用
经验分享
Elihuss3 小时前
关于RK3506 的MCU软复位后跑不起问题
linux·单片机·嵌入式硬件
fengfuyao9853 小时前
GRBL 1.1 移植到 STM32 (HAL库)
stm32·单片机·嵌入式硬件
无人装备硬件开发爱好者3 小时前
STM32G474 驱动 1.54 寸三色电子墨水屏实现贪吃蛇游戏完整指南
stm32·嵌入式硬件·游戏
其实秋天的枫3 小时前
【26年6月】英语四级高频核心词汇1500+历年真题pdf电子版
经验分享·pdf
许长安3 小时前
RingBuffer:面向网络编程的环形缓冲区实现
服务器·网络·c++·经验分享·笔记·缓存