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驱动文件

八、总结


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

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Cloud学习(十一)【深入Elasticsearch 分布式搜索引擎03】

文章目录 数据聚合聚合的种类DSL实现聚合RestAPI实现聚合 自动补全拼音分词器自定义分词器自动补全查询completion suggester查询RestAPI实现自动补全 数据同步数据同步思路分析实现elasticsearch与数据库数据同步 集群搭建ES集群创建es集群集群状态监控创建索引库1&#xff09…

[autojs]autojs开关按钮的简单使用

"ui"; ui.layout(<vertical><Switch id"autoService" text"无障碍服务"checked"false"textSize"15sp"/><button text"第二个按钮"/></vertical> ); ui.autoService.on("check"…

2022年09月 Scratch(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 数字:1,2,3,4,6,9,13,19,28,…的下一项是多少? A:37 B:39 C:41 D:47 答案:C 因为1+3=42+4=63+6=94+9=1313+6=199+19=28所以下一项为:28+13=41 第2题 下图红框中…

【Java 进阶篇】Redis:打开缓存之门

介绍 Redis&#xff08;Remote Dictionary Server&#xff09;是一个高性能的键值对存储系统&#xff0c;被广泛用作缓存、消息中间件和数据库。它以其快速的读写能力、支持多种数据结构和丰富的功能而闻名。在这篇博客中&#xff0c;我们将深入了解Redis的概念、安装以及基本…

企业数字化转型所需的数据在哪里找?企业数据运营有什么用?

现阶段&#xff0c;越来越多企业考虑数字化转型。特别是中小型企业&#xff0c;他们察觉到&#xff1a;数字化转型的关键在于数据的运营。只有通过数据的有效管理和不断挖掘&#xff0c;企业才可以更好地了解市场需求&#xff0c;优化业务流程&#xff0c;提高决策效率&#xf…

linux ld 链接器学习笔记

ld链接器笔记 1. 首先编写一段汇编代码 这里的汇编语法时 AT&T语法,是gcc原生支持的语法,底层使用 gas(gnu assembler) 完成汇编,相较于 Intel x86语法, AT&T 语法要更加古老,因此大多数人更加偏向于使用 Intel 的语法. nasm 编译器支持x86语法.自从2.10版本&#xf…

【Python进阶】近200页md文档14大体系第4篇:Python进程使用详解(图文演示)

本文从14大模块展示了python高级用的应用。分别有Linux命令&#xff0c;多任务编程、网络编程、Http协议和静态Web编程、htmlcss、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。 Python全套笔记直接地址…

Spring Boot创建和使用(重要)

Spring的诞生是为了简化Java程序开发的&#xff01; Spring Boot的诞生是为了简化Spring程序开发的&#xff01; Spring Boot就是Spring框架的脚手架&#xff0c;为了快速开发Spring框架而诞生的&#xff01;&#xff01; Spring Boot的优点&#xff1a; 快速集成框架&#x…

三维控件中定位一个点_vtkPointWidget

开发环境&#xff1a; Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码 demo解决问题&#xff1a;允许用户使用三维光标在三维空间中定位一个点。关键类vtkPointWidget , 光标具有轮廓边界框、轴对齐十字准线和轴阴影&#xff…

特征工程完整指南 - 第二部分

苏米特班迪帕迪亚 照片由Dan Cristian Pădureş在Unsplash上拍摄 一、说明 DATA&#xff0c;通常被称为原油&#xff0c;需要经过加工和清洁才能有效地用于各种用途。正如我们不直接使用来自其来源的石油一样&#xff0c;数据也经过类似的处理以提取其真正价值。 二、特征选…

【Python】重磅!这本30w人都在看的Python数据分析畅销书更新了!

Python 语言极具吸引力。自从 1991 年诞生以来&#xff0c;Python 如今已经成为最受欢迎的解释型编程语言。 【文末送书】今天推荐一本Python领域优质数据分析书籍&#xff0c;这本30w人都在看的书&#xff0c;值得入手。 目录 作译者简介主要变动导读视频购书链接文末送书 pan…

7种SQL的进阶用法

1.自定义排序&#xff08;ORDER BY FIELD&#xff09; 在MySQL中ORDER BY排序除了可以用ASC和DESC之外&#xff0c;还可以使用自定义排序方式来实现。 CREATE TABLE movies ( id INT PRIMARY KEY AUTO_INCREMENT, movie_name VARCHAR(255), actors VARCHAR(255), price DEC…