Tina SDK Linux Kernel 基本使用(实战篇:为开发板添加用户按键驱动支持)

Tina SDK Linux Kernel 基本使用(实战篇:为开发板添加用户按键驱动支持)

本文是全志Tina-SDK Linux内核开发实战系列的第二篇,以 100ASK_T113s3-Pro开发板上的用户按键(USER KEY) 为例,手把手带你完成从硬件原理图分析、Pinctrl/GPIO子系统理解、设备树修改、内核模块配置到驱动加载验证的完整流程。学完本节,你将掌握为任何嵌入式Linux系统添加独立按键或GPIO输入设备的方法,并深入理解Pinctrl框架在设备树中的配置方式。

本文延续上一篇的超详细风格,所有内容全面展开,不偷工减料。

🎯 本任务的学习目标和重点掌握程度

分级 图标 含义 工作要求
必须掌握 ⭐⭐⭐ 独立作业,考核核心 能独立完成从原理图到设备树再到验证的全过程。
重点掌握 ⭐⭐ 了解原理,能按文档完成 理解Pinctrl基本概念,能看懂设备树中的引脚配置。
了解即可 知道概念,能复述 知道Pinctrl框架的分层,面试能说清楚。

优先掌握:必须掌握⭐⭐⭐的内容是你的核心竞争力;重点掌握⭐⭐能帮你快速定位问题;了解即可⭐部分可以后续再深入学习。

