文章目录
[1. I2C协议的"双线制"通信](#1. I2C协议的“双线制”通信)
[2. I2C的地址寻址机制](#2. I2C的地址寻址机制)
[二、Linux I2C驱动框架的分层设计](#二、Linux I2C驱动框架的分层设计)
[1. I2C核心](#1. I2C核心)
[2. I2C适配器](#2. I2C适配器)
[3. I2C设备驱动](#3. I2C设备驱动)
一、I2C协议的核心原理
1. I2C协议的"双线制"通信
SDA(数据线) 和 SCL(时钟线) 是I2C通信的两条物理信号线。SDA:双向数据传输线,用于发送和接收数据。SCL:由主设备控制的时钟信号线,用于同步数据传输。
通信规则:
(1)起始信号(START):SCL高电平时,SDA从高变低,表示通信开始。
(2)停止信号(STOP):SCL高电平时,SDA从低变高,表示通信结束。
(3)数据位:每个字节传输需8个时钟周期,数据在SCL高电平时稳定,在SCL低电平时变化。
(4)应答(ACK/NACK):接收方在第9个时钟周期拉低SDA(ACK)表示成功接收,否则为NACK。
2. I2C的地址寻址机制
每个从设备有唯一的 7位地址(如AP3216C地址为0x1e
),由主设备通过地址字段选择目标设备。地址字段由 7位设备地址 + 1位读/写标志位 组成:读操作:标志位为1(如0x1e | 0x01 = 0x1f
)。写操作:标志位为0(如0x1e | 0x00 = 0x1e
),即0写1读。
二、Linux I2C驱动框架的分层设计
Linux内核将I2C驱动分为三层架构,实现硬件无关的通用接口:
1. I2C核心
(1)作用:提供I2C总线驱动和设备驱动的注册/注销接口,管理I2C总线的仲裁、重试和协议细节。
(2)关键API:i2c_add_adapter()
/ i2c_del_adapter()
:注册/注销I2C适配器。i2c_register_driver()
/ i2c_del_driver()
:注册/注销I2C设备驱动。i2c_transfer()
:执行多消息传输(如发送地址+读取数据)。
2. I2C适配器
(1)作用:对应SoC中的I2C控制器(如STM32的硬件I2C模块),提供与从设备通信的底层能力。
(2)关键数据结构:
struct i2c_adapter {
const struct i2c_algorithm *algo; //通信算法
struct i2c_bus_recovery_info *bus_recovery_info; //总线恢复机制
struct device dev; //设备模型抽象
};
(3)通信方法:通过i2c_algorithm
定义的master_xfer
函数实现具体的数据传输。
3. I2C设备驱动
(1)作用:针对具体I2C设备(如AP3216C传感器)实现读写寄存器、解析数据等逻辑。
(2)关键数据结构:
struct i2c_driver {
int (*probe)(struct i2c_client *client, const struct i2c_device_id *id); //设备匹配成功后的初始化
int (*remove)(struct i2c_client *client); // 设备移除时的清理
const struct i2c_device_id *id_table; // 传统ID匹配列表
const struct of_device_id *of_match_table; // 设备树匹配表
};
三、I2C驱动开发测试
(1)首先在设备树文件的i2c节点下创建对应的子设备节点,如下:

(2)编写对应的ap3216c驱动文件,在其中的驱动文件中主要完成对读寄存器,写寄存器,读写数据函数 相关的代码编写,即调用i2c_transfer来实现主机对从机设备的数据发送来完成对从机寄存器数据的读写操作,即读数据:主设备发送从设备地址 + 寄存器地址(写操作),主设备再次发送从设备地址(读操作),并读取数据。写数据:主设备发送从设备地址 + 寄存器地址 + 数据。如下所示:
读数据:
写数据:

编写驱动文件以及测试文件后加载到内核:


重启开发板:

查看定义得节点信息:
加载驱动后测试:
