本文在树莓派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 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。
启动树莓派,上传,安装模块,按下按钮:
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的。