资讯详情

【i.MX6ULL】驱动开发13——电容触摸驱动实践(下)

本文介绍了电容触摸驱动的编写,包括设备树的修改和驱动程序(IIC驱动 中断 input子系统),并通过实时打印触摸坐标值来测试触摸功能。

本文首先介绍一下测试触摸是库——tslib,可以用它。然后回头分析分析以及通过具体含义。

文章目录

  • 1 tslib的使用
    • 1.1 tslib库移植
      • 1.1.1 ubuntu上编译tslib
      • 1.1.2 配置在开发板上tslib
    • 1.2 tslib库测试
      • 1.2.1 屏幕校准
      • 1.2.2 多点触摸拖拉试验
      • 1.2.3 多点触摸划线测试
  • 2 多点触摸(MT)协议讲解
    • 2.1 TypeA协议
    • 2.2 TypeB协议
    • 2.3 多点触摸API函数
      • 2.3.1 input_mt_init_slots
      • 2.3.2 input_mt_slot
      • 2.3.3 input_mt_report_slot_state
      • 2.3.4 input_report_abs
      • 2.3.5 input_mt_report_pointer_emulation
  • 3 input子系统上报数据含义讲解
    • 3.1 input子系统简介
    • 3.2 input输出事件
      • 3.2.1 事件类型
      • 3.2.2 按键值类型
    • 3.3 触摸数据报告实例分析
  • 4 将触摸驱动器编译成内核
  • 5 总结
    • 附:演示视频

1 tslib的使用

Tslib它是一个开源程序,可以为触摸屏驱动的采样提供滤波、抖动、校准等功能,为上层应用提供了一个

1.1 tslib库移植

首先下载tslib库的源码:https://github.com/libts/tslib/tags

最新的是1.22,但本文先用1.21版本

1.1.1 ubuntu上编译tslib

复制下载的源代码ubuntu然后在虚拟机中解压:

tar xvf tslib-1.21.tar.bz2  

编译 tslib 需要先在 ubuntu 中安装一些文件

sudo apt-get install autoconf  sudo apt-get install automake  sudo apt-get install libtool  

在 ubuntu 一个名字叫中创tslib将编译结果存储在目录中,然后执行以下指令进行编译:

cd tslib-1.21/  ./autogen.sh  ./configure --host=arm-linux-gnueabihf --prefix=/home/xxpcb/myTest/imx6ull/otherlib/tslib/tslib/ make make install 

编译完成后,make install会将编译成果复制到指定的tslib目录中:

可以看出,最终的编译生成了五个文件夹。

1.1.2 配置在开发板上tslib

将编译的五个文件夹复制到开发板的根文件系统中:

sudo cp * -rf ~/myTest/nfs/rootfs/ 

然后打开板**/etc/ts.conf** 找到以下行:

module_raw input   

如果这句话前面有#注释,删除#。我没有默认,所以我不需要修改它

打开板子的**/etc/profile**文件,我的板此时没有这个文件,所以我新建了一个文件,然后添加了以下内容:

export TSLIB_TSDEVICE=/dev/input/event2  export TSLIB_CALIBFILE=/etc/pointercal  export TSLIB_CONFFILE=/etc/ts.conf  export TSLIB_PLUGINDIR=/lib/ts  export TSLIB_CONSOLEDEVICE=none  export TSLIB_FBDEVICE=/dev/fb0  

1.2 tslib库测试

1.2.1 屏幕校准

不需要校准就可以看电容屏tslib输入以下指令:

ts_calibrate  

校准完成后如不满意,删除/etc/pointercal文件即可

1.2.2 多点触摸拖拉试验

使用以下说明:

ts_test_mt 

然后会出现触摸测试界面,先测试Drag功能,手指接触屏幕后移动,屏幕上的交叉标记会随之移动:

1.2.3 多点触摸划线测试

或者刚才的指令,然后测试Draw当手指接触屏幕后移动时,屏幕上会出现滑动轨迹线:

2 多点触摸(MT)协议讲解

