硬件原理
从图中可以看到按键断开时,由于接了上拉电阻,所以CPU检测到默认是高电平的,当按键被按下时,电路导通,所以KEY0引脚变成低电平,即低电平有效。
那么按键是接到CPU哪个引脚呢?代码里需要操作该引脚。
通过在电路原理图中搜索KEY0,可以发现他是接到了UART1_CTS上,再搜索UART1_CTS,发现它接到了CPU的K15,做按键驱动我们需要将其复用为普通IO即可,即GPIO1_IO18,硬件电路分析完毕。
软件编写
这里采用kernel的dts,gpio和pinctrl子系统去完成对按键引脚的初始化和电平读取等。
修改imx6ull-14x14-evk.dts文件
#include <dt-bindings/input/input.h>#include "imx6ull.dtsi" / {`````省略````` key { #address-cells = <1>; #size-cells = <1>; compatible = "key"; pinctrl-name = "default"; pinctrl-0 = <&pinctrl_key>; key-gpio = <&gpio1 18 GPIO_ACTIVE_LOW>; // 低电平有效 status = "okay"; }`````省略`````};`````省略````` &iomuxc_snvs { pinctrl-names = "default_snvs"; pinctrl-0 = <&pinctrl_hog_2>; imx6ul-evk { `````省略````` pinctrl_key: keygrp { fsl,pin = < MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080 >; }; };`````省略`````};`````省略`````
在根节点/下添加key节点,key节点调用pinctrl节点,设置GPIO1_IO18的寄存器地址。
编译dts
输入make dtbs,生成了一堆dtb文件,我用的是imx6ull-14x14-evk.dtb,将其拷贝到tftpboot目录下,我的板子使用tftpboot加载zImage和dtb文件。
如何判断刚刚添加的key设备节点是否有效?
进入/proc/device-tree, 可以查看到有key节点,说明添加成功。
编写按键驱动程序
key.c
#include <linux/kernel.h>#include <linux/init.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/platform_device.h>#include <asm/uaccess.h>#include <linux/gpio.h>#include <linux/miscdevice.h>#include <linux/of.h>#include <linux/of_gpio.h> #include "key.h" struct key_dev dev; static int key_open(struct inode *nd, struct file *flip){ flip->private_data = &dev; return 0;} static ssize_t key_read(struct file *flip, char __user *buf, size_t size, loff_t *offset){ int isPress; int ret; isPress = gpio_get_value(dev.gpio); pr_info("[kernel] isPress=%d\n", isPress); ret = copy_to_user(buf, &isPress, sizeof(isPress)); return ret;} static struct file_operations key_fops= { .owner = THIS_MODULE, .open = key_open, .read = key_read,}; struct miscdevice key_miscdev = { .minor = 143, .name = "key", .fops = &key_fops,}; static int key_probe(struct platform_device * pdev){ int err; dev.np = of_find_node_by_path("/key"); if (!dev.np) { pr_err("can't find key in dts\n"); return -EINVAL; } dev.gpio = of_get_named_gpio(dev.np, "key-gpio", 0); if (!gpio_is_valid(dev.gpio)) { return -ENODEV; } err = misc_register(&key_miscdev); if (err < 0) { pr_err("KEY error: cannot register device\n"); return err; } return 0;} static int key_remove(struct platform_device *pdev){ // 注销misc设备驱动 (void)misc_deregister(&key_miscdev); return 0;} static const struct of_device_id key_of_match_table[] = { { .compatible = "key" }, {},}; static struct platform_driver key_drv = { .probe = key_probe, .remove = key_remove, .driver = { .owner = THIS_MODULE, .name = "key", .of_match_table = key_of_match_table, }}; static int __init key_init(void){ return platform_driver_register(&key_drv);} static void __exit key_exit(void){ platform_driver_unregister(&key_drv);} module_init(key_init);module_exit(key_exit);MODULE_LICENSE("GPL");
key.h
#ifndef __KEY_H#define __KEY_H struct key_dev { dev_t dev_id; struct cdev cdev; struct class *class; struct device *device; struct device_node *np; int gpio;}; #endif
对misc进行简要说明,misc设备驱动是杂项设备驱动,它其实也是一种字符设备,可以理解成封装好了更多的步骤。正常我们注册一般的字符设备驱动需要以下步骤:
- alloc_chrdev_region // 注册字符设备驱动
- cdev_init
- cdev_add
- class_create //创建类
- device_create // 创建设备
而杂项设备只需一个函数搞定,杂项设备的minor也是可以用动态注册,自动分配。
应用层程序
key.c
#include "stdio.h"#include "unistd.h"#include "stdlib.h"#include "sys/types.h"#include "fcntl.h"#include "sys/stat.h"#include "key.h" int main(int argc, char *argv[]){ char *filename = NULL; int fd = -1; char isPress; int ret; filename = argv[1]; fd = open(filename, O_RDWR); if (fd < 0) { printf("open %s fail\n", filename); return -1; } ret = read(fd, &isPress, sizeof(isPress)); if (ret < 0) { printf("read key value fail\n"); close(fd); return -1; } if (isPress == 0) printf("key is press, isPress=%d\n", isPress); else printf("key is loosen, isPress=%d\n", isPress); close(fd); return 0;}
key.h
#ifndef __KEY_H#define __KEY_H #endif
测试
测试OK!
号主:一枚机械专业本科生,经历了转行,从外包逆袭到芯片原厂的Linux驱动开发工程师,深入操作系统的世界,贯彻终身学习、终身成长的理念。平时喜欢折腾,寒冬之下,抱团取暖,期待你来一起探讨技术、搞自媒体副业,程序员接单和投资理财。【对了,不定期送闲置开发板、书籍、键盘等等】。
如果你想了解我的转行经验,欢迎找我交流~gongzhong号【哆哆jarvis】
一起不断探索自我、走出迷茫、找到热爱,希望和你成为朋友,一起成长~