本文在树莓派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的。