千家信息网

Linux下电容触摸屏程序编写方法是什么

发表于:2025-01-27 作者:千家信息网编辑
千家信息网最后更新 2025年01月27日,这篇文章主要介绍"Linux下电容触摸屏程序编写方法是什么",在日常操作中,相信很多人在Linux下电容触摸屏程序编写方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家
千家信息网最后更新 2025年01月27日Linux下电容触摸屏程序编写方法是什么

这篇文章主要介绍"Linux下电容触摸屏程序编写方法是什么",在日常操作中,相信很多人在Linux下电容触摸屏程序编写方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Linux下电容触摸屏程序编写方法是什么"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

54.2 硬件原理图
在本实验中使用迅为的 7 寸屏为例,使用的是 FT5426 触摸芯片。

从原理图中得知,7 寸屏使用 I2C2,触摸屏复位引脚为 SNVS_TAMPER9,中断引脚为 GPIO_9。

54.3 实验程序编写
54.3.1 修改设备树文件
1 、添加 FT5426 的 的 pinctrl 信息
FT5426 触摸芯片用到了 4 个 IO,一个复位 IO、一个中断 IO、I2C2 的 SCL 和 SDA,所以我们需要先在设备树中添加 IO 相关的信息。复位 IO 和中断 IO 是普通的 GPIO,因此这两个 IO 可以放到同一个节点下去描述,I2C2 的 SCL 和 SDA 属于 I2C2,因此这两个要放到同一个节点下去描述。首先是复位 IO 和中断 IO,topeet_emmc_4_3.dts 文件里面默认有个名为"pinctrl_tsc"的节点,如果被删除了的话就自行创建,在此节点下添加触摸屏的复位 IO 和中断 IO 信息,修改以后的"pinctrl_tsc"节点内容如下所示:
1 pinctrl_tsc: tscgrp {
2 fsl,pins = <
3 MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x10B0 /* TSC_RST */
4 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0xF080 /* TSC_INT */
5 >;
6 };
继续添加 I2C2 的 SCL 和 SDA 这两个 IO 信息,topeet_emmc_4_3.dts 里面默认就已经添加了 I2C2的 IO 信息,这是 NXP 官方添加的,所以不需要我们去修改。找到"pinctrl_i2c1"节点,此节点就是用于描述 I2C2 的 IO 信息,节点内容如下所示:
1 pinctrl_i2c2: i2c2grp {
2 fsl,pins = <
3 MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
4 MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
5 >;
6 };
最后在检查一下这四个引脚有没有被其他外设使用。如果有的话就需要屏蔽掉。

2 、添加 FT5426 节点
FT5426 这个触摸 IC 挂载 I2C2 下,因此需要向 I2C2 节点下添加一个子节点,此子节点用于描述FT5426,添加完成以后的 I2C2 节点内容如下所示:
1 &i2c2 {
2 clock_frequency = <100000>;
3 pinctrl-names = "default";
4 pinctrl-0 = <&pinctrl_i2c2>;
5 status = "okay";
6
7 /****************************/
8 /* 省略掉其他的设备节点 */
9 /****************************/
10
11
12 ft5426: ft5426@38 {
13 compatible = "edt,edt-ft5426";
14 reg = <0x38>;
15 pinctrl-names = "default";
16 pinctrl-0 = <&pinctrl_tsc>;
17 interrupt-parent = <&gpio1>;
18 interrupts = <9 0>;
19 reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
20 interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
21 };
22 };
第 12 行,触摸屏所使用的 FT5426 芯片节点,挂载 I2C2 节点下,FT5426 的器件地址为 0X38。
第 14 行,reg 属性描述 FT5426 的器件地址为 0x38。
第 16 行,pinctrl-0 属性描述 FT5426 的复位 IO 和中断 IO 所使用的节点为 pinctrl_tsc。
第 17 行,interrupt-parent 属性描述中断 IO 对应的 GPIO 组为 GPIO1。
第 18 行,interrupts 属性描述中断 IO 对应的是 GPIO1 组的 IOI09。
第 19 行,reset-gpios 属性描述复位 IO 对应的 GPIO 为 GPIO5_IO09。
第 20 行,interrupt-gpios 属性描述中断 IO 对应的 GPIO 为 GPIO1_IO09。

