1. IMX6ULL按键驱动开发概述
在嵌入式Linux系统开发中,按键驱动是最基础也最具代表性的输入设备驱动之一。IMX6ULL作为NXP推出的高性能、低功耗处理器,广泛应用于工业控制、物联网终端等领域。本文将基于IMX6ULL平台,详细讲解Linux按键驱动的三种实现方式及其演进过程。
按键驱动的核心功能是检测按键状态变化并将事件上报给应用层。传统单片机开发中常用轮询方式检测按键,但在Linux系统中这种方式会带来极高的CPU占用率。我们将从最基础的GPIO轮询驱动开始,逐步演进到使用中断和等待队列的高效实现,最终实现完全符合Linux设备驱动模型的设备树版本。
提示:本文假设读者已具备Linux驱动开发基础,了解字符设备驱动、文件操作接口等概念。所有代码示例均基于Linux 4.1.15内核版本。
2. 驱动设计核心架构
2.1 技术栈组成
一个完整的Linux按键驱动涉及多个内核子系统的协同工作:
- GPIO子系统:提供统一的GPIO操作接口,屏蔽不同SoC的寄存器差异
- 中断子系统:管理硬件中断资源,提供中断注册和处理机制
- 等待队列:实现进程阻塞和唤醒,是高效I/O的核心机制
- 设备树:描述硬件连接关系,实现驱动与硬件的解耦
- Platform总线:Linux标准驱动模型,实现驱动与设备的匹配
2.2 三种实现方案对比
我们设计了三个版本的驱动,体现从简单到完善的演进过程:
| 版本 | 实现方式 | CPU占用 | 实时性 | 可移植性 | 适用场景 |
|---|---|---|---|---|---|
| V1 | GPIO轮询 | 高(99%) | 差 | 中 | 学习验证 |
| V2 | 中断+等待队列 | 低(<1%) | 好 | 中 | 产品原型 |
| V3 | 设备树+中断 | 低(<1%) | 好 | 高 | 正式产品 |
3. 硬件环境搭建
3.1 IMX6ULL按键电路
IMX6ULL开发板上的按键通常采用如下连接方式:
code复制按键 -> GPIO1_IO04 -> 10K上拉电阻 -> 3.3V
|
10K下拉电阻 -> GND
按键未按下时,GPIO输入为高电平;按下时变为低电平。这种设计能有效防止电平浮动。
3.2 设备树配置
设备树(DTS)是Linux内核描述硬件的重要机制。对于按键设备,我们需要在设备树中添加如下节点:
dts复制ptkey {
compatible = "pt-key";
ptkey-gpio = <&gpio1 4 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio1>;
interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
};
关键属性说明:
compatible: 驱动匹配标识,必须与驱动中的定义一致ptkey-gpio: 指定使用的GPIO引脚及有效电平interrupts: 定义中断号和触发方式(下降沿触发)
4. 基础轮询驱动实现(V1)
4.1 驱动初始化
轮询版本驱动的核心是在probe函数中初始化GPIO:
c复制static int key_gpio;
static int probe(struct platform_device *pdev)
{
struct device_node *node;
int ret;
// 查找设备树节点
node = of_find_node_by_path("/ptkey");
if (!node) {
dev_err(&pdev->dev, "Failed to find dts node\n");
return -ENODEV;
}
// 获取GPIO编号
key_gpio = of_get_named_gpio(node, "ptkey-gpio", 0);
if (key_gpio < 0) {
dev_err(&pdev->dev, "Invalid gpio number\n");
return key_gpio;
}
// 申请GPIO资源
ret = gpio_request(key_gpio, "key-gpio");
if (ret) {
dev_err(&pdev->dev, "GPIO request failed\n");
return ret;
}
// 配置为输入模式
gpio_direction_input(key_gpio);
