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中的异常体系?throw和throws的区别?

    一.java中的异常体系 Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常.其中异常类Exception又分为运行时异常(Ru ...

  2. Linux用户无法使用sudo命令

    新建的用无法使用sudo命令,出现这样的提示: xiaojing is not in the sudoers file. This incident will be reported 原来是新建的用户 ...

  3. 学习Solr(一)

    一.安装 1.需要的安装包:apache-tomcat-7.0.47.tar.gz.solr-4.10.3.tgz.tgz(jdk自行安装) 2.解压tomcat并创建solr文件夹 [root@lo ...

  4. Spring Mvc 源代码之我见 一

    spring mvc 是一个web框架,包括controller.model.view 三大块.其中,核心在于model这个模块,用于处理请求的request. 和之前的博客一样,关键的代码,我会标注 ...

  5. MyBatis Plus 2.3 个人笔记-04-配置文件与插件使用

    接入 springboot application.yml配置 1.mapper 扫描 mybatis-plus: # 如果是放在src/main/java目录下 classpath:/com/you ...

  6. Unsafe Rust 能做什么

    在不安全的 Rust 中唯一不同的是,你可以: 对原始指针进行解引用 调用"不安全"的函数(包括 C 函数.编译器的内建指令和原始分配器. 实现"不安全"的特性 ...

  7. 付费漫画下载、付费韩漫下载、漫画VIP下载、VIP韩漫下载哪里下

    需要的 来qq:6686496 最近迷上了韩漫(你懂的),主要为了打发时间上班摸鱼,,找了好多网站都是要收费的,就想着试着用爬虫做一个破解. 最简单的第一步,通过url分析出漫画ID.(直接看url就 ...

  8. volist标签的各种属性

    volist标签通常用于查询数据集(select方法)的结果输出,通常模型的select方法返回的结果是一个二维数组,可以直接使用volist标签进行输出. 在控制器中首先对模版赋值: $User = ...

  9. 基于React的仿QQ音乐(移动端)

    前言 由于这段时间工作上也是挺忙的,就没有时间去写这个项目,中间一直都是写写停停,进度也是非常慢的.正好前几天都还比较空,就赶紧抓着空闲时间去写这个项目,最后紧赶慢赶地完成了.本项目采用了React的 ...

  10. ES6-11学习笔记--Iterator

    迭代器 Iterator 是一种接口机制,为各种不同的数据结构提供统一访问的机制 主要供for...of消费 一句话:不支持遍历的数据结构"可遍历"   具备Symbol.iter ...