1.多点电容触摸简介
ATK-7016 这款屏幕其实是由 TFT LCD+
触摸屏组合起来的。底下是
LCD
面板,上面是触摸面板,将两个封装到一起就成了带有触摸屏的 LCD
屏幕。电容触摸屏也是需要一个驱动
IC的,驱动 IC
一般会提供一个
I2C
接口给主控制器,主控制器可以通过
I2C
接口来读取驱动
IC里面的触摸坐标数据。ATK-7016
、
ATK-7084
这两款屏幕使用的触摸控制
IC
是
FT5426
,
ATK- 4342 使用的驱动
IC
是
GT9147
。这三个电容屏触摸
IC
都是
I2C
接口的,使用方法基本一样。
FT5426 这款驱动
IC
采用
15*28
的驱动结构,也就是
15
个感应通道,
28
个驱动通道,最
多支持
5
点电容触摸。
ATK-7016
的电容触摸屏部分有
4
个
IO
用于连接主控制器:
SCL
、
SDA
、
RST
和
INT
,
SCL
和
SDA
是
I2C
引脚,
RST
是复位引脚,
INT
是中断引脚。一般通过
INT
引
脚来通知主控制器有触摸点按下,然后在
INT
中断服务函数中读取触摸数据。也可以不使用中
断功能,采用轮询的方式不断查询是否有触摸点按下,和所有的 I2C 器件一样,FT5426 也是通过读写寄存器来完成初始化和触摸坐标数据读取的,本节主要内容就是读写FT5426 的寄存器。FT5426 的 I2C 设备地址为 0X38,FT5426 的寄存器有很多,只用到了其中的一部分,如表所示:

2.多点触摸(MT)协议详解
老版本的 linux
内核是不支持多点电容触摸的
(Multi-touch
,简称
MT)
,
MT
协议是后面加入的,因此如果使用 2.x
版本
linux
内核的话可能找不到
MT
协议。
MT
协议被分为两种类型,
Type A 和
TypeB
,这两种类型的区别如下:
TypeA
:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据
(
此类型在实际使
用中非常少!
)
。
Type B
:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过
slot
更新某一个
触摸点的信息,
FT5426
就属于此类型,一般的多点电容触摸屏
IC
都有此能力。
触摸点的信息通过一系列的 ABS_MT
事件
(
有的资料也叫消息
)
上报给
linux
内核,只有
ABS_MT
事件是用于多点触摸的,
ABS_MT
事件定义在文件
include/uapi/linux/input.h
中,相关
事件如下所示:
852 #define ABS_MT_SLOT 0x2f /* MT slot being modified */
853 #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
854 #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
855 #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
856 #define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
857 #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
858 #define ABS_MT_POSITION_X 0x35 /* Center X touch position */
859 #define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
860 #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
861 #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
862 #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
863 #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
864 #define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
865 #define ABS_MT_TOOL_X 0x3c /* Center X tool position */
866 #define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
在 上 面 这 些 众 多 的ABS_MT 事 件 中 , 我 们 最 常 用 的 就 是 ABS_MT_SLOT
、
ABS_MT_POSITION_X 、ABS_MT_POSITION_Y 和 ABS_MT_TRACKING_ID
。其中
ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 用 来 上报 触 摸点 的 (X,Y)
坐 标 信息 ,
ABS_MT_SLOT
用 来 上 报 触 摸 点
ID
,对于
Type B
类 型 的 设 备 , 需 要 用 到 ABS_MT_TRACKING_ID 事件来区分触摸点。
对于 TypeA
类型的设备,通过
input_mt_sync()
函数来隔离不同的触摸点数据信息,此函数
原型如下所示:
void input_mt_sync(struct input_dev *dev)
此函数只要一个参数,类型为 input_dev,用于指定具体的
input_dev
设备。
input_mt_sync()
函数会触发
SYN_MT_REPORT
事件,此事件会通知接收者获取当前触摸数据,并且准备接收
下一个触摸点数据。
对于 Type B
类型的设备,上报触摸点信息的时候需要通过
input_mt_slot()
函数区分是哪一
个触摸点,
input_mt_slot()
函数原型如下所示:
void input_mt_slot(struct input_dev *dev, int slot)
此函数有两个参数,第一个参数是 input_dev
设备,第二个参数
slot
用于指定当前上报的是
哪个触摸点信息。
input_mt_slot()
函数会触发
ABS_MT_SLOT
事件,此事件会告诉接收者当前
正在更新的是哪个触摸点
(slot)
的数据。
不管是哪个类型的设备,最终都要调用 input_sync()
函数来标识多点触摸信息传输完成,告
诉接收者处理之前累计的所有消息,并且准备好下一次接收。
Type B
和
Type A
相比最大的区
别就是
Type B
可以区分出触摸点, 因此可以减少发送到用户空间的数据。
Type B
使用
slot
协
议区分具体的触摸点,
slot
需要用到
ABS_MT_TRACKING_ID
消息,这个
ID
需要硬件提供,
或者通过原始数据计算出来。对于
TypeA
设备,内核驱动需要一次性将触摸屏上所有的触摸点
信息全部上报,每个触摸点的信息在本次上报事件流中的顺序不重要,因为事件的过滤和手指
(
触摸点
)
跟踪是在内核空间处理的。
Type B 设备驱动需要给每个识别出来的触摸点分配一个
slot
,后面使用这个
slot
来上报触
摸点信息。可以通过
slot
的
ABS_MT_TRACKING_ID
来新增、替换或删除触摸点。一个非负数
的
ID
表示一个有效的触摸点,
-1
这个
ID
表示未使用
slot
。一个以前不存在的
ID
表示这是一个
新加的触摸点,一个
ID
如果再也不存在了就表示删除了。
有些设备识别或追踪的触摸点信息要比他上报的多,这些设备驱动应该给硬件上报的每个
触摸点分配一个
Type B
的
slot
。一旦检测到某一个
slot
关联的触摸点
ID
发生了变化,驱动就
应该改变这个
slot
的
ABS_MT_TRACKING_ID
,使这个
slot
失效。如果硬件设备追踪到了比他
正在上报的还要多的触摸点,那么驱动程序应该发送
BTN_TOOL_*TAP
消息,并且调用
input_mt_report_pointer_emulation()
函数,将此函数的第二个参数
use_count
设置为
false
。
2.1Type A 触摸点信息上报时序
1 ABS_MT_POSITION_X x[0]
2 ABS_MT_POSITION_Y y[0]
3 SYN_MT_REPORT
4 ABS_MT_POSITION_X x[1]
5 ABS_MT_POSITION_Y y[1]
6 SYN_MT_REPORT
7 SYN_REPORT
对于 Type A 类型的设备,发送触摸点信息的时序如下所示,这里以
2
个触摸点为例:
第 1
行,通过
ABS_MT_POSITION_X 事件上报第一个触摸点的 X
坐标数据,通过
input_report_abs
函数实现,下面同理。
第 2
行,通过
ABS_MT_POSITION_Y
事件上报第一个触摸点的
Y
坐标数据。
第 3
行,上报
SYN_MT_REPORT
事件,通过调用
input_mt_sync
函数来实现。
第 4
行,通过
ABS_MT_POSITION_X
事件上报第二个触摸点的
X
坐标数据。
第 5
行,通过
ABS_MT_POSITION_Y
事件上报第二个触摸点的
Y
坐标数据。
第 6
行,上报
SYN_MT_REPORT
事件,通过调用
input_mt_sync
函数来实现。
第 7
行,上报
SYN_REPORT
事件,通过调用
input_sync
函数实现。
我们在编写 TypeA
类型的多点触摸驱动的时候就需要按照示例代码
中的时序上报坐标信息。Linux
内核里面也有
Type A
类型的多点触摸驱动,找到
st2332.c
这个驱动文件,路径为 drivers/input/touchscreen/st1232.c
,找到
st1232_ts_irq_handler
函数,此函数里面就是上报触摸点坐标信息的。
103 static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
104 {
......
111 ret = st1232_ts_read_data(ts);
112 if (ret < 0)
113 goto end;
114
115 /* multi touch protocol */
116 for (i = 0; i < MAX_FINGERS; i++) {
117 if (!finger[i].is_valid)
118 continue;
119
120 input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
121 input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
122 input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
123 input_mt_sync(input_dev);
124 count++;
125 }
......
140
141 /* SYN_REPORT */
142 input_sync(input_dev);
143
144 end:
145 return IRQ_HANDLED;
146 }
第 111
行,获取所有触摸点信息。
第 116~125
行,按照
Type A
类型轮流上报所有的触摸点坐标信息,第
121
和
122
行分别上
报触摸点的
(X,Y)
轴坐标,也就是
ABS_MT_POSITION_X
和
ABS_MT_POSITION_Y
事件。每上报完一个触摸点坐标,都要在第 123
行调用
input_mt_sync
函数上报一个
SYN_MT_REPORT
信息。
第 142
行,每上报完一轮触摸点信息就调用一次
input_sync
函数,也就是发送一个
SYN_REPORT
事件
2.2 Type B 触摸点信息上报时序
对于 Type B
类型的设备,发送触摸点信息的时序如下所示,这里以
2
个触摸点为例:
1 ABS_MT_SLOT 0
2 ABS_MT_TRACKING_ID 45
3 ABS_MT_POSITION_X x[0]
4 ABS_MT_POSITION_Y y[0]
5 ABS_MT_SLOT 1
6 ABS_MT_TRACKING_ID 46
7 ABS_MT_POSITION_X x[1]
8 ABS_MT_POSITION_Y y[1] 9 SYN_REPORT
第 1
行,上报
ABS_MT_SLOT
事件,也就是触摸点对应的
SLOT
。每次上报一个触摸点坐
标之前要先使用
input_mt_slot
函数上报当前触摸点
SLOT
,触摸点的
SLOT
其实就是触摸点
ID
,
需要由触摸
IC
提供。
第 2
行,根据
Type B
的要求,每个
SLOT
必须关联一个
ABS_MT_TRACKING_ID
,通过
修改
SLOT
关联的
ABS_MT_TRACKING_ID
来完成对触摸点的添加、替换或删除。具体用到
的函数就是
input_mt_report_slot_state
,如果是添加一个新的触摸点,那么此函数的第三个参数
active
要设置为
true
,
linux
内核会自动分配一个
ABS_MT_TRACKING_ID
值,不需要用户去指
定具体的
ABS_MT_TRACKING_ID
值。
第 3
行,上报触摸点
0
的
X
轴坐标,使用函数
input_report_abs
来完成。
第 4
行,上报触摸点
0
的
Y
轴坐标,使用函数
input_report_abs
来完成。
第 5~8
行,和第
1~4
行类似,只是换成了上报触摸点
0
的
(X,Y)
坐标信息
第 9
行,当所有的触摸点坐标都上传完毕以后就得发送
SYN_REPORT
事件,使用
input_sync 函数来完成。 当一个触摸点移除以后,同样需要通过 SLOT
关联的
ABS_MT_TRACKING_ID
来处理,时序如下所示:
1 ABS_MT_TRACKING_ID -1
2 SYN_REPORT
第 1
行,当一个触摸点
(SLOT)
移除以后,需要通过
ABS_MT_TRACKING_ID
事件发送一
个
-1
给内核。方法很简单,同样使用
input_mt_report_slot_state
函数来完成,只需要将此函数的
第三个参数
active
设置为
false
即可,不需要用户手动去设置
-1
。
第 2
行,当所有的触摸点坐标都上传完毕以后就得发送
SYN_REPORT
事件。当要编写 Type B
类型的多点触摸驱动的时候就需要按照示例代码
中的时序上报坐标信息。Linux
内核里面有大量的
Type B
类型的多点触摸驱动程序,我们可以参考这些现成的驱动程序来编写自己的驱动代码。这里就以 ili210x
这个触摸驱动
IC
为例,看看是
Type B
类型是如何上报触摸点坐标信息的。找到 ili210x.c
这 个 驱 动 文 件 , 路 径 为 drivers/input/touchscreen/ili210x.c,找到
ili210x_report_events
函数,此函数就是用于上报
ili210x触摸坐标信息的,函数内容如下所示:
78 static void ili210x_report_events(struct input_dev *input,
79 const struct touchdata *touchdata)
80 {
81 int i;
82 bool touch;
83 unsigned int x, y;
84 const struct finger *finger;
85
86 for (i = 0; i < MAX_TOUCHES; i++) {
87 input_mt_slot(input, i);
88
89 finger = &touchdata->finger[i];
90
91 touch = touchdata->status & (1 << i);
92 input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
93 if (touch) {
94 x = finger->x_low | (finger->x_high << 8);
95 y = finger->y_low | (finger->y_high << 8);
96
97 input_report_abs(input, ABS_MT_POSITION_X, x);
98 input_report_abs(input, ABS_MT_POSITION_Y, y);
99 }
100 }
101
102 input_mt_report_pointer_emulation(input, false);
103 input_sync(input);
104 }
第 86~100
行,使用
for
循环实现上报所有的触摸点坐标,第
87
行调用
input_mt_slot
函数
上 报
ABS_MT_SLOT
事件。第
92
行 调 用
input_mt_report_slot_state
函数上报 ABS_MT_TRACKING_ID 事件,也就是给
SLOT
关联一个
ABS_MT_TRACKING_ID
。第
97
和
98
行使用
input_report_abs
函数上报触摸点对应的
(X,Y)
坐标值。
第 103 行,使用 input_sync 函数上报 SYN_REPORT
事件.
2.3 MT 其他事件的使用
在示例代码
中给出了
Linux
所支持的所有
ABS_MT
事件,大家可以根据实际需求
将这些 事 件 组 成 各 种 事 件 组 合 。 最 简 单 的 组 合 就 是
ABS_MT_POSITION_X
和
ABS_MT_POSITION_Y
,可以通过在这两个事件上报触摸点,如果设备支持的话,还可以使用
ABS_MT_TOUCH_MAJOR
和
ABS_MT_WIDTH_MAJOR
这两个消息上报触摸面积信息,关于
其他
ABS_MT
事件的具体含义大家可以查看
Linux
内核中的
multi-touch-protocol.txt
文档,这
里我们重点补充一下
ABS_MT_TOOL_TYPE
事件。
ABS_MT_TOOL_TYPE 事件用于上报触摸工具类型,很多内核驱动都不能区分出触摸设备
类型,是手指还是触摸笔?这种情况下,这个事件可以忽略掉。目前的协议支持
MT_TOOL_FINGER(
手指
)
、
MT_TOOL_PEN(
笔
)
和
MT_TOOL_PALM(
手掌
)
这三种触摸设备类
型 , 于
Type B
类 型 , 此 事 件 由
input
子系统内核处理。如果驱动程序需要上报
ABS_MT_TOOL_TYPE
事件,那么可以使用
input_mt_report_slot_state
函数来完成此工作。
关于
Linux
系统下的多点触摸
(MT)
协议就讲解到这里,简单总结一下,
MT
协议隶属于
linux
的
input
子系统,驱动通过大量的
ABS_MT
事件向
linux
内核上报多点触摸坐标数据。根据触
摸
IC
的不同,分为
TypeA
和
Type B
两种类型,不同的类型其上报时序不同,目前使用最多的
是
Type B
类型。接下来我们就根据前面学习过的
MT
协议来编写一个多点电容触摸驱动程序。
3. 硬件原理分析
触摸屏是和
RGB LCD
屏幕做在一起的,所以触摸屏也在
RGB LCD
接口上,都是连接在 I.MX6U-ALPHA 开发板底板上,原理图如图:

从图
可以看出,触摸屏连接着
I.MX6U
的
I2C2
,INT引脚连接着
I.MX6U
的
GPIO1_IO9
,RST 引脚连接着
I.MX6U
的
SNVS_TAMPER9
。在本章实验中使用中断方式读取触摸点个数和触摸点坐标数据,并且将其显示在 LCD
上。