54.3.2 编写多点电容触摸驱动
本实验例程路径:i.MX6UL 终结者光盘资料/06_Linux 驱动例程/20_multitouch
创建 ft5426.c 驱动文件,内容如下:
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16
17 #define MAX_SUPPORT_POINTS 5 /* 5 点触摸 */
18 #define TOUCH_EVENT_DOWN 0x00 /* 按下 */
19 #define TOUCH_EVENT_UP 0x01 /* 抬起 */
20 #define TOUCH_EVENT_ON 0x02 /* 接触 */
21 #define TOUCH_EVENT_RESERVED 0x03 /* 保留 */
22
23 /* FT5X06 寄存器相关宏定义 */
24 #define FT5X06_TD_STATUS_REG 0X02 /* 状态寄存器地址 */
25 #define FT5x06_DEVICE_MODE_REG 0X00 /* 模式寄存器 */
26 #define FT5426_IDG_MODE_R 0XA4 /* 中断模式 */
27 #define FT5X06_READLEN 29 /* 要读取的寄存器个数 */
28
29 struct ft5x06_dev {
30 struct device_node *nd; /* 设备节点 */
31 int irq_pin,reset_pin; /* 中断和复位 IO */
32 int irqnum; /* 中断号 */
33 void *private_data; /* 私有数据 */
34 struct input_dev *input; /* input 结构体 */
35 struct i2c_client *client; /* I2C 客户端 */
36 };
37
38 static struct ft5x06_dev ft5x06;
39
40 /*
41 * @description : 复位 FT5X06
42 * @param - client : 要操作的 i2c
43 * @param - multidev: 自定义的 multitouch 设备
44 * @return : 0,成功;其他负值,失败
45 */
46 static int ft5x06_ts_reset(struct i2c_client *client, struct ft5x06_dev *dev)
47 {
48 int ret = 0;
49
50 if (gpio_is_valid(dev->reset_pin)) { /* 检查 IO 是否有效 */
51 /* 申请复位 IO,并且默认输出低电平 */
52 ret = devm_gpio_request_one(&client->dev,
53 dev->reset_pin, GPIOF_OUT_INIT_LOW,
54 "edt-ft5x06 reset");
55 if (ret) {
56 return ret;
57 }
58
59 msleep(5);
60 gpio_set_value(dev->reset_pin, 1); /* 输出高电平,停止复位 */
61 msleep(300);
62 }
63
64 return 0;
65 }
66
67 /*
68 * @description : 从 FT5X06 读取多个寄存器数据
69 * @param - dev: ft5x06 设备
70 * @param - reg: 要读取的寄存器首地址
71 * @param - val: 读取到的数据
72 * @param - len: 要读取的数据长度
73 * @return : 操作结果
74 */
75 static int ft5x06_read_regs(struct ft5x06_dev *dev, u8 reg, void *val, int len)
76 {
77 int ret;
78 struct i2c_msg msg[2];
79 struct i2c_client *client = (struct i2c_client *)dev->client;
80
81 /* msg[0]为发送要读取的首地址 */
82 msg[0].addr = client->addr; /* ft5x06 地址 */
83 msg[0].flags = 0; /* 标记为发送数据 */
84 msg[0].buf = ® /* 读取的首地址 */
85 msg[0].len = 1; /* reg 长度*/
86
87 /* msg[1]读取数据 */
88 msg[1].addr = client->addr; /* ft5x06 地址 */
89 msg[1].flags = I2C_M_RD; /* 标记为读取数据*/
90 msg[1].buf = val; /* 读取数据缓冲区 */
91 msg[1].len = len; /* 要读取的数据长度*/
92
93 ret = i2c_transfer(client->adapter, msg, 2);
94 if(ret == 2) {
95 ret = 0;
96 } else {
97 ret = -EREMOTEIO;
98 }
99 return ret;
100 }
101
102 /*
103 * @description : 向 ft5x06 多个寄存器写入数据
104 * @param - dev: ft5x06 设备
105 * @param - reg: 要写入的寄存器首地址
106 * @param - val: 要写入的数据缓冲区
107 * @param - len: 要写入的数据长度
108 * @return : 操作结果
109 */
110 static s32 ft5x06_write_regs(struct ft5x06_dev *dev, u8 reg, u8 *buf, u8 len)
111 {
112 u8 b[256];
113 struct i2c_msg msg;
114 struct i2c_client *client = (struct i2c_client *)dev->client;
115
116 b[0] = reg; /* 寄存器首地址 */
117 memcpy(&b[1],buf,len); /* 将要写入的数据拷贝到数组 b 里面 */
118
119 msg.addr = client->addr; /* ft5x06 地址 */
120 msg.flags = 0; /* 标记为写数据 */
121
122 msg.buf = b; /* 要写入的数据缓冲区 */
123 msg.len = len + 1; /* 要写入的数据长度 */
124
125 return i2c_transfer(client->adapter, &msg, 1);
126 }
127
128 /*
129 * @description : 向 ft5x06 指定寄存器写入指定的值,写一个寄存器
130 * @param - dev: ft5x06 设备
131 * @param - reg: 要写的寄存器
132 * @param - data: 要写入的值
133 * @return : 无
134 */
135 static void ft5x06_write_reg(struct ft5x06_dev *dev, u8 reg, u8 data)
136 {
137 u8 buf = 0;
138 buf = data;
139 ft5x06_write_regs(dev, reg, &buf, 1);
140 }
141
142 /*
143 * @description : FT5X06 中断服务函数
144 * @param - irq : 中断号
145 * @param - dev_id : 设备结构。
146 * @return : 中断执行结果
147 */
148 static irqreturn_t ft5x06_handler(int irq, void *dev_id)
149 {
150 struct ft5x06_dev *multidata = dev_id;
151
152 u8 rdbuf[29];
153 int i, type, x, y, id;
154 int offset, tplen;
155 int ret;
156 bool down;
157
158 offset = 1; /* 偏移 1,也就是 0X02+1=0x03,从 0X03 开始是触摸值 */
159 tplen = 6; /* 一个触摸点有 6 个寄存器来保存触摸值 */
160
161 memset(rdbuf, 0, sizeof(rdbuf)); /* 清除 */
162
163 /* 读取 FT5X06 触摸点坐标从 0X02 寄存器开始,连续读取 29 个寄存器 */
164 ret = ft5x06_read_regs(multidata, FT5X06_TD_STATUS_REG,
rdbuf, FT5X06_READLEN);
165 if (ret) {
166 goto fail;
167 }
168
169 /* 上报每一个触摸点坐标 */
170 for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
171 u8 *buf = &rdbuf[i * tplen + offset];
172
173 /* 以第一个触摸点为例,寄存器 TOUCH1_XH(地址 0X03),各位描述如下:
174 * bit7:6 Event flag 0:按下 1:释放 2:接触 3:没有事件
175 * bit5:4 保留
176 * bit3:0 X 轴触摸点的 11~8 位。
177 */
178 type = buf[0] >> 6; /* 获取触摸类型 */
179 if (type == TOUCH_EVENT_RESERVED)
180 continue;
181
182 /* 我们所使用的触摸屏和 FT5X06 是反过来的 */
183 x = ((buf[2] << 8) | buf[3]) & 0x0fff;
184 y = ((buf[0] << 8) | buf[1]) & 0x0fff;
185
186 /* 以第一个触摸点为例,寄存器 TOUCH1_YH(地址 0X05),各位描述如下:
187 * bit7:4 Touch ID 触摸 ID,表示是哪个触摸点
188 * bit3:0 Y 轴触摸点的 11~8 位。
189 */
190 id = (buf[2] >> 4) & 0x0f;
191 down = type != TOUCH_EVENT_UP;
192
193 input_mt_slot(multidata->input, id);
194 input_mt_report_slot_state(multidata->input, MT_TOOL_FINGER, down);
195
196 if (!down)
197 continue;
198
199 input_report_abs(multidata->input, ABS_MT_POSITION_X, x);
200 input_report_abs(multidata->input, ABS_MT_POSITION_Y, y);
201 }
202
203 input_mt_report_pointer_emulation(multidata->input, true);
204 input_sync(multidata->input);
205
206 fail:
207 return IRQ_HANDLED;
208
209 }
210
211 /*
212 * @description : FT5x06 中断初始化
213 * @param - client : 要操作的 i2c
214 * @param - multidev: 自定义的 multitouch 设备
215 * @return : 0,成功;其他负值,失败
216 */
217 static int ft5x06_ts_irq(struct i2c_client *client, struct ft5x06_dev *dev)
218 {
219 int ret = 0;
220
221 /* 1,申请中断 GPIO */
222 if (gpio_is_valid(dev->irq_pin)) {
223 ret = devm_gpio_request_one(&client->dev, dev->irq_pin,
224 GPIOF_IN, "edt-ft5x06 irq");
225 if (ret) {
226 dev_err(&client->dev,
227 "Failed to request GPIO %d, error %d\n",
228 dev->irq_pin, ret);
229 return ret;
230 }
231 }
232
233 /* 2,申请中断,client->irq 就是 IO 中断, */
234 ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
235 ft5x06_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
236 client->name, &ft5x06);
237 if (ret) {
238 dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
239 return ret;
240 }
241
242 return 0;
243 }
244
245 /*
246 * @description : i2c 驱动的 probe 函数,当驱动与
247 * 设备匹配以后此函数就会执行
248 * @param - client : i2c 设备
249 * @param - id : i2c 设备 ID
250 * @return : 0,成功;其他负值,失败
251 */
252 static int ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
253 {
254 int ret = 0;
255
256 ft5x06.client = client;
257
258 /* 1,获取设备树中的中断和复位引脚 */
259 ft5x06.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);
260 ft5x06.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
261
262 /* 2,复位 FT5x06 */
263 ret = ft5x06_ts_reset(client, &ft5x06);
264 if(ret < 0) {
265 goto fail;
266 }
267
268 /* 3,初始化中断 */
269 ret = ft5x06_ts_irq(client, &ft5x06);
270 if(ret < 0) {
271 goto fail;
272 }
273
274 /* 4,初始化 FT5X06 */
275 ft5x06_write_reg(&ft5x06, FT5x06_DEVICE_MODE_REG, 0); /* 进入正常模式*/
276 ft5x06_write_reg(&ft5x06, FT5426_IDG_MODE_REG, 1); /* FT5426 中断模式 */
277
278 /* 5,input 设备注册 */
279 ft5x06.input = devm_input_allocate_device(&client->dev);
280 if (!ft5x06.input) {
281 ret = -ENOMEM;
282 goto fail;
283 }
284 ft5x06.input->name = client->name;
285 ft5x06.input->id.bustype = BUS_I2C;
286 ft5x06.input->dev.parent = &client->dev;
287
288 __set_bit(EV_KEY, ft5x06.input->evbit);
289 __set_bit(EV_ABS, ft5x06.input->evbit);
290 __set_bit(BTN_TOUCH, ft5x06.input->keybit);
291
292 input_set_abs_params(ft5x06.input, ABS_X, 0, 1024, 0, 0);
293 input_set_abs_params(ft5x06.input, ABS_Y, 0, 600, 0, 0);
294 input_set_abs_params(ft5x06.input, ABS_MT_POSITION_X,0, 1024, 0, 0);
295 input_set_abs_params(ft5x06.input, ABS_MT_POSITION_Y,0, 600, 0, 0);
296 ret = input_mt_init_slots(ft5x06.input, MAX_SUPPORT_POINTS, 0);
297 if (ret) {
298 goto fail;
299 }
300
301 ret = input_register_device(ft5x06.input);
302 if (ret)
303 goto fail;
304
305 return 0;
306
307 fail:
308 return ret;
309 }
310
311 /*
312 * @description : i2c 驱动的 remove 函数,移除 i2c 驱动的时候此函数会执行
313 * @param - client : i2c 设备
314 * @return : 0,成功;其他负值,失败
315 */
316 static int ft5x06_ts_remove(struct i2c_client *client)
317 {
318 /* 释放 input_dev */
319 input_unregister_device(ft5x06.input);
320 return 0;
321 }
322
323
324 /*
325 * 传统驱动匹配表
326 */
327 static const struct i2c_device_id ft5x06_ts_id[] = {
328 { "edt-ft5206", 0, },
329 { "edt-ft5426", 0, },
330 { /* sentinel */ }
331 };
332
333 /*
334 * 设备树匹配表
335 */
336 static const struct of_device_id ft5x06_of_match[] = {
337 { .compatible = "edt,edt-ft5206", },
338 { .compatible = "edt,edt-ft5426", },
339 { /* sentinel */ }
340 };
341
342 /* i2c 驱动结构体 */
343 static struct i2c_driver ft5x06_ts_driver = {
344 .driver = {
345 .owner = THIS_MODULE,
346 .name = "edt_ft5x06",
347 .of_match_table = of_match_ptr(ft5x06_of_match),
348 },
349 .id_table = ft5x06_ts_id,
350 .probe = ft5x06_ts_probe,
351 .remove = ft5x06_ts_remove,
352 };
353
354 /*
355 * @description : 驱动入口函数
356 * @param : 无
357 * @return : 无
358 */
359 static int __init ft5x06_init(void)
360 {
361 int ret = 0;
362
363 ret = i2c_add_driver(&ft5x06_ts_driver);
364
365 return ret;
366 }
367
368 /*
369 * @description : 驱动出口函数
370 * @param : 无
371 * @return : 无
372 */
373 static void __exit ft5x06_exit(void)
374 {
375 i2c_del_driver(&ft5x06_ts_driver);
376 }
377
378 module_init(ft5x06_init);
379 module_exit(ft5x06_exit);
380 MODULE_LICENSE("GPL");
381 MODULE_AUTHOR("topeet");
第 29~36 行,定义一个设备结构体,存放多点电容触摸设备相关属性信息。
第 38 行,定义一个名为 ft5x06 的全局变量,变量类型就是上面定义的 ft5x06_dev 结构体。
第 46~63 行,ft5x06_ts_reset 函数,用于初始化 FT5426 触摸芯片,其实就是设置 FT5426 的复位 IO为高电平,防止芯片复位。注意在第 52 行使用 devm_gpio_request_one 函数来申请复位 IO,关于"devm_"前缀的作用已经在前面做了详细的讲解。使用"devm_"前缀的 API 函数申请的资源不需要我们手动释放,内核会处理,所以这里使用 devm_gpio_request_one 函数申请 IO 以后不需要我们在卸载驱动的时候手动去释放此 IO。
第 73~98 行,ft5x06_read_regs 函数,用于连续的读取 FT5426 内部寄存器数据,就是 I2C 读取函数。
第 98~124 行,ft5x06_write_regs 函数,用于向 FT5426 寄存器写入连续的数据,也就是 I2C 写函数。
第 133~138 行,ft5x06_write_reg 函数,对 ft5x06_write_regs 函数的简单封装,向 FT5426 指定寄存器写入一个数据,用于配置 FT5426。
第 146~207 行,ft5x06_handler 函数,触摸屏中断服务函数,触摸点坐标的上报就是在此函数中完成的。第 162 行通过 ft5x06_read_regs 函数读取 FT5426 的所有触摸点信息寄存器数据,从 0X02 这个地址开始,一共 29 个寄存器。第 168~199 行的 for 循环就是一个一个的上报触摸点坐标数据,使用 Type B
时序,这个我们已经在前面说了很多次了。最后在 202 行通过 input_sync 函数上报 SYN_REPORT 事件。如果理解了前面讲解的 Type B 时序,那么此函数就很好看懂。
第 215~241 行 , ft5x06_ts_irq 函数,初始化 FT5426 的中断 IO ,第 221 行使用devm_gpio_request_one 函数申请中断 IO。第 232 行使用函数 devm_request_threaded_irq 申请中断,中断处理函数为 ft5x06_handler。
第 250~307 行,当 I2C 设备与驱动匹配以后此函数就会执行,一般在此函数中完成一些初始化工作。我们重点来看一下 277~299 行是关于 input_dev 设备的初始化,第 277~284 行申请并简单的初始化input_dev。第 286 和 288 行设置 input_dev 需要上报的事件为 EV_KEY 和 EV_ABS,需要上报的按键码为BTN_TOUCH。EV_KEY 是按键事件,用于上报触摸屏是否被按下,相当于把触摸屏当做一个按键。EV_ABS 是触摸点坐标数据,BTN_TOUCH 表示将触摸屏的按下和抬起用作 BTN_TOUCH 按键。第 290~293 行调用input_set_abs_params 函 数 设 置 EV_ABS 事 件 需 要 上 报 ABS_X 、 ABS_Y 、 ABS_MT_POSITION_X 和ABS_MT_POSITION_Y。单点触摸需要上报 ABS_X 和 ABS_Y,对于多点触摸需要上报 ABS_MT_POSITION_X 和
ABS_MT_POSITION_Y。第 294 行调用 input_mt_init_slots 函数初始化 slots,也就是最大触摸点数量,FT5426是个 5 点电容触摸芯片,因此一共 5 个 slot。最后在 299 行调用 input_register_device 函数向系统注册input_dev。
第 314~319 行,当卸载驱动的时候 ft5x06_ts_remove 函数就会执行,因为前面很多资源我们都是用"devm_"前缀函数来申请的,因此不需要手动释放。此函数只需要调用 input_unregister_device 来释放掉前面添加到内核中的 input_dev。
第 320 行~结束,剩下的就是 I2C 驱动框架那一套。

到此,关于"Linux下电容触摸屏程序编写方法是什么"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

函数 寄存器 数据 设备 节点 驱动 地址 触摸屏 信息 就是 电容 属性 芯片 方法 程序 坐标 结构 长度 成功 事件 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 给电脑安装一个数据库 闵行区电话数据库销售优点 东川区品牌软件开发市场价 数据库iphone怎么看 互联网科技精彩剪辑 河北厨芯网络技术有限公司 软件开发公司的员工辞职申请书 迷你世界炸了服务器的证据 深圳市网络安全技术有限公司 大数据软件开发简介 sql数据库使用步骤 davide数据库 数据库外键语法 奇虎360网络安全运维 赣网杯网络安全大赛颁奖 无锡健鼎软件开发工程师 win7访问xp服务器 国外数据库学习 陕西省爱易网络技术有限公司 数据库中时间相减的 地下城为什么进不了自己的服务器 查看数据库表格的软件 衡阳真友软件开发有限公司 手机突然显示服务器异常 通信行业 网络安全法 长春智能网络技术咨询诚信经营 数据库加载图片速度慢怎么解决 用浏览器刷新大话2服务器列表 江苏网络安全和信息化协会 星耀网络技术有限公司怎么样
0