HamsterBear lradc按键驱动的适配

  • 平台 - F1C200s
  • Linux版本 - 5.17.2
  • ADC按键 - 4 KEY tablet

驱动程序位于主线内核:

  • drivers/input/keyboard/sun4i-lradc-keys.c

设备树binding

  • Documentation/devicetree/bindings/input/allwinner,sun4i-a10-lradc-keys.yaml

适配流程

开启驱动程序编译开关

进入kernel目录,执行make menuconfig

输入/后搜索KEYBOARD_SUN4I_LRADC

1跳转到选项位置,修改选项为*后保存退出

查看设备树Binding,并修改添加设备树节点

示例如下

examples:
- |
lradc: lradc@1c22800 {
compatible = "allwinner,sun4i-a10-lradc-keys";
reg = <0x01c22800 0x100>;
interrupts = <31>;
vref-supply = <&reg_vcc3v0>; button-191 {
label = "Volume Up";
linux,code = <115>;
channel = <0>;
voltage = <191274>;
}; button-392 {
label = "Volume Down";
linux,code = <114>;
channel = <0>;
voltage = <392644>;
};
};

修改后的lradc节点

底板有4个按键,linux,code对应input evnet按键code值

        lradc: lradc@1c23400 {
compatible = "allwinner,sun4i-a10-lradc-keys";
reg = <0x01c23400 0x100>;
interrupts = <22>;
vref-supply = <&reg_vcc3v3>; button-132 {
label = "PRE";
linux,code = <105>;
channel = <0>;
voltage = <174603>;
}; button-196 {
label = "NEXT";
linux,code = <106>;
channel = <0>;
voltage = <419047>;
}; button-233 {
label = "OK";
linux,code = <28>;
channel = <0>;
voltage = <698412>;
}; button-271 {
label = "BACK";
linux,code = <14>;
channel = <0>;
voltage = <803174>;
};
};

设备注册到/dev/input/event0

驱动程序上报的数据

[21037.576786] adckey val: 5, voltage: 174603
0000000 522d 0000 cecc 0008 0001 0069 0001 0000
0000010 522d 0000 cecc 0008 0000 0000 0000 0000
0000020 522d 0000 0bd6 000c 0001 0069 0000 0000
0000030 522d 0000 0bd6 000c 0000 0000 0000 0000
[21038.829430] adckey val: 12, voltage: 419047
0000040 522e 0000 aa05 000c 0001 006a 0001 0000
0000050 522e 0000 aa05 000c 0000 0000 0000 0000
0000060 522f 0000 f228 0000 0001 006a 0000 0000
0000070 522f 0000 f228 0000 0000 0000 0000 0000
[21041.763838] adckey val: 19, voltage: 663492
0000080 5231 0000 a9cd 000b 0001 001c 0001 0000
0000090 5231 0000 a9cd 000b 0000 0000 0000 0000
00000a0 5232 0000 4117 0000 0001 001c 0000 0000
00000b0 5232 0000 4117 0000 0000 0000 0000 0000
[21042.978050] adckey val: 25, voltage: 873015
00000c0 5232 0000 ee8e 000e 0001 000e 0001 0000
00000d0 5232 0000 ee8e 000e 0000 0000 0000 0000
00000e0 5233 0000 5964 0003 0001 000e 0000 0000
00000f0 5233 0000 5964 0003 0000 0000 0000 0000

LVGL的适配

修改官方移植模板文件lv_port_indev_template.c

