上篇文章介紹了LCD屏幕的使用,這個屏幕還有觸摸功能,本篇就來介紹LCD的觸摸功能的使用。
關于觸摸的內容有點多,分為上下兩篇進行講解,本篇先介紹觸摸驅動的編寫以及將觸摸點坐標實時打印出來進行測試,先有一個整體的使用感受,下篇文章再介紹具體的觸摸上報協議以及圖形化的測試方法。
1 觸摸介紹
LCD的觸摸功能,本質就是顯示屏上再疊加一層透明的觸摸屏,實現觸摸的方式與LCD進行交互。
電阻觸摸屏是一種傳感器,其結構是薄膜加上玻璃的結構,兩結構相鄰的一面上均涂有ITO(一種導電性和透明性很好的)涂層。當觸摸操作時,兩層結構擠壓接觸,經由感應器傳出相應的電信號,通過運算轉化為屏幕上的X、Y值。
電容技術觸摸屏CTP(Capacity Touch Panel)是利用人體的電流感應進行工作的。電容屏是一塊四層復合玻璃屏,電容式觸摸屏就是支持多點觸摸的人機交互方式,普通電阻式觸摸屏只能進行單一點的觸控。
1.1 硬件原理圖
本篇使用的是野火的7寸電容觸摸屏,分辨率和屏幕一樣,800x480。觸摸驅動芯片我GT911,是IIC接口的芯片。
觸摸芯片有四個引腳:
SCL:觸摸芯片的IIC 通信引腳
RSTN:觸摸芯片的復位引腳
INT:觸摸芯片的中斷引腳
對應板子原理圖的觸摸接口如下:
對應屏幕原理圖的觸摸接口如下:
2 編寫觸摸驅動代碼
觸摸芯片用到IIC通信,還要用到復位引腳和中斷引腳,因此需要先在設備樹中對引腳信息進行配置。
2.1 修改設備樹
修改imx6ull_myboard.dts文件。
在設備樹中把觸摸要用到的引腳追加到 iomuxc即可。
引腳 | 功能 |
---|---|
UART4_RX_DATA | 復用為 I2C1_SDA,用作 IIC1 的 SDA 引腳 |
UART4_TX_DATA | 復用為 I2C1_SCL,用作 IIC1 的 SCL 引腳 |
LCD_RST | 復用為 GPIO3_IO04 用作觸摸芯片的復位引腳 |
SNVS_TAMPER9 | 復用為 GPIO5_IO09 用作觸摸芯片的 irq 引腳,接收觸摸中斷 |
需要注意的是,SNVS_TAMPER9 引腳被復用為 GPIO5_IO09,需要追加到 iomuxc_snvs 節點。
2.1.1 IIC引腳
觸摸芯片用到的是IIC1,這兩個引腳在設備樹中以及默認添加了,無需修改:
2.1.2 復位引腳
&iomuxc節點中添加:
/*my gt911*/
pinctrl_tsc_reset: tscresetgrp {
fsl,pins = <
/* used for tsc reset */
MX6UL_PAD_LCD_RESET__GPIO3_IO04 0x10b0
>;
};
2.1.3 中斷引腳
&iomuxc_snvs節點中添加:
/*my gt911*/
pinctrl_tsc_irq: tsc_irq {
fsl,pins = <
/* used for tsc irq */
MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x4001b8b0
>;
}
2.1.4 IIC設備添加GT911
GT911觸摸驅動作為一個IIC設備掛載在IIC1總線上,找到IIC1節點:
需要在 IIC1 設備節點下追加相應的子節點:
gt911_tsc@5d {
compatible = "goodix,gt911";
reg = <0x5d>;
pinctrl-0 = <&pinctrl_tsc_reset>;
pinctrl-1 = <&pinctrl_tsc_irq>;
reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
irq-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;
interrupt-parent = <&gpio5>;
interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
};
修改后:
reg = <0x5d>是GT911觸摸芯片在 IIC1總線上的地址。
2.2 觸摸芯片數據寄存器
查看GT911的數據手冊,找到寄存器相關的表格:
主要關注以下這些寄存器,它們是用來讀取觸摸坐標點的:
Addr | Access | bit7~bit0 |
---|---|---|
0x814E | R/W | buffer status(7) large detect(6) Reserved(5~4) number of touch points(3~0) |
0x814F | R | track id |
0x8150 | R | point 1 x coordinate (low byte) |
0x8151 | R | point 1 x coordinate (high byte) |
0x8152 | R | point 1 y coordinate (low byte) |
0x8153 | R | point 1 y coorte (high byte) |
0x8154 | R | Point 1 size (low byte) |
0x8155 | R | Point 1 size (high byte) |
0x8156 | R | Reserved |
0x8157 | R | track id |
... | ... | ... |
0x815F | R | track id |
... | ... | ... |
0x8167 | R | track id |
... | ... | ... |
0x816F | R | track id |
0x8170 | R | point 5 x coordinate (low byte) |
0x8171 | R | point 5 x coordinate (high byte) |
0x8172 | R | point 5 y coordinate (low byte) |
0x8173 | R | point 5 y coordinate (high byte) |
0x8174 | R | Point 5 size (low byte) |
0x8175 | R | Point 5 size (high byte) |
0x8176 | R | Reserved |
0x814E:這個寄存器很重要,它是可讀可寫的寄存器,通過讀取該寄存器,可以知道當前是否有觸摸點(由最高位表示),以及有幾個觸摸點(由低3位表示)
0x814F~0x8156:是第一組觸摸的坐標數據
0x814F:是觸摸點的追蹤id,GT911支持5點觸摸,這里id的取值為0~4
0x8150:觸摸點1的x坐標(低字節)
0x8151:觸摸點1的x坐標(高字節)y
0x8152:觸摸點1的y坐標(低字節)
0x8153:觸摸點1的y坐標(高字節)
0x8154~0x8156:暫不使用
0x8157以后的寄存器:與第一組觸摸的坐標數據的含義類似,一個有五組
注:GT911支持硬件追蹤觸摸點,因此為每個觸摸點提供了一個track id,舉個簡單的例子,當5個手指依次觸摸到屏幕時,5組坐標寄存器中的track id會依次是0、1、2、3、4,當松開第1個手指時,即track id為0的點沒有了,此時5組坐標寄存器,是只有前45組坐標寄存器有數據,track id會依次是1、2、3、4(理解這個很重要,因為我一開始想當然的誤認為,移開第1個手指時,是第1組坐標寄存器沒數據了)
2.3 編寫驅動程序
新建gt911.c文件作為驅動文件
觸摸芯片GT911的使用,本質是使用IIC通信,進行數據的讀寫,因為觸摸屏的驅動,實際就是IIC驅動。另外,觸摸的數據是通過中斷的方式觸發的,因此觸摸驅動的編寫,涉及到中斷的處理。在中斷時,讀取到觸摸數據后,要傳遞到應用層,這里是使用Linux的input子系統(這也是Linux的一種軟件分層設計的方式)。
所以,編寫觸摸驅動,主要涉及3點:
IIC協議的驅動
中斷的處理(獲取觸摸數據)
input子系統(將觸摸數據傳遞到應用層)
2.3.1 IIC驅動架構
GT911的驅動按照IIC驅動來寫,當驅動運行時,會自動運行gt911_probe,在這個函數中會進行各種初始化操作。另外注意匹配列表,這里的“goodix,gt911”對應設備樹中添加的設備節點,兩處的名字要一致。
/* 匹配列表 */
static const struct of_device_id gt911_of_match[] = {
{.compatible = "goodix,gt911"},
{/* Sentinel */}
};
/* i2c驅動結構體 */
struct i2c_driver gt911_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "gt911", /* 驅動名字 用于和設備匹配 適用于沒有設備樹的情況*/
.of_match_table =gt911_of_match, /* 設備樹匹配列表 */
},
.probe =gt911_probe,
.remove =gt911_remove,
.id_table = gt911_id, /* id配置列表 */
};
2.3.2 驅動的初始化流程
gt911_probe函數進行觸摸驅動的初始化,基本流程就是從設備樹獲取觸摸節點,然后進行IO的初始化,中斷和復位的初始化以及觸摸器件的初始化等。
static int gt911_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
u8 ret = 0;
gt911.client = client;
printk("[BSP] gt911 driver and device has match!\r\n");
/* 獲取設備樹中的中斷和復位引腳 */
printk("[BSP] get gpios\r\n");
gt911.irq_pin = of_get_named_gpio(client->dev.of_node, "irq-gpios", 0);
gt911.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);
/* 初始化復位引腳 */
ret = gt911_ts_reset(client, >911);
/* 初始化gt911 */
printk("[BSP] init gt911\r\n");
gt911_write_reg(>911, GT_CTRL_REG, 2); /* 軟復位 */
mdelay(100);
gt911_write_reg(>911, GT_CTRL_REG, 0); /* 停止軟復位 */
mdelay(100);
/* input 注冊設備*/
printk("[BSP] init input device\r\n");
gt911.input = devm_input_allocate_device(&client->dev);
/* 初始化input */
gt911.input->name = client->name;
gt911.input->id.bustype = BUS_I2C;
gt911.input->dev.parent = &client->dev;
/* 設置input設備需要上報哪些事件*/
__set_bit(EV_SYN, gt911.input->evbit);
__set_bit(EV_KEY, gt911.input->evbit); /* 按鍵事件 */
__set_bit(EV_ABS, gt911.input->evbit); /* 重復事件 */
/* 設置input設備需要上報哪些按鍵*/
__set_bit(BTN_TOUCH, gt911.input->keybit); /* 觸摸值 */
/* 多點觸摸 */
input_mt_init_slots(gt911.input, MAX_SUPPORT_POINTS, 0); /*觸摸點的數量 */
input_set_abs_params(gt911.input, ABS_MT_POSITION_X,0, 800, 0, 0);
input_set_abs_params(gt911.input, ABS_MT_POSITION_Y,0, 480, 0, 0);
/* 注冊input */
ret = input_register_device(gt911.input);
/* 最后初始化中斷 */
ret = gt911_ts_irq(client, >911);
printk("[BSP] %s done \r\n",__FUNCTION__);
return 0;
}
2.3.3 復位與中斷的初始化
復位引腳的初始化主要就是拉低再拉高復位引腳,實現復位,主要內容為:
/* 申請復位IO 并且默認輸出高電平 */
devm_gpio_request_one(&client->dev,
dev->reset_pin,
GPIOF_OUT_INIT_HIGH,
"gt911 reset");
gpio_set_value(dev->reset_pin, 0); /* 復位 */
msleep(10);
gpio_set_value(dev->reset_pin, 1); /* 停止復位 */
msleep(300);
中斷的初始化,包括IO的申請和中斷函數的注冊:
/* 申請復位 IO */
devm_gpio_request_one(&client->dev,
dev->irq_pin,
GPIOF_IN,
"gt911 irq");
/* 申請中斷 */
devm_request_threaded_irq(&client->dev,
client->irq,
NULL,
gt911_irq_handler, /* 中斷處理函數 */
IRQF_TRIGGER_FALLING | IRQF_ONESHOT, /* 觸發方式 */
client->name,
>911);
2.3.4 中斷處理函數
這里僅貼出gt911_irq_handler的主要內容,基本思路是先讀取0x814E(GT_GSTID_REG)這一個寄存器,判斷觸摸點的數量,然后再讀取對應的坐標點數據寄存器,依次上報數據。
/* -----讀取觸摸信息寄存器----- */
ret = gt911_read_regs(dev, GT_GSTID_REG, &data, 1);
if(data == 0x00) /* 沒有觸摸數據*/
{
goto fail;
}
else
{ /* 統計觸摸信息 */
status = data >> 7; // bit7:1表示坐標(或按鍵)已經準備好,主控可以讀取 0 表示未就緒,數據無效
large_detect = (data >> 6) & 0x01; // bit6:
touch_num = data & 0x0f; // bit3~0:屏上的坐標點個數
}
if(touch_num) /* 有觸摸按下 */
{
/* -----讀取具體的觸摸點數據寄存器----- */
gt911_read_regs(dev, GT_TP1_REG, buf, BUFFER_SIZE);
id = buf[0]; // 數據中的第一個觸摸點的id
touch_index |= (0x01input, MT_TOOL_FINGER, true); // 指定手指觸摸 連續觸摸
input_report_abs(dev->input, ABS_MT_POSITION_X, input_x); // 上報觸摸點坐標信息
input_report_abs(dev->input, ABS_MT_POSITION_Y, input_y); // 上報觸摸點坐標信息
printk("[%d](%d, %d) ", id, input_x, input_y);
report_num++;
if (report_num < touch_num)
{
pos += 8;
id = buf[pos];
touch_index |= (0x01input, MT_TOOL_FINGER, false); // 關閉手指觸摸
}
}
printk("\r\n");
}
else if(last_index)/* 觸摸釋放 */
{
for (i = 0; i < 5; i++)
{
if ((last_index & (0x01<input, i); /* 上報觸摸點 */
input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, false); // 關閉手指觸摸
}
}
}
last_index = touch_index;
input_mt_report_pointer_emulation(dev->input, true);
input_sync(dev->input); /* 同步數據 數據上報完成 */
data = 0x00; /* 向0x814E寄存器寫0 不然就會一直進入中斷 */
gt911_write_regs(dev, GT_GSTID_REG, &data, 1); //寫入)))>);>);>
總結一下GT911多點觸摸驅動的執行流程:
3 使用Linux內核自帶的驅動(未測試)
對于觸摸屏的驅動,NXP已經編寫好了觸摸驅動,加以修改可以在自己的板子上使用。
不過我沒有測試成功,以后有時間再搞,所以這一部分內容可以跳過。
我這個7寸屏的驅動型號為GT911,屬于 GOODIX 公司生產的觸摸芯片,該觸摸驅動已默認添加到了Linux內核中,位于:/drivers/input/touchscreen/goodix.c。
使用Linux內核自代的驅動,還需要進行內核配置。在Linux內核源碼目錄,輸入以下指令打開內核的圖形化配置:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
到達Linux內核配置界面,然后按下路徑找到對應的配置項:
-> Device Drivers
-> Input device support
-> Touchscreens (INPUT_TOUCHSCREEN [=y])
<*> Goodix I2C touchscreen
最終到達這個界面:
按下y勾選上星號,連按多次ESC退出,最后提示保存,按下y保存配置。
然后需要重新編譯zImage和設備樹,到Linux內核源碼目錄,執行之前的編寫的編譯腳本
./build_myboard.sh
編譯的時候會彈出Linux圖形配置界面, 不需要做任何的配置, 直接按兩下ESC鍵退出圖形界面
將編譯出zImage(arch/arm/boot目錄)和imx6ull-myboard.dtb (arch/arm/boot/dts目錄)復制到網絡啟動位置
cp arch/arm/boot/zImage ~/myTest/tftpboot/nxp/
cp arch/arm/boot/dts/imx6ull-myboard.dtb ~/myTest/tftpboot/nxp/
4 觸摸測試
使用自己編寫的觸摸驅動程序,進行測試。
make imx6ull-myboard.dtb
cp arch/arm/boot/dts/imx6ull-myboard.dtb ~/myTest/tftpboot/nxp/
4.1 編譯設備樹
首先是編譯設備樹,驗證添加的觸摸節點是否工作正常,在Linux內核源碼目錄執行下面的命令,重新編譯設備樹并拷貝到網絡啟動位置。
make imx6ull-myboard.dtb
cp arch/arm/boot/dts/imx6ull-myboard.dtb ~/myTest/tftpboot/nxp/
然后重啟開發板,可以先到如下位置,查看設備樹的節點是否正常:
4.2 編譯驅動文件
然后是編譯驅動文件,也就是gt911.c,編譯方式和之前一樣,在ubuntu中使用Makefile進行交叉編譯。
本篇暫未用到對應的觸摸應用程序,所有的觸摸坐標打印都是在驅動程序中通過printk的方式進行內核打印。
編譯完驅動后,將對應的.ko文件復制到板子中。
4.3 測試觸摸點的坐標輸出
先加載觸摸驅動,串口會打印出為觸摸分配的event,我這里是event2。
然后執行下面的指令進行觸摸測試:
hexdump /dev/input/event2
將手指放到屏幕上,就可以在LCD屏幕上看到坐標值的打印,比如將手指放到屏幕左下角,對應輸出的值大致就是屏幕的最大位置(800,480):
GT911支持多點觸摸,驅動程序中也對多點數據進行了獲取和打印,將多個手指放到屏幕上,可以看到最多有5個觸摸點的坐標打印:
5 總結
本篇主要介紹了多點觸摸芯片GT911的驅動編寫與使用,并通過將觸摸點實時打印的方式,測試觸摸功能。
附:視頻演示
https://www.bilibili.com/video/BV1sZ4y1Q7da
-
嵌入式
+關注
關注
5092文章
19177瀏覽量
307635 -
lcd
+關注
關注
34文章
4438瀏覽量
168373 -
驅動
+關注
關注
12文章
1851瀏覽量
85634 -
電容觸摸
+關注
關注
0文章
70瀏覽量
16481 -
i.MX6
+關注
關注
1文章
37瀏覽量
16349
發布評論請先 登錄
相關推薦
評論