一、硬件与内核准备
-
硬件连接
确保I2C设备正确连接到开发板的I2C总线接口(通常标注为SCL时钟线和SDA数据线)。检查电压匹配(一般为3.3V或5V),并确认设备地址(如0x50)。 -
启用内核支持
在Linux内核配置中启用I2C子系统:make menuconfig
选择以下选项:
- Device Drivers → I2C support → I2C Hardware Bus support(选择对应平台的I2C控制器)
- I2C device interface(启用用户空间访问接口
/dev/i2c-*
)
二、设备树配置(DTS)
在设备树文件(如*.dts
)中定义I2C控制器和从设备:
i2c@fdd40000 {
compatible = "rockchip,rk3399-i2c"; // 匹配驱动名称
reg = <0x00 0xfdd40000 0x00 0x1000>; // 寄存器地址范围
clocks = <&cru 7>, <&cru 0x2d>; // 时钟源
#address-cells = <1>; // 从设备地址长度
#size-cells = <0>; // 无地址空间大小
// 定义从设备(例如触摸芯片)
ilitek@41 {
compatible = "ilitek,ili2511"; // 设备驱动匹配名
reg = <0x41>; // 设备I2C地址
};
};
修改后需重新编译设备树并烧录到开发板。
三、用户空间快速测试
-
安装i2c-tools工具
sudo apt-get install i2c-tools
-
扫描I2C总线
sudo i2cdetect -y 0 # 扫描总线0上的设备地址
输出示例:
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- 47 -- -- -- -- -- -- -- -- 50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
此处
0x50
表示检测到一个设备。 -
读写寄存器
- 写入寄存器(例如向地址0x50的寄存器0x01写入0xAA):
sudo i2cset -y 0 0x50 0x01 0xAA
- 读取寄存器:
sudo i2cget -y 0 0x50 0x01
- 写入寄存器(例如向地址0x50的寄存器0x01写入0xAA):
四、编写用户态C程序
使用系统调用直接操作I2C设备:
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("/dev/i2c-0", O_RDWR); // 打开I2C总线设备
ioctl(fd, I2C_SLAVE, 0x50); // 设置从机地址
// 写入寄存器地址0x01
uint8_t reg_addr = 0x01;
write(fd, ®_addr, 1);
// 读取数据
uint8_t data;
read(fd, &data, 1);
printf("读取值: 0x%02X\n", data);
close(fd);
return 0;
}
编译命令:
gcc i2c_example.c -o i2c_example
五、内核驱动开发(示例)
-
注册驱动
在驱动代码中定义设备匹配表:static const struct i2c_device_id ilitek_id[] = { { "ilitek,ili2511", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, ilitek_id); static struct i2c_driver ilitek_driver = { .probe = ilitek_probe, // 设备探测函数 .remove = ilitek_remove, // 设备移除函数 .id_table = ilitek_id, // 设备匹配表 .driver = { .name = "ilitek_i2c", }, };
-
实现数据传输
在probe
函数中初始化设备并注册字符设备:static int ilitek_probe(struct i2c_client *client) { // 初始化设备(例如配置触摸芯片) i2c_smbus_write_byte_data(client, 0x01, 0x00); // 复位寄存器 return 0; }
六、调试技巧
-
查看内核日志
dmesg | grep i2c # 检查驱动加载和设备识别情况
-
信号检查
使用示波器观察SCL/SDA波形,确认起始信号、地址位和数据时序是否符合I2C协议。 -
常见问题
- 设备无响应:检查地址是否正确、电源是否稳定。
- 数据错误:尝试降低时钟频率(通过
i2cset
调整总线速度)。
七、进阶学习方向
- 多设备管理:在设备树中定义多个从机节点。
- 中断处理:在驱动中实现IRQ处理函数。
- 电源管理:实现
suspend
/resume
回调以支持休眠唤醒。