Linux 多点电容触摸屏实验(1)

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 上。

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值