github主页:https://github.com/snqx-lqh
本项目github地址:https://github.com/snqx-lqh/RaspberryPiDriver
本项目硬件地址:https://oshwhub.com/from_zero/shu-mei-pai-kuo-zhan-ban
欢迎交流
笔记说明
用按键来测试GPIO中断相关的实验,使用gpio子系统控制电平,使用gpiod的api。
主要参考的文章
正点原子《I.MX6U 嵌入式 Linux 驱动开发指南 V1.81》
韦东山《01_嵌入式Linux应用开发完全手册V5.1_IMX6ULL_Pro开发板》
本节源码路径02_Firmware/07_key_drv_irq
设备树
中断设备,主要配置按键相关,然后配置的gpio主要需要说明的就是加了interrupt-parent和interrupts,interrupts分别需要填写的就是中断的引脚,和中断的方式,2,是下降沿中断。可以使用,
的方式多加几个引脚。这里为了减少篇幅,只是添加了按键相关的,完整的看项目源代码。
// Definitions for gpio-key module
/dts-v1/;
/plugin/;/ {compatible = "brcm,bcm2835";fragment@0{target-path = "/";__overlay__ {shb_key: shb_key@0{compatible = "shb-key";pinctrl-names = "default";pinctrl-0 = <&shb_key_pins>;status = "okay";key1-gpios = <&gpio 26 0>;key2-gpios = <&gpio 21 0>;key3-gpios = <&gpio 20 0>;interrupt-parent = <&gpio>;interrupts = <26 2>,<21 2>,<20 2>;};};};fragment@1 {// Configure the gpio pin controllertarget = <&gpio>;__overlay__ {shb_key_pins: shb_key_pins@0 {brcm,pins = <26 21 20>; // gpio numberbrcm,function = <0 0 0>; // 0 = input, 1 = outputbrcm,pull = <2 2 2>; // 0 = none, 1 = pull down, 2 = pull up};};};
};
驱动编写
为了方便,关于按键这一节的代码,我全部都是使用的misc设备,方便注册。
比较核心的代码就是中断的注册和中断服务函数的编写,如下:
先获取中断引脚,然后转到中断设备号,再注册中断。
中断服务函数可以传入参数。在释放的时候需要释放中断号。
typedef struct{int key_num;struct gpio_desc *key_gpiod;int key_irq;
}key_gpio_t;typedef struct{dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct device_node *node; /* KEY 设备节点 */key_gpio_t key_gpio[3];
}key_dev_t;static key_dev_t key_dev;static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{key_gpio_t *gpio_key = dev_id;int val;val = gpiod_get_value(gpio_key->key_gpiod);printk("key %d %d\n", gpio_key->key_num, val); return IRQ_RETVAL(IRQ_HANDLED);
}static int key_probe(struct platform_device *dev)
{ int ret;//读节点信息key_dev.key_gpio[0].key_gpiod = gpiod_get(&dev->dev, "key1", 0);key_dev.key_gpio[1].key_gpiod = gpiod_get(&dev->dev, "key2", 0);key_dev.key_gpio[2].key_gpiod = gpiod_get(&dev->dev, "key3", 0);key_dev.key_gpio[0].key_num = 1;key_dev.key_gpio[1].key_num = 2;key_dev.key_gpio[2].key_num = 3;/* 初始化key相关 */ret = gpiod_direction_input(key_dev.key_gpio[0].key_gpiod);ret = gpiod_direction_input(key_dev.key_gpio[1].key_gpiod);ret = gpiod_direction_input(key_dev.key_gpio[2].key_gpiod);key_dev.key_gpio[0].key_irq = gpiod_to_irq(key_dev.key_gpio[0].key_gpiod);key_dev.key_gpio[1].key_irq = gpiod_to_irq(key_dev.key_gpio[1].key_gpiod);key_dev.key_gpio[2].key_irq = gpiod_to_irq(key_dev.key_gpio[2].key_gpiod);//注册gpio中断ret = request_irq(key_dev.key_gpio[0].key_irq, gpio_key_isr, IRQF_TRIGGER_FALLING, "shb_gpio_key_0", &key_dev.key_gpio[0]);ret = request_irq(key_dev.key_gpio[1].key_irq, gpio_key_isr, IRQF_TRIGGER_FALLING, "shb_gpio_key_1", &key_dev.key_gpio[1]);ret = request_irq(key_dev.key_gpio[2].key_irq, gpio_key_isr, IRQF_TRIGGER_FALLING, "shb_gpio_key_2", &key_dev.key_gpio[2]);/* 注册misc字符设备驱动 */ret = misc_register(&key_miscdev);if(ret < 0){printk("misc device register faikey!\r\n");return -EFAULT;}return 0;
}static int key_remove(struct platform_device *dev)
{gpiod_put(key_dev.key_gpio[0].key_gpiod);gpiod_put(key_dev.key_gpio[1].key_gpiod);gpiod_put(key_dev.key_gpio[2].key_gpiod);for (int i = 0; i < 3; i++){free_irq(key_dev.key_gpio[i].key_irq, &key_dev.key_gpio[i]);}/* 注销misc设备 */misc_deregister(&key_miscdev);return 0;
}