一、背景描述
1. 处理器与Linux 版本
ROCKCHIP RV1106
Linux 5.10.110
2. 按键对应的IO口
gpio1_pd1
3. 检测算法
按键按下
按键被按下时,按键IO
产生下降沿中断,在中断处理函数中,开启定时器进行防抖处理,防抖时间结束,按键还是保持低电平状态,则用input
子系统的上报按键按下事件。
按键弹起
按键弹起时,按键IO
产生上升沿中断,在中断处理函数中,开启定时器进行防抖处理,防抖时间结束,按键还是保持高电平状态,则用input
子系统的上报按键弹起事件。
二、修改设备树
1. 添加 pinctrl 子节点
&pinctrl{
gpio1-pd1 {
gpio1_pd1:gpio1-pd1{
rockchip,pins = <1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};
2. 添加gpio 子节点
gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_LOW>;
3.中断相关的设备树属性
interrupts-parent = <&gpio1>;
interrupts = <RK_PD1 IRQ_TYPE_EDGE_BOTH>;
4. 按键对应的IO 节点的定义如下
gpio1pd1:gpio1pd1{
compatible = "gpio1_pd1";
pinctrl-names = "default"; pinctrl-0 = <&gpio1_pd1>;
regulator-name ="gpio1_pd1";
gpios = <&gpio1 RK_PD1 GPIO_ACTIVE_HIGH>;
interrupts-parent = <&gpio1>; interrupts = <RK_PD1 IRQ_TYPE_EDGE_FALLING>;
regulator-always-on;
};
三、遇到的问题
1. 按键按下时,能响应中断处理函数,但是开启定时器进行防抖时,定时器超时中断没执行
在中断处理函数中,调用 mod_timer
函数修改超时时间并开启定时器时,第二个参数理解出错,当时是这样写的:
mod_timer( &g_key.timer, 20 );
写mcu
程序时,软件定时器的超时时间一般是ms
为单位,现在切换到Linux
驱动程序,没切换过来,还想着填入一个20 ms
作为超时时间。
实际上,mod_timer
函数的第二个参数描述的是在系统节拍为 expires
时,调用超时处理函数。所以,应该改成下面所示:
mod_timer( &g_key.timer, jiffies + msecs_to_jiffies( 20 ) );
2. 驱动层在防抖结束之后,使用input 子系统上报了事件,但是应用层没读到上报的事件(或者经常没读到上报的事件)
上报事件代码
定时器超时处理函数如下,在超时函数中上报按键事件。
void key_drv_timer_handler( struct timer_list *timer )
{
if ( !gpio_get_value( g_key.gpio_num ) )
input_report_key( g_key.input_device, KEY_0, 0 );
else
input_report_key( g_key.input_device, KEY_0, 1 );
input_sync( g_key.input_device );
}
原因
在调用 request_irq
申请中断时,只使能了下降沿中断(IRQF_TRIGGER_FALLING
),没有使能上升沿中断(IRQF_TRIGGER_RISING
)。每次都是上报了按键为低的情况,input
子系统可能会以为按键的状态一直都是拉低,没弹起。