11. input子系统:触摸屏

在上节内容中,已经讲解到了如何使用input输入子系统读取按键值, 触摸屏也是属于input输入子系统的设备,关于input输入子系统 的内容请参考 input子系统:按键检测

11.1. 电容触摸屏

11.1.1. 使能电容触摸屏相关设备树插件

野火IMX8M提供了很多的设备树插件,用于控制板子上外设的开启,首先我们先需要开启触摸屏相关的设备树插件。修改 /boot/uEnv.txt 文件内容, 使能触摸屏设备树相关插件内容,并且重启。

如果是20240912之前的镜像,仅支持野火5.5寸mipi屏幕,因为HDMI是通过mipi转的,开启mipi屏幕的时候需要关闭HDMI插件,然后开启触摸和mipi设备树插件:

/boot/uEnv.txt
1
2
3
4
5
6
#注释掉HDMI设备树插件
#dtoverlay=/usr/lib/linux-image-5.4.47-imx8mm/freescale/overlays/imx8mm-fire-hdmi.dtbo

#开启触摸和mipi设备树插件
dtoverlay=/usr/lib/linux-image-5.4.47-imx8mm/freescale/overlays/imx8mm-fire-touch-capacitive-goodix.dtbo
dtoverlay=/usr/lib/linux-image-5.4.47-imx8mm/freescale/overlays/imx8mm-fire-mipi-hx8399.dtbo

如果是20240912及以后的镜像,支持野火5.5、7、10.1寸mipi屏幕,因为HDMI是通过mipi转的,开启mipi屏幕的时候需要关闭HDMI插件,然后开启mipi设备树插件(显示和触摸已经写到同一个设备树插件):

/boot/uEnv.txt
1
2
3
4
5
6
7
#注释掉HDMI设备树插件
#dtoverlay=/usr/lib/linux-image-5.4.47-imx8mm/freescale/overlays/imx8mm-fire-hdmi.dtbo

#根据连接的屏幕开启以下其中一个插件,以5.5寸mipi屏幕为例
dtoverlay=/usr/lib/linux-image-5.4.47-imx8mm/freescale/overlays/imx8mm-fire-5.5-mipi-hx8399.dtbo
#dtoverlay=/usr/lib/linux-image-5.4.47-imx8mm/freescale/overlays/imx8mm-fire-7-mipi-ek79007.dtbo
#dtoverlay=/usr/lib/linux-image-5.4.47-imx8mm/freescale/overlays/imx8mm-fire-10.1-mipi-ili9881c.dtbo

查看 /dev/input 以及 /dev/input/by-path 目录下的内容:

1
2
3
4
5
6
7
8
9
 root@lubancat:~# ls -l /dev/input
 总用量 0
 drwxr-xr-x 2 root root      80  6月 18 22:55 by-path
 crw-rw---- 1 root input 13, 64  6月 18 22:55 event0
 crw-rw---- 1 root input 13, 65  6月 18 22:55 event1
 root@lubancat:~# ls -l /dev/input/by-path/
 总用量 0
 lrwxrwxrwx 1 root root 9  6月 18 22:55 platform-30370000.snvs:snvs-powerkey-event -> ../event0
 lrwxrwxrwx 1 root root 9  6月 18 22:55 platform-30a40000.i2c-event -> ../event1

从以上输出可知,event0是ONOFF按键,event1对应屏幕i2c触摸,不同板子情况可能不同。

11.1.2. 使用evtest测试屏幕

通过以下命令下载evtest工具

1
 sudo apt install evtest

