首先在imx6ull按键在GPIO1 的 io18
在设备树上添加好信息
还要检查该 io 口有没有被复用为别的功能,有的话注释掉。
&iomuxc
pinctrl_key_1: key-1{
fsl,pins = <
MX6UL_PAD_UART1_CTS_B__GPIO1_IO18 0xF080
>;
};
根文件下:
key{
compatible = "lakzhu,key";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_key_1>;
key-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
status = "ok";
};
更改完后编译并且下载到开发板。
驱动注册与卸载:
#define KEY_COUNT 1
#define KEY_NAME "key"
static int __init key__init(void)
{
}
static void __exit key_exit(void)
{
}
module_init(key__init);
module_exit(key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lakzhu");
创建设备结构体:
struct key_dev{
dev_t devid;
int major;
int minor;
struct cdev cdev;
struct class *class;
struct device *device;
struct device_node *nd;
int key_gpio;
atomic_t key_value;
};
struct key_dev key;
操作函数:
通过 gpio_get_value 来读取按键的值,若是为 0 就表示按下了,为 1 为未按下。当按键松开后,将结构体中的原子变量改为 key0 表示按下,反之则为 key1 这里 key0 与 key1 的值无意义,知识一个代表而已。
#define KEY0 0XF0 //有效
#define KEY1 0X00 //无效
static int key_open(struct inode *inode, struct file *filp)
{
int ret = 0;
filp->private_data = &key;
return ret;
}
static int key_release(struct inode *inode, struct file *filp)
{
int ret = 0;
return ret;
}
static ssize_t key_write(struct file *filp, const char __user *buff, size_t count,loff_t *ppos)
{
int ret = 0;
return ret;
}
static ssize_t key_read(struct file *filp, char __user *buff, size_t count, loff_t *ppos)
{
struct key_dev *dev = filp->private_data;
int ret = 0, value;
if(gpio_get_value(dev->key_gpio) == 0){
//按下 等待释放
while(!gpio_get_value(dev->key_gpio));
atomic_set(&dev->key_value, KEY0);
}else{
atomic_set(&dev->key_value, KEY1);
}
value = atomic_read(&dev->key_value);
ret = copy_to_user(buff, &value, sizeof(value));
return ret;
}
static const struct file_operations filp = {//连接 .c 文件的open write 与 key_open key_write等操作
.owner = THIS_MODULE,
.open = key_open,
.release = key_release,
.write = key_write,
.read = key_read,
};
驱动初始化:
经典的字符设备初始化。
static int __init key__init(void)
{
int ret=0;
atomic_set(&key.key_value, KEY1);
//初始化设备号
if(key.major){
key.devid = MKDEV(key.major, 0);
ret = register_chrdev_region(key.devid, KEY_COUNT, KEY_NAME);
}else{
ret = alloc_chrdev_region(&key.devid, 0, KEY_COUNT, KEY_NAME);
gpioled.major = MAJOR(gpioled.devid);
gpioled.minor = MINOR(gpioled.devid);
}
if(ret < 0){
ret = -EINVAL;
goto fail_devid;
}
printk("maj:%d , min:%d",key.major, key.minor);
// 初始化字符设备
key.cdev.owner = THIS_MODULE;
cdev_init(&key.cdev, &filp);
ret = cdev_add(&key.cdev, key.devid, KEY_COUNT);
if(ret < 0){
ret = -ENAVAIL;
goto fail_dev;
}
//创建设备节点
key.class = class_create(THIS_MODULE, KEY_NAME);
if(IS_ERR(key.class)){
ret = PTR_ERR(key.class);
goto fail_class;
}
//获取设备
key.device = device_create(key.class, NULL, key.devid, NULL, KEY_NAME);
if(IS_ERR(key.device)){
ret = PTR_ERR(key.device);
goto fail_device;
}
ret = keyio_init(&key);
if(ret < 0){
goto fail_device;
}
return ret;
fail_device:
class_destroy(key.class);
fail_class:
cdev_del(&key.cdev);
fail_dev:
unregister_chrdev_region(key.devid, KEY_COUNT);
fail_devid:
return ret;
}
static void __exit key_exit(void)
{
//删除字符设备
cdev_del(&key.cdev);
//注销设备
unregister_chrdev_region(key.devid, KEY_COUNT);
//删除设备
device_destroy(key.class, key.devid);
//删除类
class_destroy(key.class);
//删除gpio
gpio_free(key.key_gpio);
}
设备树中gpio的获取:
获取节点中的按键设备的信息,将gpio设为输入。
static int keyio_init(struct key_dev *dev)
{
int ret = 0;
//获取设备节点
dev->nd = of_find_node_by_path("/key");
if(dev->nd == NULL){
ret = -ENAVAIL;
goto fail_nd;
}
//获取gpio信息
dev->key_gpio = of_get_named_gpio(dev->nd, "key-gpios", 0);
if(dev->key_gpio < 0){
ret = -ENAVAIL;
goto fail_gpio;
}
ret = gpio_request(dev->key_gpio, "key0");
if(ret){
ret = -ENAVAIL;
printk("io request fail");
goto fail_quest;
}
ret = gpio_direction_input(dev->key_gpio);
if(ret){
ret = -ENAVAIL;
goto fail_input;
}
return ret;
fail_input:
gpio_free(dev->key_gpio);
fail_quest:
fail_gpio:
fail_nd:
device_destroy(dev->class, dev->devid);
return ret;
}
keyApp.c 的编写:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define KEY0 0XF0 //无效
#define KEY1 0X00 //有效
int main(int argc, char *argv[])
{
int keyvalue;
int fd, ret;
char *filename;
if(argc != 2){
printf("error usage");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR);
if(fd < 0){
printf("file open error:%s",argv[1]);
return -1;
}
while(1) {
read(fd, &keyvalue, sizeof(keyvalue));
if (keyvalue == KEY0) { /* KEY0 */
printf("KEY0 Press, value = %#X\r\n", keyvalue); /* 按下 */
}
}
ret = close(fd);
if(ret < 0){
printf("file %s close failed!\r\n", argv[1]);
return -1;
}
return 0;
}
结果展示:
这只是最基础的按键读取,练最基础消抖都没做,当然我们也只是学习一下驱动开发流程,按键处理已经在 stm32 中做过太多了,现在最主要的还是学习驱动开发思路。