Linux 输入设备 自定义键盘 input输入子系统 gpio-keys按键驱动
2021/7/22 7:07:44
本文主要是介绍Linux 输入设备 自定义键盘 input输入子系统 gpio-keys按键驱动,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 前言
- 查看include/uapi/linux/input.h
- 设备树添加
- make menuconfig驱动
- 编译ko模块
- 查看驱动运行状态
- 查看/proc/bus/input/devices设备
- 查看dev/input
- 按键测试
- hexdump
- 应用程序
- 过程中问题及解决方法
- 常见问题
- 按键硬件注意
前言
设计板需要提供六个按键进行人机交互,起初准备使用CH455G键盘扫描芯片,设计键盘电路
随着旋转编码器Linux内核驱动的调试成功
Linux 输入设备调试详解(零基础开发)Rotary_Encoder旋转编码器模块(EC11)通用GPIO为例 挂载input输入子系统
对于更加简单,参考资料更加多的按键输入,可以尝试使用Linux内核驱动来解决,减少外围电路的设计负担,以及调试i2c的痛苦
有了之前调试旋转编码器的经验,这次也是信心十足,但整个过程还是花费了三天左右的时间,并且中间犯了一个常识性错误
查看include/uapi/linux/input.h
对于按键,先准备好input.h文件
include/uapi/linux/input.h
设备树添加
要使用Linux 内核自带的按键驱动程序很简单, 只需要根据Documentation/devicetree/bindings/input/gpio-keys.txt
这个文件在设备树中添加指定的设备节点即可,节点要求如下:
①、节点名字为“gpio-keys”。
②、gpio-keys 节点的compatible 属性值一定要设置为“gpio-keys”。
③、所有的KEY 都是gpio-keys 的子节点,每个子节点可以用如下属性描述自己:
gpios:KEY 所连接的GPIO 信息。
interrupts:KEY 所使用GPIO 中断信息,不是必须的,可以不写。
label:KEY 名字
linux,code:KEY 要模拟的按键,也就是示例代码58.1.2.4 中的这些按键。
④、如果按键要支持连按的话要加入autorepeat。
在设备树中添加所需
gpio-keys { compatible = "gpio-keys"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpio_keys>; autorepeat; key-up { label = "key-up"; gpios = <&gpio3 29 GPIO_ACTIVE_LOW>; gpio-key,wakeup; linux,code = <KEY_UP>; // 103 }; key-down { label = "key-down"; gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; gpio-key,wakeup; linux,code = <KEY_DOWN>; // 108 }; key-left { label = "key-left"; gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; gpio-key,wakeup; linux,code = <KEY_LEFT>; // 105 }; key-right { label = "key-right"; // gpios = <&gpio5 30 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_CSI0_DAT12__GPIO5_IO30 // gpios = <&gpio6 1 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_CSI0_DAT15__GPIO6_IO01 gpios = <&gpio2 20 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_EIM_A18__GPIO2_IO20 gpio-key,wakeup; linux,code = <KEY_RIGHT>; // 106 }; key-enter { label = "key-enter"; // gpios = <&gpio5 31 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_CSI0_DAT13__GPIO5_IO31 // gpios = <&gpio6 2 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_CSI0_DAT16__GPIO6_IO02 gpios = <&gpio2 18 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_EIM_A20__GPIO2_IO18 gpio-key,wakeup; linux,code = <KEY_ENTER>; // 28 }; key-esc { label = "key-esc"; // gpios = <&gpio6 0 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_CSI0_DAT14__GPIO6_IO00 // gpios = <&gpio6 3 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_CSI0_DAT17__GPIO6_IO03 gpios = <&gpio2 17 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_EIM_A21__GPIO2_IO17 gpio-key,wakeup; linux,code = <KEY_ESC>; // 1 }; /*EC11按键添加*/ key-ec11 { label = "key-ec11"; gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; // MX6QDL_PAD_EIM_A16__GPIO2_IO22 gpio-key,wakeup; linux,code = <KEY_1>; // 2 }; };
注意:KEY 按键信息,名字设置为“key-enter”,对于这个按键linux,code = <KEY_ENTER>;,也就是回车键,效果和键盘上的回车键一样。KEY_ENTER的宏定义就在之前所说include/uapi/linux/input.h
中
添加pinctrl子系统信息
pinctrl_gpio_keys: gpio_keysgrp { fsl,pins = < MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x1b0b0 MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0 MX6QDL_PAD_GPIO_5__GPIO1_IO05 0x1b0b0 /* 2021.07.19 * 添加三个key 右、确定、取消 */ MX6QDL_PAD_EIM_A18__GPIO2_IO20 0x1b0b0 MX6QDL_PAD_EIM_A20__GPIO2_IO18 0x1b0b0 MX6QDL_PAD_EIM_A21__GPIO2_IO17 0x1b0b0 /* * 2021.07.21 * 添加 EC11按键 */ MX6QDL_PAD_EIM_A16__GPIO2_IO22 0x1b0b0 >; };
保存,编译dtb
make dtbs -32
在输出信息中可以看到,生成了我需要的imx6q-c-sabresd.dtb
设备树文件
make menuconfig驱动
make menuconfig
搜索到了我们需要的普通GPIO的按键驱动
-> Device Drivers -> Input device support -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y]) -> Keyboards (INPUT_KEYBOARD [=y]) ->GPIO Buttons
选中以后就会在.config
文件中出现“CONFIG_KEYBOARD_GPIO=y
”这一行,Linux 内核就会根据这一行来将KEY 驱动文件编译进Linux 内核。Linux 内核自带的KEY 驱动文件为drivers/input/keyboard/gpiokeys.c
,gpio_keys.c
采用了platform 驱动框架,在KEY 驱动上使用了input 子系统实现。
nano drivers/input/keyboard/gpio_keys.c
找到了驱动,按照调试内核驱动的老规矩,首先我们在内核驱动中先不开启gpio-keys驱动,而是提取出来编译成ko模块进行测试
所以在make menuconfig
找到驱动的位置后,取消掉驱动,然后编译,生成zImage
文件
现在就可以把dtb文件和zImage文件烧录进板子了
编译ko模块
在编译驱动之前,先给驱动加上各种printk打印信息
处理完驱动,然后编写makefile
# ,%%%%%%%%, # ,%%/\%%%%/\%% # ,%%%\c''''J/%%% # %. %%%%/ o o \%%% # `%%. %%%% |%%% # `%% `%%%%(__Y__)%%' # // ;%%%%`\-/%%%' # (( / `%%%%%%%' # \\ .' | # \\ / \ | | # \\/ ) | | # \ /_ | |__ # (____________))))))) 攻城狮 # 调试驱动和应用程序用Makefile # 编译模块 # 开发板Linux内核的实际路径 # KDIR变量 KDIR:=/work/linux-4.1.15 # 获取当前目录 PWD:=$(shell pwd) # obj-m表示将 chrdevbase.c这个文件 编译为 name.ko模块。 obj-m += gpio_keys.o # 编译成模块 all: make -C $(KDIR) M=$(PWD) modules clean: make -C $(KDIR) M=$(PWD) clean
大功告成,执行make,编译成ko模块
发送到板子
scp gpio_keys.ko root@192.168.0.232:/work
查看驱动运行状态
运行ko文件
没有任何错误,非常的完美,运气非常的不错
但是为了谨慎,还是要查看驱动的加载情况
查看/proc/bus/input/devices设备
查看/proc/bus/input/devices
nano /proc/bus/input/devices
可以看到我们gpio-keys
查看dev/input
在input节点下,可以看到我们的event2
从驱动加载情况上来看,驱动正常运行,没有问题
按键测试
这里测试按键的输入有好多种方法,这里列举几个
hexdump
hexdump /dev/input/event2
可以看到信号的输入,但是没有办法直观的判断是哪个按键的
应用程序
这里有一个简单的应用程序
// _ooOoo_ // // o8888888o // // 88" . "88 // // (| ^_^ |) // // O\ = /O // // ____/`---'\____ // // .' \\| |// `. // // / \\||| : |||// \ // // / _||||| -:- |||||- \ // // | | \\\ - /// | | // // | \_| ''\---/'' | | // // \ .-\__ `-` ___/-. / // // ___`. .' /--.--\ `. . ___ // // ."" '< `.___\_<|>_/___.' >'"". // // | | : `- \`.;`\ _ /`;.`/ - ` : | | // // \ \ `-. \_ __\ /__ _/ .-` / / // // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // // 佛祖保佑 永不宕机 永无BUG // #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <linux/input.h> int main(int argc, char *argv[]) { struct input_event in_ev = {0}; int fd = -1; /* 校验传参 */ if (2 != argc) { fprintf(stderr, "usage: %s <input-dev>\n", argv[0]); exit(-1); } /* 打开文件 */ if (0 > (fd = open(argv[1], O_RDONLY))) { perror("open error"); exit(-1); } for ( ; ; ) { /* 循环读取数据 */ if (sizeof(struct input_event) != read(fd, &in_ev, sizeof(struct input_event))) { perror("read error"); exit(-1); } printf("type:%d code:%d value:%d\n", in_ev.type, in_ev.code, in_ev.value); } }
执行交叉编译
$CC gpio_key_app.c -o gpio_key_app
通过网络发送到板子上
scp gpio_key_app root@192.168.0.232:/work
运行应用程序
./gpio_key_app /dev/input/event2
按动我们的按键,就可以看到按键的数据
为了可以更直观一些,可以使用这个应用程序
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/input.h> #define NOKEY 0 int main() { int keys_fd; char ret[2]; struct input_event t; char *dev; setvbuf(stdout, (char *)NULL, _IONBF, 0);//disable stdio out buffer; // dev = getenv("KEYPAD_DEV"); keys_fd = open("/dev/input/keypad", O_RDONLY); if(keys_fd<=0) { printf("open %s device error!\n",dev); return 0; } while(1) { if(read(keys_fd,&t,sizeof(t))==sizeof(t)) { if(t.type==EV_KEY) if(t.value==0 || t.value==1) { //printf("%d \n", t.code); switch(t.code) { case 103: printf("key103 key-up %s\n",(t.value)?"Presse":"Released"); break; case 108: printf("key108 key-down %s\n",(t.value)?"Pressed":"Released"); break; case 106: printf("key106 key-right %s\n",(t.value)?"pressed":"Released"); break; case 105: printf("key105 key-left %s\n",(t.value)?"Released":"Pressed"); break; case 28: printf("key28 key-enter %s\n",(t.value)?"Pressed":"Released"); break; case 1: printf("key1 key-esc %s\n",(t.value)?"Released":"Pressed"); break; case 2: printf("key2 key-ec11 %s\n",(t.value)?"Released":"Pressed"); break; default: break; } } } } close(keys_fd); return 0; }
编译
$CC key_app.c -o key_app
下载
scp key_app root@192.168.0.232:/work
这个应用程序中已经调用了键盘的设备节点,所以直接打开就可以使用
./key_app
过程中问题及解决方法
在实际调试过程中显然没有这么顺利,过程中遇到了很多的问题,这里集中在一起进行记录
常见问题
①、是否使能Linux 内核KEY 驱动。
②、设备树中gpio-keys 节点是否创建成功。
③、在设备树中是否有其他外设也使用了KEY 按键对应的GPIO,但是我们并没有删除掉这些外设信息。检查Linux 启动log 信息,看看是否有类似下面这条信息:
gpio-keys gpio_keys:Failed to request GPIO 18, error -16
上述信息表示GPIO 18 申请失败,失败的原因就是有其他的外设正在使用此GPIO。
正常则是
按键硬件注意
对于按键的使用,这里一定要注意,需要拉高使用,拉高之后,电平才会稳定,按键的电平监测也会稳定,也不容易出现干扰
起初我就是没有意识到按键电平需要拉高的问题,板子上很多GPIO没有办法很好的按照理论拉高,还有就是因为使用了内核驱动,所以对于GPIO的内部操作是黑箱操作,不知道GPIO的电平究竟发生了什么
在对按键进行拉高之后,按键程序立刻有了输入
这篇关于Linux 输入设备 自定义键盘 input输入子系统 gpio-keys按键驱动的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-18git仓库有更新,jenkins 自动触发拉代码怎么配置的?-icode9专业技术文章分享
- 2024-12-18Jenkins webhook 方式怎么配置指定的分支?-icode9专业技术文章分享
- 2024-12-13Linux C++项目实战入门教程
- 2024-12-13Linux C++编程项目实战入门教程
- 2024-12-11Linux部署Scrapy教程:新手入门指南
- 2024-12-11怎么将在本地创建的 Maven 仓库迁移到 Linux 服务器上?-icode9专业技术文章分享
- 2024-12-10Linux常用命令
- 2024-12-06谁看谁服! Linux 创始人对于进程和线程的理解是…
- 2024-12-04操作系统教程:新手入门及初级技巧详解
- 2024-12-04操作系统入门:新手必学指南