在终端上执行evtest命令并选择触摸屏进行测试。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 root@lubancat:~# evtest
 No device specified, trying to scan all of /dev/input/event*
 Available devices:
 /dev/input/event0:      30370000.snvs:snvs-powerkey
 /dev/input/event1:      Goodix Capacitive TouchScreen
 Select the device event number [0-1]: 1
 Input driver version is 1.0.1
 Input device ID: bus 0x18 vendor 0x416 product 0x38f version 0x1060
 Input device name: "Goodix Capacitive TouchScreen"
 Supported events:
 Event type 0 (EV_SYN)
 Event type 1 (EV_KEY)
     Event code 125 (KEY_LEFTMETA)
     Event code 330 (BTN_TOUCH)
 Event type 3 (EV_ABS)
     Event code 0 (ABS_X)
     Value      0
     Min        0
     Max     1079
     Event code 1 (ABS_Y)
     Value      0
     Min        0
     Max     1919
     Event code 47 (ABS_MT_SLOT)
     Value      0
     Min        0
     Max        4
     Event code 48 (ABS_MT_TOUCH_MAJOR)
     Value      0
     Min        0
     Max      255
     Event code 50 (ABS_MT_WIDTH_MAJOR)
     Value      0
     Min        0
     Max      255
     Event code 53 (ABS_MT_POSITION_X)
     Value      0
     Min        0
     Max     1079
     Event code 54 (ABS_MT_POSITION_Y)
     Value      0
     Min        0
     Max     1919
     Event code 57 (ABS_MT_TRACKING_ID)
     Value      0
     Min        0
     Max    65535
 Properties:
 Property type 1 (INPUT_PROP_DIRECT)
 Testing ... (interrupt to exit)
 Event: time 1702197058.929675, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 0
 Event: time 1702197058.929675, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 442
 Event: time 1702197058.929675, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 1110
 Event: time 1702197058.929675, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 48
 Event: time 1702197058.929675, type 3 (EV_ABS), code 50 (ABS_MT_WIDTH_MAJOR), value 48
 Event: time 1702197058.929675, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
 Event: time 1702197058.929675, type 3 (EV_ABS), code 0 (ABS_X), value 442
 Event: time 1702197058.929675, type 3 (EV_ABS), code 1 (ABS_Y), value 1110
 Event: time 1702197058.929675, -------------- SYN_REPORT ------------
 Event: time 1702197059.077347, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 444
 Event: time 1702197059.077347, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 1111
 Event: time 1702197059.077347, type 3 (EV_ABS), code 0 (ABS_X), value 444
 Event: time 1702197059.077347, type 3 (EV_ABS), code 1 (ABS_Y), value 1111
 Event: time 1702197059.077347, -------------- SYN_REPORT ------------

根据以上信息即可知道当触摸屏幕时有什么事件产生。

11.1.3. 编写应用程序

触摸屏检测相关的应用程序与按键检测的应用程序类似,如下所示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>

 #include <linux/input.h>
 #include <linux/input-event-codes.h>

 #include <unistd.h>

 #define  default_path "/dev/input/event1"

 int  main(int argc,char * argv[])
 {
     int fd;
     int ret;
     char * path;
     struct input_event event;

     int x,y;

     if (argc == 2)
     {
         path = argv[1];
     }
     else
     {
         path = default_path;
     }

     //打开设备
     fd = open(path,O_RDONLY);
     if(fd < 0)
     {
         perror(path);
         exit(-1);
     }

     while (1)
     {
         memset(&event, 0, sizeof(struct input_event));
         //读取按键值
         ret = read(fd,&event,sizeof(struct input_event));

         if (ret == sizeof(struct input_event))
         {
             //触发事件类似判断
             if(event.type == EV_ABS)
             {
                 //X、Y轴坐标
                 if(event.code == ABS_X)
                     x = event.value;
                 else if(event.code == ABS_Y)
                     y = event.value;
             }
             //打印坐标
             if(event.type == EV_SYN)    //EV_SYN
             {
                 printf("touch x = %d,y = %d\n", x, y);
             }
         }
     }
     close(fd);
     return 0;
 }

通过以下命令在开发板上编译

1
gcc -o touch touch.c

运行程序后,点击触摸屏将不断打印坐标信息。

11.1.4. 使用libts工具重新校准电容屏

电容屏是不需要重新校准的,读取出来的原始数据就是坐标值了, libts是一种实用的触摸工具,能够用于触摸屏的校准,将触摸位置与屏幕显示位置统一起来。

