• HamsterBear Linux Low Res ADC按键驱动的适配 + LVGL button移植


    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
    image

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

    查看设备树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

    sun4i lradc 输入事件驱动解析

  • 相关阅读:
    阿里平头哥发布RISC-V高能效处理器玄铁C908,打造端云一体生态
    【微服务】SpringBoot监听器机制以及在Nacos中的应用
    去哪里找图标?
    java正则表达式教程
    智能网联汽车终端T-BOX应用方案——主控芯片ACM32F403、安全芯片S6A/S6B
    【C++】STL-priority_queue
    【目标检测】英雄联盟能用YOLOv5实时目标检测了 支持onnx推理
    linux上搭建svn多仓库环境
    微信小程序的缓存、跳转与请求
    主成分分析法在图像压缩和重建中的应用研究-含Matlab代码
  • 原文地址:https://www.cnblogs.com/hfwz/p/16028974.html