嵌入式Linux驱动开发(I2C专题)(二)

本文围绕I2C系统的重要结构体展开,介绍了I2C硬件框架、传输协议和Linux软件框架。阐述了在Linux中如何表示I2C Controller、I2C Device和要传输的数据,如用i2c_adapter表示I2C BUS,i2c_client表示I2C Device,i2c_msg表示传输数据。还说明了内核里通过i2c_transfer函数传输数据。

I2C系统的重要结构体

参考资料:

  • Linux驱动程序: drivers/i2c/i2c-dev.c
  • I2CTools: https://mirrors.edge.kernel.org/pub/software/utils/i2c-tools/

1. I2C硬件框架

在这里插入图片描述

2. I2C传输协议

在这里插入图片描述

3. Linux软件框架

在这里插入图片描述

4. 重要结构体

使用一句话概括I2C传输:APP通过I2C Controller与I2C Device传输数据。
在Linux中:

  • 怎么表示I2C Controller
    • 一个芯片里可能有多个I2C Controller,比如第0个、第1个、……

    • 对于使用者,只要确定是第几个I2C Controller即可

    • 使用i2c_adapter表示一个I2C BUS,或称为I2C Controller

    • 里面有2个重要的成员:

      • nr:第几个I2C BUS(I2C Controller)
      • i2c_algorithm,里面有该I2C BUS的传输函数,用来收发I2C数据
    • i2c_adapter
      在这里插入图片描述

    • i2c_algorithm
      在这里插入图片描述

  • 怎么表示I2C Device
    • 一个I2C Device,一定有设备地址
    • 它连接在哪个I2C Controller上,即对应的i2c_adapter是什么
    • 使用i2c_client来表示一个I2C Device
      在这里插入图片描述
  • 怎么表示要传输的数据
    • 在上面的i2c_algorithm结构体中可以看到要传输的数据被称为:i2c_msg

    • i2c_msg
      在这里插入图片描述

    • i2c_msg中的flags用来表示传输方向:bit 0等于I2C_M_RD表示读,bit 0等于0表示写

    • 一个i2c_msg要么是读,要么是写

    • 举例:设备地址为0x50的EEPROM,要读取它里面存储地址为0x10的一个字节,应该构造几个i2c_msg?

      • 要构造2个i2c_msg

      • 第一个i2c_msg表示写操作,把要访问的存储地址0x10发给设备

      • 第二个i2c_msg表示读操作

      • 代码如下

  u8 data_addr = 0x10;
  i8 data;
  struct i2c_msg msgs[2];
  
  msgs[0].addr   = 0x50;
  msgs[0].flags  = 0;
  msgs[0].len    = 1;
  msgs[0].buf    = &data_addr;
  
  msgs[1].addr   = 0x50;
  msgs[1].flags  = I2C_M_RD;
  msgs[1].len    = 1;
  msgs[1].buf    = &data;

5. 内核里怎么传输数据

使用一句话概括I2C传输:

  • APP通过I2C Controller与I2C Device传输数据
  • APP通过i2c_adapter与i2c_client传输i2c_msg
  • 内核函数i2c_transfer
    • i2c_msg里含有addr,所以这个函数里不需要i2c_client
      在这里插入图片描述
<think>嗯,用户想了解嵌入式LinuxI2C总线驱动开发的教程或示例代码。首先,我需要回忆一下Linux内核中I2C子系统的结构。LinuxI2C子系统分为控制器驱动(适配器)、设备驱动和核心层。控制器驱动负责处理具体的硬件操作,比如寄存器读写,而设备驱动则是针对具体的I2C设备,比如传感器或EEPROM。核心层则提供注册和通信的接口。 接下来,用户可能需要一个简单的示例,展示如何编写一个I2C设备驱动。比如,假设有一个I2C温度传感器,地址是0x48,那么设备驱动需要实现probe、read等函数。需要用到i2c_driver结构体,并注册到内核中。同时,设备树(Device Tree)的配置也是关键,用户需要在设备树中添加相应的节点,指定I2C总线和设备地址。 另外,用户可能对用户空间的访问方法感兴趣,比如通过sysfs或i2c-tools进行调试。这时候可以提到使用i2cget、i2cset等命令,或者直接在应用程序中使用ioctl调用。同时,需要注意内核中I2C设备驱动的加载顺序和依赖关系,比如确保控制器驱动已经正确加载。 可能还需要考虑错误处理和调试技巧,比如使用dmesg查看内核日志,检查设备是否成功注册,以及数据传输是否有误。此外,引用中的platform_device和platform_driver的关系可能相关,因为在某些情况下,I2C设备可能作为platform设备存在,需要匹配驱动。 最后,用户的问题可能涉及到如何修改现有驱动以支持不同配置,比如引用3中提到修改音频驱动实现双通道录音。类似地,修改I2C驱动可能需要调整传输模式或时钟频率等参数。需要确保代码中的I2C消息结构正确,并使用正确的API函数,比如i2c_transfer或SMBus函数。</think>### 嵌入式 Linux I2C 总线驱动开发指南 #### 一、I2C子系统框架 Linux内核中I2C子系统分为三个层级: 1. **I2C核心层**:提供总线注册/注销、设备匹配等基础功能 2. **I2C控制器驱动(适配器驱动)**:实现具体SoC的I2C控制器操作,如寄存器读写 3. **I2C设备驱动**:针对具体外设(如EEPROM、传感器)的功能实现 #### 、设备驱动开发步骤 1. **定义设备树节点**(以STM32MP157为例): ```dts &i2c1 { status = "okay"; clock-frequency = <100000>; temp_sensor@48 { compatible = "vendor,tmp175"; reg = <0x48>; }; }; ``` 2. **实现驱动结构体**: ```c static struct i2c_driver tmp175_driver = { .driver = { .name = "tmp175", .of_match_table = tmp175_of_match, }, .probe = tmp175_probe, .remove = tmp175_remove, .id_table = tmp175_id, }; ``` 3. **实现关键函数**(以温度读取为例): ```c static int tmp175_read_temp(struct i2c_client *client) { u8 buf[2]; int ret = i2c_master_recv(client, buf, 2); if (ret < 0) return ret; int temp = (buf[0] << 8) | buf[1]; return temp >> 7; // TMP175为9位精度 } ``` #### 三、用户空间访问方法 1. 使用i2c-tools调试: ```bash i2cdetect -y 1 # 扫描I2C总线设备 i2cget -y 1 0x48 0x00 # 读取寄存器 ``` 2. 通过sysfs接口操作: ```c int fd = open("/dev/i2c-1", O_RDWR); ioctl(fd, I2C_SLAVE, 0x48); i2c_smbus_write_byte(fd, 0x00); int temp = i2c_smbus_read_byte(fd); ``` #### 四、关键API参考 1. **数据传输函数**: ```c i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) i2c_smbus_read_byte(struct i2c_client *client) ``` 2. **设备注册函数**: ```c module_i2c_driver(tmp175_driver) // 简化注册过程 ``` #### 五、常见问题排查 1. 确认设备树节点时钟频率与设备匹配 2. 检查`i2c-dev`模块是否加载 3. 使用示波器验证物理信号完整性 4. 通过`dmesg | grep i2c`查看内核日志[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式学习者。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值