通过以下命令下载libts-bin工具

1
sudo apt install libts-bin

使用以下命令进行屏幕校准,执行以下两条命令之后,显示屏将会显示需要点击的位置, 依次点击完成后完成屏幕

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
 #设置环境变量,并将/dev/input/event1替换为自己的触摸输入设备
 export TSLIB_TSDEVICE=/dev/input/event1  #这条命令建议手打

 #进行屏幕校准
 ts_calibrate

 #终端打印消息
 root@lubancat:/# ts_calibrate
 xres = 1080, yres = 1920
 Took 1 samples...
 Top left : X =   44 Y =   43
 Took 1 samples...
 Top right : X = 1060 Y =   54
 Took 1 samples...
 Bot right : X = 1057 Y = 1896
 Took 1 samples...
 Bot left : X =   15 Y = 1898
 Took 1 samples...
 Center : X =  560 Y =  964
 11.004611 0.952012 0.008295
 6.290519 -0.004122 0.984516
 Calibration constants: 721198 62391 543 412255 -270 64521 65536

提示

重新执行ts_calibrate能够对屏幕进行再次校准。

执行ts_print命令后触摸触摸屏将会打印出相对应的坐标,如下所示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 root@lubancat:/# ts_print
 1702256579.519596:    533   1450    255
 1702256579.699112:    533   1450      0
 1702256580.806891:    292   1144    255
 1702256581.156257:    292   1144      0
 1702256582.008168:    236   1662    255
 1702256582.633285:    236   1662      0
 1702256583.238694:    626   1044    255
 1702256583.367507:    626   1044      0
 1702256583.867282:    537   1619    255
 1702256583.950065:    537   1619      0

关于libts工具使用的详细说明可参考以下链接: https://github.com/libts/tslib

11.1.5. 触摸屏相关设备树插件

野火IMX8M提供了很多的设备树插件源码,若想要修改触摸屏设备树插件, 可参考:

其中触摸屏的设备树插件为 imx8mm-fire-touch-capacitive-goodix-overlay.dts ,源码如下所示

/arch/arm64/boot/dts/freescale/overlays/imx8mm-fire-touch-capacitive-goodix-overlay.dts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 /dts-v1/;
 /plugin/;

 #include "../imx8mm-pinfunc.h"
 #include "dt-bindings/gpio/gpio.h"
 #include "dt-bindings/interrupt-controller/arm-gic.h"

 / {
         fragment@0 {
                 target = <&i2c3>;
                 __overlay__ {
                         clock-frequency = <100000>;
                         pinctrl-names = "default";
                         pinctrl-0 = <&pinctrl_i2c3>;
                         status = "okay";

                         #address-cells = <1>;
                         #size-cells = <0>;

                         gtxx_tsc@5d {
                                 compatible = "goodix,gt911";
                                 pinctrl-names = "default";
                                 pinctrl-0 = <&pinctrl_tsc>;
                                 reg = <0x5d>;
                                 status = "okay";

                                 reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
                                 irq-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
                                 interrupt-parent = <&gpio1>;
                                 interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
                                 touchscreen-inverted-x = <1>;
                                 touchscreen-inverted-y = <1>;
                         };
                 };
         };

         fragment@1 {
                 target= <&iomuxc>;
                 __overlay__{
                         pinctrl_i2c3: i2c3grp {
                                 fsl,pins = <
                                         MX8MM_IOMUXC_I2C3_SCL_I2C3_SCL                  0x400001c3
                                         MX8MM_IOMUXC_I2C3_SDA_I2C3_SDA                  0x400001c3
                                 >;
                         };

                         pinctrl_tsc: tscgrp {
                                 fsl,pins = <
                                         MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23               0x149
                                         MX8MM_IOMUXC_GPIO1_IO09_GPIO1_IO9               0x1d6
                                 >;
                         };
                 };
         };
 };

若想修改触摸屏控制芯片相关引脚,仅需要修改以上高亮部分代码即可。