/* lv_port_indev_linux.c */
void lv_port_indev_init(void)
{
/**
* Here you will find example implementation of input devices supported by LittelvGL:
* - Touchpad
* - Mouse (with cursor support)
* - Keypad (supports GUI usage only with key)
* - Encoder (supports GUI usage only with: left, right, push)
* - Button (external buttons to press points on the screen)
*
* The `..._read()` function are only examples.
* You should shape them according to your hardware
*/ static lv_indev_drv_t indev_drv; ... ... /*------------------
* Button
* -----------------*/ /*Initialize your button if you have*/
button_init(); /*Register a button input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_BUTTON;
indev_drv.read_cb = button_read;
indev_button = lv_indev_drv_register(&indev_drv); /*Assign buttons to points on the screen*/
static const lv_point_t btn_points[4] = {
{102, 215}, /* Button 0 -> x:102; y:215 */
{180, 216}, /* Button 1 -> x:180; y:216 */
{140, 120},
{142, 215},
};
lv_indev_set_button_points(indev_button, btn_points);
} static int button_fd;
static struct input_event events[2];
static struct input_event event;
/*Initialize your buttons*/
static void *button_input_thread_function(void *privdata)
{
while(1){
if(read(button_fd, &events, 2*sizeof(struct input_event)) > 0){
// printf("type : %d, code : %d, value : %d\n", events[0].type, events[0].code, events[0].value);
}
event = events[0];
// pthread_mutex_lock(&g_mutex);
// pthread_cond_signal(&g_cond);
// pthread_mutex_unlock(&g_mutex);
} } static void button_init(void)
{
/*Your code comes here*/
pthread_t tid; button_fd = open("/dev/input/event0", O_RDONLY); pthread_create(&tid, NULL, button_input_thread_function, NULL);
} /*Will be called by the library to read the button*/
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{ static uint8_t last_btn = 0; /*Get the pressed button's ID*/
int8_t btn_act = button_get_pressed_id(); if(btn_act >= 0) {
data->state = LV_INDEV_STATE_PR;
last_btn = btn_act;
}
else {
data->state = LV_INDEV_STATE_REL;
} /*Save the last pressed button's ID*/
data->btn_id = last_btn;
} /*Get ID (0, 1, 2 ..) of the pressed button*/
static int8_t button_get_pressed_id(void)
{
uint8_t key = -1; /*Check to buttons see which is being pressed (assume there are 2 buttons)*/
// pthread_mutex_lock(&g_mutex);
// pthread_cond_wait(&g_cond, &g_mutex);
// pthread_mutex_unlock(&g_mutex);
switch(event.code){
case KEY_LEFT:
key = 0;
break;
case KEY_RIGHT:
key = 1;
break;
case KEY_ENTER:
key = 2;
break;
case KEY_BACKSPACE:
key = 3;
break;
default:
key = -1;
break;
} return (key + event.value)>key?key:-1;
/*No button pressed*/
} /*Test if `id` button is pressed or not*/
static bool button_is_pressed(uint8_t id)
{
/*Your code comes here*/ return false;
}

简单解释下代码中的一些操作:

在主init函数中设置的这个数组

static const lv_point_t btn_points[4] = {
{102, 215}, /* Button 0 -> x:102; y:215 */
{180, 216}, /* Button 1 -> x:180; y:216 */
{140, 120},
{142, 215},
};

是用来模拟点击lvgl屏幕的某个x,y位置,设置完该数组后,需要将其与indev_drv关联起来

//lv_indev_t * indev_button;

lv_indev_set_button_points(indev_button, btn_points);

为什么要一次读两个event?

