上篇文章介绍了电容触摸驱动的编写,包括设备树的修改和驱动程序(IIC驱动+中断+input子系统),并通过将触摸坐标值实时打印出来的方式,对触摸功能进行测试。 本篇,先来介绍一会测试触摸是库——tslib,使用它可以进行图形化的触摸测试。之后,再回头来分析分析触摸协议上报的原理以及通过input子系统上报的数据的具体含义。 1 tslib的使用Tslib是一个开源的程序,能够为触摸屏驱动获得的采样提供诸如滤波、去抖、校准等功能,通常作为触摸屏驱动的适配层,为上层的应用提供了一个统一的接口。 1.1 tslib库移植目前最新的是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目录中: 可以看到最终编译生成的是5个文件夹。 1.1.2 开发板上配置tslib将编译出的5个文件夹整个复制到开发板的根文件系统中: - sudo cp * -rf ~/myTest/nfs/rootfs/
复制代码然后打开板子的/etc/ts.conf 文件,找到下面这一行: 如果这句前面有“#”注释,就删除掉“#“,我这个默认是没有的,所以不用修改 打开板子的/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
复制代码- TSLIB_TSDEVICE :触摸设备文件,要根据具体情况设置为/dev/input/event1还是event2(如果接口鼠标键盘,这个编号可能还会变,比如我接了无线键盘后,触摸就又变成了event)
TSLIB_CALIBFILE :校准文件,此文件可以不存在,校准的时候会自动生成 TSLIB_CONFFILE :触摸配置文件,在移植 tslib 的时候会生成 TSLIB_PLUGINDIR :tslib 插件目录位置 TSLIB_CONSOLEDEVICE :控制台设置,这里不设置,设为none TSLIB_FBDEVICE:FB 设备,也就是屏幕,也要根据实际情况配置设置为/dev/fb0或是其它
1.2 tslib库测试1.2.1 屏幕校准电容屏可以不用校准,不过也可以看看tslib的校准测试用例,输入如下指令: 校准完成以后如果不满意,删除掉/etc/pointercal文件即可 1.2.2 多点触摸拖拽测试使用如下指令: 然后会出现一个触摸测试界面,先测试Drag功能,手指接触屏幕后进行移动,屏幕上的十字标记就会跟着移动: 1.2.3 多点触摸划线测试还是刚才的指令,再来测试Draw功能,手指接触屏幕后进行移动,屏幕上就会出现滑过的轨迹线: 2 多点触摸(MT)协议讲解多点触摸协议,即Multi-touch (MT) Protocol,该协议的介绍,在linux内核源码中有对应的文档,如下图: 多点电容触摸的协议分为两种类型:TypeA和TypeB,目前基本都是使用TypeB协议。 触摸点的信息通过一系列的 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
复制代码- 首先每上报一个点的x和y
然后上报一个SYN_MT_REPORT 依次循环上报其它点 所有的点上报完后,再上报一个SYN_REPORT
当第一个触点离开后,上报的时序如下(就是只上报剩下的那一个): - ABS_MT_POSITION_X x[1]
- ABS_MT_POSITION_Y y[1]
- SYN_MT_REPORT
- SYN_REPORT
复制代码当第二个触点也离开后,上报的时序如下(就是上报空数据): 如果驱动除了ABS_MT事件外还上报BTN_TOUCH或ABS_PRESSURE之一,则最后一个SYN_MT_REPORT事件可能被忽略。另外,最后的SYN_REPORT会被输入内核放弃,从而导致没有空触事件到达用户层。 2.2 TypeB协议TypeB协议适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过slot更新某一个触摸点的信息。 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
复制代码当触点45在X方向上移动后,上报的时序如下: - ABS_MT_SLOT 0
- ABS_MT_POSITION_X x[0]
- SYN_REPORT
复制代码当slot 0中触点离开后,上报的时序如下: - 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包括: 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件功能,就需要注册EV_KEY事件,若还要使用连按功能,需要注册EV_REP事件。 如果要使用触摸屏的inpu件功能,就需要注册EV_KEY事件, 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
复制代码来分析一下每行输出的含义: 第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,在最下面添加下面一行:
然后(使用之前编写的编译脚本)重新编译linux内核 再将zImage拷贝到板子中,重新启动板子。 正常情况下,在内核启动的时候就打印出触摸驱动的event编号信息,我这里确实也打印了,只是随后一直刷IIC错误: 暂时看不出来是什么原因,才这居打印看,触摸开始读数据时才会进到这里,感觉像是触摸驱动刚加载完成,就触发了中断,但在中断里通过IIC读取触摸数据时,又出现了问题。。。 一个暂时的替代方式是,可以在开机自启动文件中进行触摸驱动的加载,在/etc/init.d/rcS文件中补充如下语句即可: - cd /lib/modules/4.1.15
- depmod
- modprobe gt911.ko
- cd /
复制代码5 总结 本篇首先介绍了测试触摸是库——tslib,使用它可以进行图形化的触摸测试。随后,又分析触摸协议上报的原理以及通过input子系统上报的数据的具体含义。
|