Linux学习第44天:Linux 多点电容触摸屏实验(二):难忘记第一次牵你手的温存

Linux版本号4.1.15   芯片I.MX6ULL                                    大叔学Linux    品人间百味  思文短情长 


        本章的思维导图内容如下:

二、硬件原理图分析

三、实验程序编写

1、修改设备树

1)、添加FT5426所使用的IO

        一个复位 IO、一个中断 IO、 I2C2 的 SCL 和 SDA。

        检查有没有被占用。

2)、添加FT5426节点

 &i2c2 {
2 clock_frequency = <100000>;
3 pinctrl-names = "default";
4 pinctrl-0 = <&pinctrl_i2c2>;
5 status = "okay";
6 7
/****************************/
8 /* 省略掉其他的设备节点 */
9 /****************************/
10
11 /* zuozhongkai FT5406/FT5426 */
12 ft5426: ft5426@38 {
13 compatible = "edt,edt-ft5426";
14 reg = <0x38>;
15 pinctrl-names = "default";
16 pinctrl-0 = <&pinctrl_tsc
17 &pinctrl_tsc_reset >;
18 interrupt-parent = <&gpio1>;
19 interrupts = <9 0>;
20 reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
21 interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
22 };
23 };

2、编写多点电容触摸驱动

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

        代码挺多的,就不贴了。

四、运行测试

1、编译驱动程序

1 KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imxrel_imx_4.1.15_2.1.0_ga_alientek
......
4 obj-m := ft5x06.o
......
11 clean:
12 $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

2、运行测试

depmod //第一次加载驱动的时候需要运行此命令
modprobe ft5x06.ko //加载驱动模块

        生成eventx触摸文件,触摸屏幕,会看见文件上报信息内容变化。

3、将驱动添加到内核中

1)、将驱动文件放到合适的位置

2)、修改对应的Makefile

        最后一行,添加一行:

obj-y += ft5x06.o

        修改完成以后重新编译 linux 内核,然后用新的 zImage 启动开发板。

hexdump /dev/input/event1 //查看触摸屏原始数据上报信息

        查看上报数据内容,检验触屏驱动正确性。

以下内容将在下节更新:

五、tslib移植与使用

1、tslib移植

1)、获取tslib源码

2)、修改tslib源码所属用户

3)、ubuntu工具安装

4)、编译tslib

5)、配置tslib

6)、tslib测试

六、使用内核自带的驱动

1、修改edt-ft5x06.c

2、使能内核自带的FT5X06驱动

3、修改设备树

七、4.3.寸屏触摸驱动实验

1、修改设备树pinctrl_tsc节点内容

2、在设备树的i2c2节点下添加tgt9147子节点

3、修改设备树的lcdif节点

4、编译GT9147驱动文件

八、总结


本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/175738.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Git本地库操作

对本地库的操作很少&#xff0c;我们学习1~6节即可&#xff0c;其他了解下。我们可以在idea中完成对本地库还有远程库的操作&#xff0c;可视化界面用起来更加舒适而且也不会混淆。 1. Git概述 Git 是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小…

技术为业务赋能:深度剖析开发与业务的紧密结合

技术为业务赋能&#xff1a;深度剖析开发与业务的紧密结合 很多做开发的同学有一种认知&#xff0c;技术最牛&#xff0c;进而忽视了对业务的理解和积累&#xff0c;眼里认为技术和游戏一样&#xff0c;有着层出不穷的新技术&#xff0c;更新迭代的非常快&#xff0c;而业务方…

【考研】数据结构(更新到双链表)

声明&#xff1a;所有代码都可以运行&#xff0c;可以直接粘贴运行&#xff08;只有库函数没有声明&#xff09; 线性表的定义和基本操作 基本操作 定义 静态&#xff1a; #include<stdio.h> #include<stdlib.h>#define MaxSize 10//静态 typedef struct{int d…

NEJM一篇新文为例,聊聊孟德尔随机化研究mr

2019年3月14日&#xff0c;新英格兰医学杂志发表了一篇论著&#xff0c;Mendelian Randomization Study of ACLY and Cardiovascular disease, 即《ACLY和心血管疾病的孟德尔随机化研究》。与小咖在2017年1月9日报道的一篇发表在新英格兰医学的孟德尔随机化研究——精读NEJM&am…

2023年中国工业炉分类、产量及市场规模分析[图]

工业炉是指在工业生产中利用燃料燃烧或电能等转换产生的热量&#xff0c;将物料或工件进行熔炼、熔化、焙&#xff08;煅&#xff09;烧、加热、干馏、气化等的热工设备&#xff1b;广泛应用于机械、冶金、化工及陶瓷等国民经济的各行各业&#xff0c;具有生产效率高、产品质量…

又3本“On Hold”期刊被剔除!这本Elsevier旗下中科院2区TOP仍在调查中!

【SciencePub学术】 此前&#xff0c;继又2本期刊被“On Hold”&#xff01;标识后&#xff0c;仍处于“On Hold”状态的期刊有8本&#xff0c;其中包括4本SCI期刊和4本ESCI期刊。 2023年11月20日&#xff0c;科睿唯安更新了Web of Science核心期刊目录。 本次11月更新共64本期…

