从零构建I2C驱动框架:MPU6050在Linux下的设备驱动开发实战
在嵌入式Linux开发领域,I2C设备驱动的开发是一个既基础又关键的技能点。无论是智能路灯、工业传感器还是消费电子产品,I2C总线都因其简洁的两线设计和多设备支持特性而广受欢迎。MPU6050作为一款集成了三轴陀螺仪和三轴加速度计的经典运动处理传感器,是学习I2C驱动开发的绝佳案例。本文将带你从零开始,在Linux系统下构建完整的MPU6050驱动框架,深入理解I2C子系统的架构设计与实现细节。
1. Linux I2C子系统架构解析
Linux内核的I2C子系统采用分层设计,清晰地分离了硬件控制与设备逻辑。整个架构分为三个核心层次:I2C核心层、I2C总线驱动层和I2C设备驱动层。
I2C核心层(i2c-core)提供了整个子系统的框架,负责维护i2c_bus_type总线类型,实现设备与驱动的匹配机制。它还提供了通用的传输函数i2c_transfer()和i2c_master_send()/i2c_master_recv()等,这些函数会被底层总线驱动具体实现。
I2C总线驱动层直接操作硬件控制器,负责将核心层的通用请求转换为具体的寄存器操作。以RK3x系列芯片为例,其驱动结构体定义如下:
struct rk3x_i2c {
struct i2c_adapter adap;
struct device *dev;
void __iomem *regs;
struct clk *clk;
struct i2c_msg *msg;
// ... 其他硬件相关字段
};
这个结构体包含了适配器、设备信息、寄存器映射、时钟控制等关键元素,是连接硬件与Linux I2C框架的桥梁。
I2C设备驱动层则专注于特定设备的功能实现,如MPU6050。它通过i2c_driver结构体注册到系统,并在probe函数中初始化设备特性:
static struct i2c_driver mpu6050_driver = {
.driver = {
.name = "mpu6050",
.of_match_table = mpu6050_of_match,
},
.probe = mpu6050_probe,
.remove = mpu6050_remove,
.id_table = mpu6050_id,
};
提示:现代Linux驱动开发强烈推荐使用设备树(Device Tree)来描述硬件配置,这避免了硬编码硬件参数,提高了驱动的可移植性。
2. 设备树配置与硬件连接
设备树是嵌入式Linux系统中描述硬件配置的数据结构,它为内核提供了不依赖于硬件的设备信息。对于I2C设备,正确的设备树配置是驱动正常工作的前提。
MPU6050通常连接到SoC的某个I2C控制器上,以下是一个典型的设备树节点配置示例:
&i2c1 {
status = "okay";
clock-frequency = <100000>;
mpu6050: imu@68 {
compatible = "invensense,mpu6050";
reg = <0x68>;
interrupt-parent = <&gpio1>;
interrupts = <14 IRQ_TYPE_EDGE_RISING>;
i2c-pull-up;
vdd-supply = <&vdd_3v3>;
vddio-supply = <&vdd_3v3>;
};
};
这个配置片段定义了I2C1控制器的工作参数和连接的MPU6050设备。关键配置项包括:
- clock-frequency:设置I2C总线速度为100kHz(标准模式)
- reg:指定设备地址为0x68(AD0引脚接地时)
- interrupts:配置中断引脚和触发方式
- vdd-supply和vddio-supply:定义电源供应
硬件连接方面,MPU6050需要正确连接到开发板的I2C总线:
| MPU6050引脚 | 开发板引脚 | 备注 |
|---|---|---|
| VCC | 3.3V | 电源正极 |
| GND | GND | 电源地 |
| SCL | I2C_SCL | 时钟线,需上拉 |
| SDA | I2C_SDA | 数据线,需上拉 |
| AD0 | GND/VCC | 地址选择脚 |
| INT | GPIO | 中断输出 |
注意:I2C总线必须使用上拉电阻(通常为4.7kΩ),分别连接到SCL和SDA线上。许多开发板已经内置了这些上拉电


1312

被折叠的 条评论
为什么被折叠?



