Lazy loaded image
🧭I2C IMU 驱动实战(IIO 子系统)
Words 1993Read Time 5 min
2026-3-2
2026-3-2
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_IIOCONFIG_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.ko
modinfo 输出 depends: industrialio
file fake_imu.ko 显示 ARM ELF relocatable
设备树中 i2c1 节点下存在 fake_imu@68 子节点
insmoddmesg 显示 probe OK, addr=0x68
/sys/bus/iio/devices/iio:device0/name 输出 fake_imu
in_accel_z_raw 读取返回 1000
iio_info -d 0 列出三轴通道
rmmoddmesg 显示 remove called

10. 常见问题排查

现象
原因
解决方案
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 只需替换以下部分:
  1. probe 中添加 WHO_AM_I 寄存器检测
    1. read_raw 中替换为真实寄存器读取
      1. DT compatible 改为 invensense,mpu6050
      1. 添加电源管理devm_regulator_get + pm_ops

      12. 下一步扩展方向

      1. 触发缓冲(Triggered Buffer) — 接入 IIO 触发器,实现中断驱动的连续数据采集
      1. libiio 用户态应用 — 用 iio_channel_read 替代 sysfs 读取,支持高频采样
      1. IIO 事件机制 — 配置阈值告警,通过 iio_push_event 上报超量程事件
      1. 对接 MIPI Camera 流水线 — IMU + 摄像头时间戳同步,构建完整感知平台
      上一篇
      XIAOMI 面试题
      下一篇
      用面试拷问嵌入式技术栈

      Comments
      Loading...