本文在树莓派3上,使用GPIO按钮触发中断,在isr中打印信息。
GPIO连接方法,如下图:
按钮按下将检测到高电平,按钮弹起为低电平。按钮弹起时,无电流。3.3K可以替换为10K的电阻。使用1K电阻,达到GPIO的电压有一点压降,3.24伏,低于3.3V。
模块代码:
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    20static 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。
启动树莓派,上传,安装模块,按下按钮:
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的。