您好,登錄后才能下訂單哦!
這篇文章主要介紹“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下電容觸摸屏程序編寫方法是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。