1. Sensor驱动开发概述
大家好,我是你们的讲师。今天咱们聊聊Sensor驱动开发这件事。
传感器在嵌入式系统里,说白了就是系统的「五官」。没有传感器,你的设备就是个瞎子、聋子。我做过一个智能家居项目,客户说设备老是死机,查了三天才发现是温度传感器驱动没写好,中断处理函数里做了太多事,把系统拖垮了。嗯,从那以后我对传感器驱动就格外上心。
1.1 传感器在嵌入式系统中的作用
传感器负责把物理世界的信号——温度、压力、加速度、光线——变成电信号,再通过ADC或者数字接口送给处理器。处理器拿到数据后,才能做判断、做控制。
你想想看,一个手机如果没有加速度计,屏幕翻转功能就废了。一辆汽车如果没有轮速传感器,ABS刹车系统根本没法工作。传感器就是嵌入式系统的「感知层」,没有它,上层应用就是空中楼阁。
核心要点:传感器驱动开发,本质上是「物理世界」和「数字世界」之间的翻译官。你要把芯片手册里的寄存器配置,翻译成Linux内核能理解的代码。
我在项目中遇到过最头疼的事,是客户选了一颗非常冷门的陀螺仪芯片,数据手册只有日文版。我硬是靠着示波器量SPI波形,反推寄存器配置。所以各位,学好驱动开发,关键时刻能救命。
1.2 Linux内核驱动框架简介
Linux内核的驱动框架,说白了就是一套「标准化接口」。你写驱动,不需要从头造轮子。内核已经帮你搭好了架子,你只需要填自己的代码。
常见的驱动模型有这些:
- 字符设备驱动:最基础的类型,传感器通常属于这一类。通过
open/read/write/ioctl操作。 - 平台设备驱动:用于那些不依赖具体总线的设备,比如SoC内部集成的传感器。
- I2C/SPI设备驱动:大多数数字传感器都挂在这两种总线上。内核提供了完善的总线抽象层。
我个人习惯把驱动分成三层:
- 硬件层:直接操作寄存器,读写芯片内部地址。
- 核心层:实现Linux驱动框架要求的接口,比如
probe()、remove()。 - 用户接口层:通过sysfs、ioctl或者IIO框架,把数据送给用户空间。
小技巧:写驱动时,先把硬件层调通。我习惯先写一个裸机测试程序,确认寄存器读写没问题,再往内核框架里套。这样出了问题,能快速定位是硬件问题还是框架问题。
1.3 Sensor子系统概览(IIO / Input)
Linux内核里,传感器驱动主要走两条路:IIO子系统和Input子系统。
为什么会有两套?因为传感器的用途不一样。
| 子系统 | 适用场景 | 典型设备 | 数据特点 |
|---|---|---|---|
| IIO | 工业级、高精度数据采集 | 加速度计、陀螺仪、磁力计、ADC | 连续采样、多通道、可配置触发 |
| Input | 人机交互、事件触发 | 触摸屏、按键、接近传感器 | 事件驱动、上报坐标/状态 |
IIO子系统,全称Industrial I/O。名字虽然叫工业IO,但手机里的传感器也用它。IIO提供了统一的接口,用户空间可以通过/sys/bus/iio/devices/访问数据。它还支持硬件触发、缓冲区管理,适合做连续数据采集。
我记得有一次调试一个6轴IMU,用IIO的trigger模式,CPU占用率从15%降到了2%。因为数据采集完全由硬件触发完成,不用CPU轮询。
Input子系统,大家更熟悉。鼠标、键盘、触摸屏都用它。传感器如果只是用来检测「有没有人靠近」「屏幕要不要翻转」,走Input子系统更合适。它上报的是事件,不是原始数据。
避坑指南:我曾经把一颗光线传感器写成了Input驱动,结果用户想读lux值,发现只能读到「亮/暗」两个状态。后来改成IIO驱动,才把完整的照度数据暴露出来。选子系统之前,先想清楚用户要什么。
下面这张图,是我自己总结的Sensor驱动知识体系。你可以看到,从硬件到用户空间,中间经过了哪些层。
这张图把Sensor驱动的数据流向画得很清楚。从最底层的硬件寄存器,到内核驱动层的probe/remove,再到IIO或Input子系统,最后暴露给用户空间。每一层都有自己该干的事,别越级。
举个例子,你写一个加速度计驱动:
- 硬件层:你要知道怎么通过I2C读写寄存器,怎么设置量程和采样率。
- 内核驱动层:你要实现
i2c_driver结构体,在probe里初始化芯片。 - 子系统层:选IIO,注册
iio_dev,实现read_raw回调。 - 用户空间:用户通过
/sys/bus/iio/devices/iio:device0/in_accel_x_raw读到原始数据。
总结一下:Sensor驱动开发,核心就三件事——读懂芯片手册、选对内核框架、写好寄存器配置。后面我们会一步步拆解,从最简单的温度传感器开始,到复杂的6轴IMU,每个案例我都会带上我踩过的坑。
嗯,第一章就到这里。内容不多,但都是基础。打好地基,后面盖楼才稳。