多点触摸协议,即Multi-touch (MT) Protocol,本协议的介绍,在linux核源代码中有相应的文档,如下图所示:

多点电容触摸协议分为两类:TypeA和TypeB,目前基本都是用的TypeB协议。

  • TypeA该协议适用于无法区分或跟踪触摸点的原始数据。
  • TypeB协议适用于这类设备通过触摸设备 slot更新某一个触摸点的信息。

触摸点的信息通过一系列的 ABS_MT事件上报给linux内核,这些事件的定义在include/uapi/linux/input.h中:

比较常用的有:

  • ABS_MT_SLOT :上报触摸点ID
  • ABS_MT_POSITION_X:上报触摸点的X坐标信息
  • ABS_MT_POSITION_Y:上报触摸点的Y坐标信息
  • ABS_MT_TRACKING_ID:TypeB区分触摸点

下面具体介绍两种协议的区别。

2.1 TypeA协议

TypeA协议适用于触摸点不能被区分或者追踪,此类设备上报原始数据。

TypeA协议发送触摸点信息的时序如下(以 2 个触摸点为例):

ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
SYN_MT_REPORT
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
  • 首先每上报一个点的
  • 然后上报一个
  • 依次循环上报其它点
  • 所有的点上报完后,再上报一个

,上报的时序如下(就是只上报剩下的那一个):

ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT

,上报的时序如下(就是上报空数据):

SYN_MT_REPORT
SYN_REPORT

如果驱动除了ABS_MT事件外还上报BTN_TOUCH或ABS_PRESSURE之一,则最后一个SYN_MT_REPORT事件可能被忽略。另外,最后的SYN_REPORT会被输入内核放弃,从而导致没有空触事件到达用户层。

2.2 TypeB协议

TypeB协议适用于的触摸设备,此类型设备通过更新某一个触摸点的信息。

TypeA协议发送触摸点信息的时序如下(以 2 个触摸点为例):

ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT
  • 每个数据点前,先上报事件,带上一个触摸点ID,此ID由
  • TypeB要求每个SLOT须关联一个,这个ID由
  • 然后上报一个点的
  • 依次循环上报其它点
  • 所有的点上报完后,再上报一个

,上报的时序如下:

ABS_MT_SLOT 0
ABS_MT_POSITION_X x[0]
SYN_REPORT

,上报的时序如下:

ABS_MT_TRACKING_ID -1
SYN_REPORT

由于slot被修改为0,因此这个ABS_MT_SLOT被忽略。这条信息移除了slot 0和触点45的联系,因此销毁触点45同时释放slot 0给另外的触点再次使用。

,上报的时序如下:

ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT

总结对比一下两个触摸协议的区别:

2.3 多点触摸API函数

了解了两种触摸协议,在编程时,就要使用其相应的API函数来实现触摸数据的上报,下面是常用的API函数。

2.3.1 input_mt_init_slots

该函数用于初始化MT的输入slots,其函数原型如下:

/** * dev: MT设备对应的input_dev * num_slots: 设备要使用的slot的数量,也就是触摸点的数量 * flags: 其他一些flags信息 * return: 0-成功 负值-失败 */
int input_mt_init_slots(struct input_dev *dev,  
                            unsigned int num_slots,  
                            unsigned int flags) 

其中第3个参数,可设置的flags包括:

#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */ 
#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */ 
#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */ 
#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */ 
#define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */

可以使用‘|’运算来同时设置多个flags标识

2.3.2 input_mt_slot

该函数用于Type B类型,用于产生 ABS_MT_SLOT事件,其函数原型如下:

/** * dev: MT设备对应的input_dev * slot: 当前发送的是哪个slot的坐标信息,也就是哪个触摸点 * return: 无 */
void input_mt_slot(struct input_dev *dev, int slot) 

2.3.3 input_mt_report_slot_state

该函数用于Type B类型,用于产生ABS_MT_TRACKING_ID和ABS_MT_TOOL_TYPE事件,其函数原型如下:

