zoukankan      html  css  js  c++  java
  • FT5X06 如何应用在10寸电容屏(linux-3.5电容屏驱动简析&移植10寸电容屏驱动到Android4.2) (by liukun321咕唧咕唧)

    这是几个月以前的东西了,在彻底遗忘之前拿出来好好写写。做个笔记,也算是造福后来人了。在做这个项目之前,没有做过电容屏的驱动,印象中的电容触摸屏是不需要校正的。IC支持多大的屏就要配多大的屏。但是拿到需求,发现要用FT5406做10寸屏,可是FT5406手册上明明写了,最大支持到8.9寸。由于经验不足,感到略懵。就去核实这个需求方案是不是搞错了?!得到的答案:蓝魔的平板也是这个搭配。这样, 那需求应该就没问题了。先看现象再说: 

             硬件搭起来看现象,如下图:

              红色区域是FT5406上报有效数据的范围(1280*600),以左上角为原点 ,X轴方向上报数据的最大值1280,Y轴方向上报的最大数据是600.。但是我用的LG的10.1寸屏,分辨率为1366*768。若想把触摸IC上报的数据和像素点的值一一对应起来,只能通过校正了。开始做校正的时候有点犯抽。竟然自己写校正算法,代码冗长不说,校准误差也特别大。 还好,后来想起了tslib这个东西。tslib是专门为电阻屏设计的一个校正库,只能校正单点触摸数据。而FT5406是支持5点触摸的。 不过只需要校正一点就可以了,这个点与其他四个点的上报数据的偏差大小无区别,只需要在驱动中做相同的消除偏差处理即可。思路有了,下面就从驱动开始说起:

    1. FT5406 在Linux 3.5 中的驱动要点----数据上报过程

    FT5406是通过IIC总线同CPU进行数据交互的,内核中的驱动框架符合一个典型IIC设备驱动+输入子系统(默认大家是了解IIC设备驱动和输入子系统驱动的)。硬件I/O的初始化和寄存器配置就不在这里赘述了, 照着手册来就可以了。重点看一下,数据上报过程,先看一个FT5406 原理图(图中标的是5206 ,没关系接口是一样的)::

        


    原理图上可以看到,用到了EINT14这根中断线。通过这条中断线,差不多就能猜到上报流程了吧:当用户触摸到触摸板以后,产生中断,在中断服务程序中读IIC。这样就完成了一次数据的上报。下面就看看内核源码的实现,先看一个流程图:

            

    中断代码实现如下:

    [cpp] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. static void ft5x0x_ts_pen_irq_work(struct work_struct *work) { //底半部中断  
    2.     struct ft5x0x_ts_data *ts = container_of(work, struct ft5x0x_ts_data, work);  
    3.   
    4.     if (!ft5x0x_read_data(ts)) {  
    5.         ft5x0x_ts_report(ts);  
    6.     }  
    7.   
    8.     enable_irq(this_client->irq);  
    9. }  
    10.   
    11. static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id) {//顶半部中断  
    12.     struct ft5x0x_ts_data *ts = dev_id;  
    13.   
    14.     disable_irq_nosync(this_client->irq);  
    15.   
    16.     if (!work_pending(&ts->work)) {  
    17.         queue_work(ts->queue, &ts->work);  
    18.     }  
    19.   
    20.     return IRQ_HANDLED;  
    21. }  

    从IC中读取触摸数据:

    [cpp] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. static int ft5x0x_read_data(struct ft5x0x_ts_data *ts) {  
    2.     struct ft5x0x_event *event = &ts->event;  
    3.     u8 buf[32] = { 0 };  
    4.     int ret;  
    5.   
    6. #ifdef CONFIG_FT5X0X_MULTITOUCH  
    7.     ret = ft5x0x_i2c_rxdata(buf, 31);  
    8. #else  
    9.     ret = ft5x0x_i2c_rxdata(buf, 7);  
    10. #endif  
    11.     if (ret < 0) {  
    12.         printk("%s: read touch data failed, %d ", __func__, ret);  
    13.         return ret;  
    14.     }  
    15.   
    16.     memset(event, 0, sizeof(struct ft5x0x_event));  
    17.   
    18.     event->touch_point = buf[2] & 0x07;  
    19.   
    20.     if (!event->touch_point) {  
    21.         ft5x0x_ts_release(ts);  
    22.         return 1;  
    23.     }  
    24.   
    25. #ifdef CONFIG_FT5X0X_MULTITOUCH  
    26.     switch (event->touch_point) {  
    27.         case 5:  
    28.             event->x[4] = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];  
    29.             event->y[4] = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];  
    30.         case 4:  
    31.             event->x[3] = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];  
    32.             event->y[3] = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];  
    33.         case 3:  
    34.             event->x[2] = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];  
    35.             event->y[2] = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];  
    36.         case 2:  
    37.             event->x[1] = (s16)(buf[0x09] & 0x0F)<<8 | (s16)buf[0x0a];  
    38.             event->y[1] = (s16)(buf[0x0b] & 0x0F)<<8 | (s16)buf[0x0c];  
    39.         case 1:  
    40.             event->x[0] = (s16)(buf[0x03] & 0x0F)<<8 | (s16)buf[0x04];  
    41.             event->y[0] = (s16)(buf[0x05] & 0x0F)<<8 | (s16)buf[0x06];  
    42.             break;  
    43.         default:  
    44.             printk("%s: invalid touch data, %d ", __func__, event->touch_point);  
    45.             return -1;  
    46.     }  
    47. #else  
    48.     if (event->touch_point == 1) {  
    49.         event->x[0] = (s16)(buf[0x03] & 0x0F)<<8 | (s16)buf[0x04];  
    50.         event->y[0] = (s16)(buf[0x05] & 0x0F)<<8 | (s16)buf[0x06];  
    51.     }  
    52. #endif  
    53.   
    54.     event->pressure = 200;  
    55.   
    56.     return 0;  
    57. }  

    上报过程代码:

    [cpp] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. static void ft5x0x_ts_report(struct ft5x0x_ts_data *ts) {  
    2.     struct ft5x0x_event *event = &ts->event;  
    3.     int x, y;  
    4.     int i;  
    5.   
    6. #ifdef CONFIG_FT5X0X_MULTITOUCH  
    7.     for (i = 0; i < event->touch_point; i++) {  
    8.         if (swap_xy) {  
    9.             x = event->y[i];  
    10.             y = event->x[i];  
    11.         } else {  
    12.             x = event->x[i];  
    13.             y = event->y[i];  
    14.         }  
    15.   
    16.         if (scal_xy) {  
    17.             x = (x * ts->screen_max_x) / TOUCH_MAX_X;  
    18.             y = (y * ts->screen_max_y) / TOUCH_MAX_Y;  
    19.         }  
    20.   
    21.         input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);  
    22.         input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);  
    23.   
    24.         input_report_abs(ts->input_dev, ABS_MT_PRESSURE, event->pressure);  
    25.         input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);  
    26.         input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i);  
    27.   
    28.         input_mt_sync(ts->input_dev);  
    29.     }  
    30. #else  
    31.     if (event->touch_point == 1) {  
    32.         if (swap_xy) {  
    33.             x = event->y[i];  
    34.             y = event->x[i];  
    35.         } else {  
    36.             x = event->x[i];  
    37.             y = event->y[i];  
    38.         }  
    39.   
    40.         if (scal_xy) {  
    41.             x = (x * ts->screen_max_x) / TOUCH_MAX_X;  
    42.             y = (y * ts->screen_max_y) / TOUCH_MAX_Y;  
    43.         }  
    44.   
    45.         input_report_abs(ts->input_dev, ABS_X, x);  
    46.         input_report_abs(ts->input_dev, ABS_Y, y);  
    47.         input_report_abs(ts->input_dev, ABS_PRESSURE, event->pressure);  
    48.     }  
    49.   
    50.     input_report_key(ts->input_dev, BTN_TOUCH, 1);  
    51. #endif  
    52.   
    53.     input_sync(ts->input_dev);  
    54. }  

    IC驱动的大致工作流程就是这样的,下面就来看看该怎么去做校正:

    一、这个电容屏是往exynos4412 核心 Android4.2设备上移植的,所以第一步要做的是往Anroid移植TSlib1.4库。简述移植过程

    1.生成configure

      ./autogen.sh

     安装tslib中遇到的错误:./autogen.sh: 4: autoreconf: not found

      是因为在不同版本的 tslib 下执行 autogen.sh 产生。它们产生的原因一样,

     因为没有安装  automake 工具,  (ubuntu 13.10)用下面的命令安装好就可以了。

     sudo apt-get install autoconf automake libtool

    2./configure --host=交叉编译器路径(注意要用对应Android平台自带的bionic c编译器而不是配套开发板的GNU C编译器)

        ac_cv_func_malloc_0_nonnull=yes -static
     

    在tslib/config.h文件中加入如下定义:
    #define TS_CONF  "/system/etc/ts.conf"
    #define PLUGIN_DIR "/system/lib"
    #define TS_POINTERCAL "/data/etc/pointercal"


    另外由于bionic c 和GNU c的差异,需要修改几个tslib的头文件编译才能通过
    将下面路径文件
    tslib/src/ts_open.c
    tslib/tests/ts_calibrate.c
    tslib/tests/fbutils.c
    中的
    #include <sys/fcntl.h>
    修改成
    #include <fcntl.h>

    将tslib/tests/ts_calibrate.c文件中
    static int clearbuf(struct tsdev *ts)
    修改为
    static void clearbuf(struct tsdev *ts)


    如果使用GNU C编译器在android shell下运行ts_calibrate会出现如下错误:

     sh: ./system/bin/ts_calibrate: No such file or directory


     3.编译make



     etc/ts.conf 的参考配置:

    修改tslib/etc/ts.conf内容如下:
    module_raw input
    module pthres pmin=1
    module variance delta=30
    module dejitter delta=100
    module linear

    4.在android源代码init.rc中声明tslib相关环境变量如下:

    # touchscreen parameters
        export TSLIB_FBDEVICE /dev/graphics/fb0
        export TSLIB_CALIBFILE /data/etc/pointercal
        export TSLIB_CONFFILE  /system/etc/ts.conf
        export TSLIB_TRIGGERDEV /dev/input/event0
        export TSLIB_TSDEVICE /dev/input/event1

     

     5.      将/src/.lib 中生成的库文件,分别全部拷贝开发板的根文件系统对应/system/lib 目录中,将tests目录中的ts_calibrate cp到system/bin中

    到此完成对tslib的移植。

    在运行ts_calibrate前首先要取消内核对多点触摸的支持,因为tslib只能处理单点的数据格式,而且单点的数据,必须要满足以下上报顺寻:

     input_report_abs(ts->input_dev, ABS_X, x);
                    input_report_abs(ts->input_dev, ABS_Y, y);
                    input_report_abs(ts->input_dev, ABS_PRESSURE, event->pressure);

    通过运行ts_calibrate,获得校正参数,存放在/data 目录下的pointercal文件中

    最后要做的就是修改内核驱动 /drivers/input/touchscreen/ft5x06_ts.c,添加校正算法(如下)并添加获得的校正参数(红色标注即为获得的校正参数)。如下:

    [cpp] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #ifdef CONFIG_INPUT_TS_LINEAR  
    2. static int ts_linear_scale(int *x, int *y, int swap_xy)  
    3. {  
    4.         int xtemp, ytemp;  
    5.         int a[7] = {<span style="color: rgb(255, 0, 0);">87701,-382,-420352,-89,84218,-936128,65536</span>};  
    6.         xtemp = *x;  
    7.         ytemp = *y;  
    8.   
    9.         if (a[6] == 0)  
    10.             return -EINVAL;  
    11.   
    12.         *x = (a[2] + a[0] * xtemp + a[1] * ytemp) / a[6];  
    13.         *y = (a[5] + a[3] * xtemp + a[4] * ytemp) / a[6];  
    14.   
    15.         if (swap_xy) {  
    16.                 int tmp = *x;  
    17.                 *x = *y;  
    18.                 *y = tmp;  
    19.         }  
    20.         return 0;  
    21. }  
    22. #endif  

    static void ft5x0x_ts_report(struct ft5x0x_ts_data *ts) {
            struct ft5x0x_event *event = &ts->event;
            int x, y;
            int i;


    #ifdef CONFIG_FT5X0X_MULTITOUCH
            for (i = 0; i < event->touch_point; i++) {
                    if (swap_xy) {
                            x = event->y[i];
                            y = event->x[i];
                    } else {
                            x = event->x[i];
                            y = event->y[i];
                    }


                    if (scal_xy) {
                            x = (x * ts->screen_max_x) / TOUCH_MAX_X;
                            y = (y * ts->screen_max_y) / TOUCH_MAX_Y;
                    }
    #ifdef CONFIG_INPUT_TS_LINEAR
                    ts_linear_scale(&x, &y, swap_xy);
    #endif

    在上报过程 首先通过static int ts_linear_scale(int *x, int *y, int swap_xy)函数将从IC获得的触摸点坐标消除偏差。
  • 相关阅读:
    vue 兼容IE报错解决方案
    JDK1.8 ArrayList 源码解析
    Mac nasm 汇编入门
    命令模式
    模板方法
    Mysql Limit 调优
    观察者模式
    外观模式
    Rest- Client
    MongoDB数据库 5分钟快速上手
  • 原文地址:https://www.cnblogs.com/liang123/p/6325230.html
Copyright © 2011-2022 走看看