Linux I2C 子系统

Linux 内核中的 I2C 子系统 提供了对 I2C(Inter-Integrated Circuit)总线的完整支持,包括 I2C 控制器驱动(Adapter)设备驱动(Client Driver) 和 用户空间访问接口


1. I2C 子系统架构

Linux I2C 子系统采用分层设计,主要分为以下部分:

层级功能
I2C Core核心层,提供注册/注销 Adapter 和 Client 的 API
I2C Bus管理 I2C 设备与驱动的匹配(基于 i2c_device_id 或 of_device_id
I2C AdapterI2C 控制器驱动(如 i2c-imxi2c-s3c2410
I2C ClientI2C 设备驱动(如 lm75 温度传感器驱动)
用户空间接口通过 /dev/i2c-* 或 sysfs 访问 I2C 设备

2. I2C 核心数据结构

(1) struct i2c_adapter

代表一个 I2C 控制器(如 SoC 的 I2C 接口),关键字段:

struct i2c_adapter {
    struct device dev;          // 关联的设备
    const struct i2c_algorithm *algo; // 通信方法(如 master_xfer)
    int nr;                    // 适配器编号(如 i2c-0)
    char name[48];             // 适配器名称(如 "i2c-imx")
    struct i2c_bus_recovery_info *bus_recovery_info; // 总线恢复
};

(2) struct i2c_client

代表一个 I2C 设备,关键字段:

struct i2c_client {
    unsigned short addr;        // 7-bit 设备地址(如 0x48)
    char name[I2C_NAME_SIZE];  // 设备名称(如 "lm75")
    struct i2c_adapter *adapter; // 所属的 I2C 控制器
    struct device dev;         // 设备模型
};

(3) struct i2c_driver

I2C 设备驱动,关键方法:

struct i2c_driver {
    int (*probe)(struct i2c_client *);    // 设备探测
    int (*remove)(struct i2c_client *);   // 设备移除
    const struct of_device_id *of_match_table; // 设备树匹配表
    const struct i2c_device_id *id_table; // 设备 ID 表
};

3. I2C 设备驱动开发

(1) 设备树(Device Tree)描述

&i2c1 {
    status = "okay";
    clock-frequency = <100000>; // 100kHz

    lm75: temperature-sensor@48 {
        compatible = "national,lm75";
        reg = <0x48>;           // I2C 地址
    };
};

(2) 驱动代码示例

#include <linux/i2c.h>
#include <linux/module.h>

static int lm75_probe(struct i2c_client *client)
{
    u8 reg_val[2];
    int temp;

    // 读取温度(LM75 的温度寄存器是 0x00)
    i2c_smbus_read_i2c_block_data(client, 0x00, 2, reg_val);
    temp = (reg_val[0] << 8) | reg_val[1];
    temp >>= 7; // LM75 温度数据格式

    printk("Temperature: %d°C\n", temp);
    return 0;
}

static const struct of_device_id lm75_of_match[] = {
    { .compatible = "national,lm75" },
    { }
};
MODULE_DEVICE_TABLE(of, lm75_of_match);

static struct i2c_driver lm75_driver = {
    .driver = {
        .name = "lm75",
        .of_match_table = lm75_of_match,
    },
    .probe = lm75_probe,
};
module_i2c_driver(lm75_driver);

4. 用户空间访问 I2C

(1) 通过 sysfs 访问

# 查看所有 I2C 适配器
ls /sys/bus/i2c/devices/

# 扫描 I2C-1 总线上的设备
i2cdetect -y 1

# 读取 I2C-1 上地址 0x48 的寄存器 0x00
i2cget -y 1 0x48 0x00

(2) 通过 /dev/i2c-* 使用 ioctl

#include <linux/i2c-dev.h>
#include <fcntl.h>

int fd = open("/dev/i2c-1", O_RDWR);
ioctl(fd, I2C_SLAVE, 0x48); // 设置从机地址

uint8_t reg = 0x00;
uint8_t buf[2];
write(fd, &reg, 1);        // 发送要读取的寄存器
read(fd, buf, 2);          // 读取 2 字节数据
close(fd);

5. I2C 子系统调试

(1) 内核配置

确保启用:

CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y    # 提供 /dev/i2c-* 接口
CONFIG_I2C_DEBUG_CORE=y # 调试支持

(2) 动态调试

# 启用 I2C 核心调试信息
echo 8 > /proc/sys/kernel/printk
dmesg | grep i2c

(3) 逻辑分析仪

  • 使用 Saleae Logic 或 PulseView 抓取 I2C 波形,检查 SCL/SDA 信号。


6. 常见问题

(1) 设备未被检测到

  • 检查 i2cdetect 是否能发现设备。

  • 确认设备树(compatible 和 reg)是否正确。

(2) 通信失败

  • 检查 clock-frequency 是否匹配设备要求。

  • 测量 SCL/SDA 电压(标准 I2C 是 3.3V/5V)。

(3) 驱动加载但未绑定设备

  • 检查 of_match_table 或 id_table 是否匹配。


7. 典型应用场景

场景示例驱动
温度传感器lm75tmp102
RTC 时钟ds1307pcf8563
EEPROMat24
触摸屏ft5x06
PMIC 电源管理max77650

总结

  • I2C Core 提供核心 API(注册 Adapter/Client)。

  • I2C Adapter 对应 SoC 的 I2C 控制器。

  • I2C Client 代表具体的 I2C 设备。

  • 可通过 设备树 或 静态声明 注册设备。

  • 用户空间可通过 i2c-tools 或 /dev/i2c-* 访问设备。

### Linux I2C 子系统的工作原理 在 Linux 内核中,I2C(Inter-Integrated Circuit)子系统用于管理硬件设备之间的串行通信协议。该子系统的算法详细描述了如何在物理层上操作 I2C 适配器,以执行诸如数据读写、起始和停止条件的发送等关键任务[^3]。 #### 主要组件 1. **驱动程序**:负责与特定的 I2C 设备交互。 2. **总线控制器**:控制 I2C 总线上所有的传输活动。 3. **客户端设备**:连接到 I2C 总线上的各个外设。 #### 数据流过程 当应用程序发起一次 I2C 操作时,请求会通过字符设备接口传递给相应的驱动模块。随后,驱动模块调用底层函数来启动实际的数据交换流程,在此期间可能会涉及到地址匹配、命令发送以及响应接收等一系列动作。 --- ### 配置方法 配置 Linux 下的 I2C 接口主要涉及以下几个方面: #### 加载必要的内核模块 确保已经加载了支持目标平台所需的 I2C 控制器驱动及其关联的设备驱动。可以通过 `modprobe` 或者直接编辑 `/etc/modules-load.d/` 文件夹下的配置文件来进行静态加载。 ```bash sudo modprobe i2c-dev ``` #### 修改 DTS (Device Tree Source) 对于 ARM 架构而言,还需要调整 DeviceTree 来声明新的 I2C 节点并指定参数属性。这一步骤通常由板级支持包提供预定义模板供开发者修改使用。 #### 编辑 udev 规则 为了让用户空间能够方便地访问新添加的 I2C 设备节点,建议创建自定义 UDev 规则以便自动分配合适的权限。 ```bash echo 'SUBSYSTEM=="i2c-dev", MODE="0666"' | sudo tee /etc/udev/rules.d/i2c.rules ``` --- ### 故障排除指南 遇到无法正常工作的 I2C 连接问题时,可以从以下几个角度入手解决: #### 日志分析 查看 dmesg 输出中的错误提示信息可以帮助定位具体哪一部分出现了异常状况;同时也可以利用 `journalctl -k` 命令获取更详细的日志记录。 #### 测试工具应用 借助于专门设计用来调试 I2C 的实用程序如 `i2cdetect`, 可以扫描整个总线寻找在线设备,并验证它们是否能被正确识别出来。 ```bash sudo apt-get install i2c-tools sudo i2cdetect -y 1 ``` #### 参数微调 有时适当调节某些高级选项比如时钟频率或者拉高电阻值也有可能改善通讯质量不佳的情况。这类改动往往需要深入研究具体的芯片手册才能做出合理的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值