/** * dev: MT设备对应的input_dev * tool_type: 触摸类型 * active: 触摸或抬起 * return: 无 */
void input_mt_report_slot_state(struct input_dev *dev, 
                                    unsigned int tool_type,  
                                            bool active) 

其中第2个参数,tool_type包括:

  • MT_TOOL_FINGER:手指
  • MT_TOOL_PEN:笔
  • MT_TOOL_PALM:手掌

其中第3个参数,active包括:

  • true: 连续触摸, input子系统内核会自动分配一个ABS_MT_TRACKING_ID给slot
  • false:触摸点抬起,表示某个触摸点无效了,input子系统内核会分配一个-1给slot

2.3.4 input_report_abs

该函数用于上报触摸点坐标,TypeA和TypeB类型都使用此函数上报触摸点坐标信息,其函数原型如下:

/** * dev: MT设备对应的input_dev * code: 要上报的是什么数据 * value: 要上报的数据值 * return: 无 */
void input_report_abs(struct input_dev *dev,  
                          unsigned int code,  
                                   int value)

其中第2个参数,code包括:

  • ABS_MT_POSITION_X
  • ABS_MT_POSITION_Y

2.3.5 input_mt_report_pointer_emulation

如果追踪到的触摸点数量多于当前上报的数量,驱动程序使用 BTN_TOOL_TAP 事件来通知用户空间当前追踪到的触摸点总数量,然后调用 input_mt_report_pointer_emulation 函数将use_count 参数设置为 false,否则的话将 use_count 参数设置为 true。

/** * dev: MT设备对应的input_dev * use_count: true-有效的触摸点数量 false-追踪到的触摸点数量多于当前上报的数量 * return: 无 */
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) 

3 input子系统上报数据含义讲解

3.1 input子系统简介

在Linux中,对于输入设备,例如按键、 鼠标、 键盘、 触摸屏等,为了更加方便统一的管理, Linux内核为此专门做了一个input子系统的框架来处理输入事件。

input是输入的意思,就是管理输入的子系统,和 pinctrl、gpio 子系统一样,都是 Linux 内核针对某一类设备而创建的框架。input 子系统框架图如下:

3.2 input输出事件

3.2.1 事件类型

evbit 表示输入事件类型,可选的事件类型定义在 include/uapi/linux/input.h 文件中,事件类型如下:

各个的含义为:

#define EV_SYN 0x00 /* 同步事件 */ 
#define EV_KEY 0x01 /* 按键事件 */ 
#define EV_REL 0x02 /* 相对坐标事件 */ 
#define EV_ABS 0x03 /* 绝对坐标事件 */ 
#define EV_MSC 0x04 /* 杂项(其他)事件 */ 
#define EV_SW 0x05 /* 开关事件 */ 
#define EV_LED 0x11 /* LED */ 
#define EV_SND 0x12 /* sound(声音) */ 
#define EV_REP 0x14 /* 重复事件 */ 
#define EV_FF 0x15 /* 压力事件 */ 
#define EV_PWR 0x16 /* 电源事件 */ 
#define EV_FF_STATUS 0x17 /* 压力状态事件 */ 

例如,如果要使用的inpu件功能,就需要注册事件,若还要使用连按功能,需要注册事件。

如果要使用的inpu件功能,就需要注册事件,

3.2.2 按键值类型

evbit、keybit、relbit 等等都是存放不同事件对应的值,Linux 内核定义了很多按键值:

#define KEY_RESERVED 0 
#define KEY_ESC 1 
#define KEY_1 2 
#define KEY_2 3 
#define KEY_3 4 
#define KEY_4 5 
//...... 
#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
#define BTN_TOUCH 0x14a
#define BTN_STYLUS 0x14b
//...... 

#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_Z 0x02
#define ABS_RX 0x03
#define ABS_RY 0x04
#define ABS_RZ 0x05

#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */

具体的定义在input.h文件中:

3.3 触摸数据上报实例分析

上篇文章只是将触摸坐标打印到了屏幕,实际是使用触摸屏时,需要将坐标数据通过input子系统上报应用层,现在来具体分析一下input子系统上报的这些数据的含义,例如按下触摸键后,串口会有如下打印:

将数据内容摘出来看:

 /*****************input_event 类型********************/ 
/*编号*/   /*tv_sec*/ /*tv_usec*/  /*type*/   /*code*/    /*value*/ 
0000000    00f6 0000   e539 0003     0003       0039      0000 0000
0000010    00f6 0000   e539 0003     0003       0035      009d 0000
0000020    00f6 0000   e539 0003     0003       0036      00c1 0000
0000030    00f6 0000   e539 0003     0001       014a      0001 0000
0000040    00f6 0000   e539 0003     0003       0000      009d 0000
0000050    00f6 0000   e539 0003     0003       0001      00c1 0000
0000060    00f6 0000   e539 0003     0000       0000      0000 0000
0000070    00f6 0000   11ad 0005     0003       0039      ffff ffff
0000080    00f6 0000   11ad 0005     0001       014a      0000 0000
0000090    00f6 0000   11ad 0005     0000       0000      0000 0000
  • type 为事件类型
    • 0000:,同步事件
    • 0001:,按键事件
    • 0003:,绝对坐标事件
  • code 为事件编码,也就是按键号
    • 0000:,单点触摸上报X坐标值
    • 0001:,单点触摸上报Y坐标值
    • 0035:,多点触摸上报X坐标值
    • 0036:,多点触摸上报Y坐标值
    • 0039:,触摸点的track id
    • 014a:,触摸按键
  • value 就是按键值, 为 1 表示按下, 为 0 的话表示松开

来分析一下每行输出的含义:

第1行:绝对坐标事件,触摸点的track id,id=0

第2行:绝对坐标事件,多点触摸X坐标值,X=0x9d (157)

第3行:绝对坐标事件,多点触摸Y坐标值,Y=0xc1 (193)

第4行:按键事件,触摸按键,1表示按键按下

第5行:绝对坐标事件,单点触摸X坐标值,X=0x9d (157)

第6行:绝对坐标事件,单点触摸Y坐标值,Y=0xc1 (193)

第7行:同步事件,由input_sync函数上报

第8行:绝对坐标事件,触摸点的track id,id=0xffffffff=-1,即触摸点离开了屏幕

第9行:按键事件,触摸按键,0表示没有按键

第10行:同步事件,由input_sync函数上报

注:上面的打印,有多点触摸和单点触摸的上报,实际上如果使用了多点触摸,可以将单点触摸的上报去掉,如下:

去掉后,再次测试,可以看到只有多点触摸数据的上报:

4 将触摸驱动编译到内核

自己编写的触摸驱动,每次系统启动后,都要手动加载驱动模块后才能使用,比较麻烦,现在驱动文件不需要再改了,就可以将自己的驱动直接编译到内核中。方法如下:

将自己写的触摸屏驱动文件拷贝到Linux内核的drivers/input/touchscreen/目录下:

cp gt911.c ../../kernel/nxp_kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/drivers/input/touchscreen/ -f

修改 drivers/input/touchscreen 目录下的 Makefile,在最下面添加下面一行:

obj-y += gt911.o

然后(使用之前编写的编译脚本)重新编译linux内核

再将zImage拷贝到板子中,重新启动板子。

正常情况下,在内核启动的时候就打印出触摸驱动的event编号信息,我这里确实也打印了,只是随后一直刷IIC错误:

暂时看不出来是什么原因,才这居打印看,触摸开始读数据时才会进到这里,感觉像是触摸驱动刚加载完成,就触发了中断,但在中断里通过IIC读取触摸数据时,又出现了问题。。。

一个是,可以在开机自启动文件中进行触摸驱动的加载,在/etc/init.d/rcS文件中补充如下语句即可:

cd /lib/modules/4.1.15
depmod
modprobe gt911.ko
cd /

5 总结

本篇首先介绍了测试触摸是库——tslib,使用它可以进行。随后,又分析以及通过的具体含义。

附:演示视频

https://www.bilibili.com/video/BV1XL4y1t7kf?spm_id_from=333.999.0.0

标签: 电容笔变接触笔

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台