在 Linux 中使用普通 GPIO 模拟 I2C 总线(即 Bit-Banging 方式)可以通过以下步骤实现。这里分为 内核驱动实现 和 用户空间实现 两种方案:
方案一:内核驱动实现(推荐)
1. 使用 i2c-gpio
内核模块
Linux 内核已提供 i2c-gpio
驱动,可直接将 GPIO 配置为 I2C 总线。
步骤:
-
确认内核配置
确保内核启用了CONFIG_I2C_GPIO
选项:zcat /proc/config.gz | grep CONFIG_I2C_GPIO
-
设备树配置(以树莓派为例)
在设备树中添加i2c-gpio
节点:/ { i2c_gpio: i2c-gpio { compatible = "i2c-gpio"; sda-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; // GPIO2 作为 SDA scl-gpios = <&gpio 3 GPIO_ACTIVE_HIGH>; // GPIO3 作为 SCL i2c-gpio,delay-us = <5>; // 时钟频率控制(单位:微秒) status = "okay"; }; };
-
加载驱动
重新编译设备树并加载:dtc -I dts -O dtb -o i2c-gpio.dtbo i2c-gpio.dts sudo dtoverlay i2c-gpio.dtbo
-
验证总线
使用i2cdetect
工具扫描设备:sudo apt install i2c-tools i2cdetect -l # 查看新生成的 I2C 总线编号(如 i2c-2) i2cdetect -y 2 # 扫描总线上的设备
方案二:用户空间实现(无需内核驱动)
如果无法修改内核配置,可直接在用户空间通过操作 /sys/class/gpio
控制 GPIO。
1. 导出 GPIO 引脚
echo 2 > /sys/class/gpio/export # SDA (GPIO2)
echo 3 > /sys/class/gpio/export # SCL (GPIO3)
echo out > /sys/class/gpio/gpio2/direction
echo out > /sys/class/gpio/gpio3/direction
2. 编写 I2C 模拟脚本(Python 示例)
import time
import os
# GPIO 引脚定义
SDA = 2
SCL = 3
# 导出 GPIO
os.system(f"echo {SDA} > /sys/class/gpio/export")
os.system(f"echo {SCL} > /sys/class/gpio/export")
os.system(f"echo out > /sys/class/gpio/gpio{SDA}/direction")
os.system(f"echo out > /sys/class/gpio/gpio{SCL}/direction")
def i2c_start():
# SDA 从高到低,SCL 保持高
set_sda(1)
set_scl(1)
time.sleep(0.005)
set_sda(0)
time.sleep(0.005)
set_scl(0)
def i2c_stop():
# SDA 从低到高,SCL 保持高
set_sda(0)
set_scl(1)
time.sleep(0.005)
set_sda(1)
def set_sda(val):
with open(f"/sys/class/gpio/gpio{SDA}/value", "w") as f:
f.write(str(val))
def set_scl(val):
with open(f"/sys/class/gpio/gpio{SCL}/value", "w") as f:
f.write(str(val))
# 示例:发送 START 信号
i2c_start()
关键注意事项
-
时序控制
I2C 时序需严格遵循协议(如 START/STOP 条件、ACK/NACK 响应)。可通过调整delay-us
参数或代码中的time.sleep()
控制时钟频率。 -
GPIO 配置
- 必须将 GPIO 设置为 开漏模式(Open-Drain),并启用外部上拉电阻(通常 4.7kΩ)。
- 如果硬件不支持开漏模式,需在代码中模拟(例如在读取 SDA 时切换 GPIO 为输入模式)。
-
并发访问
在内核驱动中需使用mutex
或spinlock
保护总线;在用户空间需确保单线程访问。 -
性能优化
用户空间实现效率较低,建议仅用于调试;生产环境优先使用内核驱动。
调试工具
- 内核日志:
dmesg | grep i2c
- I2C 工具:
i2cdetect
,i2cget
,i2cset
- 示波器/逻辑分析仪:验证 SDA/SCL 信号时序。
通过上述方法,您可以在 Linux 中灵活实现基于 GPIO 的 I2C 通信。