type
Post
date
Mar 2, 2026
slug
i2c_imu_iio_driver
category
🥳嵌入式Linux开发
icon
password
本文从零开始,逐步完成一个挂载在 I2C 总线上的虚拟 IMU(加速度计)IIO 驱动,覆盖 DT binding → i2c_driver probe/remove → iio_dev 注册 → iio_info / sysfs 验证 全流程。
1. 前置条件
确保以下环境已就绪(参考同级页面的 QEMU + 交叉编译工具链搭建指南):
交叉编译器
arm-linux-gnueabihf-gcc 可用已编译 v6.1 内核源码,且开启
CONFIG_IIO、CONFIG_I2C 支持QEMU sabrelite 能正常启动 BusyBox rootfs
rootfs 中包含
iio_info(来自 libiio 或 iio-utils)为什么选 IIO? IIO(Industrial I/O)是 Linux 为传感器类设备设计的标准子系统,提供统一的 sysfs 接口和触发缓冲机制,是 IMU、ADC、DAC 等设备的首选框架。
2. IIO 子系统关键概念
概念 | 说明 |
iio_dev | 代表一个 IIO 设备实例,类比字符设备中的 cdev |
iio_chan_spec | 描述一路传感器通道(如 X/Y/Z 加速度),包含类型、修饰符、索引等 |
iio_info | 驱动操作集,包含 read_raw / write_raw 等回调,用户读 sysfs 时触发 |
devm_iio_device_alloc | 分配 iio_dev + 私有数据,生命周期由 devm 自动管理 |
iio_device_register | 将 iio_dev 注册进内核,对应 /sys/bus/iio/devices/iio:deviceX |
3. 驱动源码
3.1 IMU IIO 驱动 — fake_imu.c
3.2 关键结构说明
元素 | 作用 |
iio_chan_spec[] | 静态声明每路传感器通道,内核据此生成 sysfs 属性文件 |
IIO_CHAN_INFO_RAW | 标记该通道支持读取原始 ADC 值,对应 in_accel_x_raw sysfs 节点 |
IIO_CHAN_INFO_SCALE | 标记支持读取物理量转换系数,对应 in_accel_x_scale sysfs 节点 |
iio_priv(indio_dev) | 取出紧跟在 iio_dev 后面的私有数据指针,替代全局变量 |
devm_iio_device_register | 注册 IIO 设备,由 devm 管理生命周期,remove 时自动注销 |
module_i2c_driver | 宏展开为 module_init/module_exit,自动注册/注销 i2c_driver |
4. Makefile
5. 编译模块
编译成功后确认产出:
注意depends: industrialio:IIO 核心是一个独立模块,加载fake_imu.ko前必须先加载industrialio.ko(或内核内建)。
6. 设备树配置
6.1 I2C 节点说明
I2C 设备必须作为 I2C 控制器节点的子节点 声明,并提供
reg(7-bit 地址)属性。6.2 创建 Overlay 源文件 — fake-imu-overlay.dts
6.3 编译 Overlay
6.4 备选:直接修改主 DTB
7. 打包进 rootfs
8. QEMU 内加载验证
8.1 启动 QEMU
8.2 挂载文件系统 & 加载模块
8.3 确认 probe 调用
8.4 查看 IIO sysfs 接口
8.5 使用 iio_info 验证(推荐)
8.6 卸载模块
9. 验证清单
make 编译无 warning,产出 fake_imu.komodinfo 输出 depends: industrialiofile fake_imu.ko 显示 ARM ELF relocatable设备树中
i2c1 节点下存在 fake_imu@68 子节点insmod 后 dmesg 显示 probe OK, addr=0x68/sys/bus/iio/devices/iio:device0/name 输出 fake_imuin_accel_z_raw 读取返回 1000iio_info -d 0 列出三轴通道rmmod 后 dmesg 显示 remove called10. 常见问题排查
现象 | 原因 | 解决方案 |
insmod: can't insert: unknown symbol iio_device_register | IIO 核心未加载 | 先 insmod industrialio.ko,或内核配置 CONFIG_IIO=y |
probe 未调用,无 probe OK 日志 | DT 节点不在 i2c 控制器下,或 compatible 不匹配 | 确认 &i2c1 { fake_imu@68 { compatible = "myvendor,fake-imu"; ... } } 结构正确 |
/sys/bus/iio/devices/ 为空 | iio_device_register 失败或 sysfs 未挂载 | 检查 dmesg 错误信息;确认 mount -t sysfs none /sys |
读 in_accel_x_raw 返回 -EINVAL | read_raw 回调未处理该 mask | 检查 iio_chan_spec.info_mask_separate 是否包含 BIT(IIO_CHAN_INFO_RAW) |
iio_info 找不到设备 | 工具版本与内核 ABI 不匹配,或 /dev/iio:device0 缺失 | 确认内核开启 CONFIG_IIO_BUFFER,或改用 sysfs 直接读取验证 |
insmod: invalid module format | vermagic 不匹配 | 确保 KERNDIR 指向 QEMU 启动时使用的同一内核树 |
11. 向真实硬件(MPU-6050)迁移
完成虚拟驱动验证后,迁移到真实 IMU 只需替换以下部分:
- probe 中添加 WHO_AM_I 寄存器检测
- read_raw 中替换为真实寄存器读取
- DT compatible 改为
invensense,mpu6050
- 添加电源管理:
devm_regulator_get+pm_ops
12. 下一步扩展方向
- 触发缓冲(Triggered Buffer) — 接入 IIO 触发器,实现中断驱动的连续数据采集
- libiio 用户态应用 — 用
iio_channel_read替代 sysfs 读取,支持高频采样
- IIO 事件机制 — 配置阈值告警,通过
iio_push_event上报超量程事件
- 对接 MIPI Camera 流水线 — IMU + 摄像头时间戳同步,构建完整感知平台
- Author:felixfixit
- URL:http://www.felixmicrospace.top/article/i2c_imu_iio_driver
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!








