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