向量数据库,展望AGI时代

无论是向量数据库&#xff0c;还是大模型&#xff0c;归根结底&#xff0c;大家在追捧它时的心态&#xff0c;焦虑大于需求。 向量数据库的热潮&#xff0c;在一定程度上“外化”了人们的焦虑。 但这并不能否定向量数据库的实际价值&#xff0c;甚至更长远来看&#xff0c;向…

Vue3实现粒子动态背景

官网&#xff1a; https://particles.js.org/ npm&#xff1a; https://www.npmjs.com/package/particles.vue3 安装 pnpm add particles.vue3 pnpm add tsparticles-slim 引入使用&#xff0c;完整代码 <template><div class"wft-particles-container&quo…

vue超好用的自定义指令封装

一、指令封装 目录结构&#xff1a; index.ts 统一注册 import { App, Directive } from "vue"; import auth from "./modules/auth"; import copy from "./modules/copy"; import waterMarker from "./modules/waterMarker"; impor…

Springboot企业网站 毕业设计-附源码73192

摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&#xff0c;应用软件的工作…

人工智能中的文本分类:技术突破与实战指导

在本文中&#xff0c;我们全面探讨了文本分类技术的发展历程、基本原理、关键技术、深度学习的应用&#xff0c;以及从RNN到Transformer的技术演进。文章详细介绍了各种模型的原理和实战应用&#xff0c;旨在提供对文本分类技术深入理解的全面视角。 关注TechLead&#xff0c;分…

API之 要求接口上传pdf 以 合同PDF的二进制数据,multpart方式上传

实现 //时间戳13位毫秒private function getMillisecond() {list($s1,$s2) explode( ,microtime());return (float)sprintf(%.0f,(floatval($s1) floatval($s2)) * 1000);}// 组装参数private function gysscPost1($url,$data){// $data[timestamp] 1694402111964;$data[tim…

主播产品话术

以电子产品为例 一、产品特点 1.高效性能:这款产品采用了最先进的技术&#xff0c;确保高效运行&#xff0c;让你的工作更加流畅。 2.便捷操作:设计简洁&#xff0c;操作方便&#xff0c;即使是不熟悉电子产品的人也能轻松上手。 3.时尚外观:多种颜色可选&#xff0c;满足你…

2023年中国离心制冷机产量及产业链分析[图]

离心制冷机是一种常用的空调制冷设备&#xff0c;目前主要应用于酒店、写字楼、商场、学校等众多大型场所的集中制冷场景。离心制冷机由离心式制冷压缩机、蒸发器、冷凝器、主电动机、抽气回收装置、润滑系统、控制柜和起动柜等零部件组成。这些零部件的组成有的采用分散型组装…

不看后悔系列 | 秒做BI报表,告别低效分析

根据经验来看&#xff0c;做企业数据分析&#xff0c;通常是由业务提出需求&#xff0c;交给IT去取数开发&#xff0c;当业务通过分析报表有了新的需求时&#xff0c;仍需交给IT去取数分析&#xff0c;这就导致业务的分析效率低。进入大数据时代&#xff0c;这样的低效数据分析…

wpf使用CefSharp.OffScreen模拟网页登录,并获取身份cookie

目录 框架信息&#xff1a;MainWindow.xamlMainWindow.xaml.cs爬取逻辑模拟登录拦截请求Cookie获取 CookieVisitorHandle 框架信息&#xff1a; CefSharp.OffScreen.NETCore 119.1.20 MainWindow.xaml <Window x:Class"Wpf_CHZC_Img_Identy_ApiDataGet.MainWindow&qu…

ASM字节码操作类库(打开java语言世界通往字节码世界的大门) | 京东云技术团队

前言&#xff1a;授人以鱼不如授人以渔&#xff0c;应用asm的文章有很多&#xff0c;简单demo的也很多&#xff0c;那么ASM都具备哪些能力呢&#xff1f;如何去学习编写ASM代码呢&#xff1f;什么样的情景需要用到ASM呢&#xff1f;让我们带着这些问题阅读这篇文章吧。 这里由…

功率放大器在无线收发系统中的作用

功率放大器在无线收发系统中也扮演着至关重要的角色。无线通信是一种通过电磁波传输信息的技术&#xff0c;它具有便捷、灵活、广覆盖等优势&#xff0c;在现代社会得到了广泛应用。而功率放大器则是无线收发系统中的核心组件之一&#xff0c;主要用于增强信号的功率和距离。下…

paramiko STELNET登陆设备

实验目的&#xff1a; 公司有一台CE12800的设备&#xff0c;管理地址位172.16.1.2&#xff0c;现在需要编写自动化脚本&#xff0c;通过ssh登陆到设备上并进行简单的信息查看。 实验拓扑&#xff1a; 实验步骤&#xff1a; 步骤1&#xff1a;将本地电脑和ensp的设备进行桥接…