static struct input_event events[2];
static struct input_event event;
/*Initialize your buttons*/
static void *button_input_thread_function(void *privdata)
{
while(1){
if(read(button_fd, &events, 2*sizeof(struct input_event)) > 0){

因为按下和松开都算一次event,只读一次会读到松开的value。

这个return是什么意思?

/*Get ID  (0, 1, 2 ..) of the pressed button*/
static int8_t button_get_pressed_id(void)
{
uint8_t key = -1; ... return (key + event.value)>key?key:-1;
}

过滤掉default的情况,event.value 值为 1 或 0

返回正确的按键id,这个id用来在上面提到的数组中确定是哪一组坐标。

button_is_pressed函数没用到,所以留空了。

最后,在button_read函数中btn_act就是刚才return的id,在

if中暂存,最后通过data->btn_id记录进indev_drv

HamsterBear Linux Low Res ADC按键驱动的适配 + LVGL button移植的更多相关文章

  1. linux输入子系统之按键驱动

    上一节中,我们讲解了Linux  input子系统的框架,到内核源码里详细分析了输入子系统的分离分层的框架等. 上一节文章链接:http://blog.csdn.net/lwj103862095/ar ...

  2. Linux按键驱动程序设计--从简单到不简单【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/51399353 混杂设备驱动模型: 1. 混杂设备描述 在Linux系统中,存在一 ...

  3. Linux按键驱动程序设计详解---从简单到不简单【转】

    转自:http://blog.csdn.net/coding__madman/article/details/51399353 版权声明:本文为博主原创文章,未经博主允许不得转载. 混杂设备驱动模型: ...

  4. Linux驱动之按键驱动编写(中断方式)

    在Linux驱动之按键驱动编写(查询方式)已经写了一个查询方式的按键驱动,但是查询方式太占用CPU,接下来利用中断方式编写一个驱动程序,使得CPU占有率降低,在按键空闲时调用read系统调用的进程可以 ...

  5. ARM Linux 驱动Input子系统之按键驱动测试

    上一篇已经谈过,在现内核的中引入设备树之后对于内核驱动的编写,主要集中在硬件接口的配置上了即xxxx.dts文件的编写. 在自己的开发板上移植按键驱动: 1.根据开发板的原理图 确定按键的硬件接口为: ...

  6. linux字符驱动之poll机制按键驱动

    在上一节中,我们讲解了如何自动创建设备节点,实现一个中断方式的按键驱动.虽然中断式的驱动,效率是蛮高的,但是大家有没有发现,应用程序的死循环里的读函数是一直在读的:在实际的应用场所里,有没有那么一种情 ...

  7. Linux嵌入式学习-烟雾传感器驱动-字符设备驱动-按键驱动

    MQ-2烟雾气敏传感器模块在X210v3开发板上的驱动. 现在需要一个MQ-2烟雾气敏传感器模块的驱动.其检测烟雾超过一定的标准后,会返回一个不同的电平,和按键驱动差不多. 但是在编写驱动的时候,需要 ...

  8. Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知(转)

    信号  ( signal ) 机制是 UNIX 系统中最为古老的进程间通信机制,很多条件可以产生一个信号. 信号的产生: 1,当用户按下某些按键时,产生信号. 2,硬件异常产生信号:除数为 0 ,无效 ...

  9. 基于ARM-contexA9按键驱动开发

    之前我们写过LED和蜂鸣器的驱动,其实那两个都是一个模版的,因为都是将IO口配置成输出模式,然后用高低电平来驱动这些设备.其实linux设备驱动,说白了跟单片机开发的方式是差不多的,只不过内核的开发基 ...

随机推荐

  1. java的泛型hei

    泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候就可以使用泛型 泛型也可以看出是一个变量,用来接受数据类型 E e :Element 元素 T t: Type 类型 /* Collecti ...

  2. Vue报错之"[Vue warn]: Invalid prop: type check failed for prop "jingzinum". Expected Number with value NaN, got String with value "fuNum"."

    一.报错截图 [Vue warn]: Invalid prop: type check failed for prop "jingzinum". Expected Number w ...

  3. python学习笔记(三)——函数

    函数定义 def 函数名(形参 . . . ) 函数体 1. 函数参数 返回值:可以有一个或多个 形参:支持默认形参.关键字形参.可变参数形参等 1.1 必须参数 调用时传入的参数必须与定义时相同. ...

  4. 重磅:前端 MVVM 与 FRP 的升阶实践 —— ReRest 可视化编程

    ReRest (Reactive Resource State Transfer) 是前端开发领域新兴的方法论体系,它继承了 MVVM 与 FRP 编程理念,在技术上有不少创新.本文从专利稿修改而来, ...

  5. Python使用逻辑回归估算OR值

    第一种是统计学方法,需要用到 statsmodels包 statsmodels是统计和计量经济学的package,包含了用于参数评估和统计测试的实用工具 第二种是机器学习,需要使用sklearn中的L ...

  6. String能变化吗?和StringBuffer的区别是什么

    [新手可忽略不影响继续学习]看 过上面例子的童鞋一定会觉得很奇怪,s = s + s1.charAt(i); 马克-to-win, s不是老在变化吗?其实s = "";时,虚拟机会 ...

  7. spring-bean依赖注入-02(通过p命名空间注入)

    上一篇博客讲述了为什么使用spring依赖注入,怎么注入,详见 spring-bean依赖注入-01(等你来点击) 废话不多说,开始使用p命名空间进行set注入 使用另外一种注入方式是这样的(具体实现 ...

  8. 北桥芯片(north bridge/host bridge)

    看下上面的图,会比较清晰的认识到北桥芯片所在位置 北桥芯片(North Bridge) 是mother board chipset(主板芯片组) 中起主导作用的最重要的组成部分,也称为主桥(Host ...

  9. VsCode 常用插件清单

    插件离线安装说明 在一些内网开发环境中,无法做到在线安装,这个时候就需要对插件进行离线安装 了 打开 VSCode 插件市场网址 Extensions for the Visual Studio fa ...

  10. 企业DevOps之路:Jenkins 流水线

    1. Pipeline 概述 Pipeline 即流水线,是 jenkins2.X 的新特性,是 jenkins 官方推荐使用的持续集成方案.与传统的自由风格项目不同,它是通过 jenkins DSL ...