ILD

gpio按钮中断模块
作者:YUAN JIANPENG 邮箱:yuanjp@hust.edu.cn
发布时间:2018-7-28 站点:Inside Linux Development

本文在树莓派3上,使用GPIO按钮触发中断,在isr中打印信息。


1 开关电路

GPIO连接方法,如下图:

按钮按下将检测到高电平,按钮弹起为低电平。按钮弹起时,无电流。3.3K可以替换为10K的电阻。使用1K电阻,达到GPIO的电压有一点压降,3.24伏,低于3.3V。


2 内核模块

模块代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
 
#define DEFAULT_GPIO_NUM    20
 
static int gpionum = DEFAULT_GPIO_NUM;    
static int irqnum = -1;
 
static irqreturn_t button_irq_handler(int irqnum, void *data)
{
    printk("button irq triggered\n");
    return IRQ_HANDLED;
}
 
static int __init mod_init(void)
{
    int ret;
 
    ret = gpio_request(gpionum, "hy-button");
    if (ret) {
        printk(KERN_ERR "request gpio failed: %d\n", ret);
        return ret;
    }
    ret = gpio_direction_input(gpionum);
    if (ret) {
        printk(KERN_ERR "set gpio to input failed: %d\n", ret);
        gpio_free(gpionum);
        return ret;
    }
    ret = gpio_to_irq(gpionum);
    if (ret < 0) {
        printk(KERN_ERR "gpio to irq failed: %d\n", ret);
        gpio_free(gpionum);
        return ret;
    }
    irqnum = ret;
    printk("gpio %d to irq %d\n", gpionum, irqnum); 
    ret = request_irq(irqnum, button_irq_handler, IRQF_TRIGGER_RISING, "button", 0);
    if (ret) {
        printk(KERN_ERR "request irq failed\n");
        return ret;
    }
    return 0;
}
 
static void __exit mod_exit(void)
{
    if (!free_irq(irqnum, 0)) {
        printk(KERN_ERR " free irq failed\n");
    }
    gpio_free(gpionum);
}
 
module_init(mod_init);
module_exit(mod_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yuan Jianpeng");


初始化:

首先使用gpio_request()向GPIO subsystem请求GPIO。然后使用gpio_direction_input()将GPIO配置为输入。


使用gpio_to_irq()获得中断号,然后使用request_irq()来注册中断处理函数。


在pinctrl驱动pinctrl-bcm2835.c中,request_irq会调用到irq_chip的irq_enable回调函数等,进行GPIO的配置:

1
2
3
4
5
6
7
8
9
static struct irq_chip bcm2835_gpio_irq_chip = {
    .name = MODULE_NAME,
    .irq_enable = bcm2835_gpio_irq_enable,
    .irq_disable = bcm2835_gpio_irq_disable,
    .irq_set_type = bcm2835_gpio_irq_set_type,
    .irq_ack = bcm2835_gpio_irq_ack,
    .irq_mask = bcm2835_gpio_irq_disable,
    .irq_unmask = bcm2835_gpio_irq_enable,
};


卸载:

调用free_irq()释放中断,第二参数要和request_irq中最后一个参数相同。

调用gpio_free()释放GPIO。


3 测试

启动树莓派,上传,安装模块,按下按钮:

1
2
3
4
5
6
7
8
/tmp # tftp -gr button.ko 192.168.2.20
/tmp # insmod button.ko 
[   18.281119] button: loading out-of-tree module taints kernel.
[   18.288183] gpio 20 to irq 154
[   18.291481] enable gpio irq 154 gpio 20
/tmp 
/tmp # [   21.179903] enter  bcm2835_gpio_irq_handler 
[   21.184250] button irq triggered


可以发现中断处理函数,是从pinctrl驱动路由到,注册的ISR的。


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.