原来使用了荔枝派nano的Lradc按键,挺好用的。但是在使用过程中发现当采样的数据线太长时,最后采样的电压会飘,导致按键不准,所以引出此文。
一、BS818A
BS818A是一款具有8个触摸按键的触摸解决方案芯片,采用串行接口用2根io线即可实现触摸控制。
当检测到有按键按下时,会在data脚输出低电平,可用来唤醒主机。主机在接收到低电位后,由clock输出时钟信号,并从data脚回读按键值。
二、按键驱动修改
内核是4.15.0-rc8,里面已经有了按键驱动,位于Device Drivers > Input device support > Keyboards->GPIO Buttons,选中它。
我们需要修改这个驱动,但是事先必须把设备树中的gpio配置好。硬件上我用的是PE9,PE10,PE9用作BS818A的data脚,PE10用作BS818A的clock脚。
pio: pinctrl@1c20800 {
......
test_pin1: test_pin@1 {
pins = "PE9";
function = "gpio_in";
};
};
mygpio-key {
compatible = "gpio-keys";
input-name = "key-test";
pinctrl-names = "default";
pinctrl-0 = <&test_pin1>;
k2@0 {
lable = "key-test";
linux,code = <232>;
gpios = <&pio 4 9 GPIO_ACTIVE_HIGH>;
};
};
接下来就是修改驱动代码了。打开内核 driver/input/keboard/gpio_keys.c文件,找到下面的函数
static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{
const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
int state;
state = gpiod_get_value_cansleep(bdata->gpiod);
if (state < 0) {
dev_err(input->dev.parent, "failed to get gpio state: %d\n", state);
return;
}
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
} else {
input_event(input, type, *bdata->code, state);
}
input_sync(input);
}
在PE9产生中断时,会进入到该函数,首先通过函数gpiod_get_value_cansleep读取指定IO的电平,即是PE9的电平。type是EV_KEY,最后上报数据就是input_event(input, type, *bdata->code, state);函数。我们要添加的代码就在下面中
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
} else {
//添加处理BS818A的代码
}
根据上面BS818A的操作方式,可以添加如下代码。
if(state==0){ //touch pressed
Clock_L();
udelay(80);
for(i=0;i<16;i++)
{
Clock_H();
udelay(80);
//read PE9 data io status
if(((*dat9)>>9)&0x01)
t_Val |= (1<>12)&0xff)==0x0A)//bit12-15 allways 1010
{
if(((t_Val>>8)&0x0f)==0x01)
{
tmpkey = t_Val&0xff;
for(i=0;i<8;i++)
{
if(tmpkey == keymap[i].keyval)
{
tmpkey = keymap[i].key;
input_event(input, type, *bdata->code, tmpkey);
break;
}
}
}
}
}
else //PRESS UP
{
input_event(input, type, *bdata->code, 0);
}
上面添加的代码中,有Clock_H和Clock_L函数,分别表示控制PE10口的电平,产生BS818A需要的clock波形。
最后编译内核,可以在根文件系统中看到/dev/input/event0节点已经生成。
三、应用层测试
#include
#include
#include
#include
#include
#include
int main(int argc, char const *argv[])
{
int fd = 0;
struct input_event event;
int ret = 0;
fd = open("/dev/input/event0",O_RDONLY);
if (fd < 0) {
perror("open");
return -1;
}
while(1){
ret = read(fd, &event, sizeof(event));
if(ret < 0) {
perror("read");
return -1;
}
if(event.type == EV_KEY && event.value>0)
printf("ret:%d, code:%d,val:%d\n", ret, event.code,event.value);
}
return 0;
}
测试结果,8个按键触摸,分别显示不同的按键代号1到8
至此,licheepi nano 添加触摸驱动测试完毕。