Tina SDK Linux Kernel 基本使用(实战篇:为开发板添加用户按键驱动支持)
本文是全志Tina-SDK Linux内核开发实战系列的第二篇,以100ASK_T113s3-Pro开发板上的用户按键(USER KEY)为例,手把手带你完成从硬件原理图分析、Pinctrl/GPIO子系统理解、设备树修改、内核模块配置到驱动加载验证的完整流程。学完本节,你将掌握为任何嵌入式Linux系统添加独立按键或GPIO输入设备的方法,并深入理解Pinctrl框架在设备树中的配置方式。
本文延续上一篇的超详细风格,所有内容全面展开,不偷工减料。
🎯 本任务的学习目标和重点掌握程度
| 分级 | 图标 | 含义 | 工作要求 |
|---|---|---|---|
| 必须掌握 | ⭐⭐⭐ | 独立作业,考核核心 | 能独立完成从原理图到设备树再到验证的全过程。 |
| 重点掌握 | ⭐⭐ | 了解原理,能按文档完成 | 理解Pinctrl基本概念,能看懂设备树中的引脚配置。 |
| 了解即可 | ⭐ | 知道概念,能复述 | 知道Pinctrl框架的分层,面试能说清楚。 |
优先掌握:必须掌握⭐⭐⭐的内容是你的核心竞争力;重点掌握⭐⭐能帮你快速定位问题;了解即可⭐部分可以后续再深入学习。
文章目录
- Tina SDK Linux Kernel 基本使用(实战篇:为开发板添加用户按键驱动支持)
- 🎯 本任务的学习目标和重点掌握程度
- 一、项目背景:我们要做什么?
- 二、理论基础:Pinctrl 子系统与 GPIO(⭐⭐ 重点掌握)
- 2.1 Pinctrl 系统架构
- 2.2 全志平台 Pinctrl 的重要节点
- 2.3 设备树中描述一个 GPIO 按键的格式
- 三、查看硬件原理图与数据手册(⭐⭐⭐ 必须掌握)
- 3.1 从原理图找到按键引脚
- 3.2 确认引脚未被其他功能占用
- 四、修改设备树(⭐⭐⭐ 必须掌握)
- 4.1 定位板级设备树文件
- 4.2 添加 gpio-keys 节点
- 4.3 检查引脚冲突
- 五、配置内核模块(⭐⭐⭐ 必须掌握)
- 5.1 进入 Tina 配置主界面
- 5.2 找到 gpio-keys 模块
- 5.3 保存配置
- 六、编译、打包与烧录(⭐⭐ 重点掌握)
- 6.1 编译系统
- 6.2 打包镜像
- 6.3 烧录镜像
- 七、验证按键功能(⭐⭐⭐ 必须掌握)
- 7.1 检查模块是否已自动加载
- 7.2 手动加载模块
- 7.3 查看输入设备列表
- 7.4 测试按键事件
- 7.5 设置开机自动加载
- 八、进阶:理解 GPIO 配置的格式
- 九、常见问题排查
- 十、面试官提问环节
- 第1问:设备树中 `gpio-keys` 节点的 `compatible` 属性为什么是 `"gpio-keys"`?它如何匹配驱动?
- 第2问:Pinctrl 子系统中的 `default` 和 `sleep` 状态是什么意思?什么时候会切换?
- 第3问:为什么在 TinaSDK 中不能直接用 `make kernel_menuconfig` 来永久保存内核配置?应该怎么做?
- 第4问:在验证按键时,`cat /dev/input/event3` 出现乱码,这是否代表失败?怎样正确观察按键事件?
- 十一、总结
一、项目背景:我们要做什么?
在嵌入式Linux产品中,经常需要用到独立按键(如用户按键(USER KEY)、复位键、音量键等)。Linux内核提供了gpio-keys驱动,可以将连接到GPIO的按键抽象为输入设备,向上层上报按键事件(如 KEY_VOLUMEDOWN、KEY_POWER等)。
本次任务:为100ASK_T113s3-Pro开发板上的USER KEY添加驱动支持,使得按下按键时系统能够检测到,并上报对应的键值(例如KEY_VOLUMEDOWN或自定义键值),后续应用可以通过/dev/input/eventX读取按键事件。
硬件连接分析:通过查阅开发板原理图(100ASK_T113-Pro_Base-SCH_V1.2.pdf)和实物图,USER KEY 连接到 T113 芯片的PB4引脚,且按键按下时引脚为低电平(GPIO_ACTIVE_LOW)。我们需要在设备树中配置该引脚为中断模式,并关联对应的键值。
二、理论基础:Pinctrl 子系统与 GPIO(⭐⭐ 重点掌握)
在动手修改设备树之前,你需要先了解一些背景知识。Linux内核使用Pinctrl(Pin Controller)子系统统一管理所有引脚的复用和电气特性。
2.1 Pinctrl 系统架构
Pinctrl 框架分为四层(参考图示):
text
Device Tree 描述引脚的配置信息(设备树节点) ↓ Pinctrl Interface 上层驱动调用的接口(如 pinctrl_select_state) ↓ Pinctrl Framework Linux 内核核心框架(处理状态、复用和配置) ↓ Pinctrl Driver 芯片厂商实现的底层驱动(全志为 SUNXI Pinctrl)Pinctrl 主要处理三类功能:
- Pin State(引脚状态):支持
default(正常运行)、sleep(休眠)、idle(空闲)等不同状态,每种状态可以配置不同的引脚功能。 - Pin Mux(引脚复用):一个引脚可以承担多种功能(如 GPIO、UART、I2C、SPI等),通过设置 Mux 值来切换。例如 PE0 可以作为
NCSI_PCLK、RGMII_RXD1、I2S1_MCLK、PWM0、SDC1_CLK、UART3_TX、TWI3_SCK等。 - Pin Config(引脚配置):配置驱动能力、上拉/下拉、输入/输出等电气特性。
2.2 全志平台 Pinctrl 的重要节点
在 T113 的设备树中,有两个 Pinctrl 节点:
| 节点名 | 寄存器地址 | 管理的引脚 | 注意 |
|---|---|---|---|
pio | 0x02000000 | PL0 之前的引脚(包括 PA~PK) | 大部分外设引脚 |
r_pio | 0x07022000 | PL0 及以后的引脚 | 部分低功耗、RTC相关引脚 |
我们使用的 PB4 属于pio管理。
2.3 设备树中描述一个 GPIO 按键的格式
gpio-keys驱动要求我们在设备树中创建一个节点,格式如下:
c
gpio-keys { compatible = "gpio-keys"; status = "okay"; user-key { gpios = <&pio PB 4 GPIO_ACTIVE_LOW>; linux,code = <114>; // KEY_VOLUMEDOWN 的键值 label = "user key"; debounce-interval = <10>; // 消抖时间(毫秒) wakeup-source; // 可作为唤醒源 }; };各属性含义:
compatible:匹配内核中的gpio-keys驱动。gpios:指定 GPIO 引脚、极性。linux,code:上报给 input 子系统的键值(<114>对应KEY_VOLUMEDOWN,也可以使用其他值如KEY_POWER、KEY_ENTER等)。label:此按键的描述名称。debounce-interval:简单消抖延迟(毫秒)。wakeup-source:系统休眠时该按键可以唤醒系统(可选).
三、查看硬件原理图与数据手册(⭐⭐⭐ 必须掌握)
3.1 从原理图找到按键引脚
查阅100ASK_T113-Pro_Base-SCH_V1.2.pdf中的按键部分(实物图标注 USER KEY 旁边有 SW2)。根据电路图,USER KEY 连接到 T113 的PB4引脚,按下时接地(低电平)。因此我们需要在设备树中配置GPIO_ACTIVE_LOW。
3.2 确认引脚未被其他功能占用
查阅T113-s3_datasheet_v1.6.pdf第40页的 GPIO Multiplex Function 表,PB4 的默认功能是LCDD-D8,但也可复用为其他功能。在我们的开发板上,PB4 未用于其他外设,因此可以直接作为 GPIO 使用。
排查冲突:在添加前,建议用
grep -r "PB4" device/检查是否已有其他设备使用了该引脚。如果有冲突,需要解除冲突或更换引脚。
四、修改设备树(⭐⭐⭐ 必须掌握)
4.1 定位板级设备树文件
回顾之前的内容,板级设备树位于:
bash
# 切换到板级配置目录 ccconfigs cd linux-5.4 vim board.dts快捷命令说明:执行ccconfigs可直接进入device/config/chips/t113/configs/100ask/linux/目录,再执行vim board.dts编辑设备树。
4.2 添加 gpio-keys 节点
在board.dts文件的合适位置(通常在根节点下,远离其他大括号),添加如下内容:
c
&pio { // ... 原有配置保持不变 ... }; /* 新增按键设备节点 */ gpio-keys { compatible = "gpio-keys"; status = "okay"; user-key { gpios = <&pio PB 4 GPIO_ACTIVE_LOW>; // PB4, 低电平有效 linux,code = <114>; // KEY_VOLUMEDOWN label = "user key"; debounce-interval = <10>; wakeup-source; }; /* 如果你还有别的按键,可以继续添加,例如: power-key { gpios = <&pio PE 1 GPIO_ACTIVE_LOW>; linux,code = <116>; // KEY_POWER label = "power key"; debounce-interval = <10>; }; */ };4.3 检查引脚冲突
检查是否有其他设备也使用了 PB4。如果在board.dts或sun8iw20p1.dtsi中搜索到 PB4,且状态为okay,则需要禁用或修改。通常情况下开发板默认未使用,可以直接添加。
验证方法:在board.dts中搜索PB4,若无其他节点使用,则安全。
五、配置内核模块(⭐⭐⭐ 必须掌握)
我们已经知道,在 TinaSDK 中,内核模块是通过make menuconfig而不是make kernel_menuconfig来永久选中的。
5.1 进入 Tina 配置主界面
bash
# 回到 SDK 根目录 cd ~/tina-d1-h source build/envsetup.sh lunch 4 # 选择 t113_100ask-tina make menuconfig5.2 找到 gpio-keys 模块
在菜单中依次进入:
text
Kernel modules ---> Input modules ---> [*] kmod-input-gpio-keys ---> GPIO key support使用Y键选中该项(变为<*>)。注意我们不需要kmod-input-gpio-keys-polled(轮询方式),除非你的按键不适合中断方式。
5.3 保存配置
按Esc两次退出到主界面,选择<Save>,确认保存为.config,然后退出。
配置保存后,Tina 会在后续make时自动将CONFIG_KEYBOARD_GPIO等选项写入内核的.config,并编译gpio-keys.ko模块。
六、编译、打包与烧录(⭐⭐ 重点掌握)
6.1 编译系统
bash
# 在 SDK 根目录执行 make -j$(nproc)编译过程中,你会看到系统编译gpio_keys.ko模块的日志(类似下图):
text
CC [M] drivers/input/keyboard/gpio_keys.o Building modules, stage 2. CC [M] drivers/input/keyboard/gpio_keys.mod.o LD [M] drivers/input/keyboard/gpio_keys.ko6.2 打包镜像
bash
pack打包成功后,最终镜像路径为:
text
/home/ubuntu/tina-d1-h/out/t113-100ask/tina_t113-100ask_uart3.img使用ls -lh查看大小(约43MB)。
6.3 烧录镜像
将镜像复制到 Windows(通过共享文件夹或拖拽),使用PhoenixSuit线刷到开发板的 SPI NAND 中。
七、验证按键功能(⭐⭐⭐ 必须掌握)
烧录完成后,启动开发板,通过串口登录。
7.1 检查模块是否已自动加载
首先查看lsmod,看gpio_keys是否已在模块列表中:
bash
lsmod | grep gpio_keys如果未出现,需要手动安装或设置开机自动加载(后面会讲)。按照预期,Tina 默认不会自动加载 gpio_keys.ko,需要手动处理。
7.2 手动加载模块
进入模块目录并手动安装:
bash
cd /lib/modules/5.4.61/ insmod gpio_keys.ko加载后,内核日志会显示:
text
input: gpio-keys as /devices/platform/gpio-keys/input/input3此时新的输入设备节点/dev/input/event3已创建。
7.3 查看输入设备列表
bash
cat /proc/bus/input/devices在输出中找到gpio-keys段,确认其对应的H行(Handlers)为event2。
7.4 测试按键事件
bash
cat /dev/input/event2然后按下开发板上的 USER KEY 按键,终端上应出现二进制乱码输出(表明有数据上报)。你也可以使用hexdump查看具体数据:
bash
hexdump /dev/input/event3按下按键会输出类似:
text
0000000 0a9a 0000 3b2c 0008 0001 0072 0001 0000 ...其中0001 0072中的0x72就是十进制 114,即KEY_VOLUMEDOWN。说明按键驱动工作正常。
7.5 设置开机自动加载
为了避免每次都要insmod,可以修改系统启动脚本/etc/init.d/rc.modules:
bash
vi /etc/init.d/rc.modules在文件中仿照其他.ko的加载方式,添加一行:
bash
/sbin/insmod /lib/modules/5.4.61/gpio_keys.ko保存后重启,系统即会自动加载 gpio_keys 模块。
八、进阶:理解 GPIO 配置的格式
在设备树中,gpios = <&pio PB 4 GPIO_ACTIVE_LOW>;是一个简化的写法。更完整的 GPIO 属性在旧版设备树中可能使用 6 个数字:
text
gpios = <&pio bank pin mux pull drive data>;对应关系:
| 字段 | 含义 | 示例值 |
|---|---|---|
&pio | 指向哪个 Pinctrl 控制器 | &pio或&r_pio |
| bank | GPIO 组 | PB对应数值 1? 但设备树中通常直接写 PB,由宏转换 |
| pin | 组内序号 | 4 |
| mux | 复用模式,输入为 0, 输出为 1 | 0(输入) |
| pull | 上下拉,0=禁用,1=上拉,2=下拉 | 0 |
| drive | 驱动能力 | 通常 0xffffffff 表示默认 |
| data | 输出电平(仅输出时有效) | 0xffffffff 忽略 |
但在新的设备树中,gpios = <&pio PB 4 GPIO_ACTIVE_LOW>;使用了 GPIO 子系统中定义的标志宏,更简洁。
九、常见问题排查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
lsmod看不到gpio_keys | 模块未编译或未安装 | 检查make menuconfig中是否选中,重新make |
insmod失败,提示Unknown symbol | 依赖模块未加载 | 检查input-core是否已编译进内核 |
按键无反应,cat /dev/input/eventX无输出 | 设备树配置错误或引脚冲突 | 检查gpios的引脚号和极性,确认无其他设备占用 PB4 |
| 按键上报乱码,但无正确键值 | 测试工具问题 | 用hexdump查看具体上报数据,确认linux,code值正确 |
十、面试官提问环节
第1问:设备树中gpio-keys节点的compatible属性为什么是"gpio-keys"?它如何匹配驱动?
参考答案:compatible属性是设备树与内核驱动匹配的关键字段。内核中的gpio-keys驱动通过of_match_table声明自己支持"gpio-keys"。当内核解析设备树时,发现节点compatible为"gpio-keys",就会调用该驱动的probe函数来初始化设备。
第2问:Pinctrl 子系统中的default和sleep状态是什么意思?什么时候会切换?
参考答案:
default:系统正常运行时的引脚状态(如 UART 的 TX/RX 引脚工作在 UART 模式)。sleep:系统进入休眠状态时的引脚状态,通常会将引脚设置为gpio_in或高阻态以节省功耗。
当系统通过pm_runtime或suspend/resume切换电源状态时,Pinctrl 框架会自动调用pinctrl_select_state来切换引脚配置。
第3问:为什么在 TinaSDK 中不能直接用make kernel_menuconfig来永久保存内核配置?应该怎么做?
参考答案:
因为 TinaSDK 的内核配置是由多个片段动态合并而成的(generic/config-5.4+board/linux/config-5.4)。直接修改.config会在下次make时被覆盖。正确做法是通过make menuconfig(Tina主配置)中的Kernel modules选项来选择需要的内核模块,这些选项会被转化为内核配置片段,永久保存在modules.mk或config-5.4中。如果需要修改更深层次的内核选项,应修改板级config-5.4文件。
第4问:在验证按键时,cat /dev/input/event3出现乱码,这是否代表失败?怎样正确观察按键事件?
参考答案:cat将二进制数据直接打印到终端会造成乱码,这并不代表失败,反而说明有数据上报。要正确查看按键事件,可以使用hexdump /dev/input/event3查看十六进制数据,或者安装evtest工具:evtest /dev/input/event3,它会解析并显示每个事件的具体类型、键值和状态。
十一、总结
本文带你完整走了一遍为 T113 开发板添加用户按键驱动支持的流程,包括:
- 硬件分析:从原理图找到 USER KEY 的引脚 PB4 和极性。
- 设备树修改:添加
gpio-keys节点,配置 GPIO 和键值。 - 内核模块配置:在 Tina 的
make menuconfig中选中kmod-input-gpio-keys。 - 编译与烧录:执行
make和pack,生成镜像并烧录。 - 验证与动手:手动加载模块,用
hexdump或evtest测试,最后设为开机自动加载。
同时,你还深入了解了 Pinctrl 子系统的概念、设备树中 GPIO 配置的格式,以及 TinaSDK 中内核模块的配置机制。
| 学习阶段 | 任务 |
|---|---|
| ⭐ 入门 | 按本文步骤完成按键驱动添加,成功看到按键事件。 |
| ⭐⭐ 进阶 | 修改linux,code为其他值(如 KEY_POWER),并观察上层应用反应。 |
| ⭐⭐⭐ 高级 | 查阅 Pinctrl 驱动源码,理解引脚状态切换的实现细节。 |
整个系列完结撒花!你从一个完全不懂嵌入式 Linux 的小白,到现在已经能够独立为开发板添加 LCD 触摸屏和按键驱动,理解和修改设备树,配置内核模块,烧录验证。你已经具备了嵌入式 Linux 驱动开发的初步能力。后续可以深入学习 I2C/SPI 子系统、设备树语法、内核调试等高级主题。
祝你职场顺利,考核满分!🎉