文章目录

    • [Tina SDK Linux Kernel 基本使用(实战篇:为开发板添加用户按键驱动支持)](#Tina SDK Linux Kernel 基本使用(实战篇:为开发板添加用户按键驱动支持))
    • [🎯 本任务的学习目标和重点掌握程度](#🎯 本任务的学习目标和重点掌握程度)
    • 一、项目背景:我们要做什么?
    • [二、理论基础:Pinctrl 子系统与 GPIO(⭐⭐ 重点掌握)](#二、理论基础:Pinctrl 子系统与 GPIO(⭐⭐ 重点掌握))
      • [2.1 Pinctrl 系统架构](#2.1 Pinctrl 系统架构)
      • [2.2 全志平台 Pinctrl 的重要节点](#2.2 全志平台 Pinctrl 的重要节点)
      • [2.3 设备树中描述一个 GPIO 按键的格式](#2.3 设备树中描述一个 GPIO 按键的格式)
    • [三、查看硬件原理图与数据手册(⭐⭐⭐ 必须掌握)](#三、查看硬件原理图与数据手册(⭐⭐⭐ 必须掌握))
      • [3.1 从原理图找到按键引脚](#3.1 从原理图找到按键引脚)
      • [3.2 确认引脚未被其他功能占用](#3.2 确认引脚未被其他功能占用)
    • [四、修改设备树(⭐⭐⭐ 必须掌握)](#四、修改设备树(⭐⭐⭐ 必须掌握))
      • [4.1 定位板级设备树文件](#4.1 定位板级设备树文件)
      • [4.2 添加 gpio-keys 节点](#4.2 添加 gpio-keys 节点)
      • [4.3 检查引脚冲突](#4.3 检查引脚冲突)
    • [五、配置内核模块(⭐⭐⭐ 必须掌握)](#五、配置内核模块(⭐⭐⭐ 必须掌握))
      • [5.1 进入 Tina 配置主界面](#5.1 进入 Tina 配置主界面)
      • [5.2 找到 gpio-keys 模块](#5.2 找到 gpio-keys 模块)
      • [5.3 保存配置](#5.3 保存配置)
    • [六、编译、打包与烧录(⭐⭐ 重点掌握)](#六、编译、打包与烧录(⭐⭐ 重点掌握))
      • [6.1 编译系统](#6.1 编译系统)
      • [6.2 打包镜像](#6.2 打包镜像)
      • [6.3 烧录镜像](#6.3 烧录镜像)
    • [七、验证按键功能(⭐⭐⭐ 必须掌握)](#七、验证按键功能(⭐⭐⭐ 必须掌握))
      • [7.1 检查模块是否已自动加载](#7.1 检查模块是否已自动加载)
      • [7.2 手动加载模块](#7.2 手动加载模块)
      • [7.3 查看输入设备列表](#7.3 查看输入设备列表)
      • [7.4 测试按键事件](#7.4 测试按键事件)
      • [7.5 设置开机自动加载](#7.5 设置开机自动加载)
    • [八、进阶:理解 GPIO 配置的格式](#八、进阶:理解 GPIO 配置的格式)
    • 九、常见问题排查
    • 十、面试官提问环节
      • [第1问:设备树中 `gpio-keys` 节点的 `compatible` 属性为什么是 `"gpio-keys"`?它如何匹配驱动?](#第1问:设备树中 gpio-keys 节点的 compatible 属性为什么是 "gpio-keys"?它如何匹配驱动?)
      • [第2问:Pinctrl 子系统中的 `default` 和 `sleep` 状态是什么意思?什么时候会切换?](#第2问:Pinctrl 子系统中的 defaultsleep 状态是什么意思?什么时候会切换?)
      • [第3问:为什么在 TinaSDK 中不能直接用 `make kernel_menuconfig` 来永久保存内核配置?应该怎么做?](#第3问:为什么在 TinaSDK 中不能直接用 make kernel_menuconfig 来永久保存内核配置?应该怎么做?)
      • [第4问:在验证按键时,`cat /dev/input/event3` 出现乱码,这是否代表失败?怎样正确观察按键事件?](#第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 主要处理三类功能:

  1. Pin State(引脚状态) :支持 default(正常运行)、sleep(休眠)、idle(空闲)等不同状态,每种状态可以配置不同的引脚功能。
  2. Pin Mux(引脚复用) :一个引脚可以承担多种功能(如 GPIO、UART、I2C、SPI等),通过设置 Mux 值来切换。例如 PE0 可以作为 NCSI_PCLKRGMII_RXD1I2S1_MCLKPWM0SDC1_CLKUART3_TXTWI3_SCK 等。
  3. 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_POWERKEY_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.dtssun8iw20p1.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 menuconfig

5.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.ko

6.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 子系统中的 defaultsleep 状态是什么意思?什么时候会切换?

参考答案

  • default:系统正常运行时的引脚状态(如 UART 的 TX/RX 引脚工作在 UART 模式)。
  • sleep:系统进入休眠状态时的引脚状态,通常会将引脚设置为 gpio_in 或高阻态以节省功耗。
    当系统通过 pm_runtimesuspend/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.mkconfig-5.4 中。如果需要修改更深层次的内核选项,应修改板级 config-5.4 文件。


第4问:在验证按键时,cat /dev/input/event3 出现乱码,这是否代表失败?怎样正确观察按键事件?

参考答案
cat 将二进制数据直接打印到终端会造成乱码,这并不代表失败,反而说明有数据上报。要正确查看按键事件,可以使用 hexdump /dev/input/event3 查看十六进制数据,或者安装 evtest 工具:evtest /dev/input/event3,它会解析并显示每个事件的具体类型、键值和状态。

十一、总结

本文带你完整走了一遍为 T113 开发板添加用户按键驱动支持的流程,包括:

  1. 硬件分析:从原理图找到 USER KEY 的引脚 PB4 和极性。
  2. 设备树修改 :添加 gpio-keys 节点,配置 GPIO 和键值。
  3. 内核模块配置 :在 Tina 的 make menuconfig 中选中 kmod-input-gpio-keys
  4. 编译与烧录 :执行 makepack,生成镜像并烧录。
  5. 验证与动手 :手动加载模块,用 hexdumpevtest 测试,最后设为开机自动加载。

同时,你还深入了解了 Pinctrl 子系统的概念、设备树中 GPIO 配置的格式,以及 TinaSDK 中内核模块的配置机制。

学习阶段 任务
⭐ 入门 按本文步骤完成按键驱动添加,成功看到按键事件。
⭐⭐ 进阶 修改 linux,code 为其他值(如 KEY_POWER),并观察上层应用反应。
⭐⭐⭐ 高级 查阅 Pinctrl 驱动源码,理解引脚状态切换的实现细节。

整个系列完结撒花! 你从一个完全不懂嵌入式 Linux 的小白,到现在已经能够独立为开发板添加 LCD 触摸屏和按键驱动,理解和修改设备树,配置内核模块,烧录验证。你已经具备了嵌入式 Linux 驱动开发的初步能力。后续可以深入学习 I2C/SPI 子系统、设备树语法、内核调试等高级主题。

祝你职场顺利,考核满分!🎉

相关推荐
日取其半万世不竭1 小时前
Excalidraw 自建部署指南:白板协作工具完全私有化
服务器·网络·数据库
瞎折腾啥啊1 小时前
VCPKG详细使用教程
linux·c++·cmake·cmakelists
我是Superman丶2 小时前
Docker 命令自用
运维·docker·容器
网络笨猪2 小时前
Nginx企业级高频场景配置大全
运维·nginx
爱莉希雅&&&2 小时前
MySQL MGR + MySQL Router 高可用集群完整笔记(含手动配置 + Shell 接管双路线)
linux·数据库·笔记·mysql·mysqlrouter·mysqlshell
牛奶2 小时前
1秒下单10万次,服务器是怎么扛住的?
大数据·服务器·后端
楼田莉子2 小时前
仿Muduo的高并发服务器:LoopThread模块及其ThreadPool模块
linux·服务器·c++·后端·学习
techdashen2 小时前
等了两年,Cloudflare 终于给规则引擎加上了通配符
服务器·rust
zhangfeng11332 小时前
宝塔服务器完全可以安装 Git,进行版本管理,而且非常简单
运维·服务器·人工智能·git·编程