嵌入式Linux的三种按键驱动方式
嵌入式linux的三种按键驱动方式
1、类似传统的mcu开发方式,基于设备树,需要编写相应的驱动程序
io初始化,中断申请注册,中断处理。mcu一般都有固定的中断处理函数,一般都有weak函数,一般只要重新改函数就行。linux方面需要按gpio号去申请irq中断号。
//设备树直接使用led口拿来做按键,图省事
mqrled {
led-gpios = <&pio PB 4 GPIO_ACTIVE_HIGH>;
};
部分关键代码
//实际产品应用需要额外加timer配合做消抖动
static irqreturn_t btn_irq(int irq, void *dev_id)
{
if(gpio_get_value(LED_IO))
printk(KERN_DEBUG" release key_irq:%d\n",irq);
else
printk(KERN_DEBUG" press key_irq:%d\n",irq);
return IRQ_HANDLED;
}
struct device_node* led_node;
led_node = of_find_node_by_path("/mqrled");
if(led_node == NULL)
{
printk(KERN_DEBUG"no led dts!!!\n");
}
LED_IO = of_get_named_gpio(led_node, "led-gpios", 0);
printk(KERN_DEBUG"LED_IO is:%d\n",LED_IO);
//io号申请中断号
key_irq = gpio_to_irq(LED_IO);
printk(KERN_DEBUG"key_irq:%d\n",key_irq);
//注册中断
ret = request_irq(key_irq, btn_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "key_irq",NULL);
if(ret){
printk("request irq failed!\n");
return -1;
}
//测试
[ 233.129895] release key_irq:67
[ 237.762791] press key_irq:67
[ 237.773132] release key_irq:67
[ 237.787830] press key_irq:67
[ 237.812533] release key_irq:67
[ 237.816057] press key_irq:67
[ 237.880647] release key_irq:67
[ 237.905658] press key_irq:67
[ 238.049449] release key_irq:67
[ 238.052980] press key_irq:67
[ 238.056313] release key_irq:67
[ 238.059838] release key_irq:67
[ 238.063358] press key_irq:67
[ 238.105547] release key_irq:67
root@TinaLinux:/mnt/UDISK# cat /proc/interrupts
CPU0 CPU1
17: 0 0 GIC-0 29 Level arch_timer
18: 46975 23928 GIC-0 30 Level arch_timer
21: 0 0 GIC-0 91 Level timer@2050000
24: 0 0 GIC-0 96 Level 2010000.iommu
26: 0 0 GIC-0 82 Level 3002000.dma-controller
34: 507 0 GIC-0 34 Level uart0
37: 233 0 GIC-0 72 Level mmc0
38: 89 0 GIC-0 73 Level mmc1
39: 45455 0 GIC-0 47 Level spi0
40: 0 0 GIC-0 98 Level cedar_dev
41: 0 0 GIC-0 43 Level sunxi-i2c2
42: 0 0 GIC-0 89 Level sunxi-gpadc
47: 0 0 GIC-0 121 Level 5410000.g2d
48: 14620 0 GIC-0 122 Level dispaly
55: 1597 0 GIC-0 61 Level sunxi_usb_udc
58: 0 0 GIC-0 65 Level ehci_hcd:usb1
59: 0 0 GIC-0 66 Level ohci_hcd:usb2
60: 0 0 GIC-0 57 Level audio jack irq
67: 47 0 sunxi_pio_edge 4 Edge key_irq //注册的按键中断,47为中断次数
197: 0 0 sunxi_pio_edge 134 Edge 4020000.sdmmc cd
IPI0: 0 0 CPU wakeup interrupts
IPI1: 0 0 Timer broadcast interrupts
IPI2: 22684 45858 Rescheduling interrupts
IPI3: 5 2 Function call interrupts
IPI4: 0 0 CPU stop interrupts
IPI5: 0 0 IRQ work interrupts
IPI6: 0 0 completion interrupts
2、基于内核的按键中断输入子系统
像按键指示灯等这种简单的驱动一般都不需要自己去额外写驱动,linux强大的子系统都已经包含进去。配合设备树只要编写对应的设备树节点就可以让内核通过平台驱动方式装载对应的设备。内核本身支持中断按键和轮询按键的输入子系统方式。
内核配置需要对应开启
内核的代码实现位置在drivers/input/keyboard/gpio-keys.c
按键中断的设备树节点如下:
gpio-keys {
compatible = "gpio-keys";//必须固定为gpio-keys
autorepeat;
status = "okay";
upisrkey {
label = "GPIO Key UP";
linux,code = <103>;
gpios = <&pio PB 4 GPIO_ACTIVE_HIGH>;
};
};
设备树更新系统启动后启动log可以看到probe到该节点,并生产input1
[ 3.169705] input: gpio-keys as /devices/platform/gpio-keys/input/input1
root@TinaLinux:/# ls /dev/input/
event0 event1 event2
root@TinaLinux:/# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio-keys"
P: Phys=gpio-keys/input0--------可以看到生产的input对应gpio key
S: Sysfs=/devices/platform/gpio-keys/input/input1
U: Uniq=
H: Handlers=event1
B: PROP=0
B: EV=100003
B: KEY=80 0 0 0
root@TinaLinux:/# cat /proc/interrupts
CPU0 CPU1
17: 0 0 GIC-0 29 Level arch_timer
18: 28023 14274 GIC-0 30 Level arch_timer
21: 0 0 GIC-0 91 Level timer@2050000
24: 0 0 GIC-0 96 Level 2010000.iommu
26: 0 0 GIC-0 82 Level 3002000.dma-controller
34: 266 0 GIC-0 34 Level uart0
37: 264 0 GIC-0 72 Level mmc0
38: 89 0 GIC-0 73 Level mmc1
39: 45331 0 GIC-0 47 Level spi0
40: 0 0 GIC-0 98 Level cedar_dev
41: 0 0 GIC-0 43 Level sunxi-i2c2
42: 0 0 GIC-0 89 Level sunxi-gpadc
47: 0 0 GIC-0 121 Level 5410000.g2d
48: 8864 0 GIC-0 122 Level dispaly
55: 985 0 GIC-0 61 Level sunxi_usb_udc
58: 0 0 GIC-0 65 Level ehci_hcd:usb1
59: 0 0 GIC-0 66 Level ohci_hcd:usb2
60: 0 0 GIC-0 57 Level audio jack irq
67: 1 0 sunxi_pio_edge 4 Edge GPIO Key UP //对应的中断信息以及中断发生次数
root@TinaLinux:/# cat /dev/input/event1 | hexdump
0000000 0267 0000 00cd 0009 0001 0067 0001 0000
0000010 0267 0000 00cd 0009 0000 0000 0000 0000
0000020 0267 0000 71c8 000b 0001 0067 0000 0000
0000030 0267 0000 71c8 000b 0000 0000 0000 0000
0000040 0267 0000 aa48 000c 0001 0067 0001 0000
0000050 0267 0000 aa48 000c 0000 0000 0000 0000
0000060 0267 0000 30e9 000e 0001 0067 0000 0000
0000070 0267 0000 30e9 000e 0000 0000 0000 0000
0000080 0269 0000 0e08 000c 0001 0067 0001 0000
0000090 0269 0000 0e08 000c 0000 0000 0000 0000
00000a0 026a 0000 c359 0000 0001 0067 0002 0000
//倒数第三列为按键keycode, 倒数第二列为按键按下类型,短按 长按还是放开
3、基于内核的按键轮询输入子系统
内核内部实现代码位置:drivers/input/keyboard/gpio-keys-polled.c
轮询按键的设备树节点
gpio_keys_polled {
compatible = "gpio-keys-polled";//必须为该名称内核才可以识别到
poll-interval = <100>;
autorepeat;
status = "okay";
downpollkey {
label = "GPIO Key DOWN";
linux,code = <108>;
gpios = <&pio PB 5 GPIO_ACTIVE_HIGH>;
};
};
//设备树更新下载后内核启动后可以看到probe到该节点并生成input0
[ 2.371525] input: gpio_keys_polled as /devices/platform/gpio_keys_polled/input/input0
root@TinaLinux:/# cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio_keys_polled"
P: Phys=gpio-keys-polled/input0
S: Sysfs=/devices/platform/gpio_keys_polled/input/input0
U: Uniq=
H: Handlers=event0
B: PROP=0
B: EV=100003
B: KEY=1000 0 0 0
root@TinaLinux:/# cat /dev/input/event0 | hexdump
0000000 0070 0000 4ef1 0009 0001 006c 0001 0000
0000010 0070 0000 4ef1 0009 0000 0000 0000 0000
0000020 0070 0000 aa53 000c 0001 006c 0000 0000
0000030 0070 0000 aa53 000c 0000 0000 0000 0000
0000040 0072 0000 9c69 0000 0001 006c 0001 0000
0000050 0072 0000 9c69 0000 0000 0000 0000 0000
0000060 0072 0000 93ed 0004 0001 006c 0002 0000
0000070 0072 0000 93ed 0004 0000 0000 0001 0000
0000080 0072 0000 5738 0005 0001 006c 0002 0000
0000090 0072 0000 5738 0005 0000 0000 0001 0000
00000a0 0072 0000 1a8d 0006 0001 006c 0002 0000
00000b0 0072 0000 1a8d 0006 0000 0000 0001 0000
00000c0 0072 0000 ddd7 0006 0001 006c 0002 0000
00000d0 0072 0000 ddd7 0006 0000 0000 0001 0000
00000e0 0072 0000 a12d 0007 0001 006c 0002 0000
2,3种方式得益于内核按键输入子系统的支持,不需要额外写内核驱动代码,应用层可以直接读取event文件就可以进行按键识别。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)