上篇文章介紹了電容觸摸驅(qū)動的編寫,包括設(shè)備樹的修改和驅(qū)動程序(IIC驅(qū)動+中斷+input子系統(tǒng)),并通過將觸摸坐標(biāo)值實時打印出來的方式,對觸摸功能進行測試。
本篇,先來介紹一會測試觸摸是庫——tslib,使用它可以進行圖形化的觸摸測試。之后,再回頭來分析分析觸摸協(xié)議上報的原理以及通過input子系統(tǒng)上報的數(shù)據(jù)的具體含義。
1 tslib的使用
Tslib是一個開源的程序,能夠為觸摸屏驅(qū)動獲得的采樣提供諸如濾波、去抖、校準(zhǔn)等功能,通常作為觸摸屏驅(qū)動的適配層,為上層的應(yīng)用提供了一個統(tǒng)一的接口。
1.1 tslib庫移植
首先下載tslib庫的源碼:https://github.com/libts/tslib/tags
目前最新的是1.22,不過本篇先使用1.21版本
1.1.1 ubuntu上編譯tslib
將下載的源碼拷貝到ubuntu虛擬機中,然后解壓:
tar xvf tslib-1.21.tar.bz2
編譯 tslib 的時候需要先在 ubuntu 中安裝一些文件
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
在 ubuntu 中創(chuàng)建一個名為“tslib”的目錄存放編譯結(jié)果,然后執(zhí)行以下指令進行編譯:
cd tslib-1.21/
./autogen.sh
./configure --host=arm-linux-gnueabihf --prefix=/home/xxpcb/myTest/imx6ull/otherlib/tslib/tslib/
make
make install
編譯完成后,make install會將編譯成果復(fù)制到指定的tslib目錄中:
可以看到最終編譯生成的是5個文件夾。
1.1.2 開發(fā)板上配置tslib
將編譯出的5個文件夾整個復(fù)制到開發(fā)板的根文件系統(tǒng)中:
sudo cp * -rf ~/myTest/nfs/rootfs/
然后打開板子的/etc/ts.conf 文件,找到下面這一行:
module_raw input
如果這句前面有“#”注釋,就刪除掉“#“,我這個默認是沒有的,所以不用修改
打開板子的/etc/profile文件,我的板子此時沒有這個文件,所以我新建了一個該文件,然后在里面加入如下內(nèi)容:
export TSLIB_TSDEVICE=/dev/input/event2
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
TSLIB_TSDEVICE :觸摸設(shè)備文件,要根據(jù)具體情況設(shè)置為/dev/input/event1還是event2(如果接口鼠標(biāo)鍵盤,這個編號可能還會變,比如我接了無線鍵盤后,觸摸就又變成了event)
TSLIB_CALIBFILE :校準(zhǔn)文件,此文件可以不存在,校準(zhǔn)的時候會自動生成
TSLIB_CONFFILE :觸摸配置文件,在移植 tslib 的時候會生成
TSLIB_PLUGINDIR :tslib 插件目錄位置
TSLIB_CONSOLEDEVICE :控制臺設(shè)置,這里不設(shè)置,設(shè)為none
TSLIB_FBDEVICE:FB 設(shè)備,也就是屏幕,也要根據(jù)實際情況配置設(shè)置為/dev/fb0或是其它
1.2 tslib庫測試
1.2.1 屏幕校準(zhǔn)
電容屏可以不用校準(zhǔn),不過也可以看看tslib的校準(zhǔn)測試用例,輸入如下指令:
ts_calibrate
校準(zhǔn)完成以后如果不滿意,刪除掉/etc/pointercal文件即可
1.2.2 多點觸摸拖拽測試
使用如下指令:
ts_test_mt
然后會出現(xiàn)一個觸摸測試界面,先測試Drag功能,手指接觸屏幕后進行移動,屏幕上的十字標(biāo)記就會跟著移動:
1.2.3 多點觸摸劃線測試
還是剛才的指令,再來測試Draw功能,手指接觸屏幕后進行移動,屏幕上就會出現(xiàn)滑過的軌跡線:
2 多點觸摸(MT)協(xié)議講解
多點觸摸協(xié)議,即Multi-touch (MT) Protocol,該協(xié)議的介紹,在linux內(nèi)核源碼中有對應(yīng)的文檔,如下圖:
多點電容觸摸的協(xié)議分為兩種類型:TypeA和TypeB,目前基本都是使用TypeB協(xié)議。
TypeA協(xié)議適用于觸摸點不能被區(qū)分或者追蹤,此類設(shè)備上報原始數(shù)據(jù)。
TypeB協(xié)議適用于有硬件追蹤并能區(qū)分觸摸點的觸摸設(shè)備,此類型設(shè)備通過slot更新某一個觸摸點的信息。
觸摸點的信息通過一系列的 ABS_MT事件上報給linux內(nèi)核,這些事件的定義在include/uapi/linux/input.h中:
比較常用的有:
ABS_MT_SLOT :上報觸摸點ID
ABS_MT_POSITION_X:上報觸摸點的X坐標(biāo)信息
ABS_MT_POSITION_Y:上報觸摸點的Y坐標(biāo)信息
ABS_MT_TRACKING_ID:TypeB區(qū)分觸摸點
下面具體介紹兩種協(xié)議的區(qū)別。
2.1 TypeA協(xié)議
TypeA協(xié)議適用于觸摸點不能被區(qū)分或者追蹤,此類設(shè)備上報原始數(shù)據(jù)。
TypeA協(xié)議發(fā)送觸摸點信息的時序如下(以 2 個觸摸點為例):
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
SYN_MT_REPORT
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
首先每上報一個點的x和y
然后上報一個SYN_MT_REPORT
依次循環(huán)上報其它點
所有的點上報完后,再上報一個SYN_REPORT
當(dāng)?shù)谝粋€觸點離開后,上報的時序如下(就是只上報剩下的那一個):
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
當(dāng)?shù)诙€觸點也離開后,上報的時序如下(就是上報空數(shù)據(jù)):
SYN_MT_REPORT
SYN_REPORT
如果驅(qū)動除了ABS_MT事件外還上報BTN_TOUCH或ABS_PRESSURE之一,則最后一個SYN_MT_REPORT事件可能被忽略。另外,最后的SYN_REPORT會被輸入內(nèi)核放棄,從而導(dǎo)致沒有空觸事件到達用戶層。
2.2 TypeB協(xié)議
TypeB協(xié)議適用于有硬件追蹤并能區(qū)分觸摸點的觸摸設(shè)備,此類型設(shè)備通過slot更新某一個觸摸點的信息。
TypeA協(xié)議發(fā)送觸摸點信息的時序如下(以 2 個觸摸點為例):
ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 45
ABS_MT_POSITION_X x[0]
ABS_MT_POSITION_Y y[0]
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT
每個數(shù)據(jù)點前,先上報ABS_MT_SLOT事件,帶上一個觸摸點ID,此ID由觸摸IC提供
TypeB要求每個SLOT須關(guān)聯(lián)一個ABS_MT_TRACKING_ID,這個ID由linux內(nèi)核自動分配
然后上報一個點的x和y
依次循環(huán)上報其它點
所有的點上報完后,再上報一個SYN_REPORT。
當(dāng)觸點45在X方向上移動后,上報的時序如下:
ABS_MT_SLOT 0
ABS_MT_POSITION_X x[0]
SYN_REPORT
當(dāng)slot 0中觸點離開后,上報的時序如下:
ABS_MT_TRACKING_ID -1
SYN_REPORT
由于slot被修改為0,因此這個ABS_MT_SLOT被忽略。這條信息移除了slot 0和觸點45的聯(lián)系,因此銷毀觸點45同時釋放slot 0給另外的觸點再次使用。
當(dāng)?shù)诙€觸點離開后,上報的時序如下:
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT
總結(jié)對比一下兩個觸摸協(xié)議的區(qū)別:
2.3 多點觸摸API函數(shù)
了解了兩種觸摸協(xié)議,在編程時,就要使用其相應(yīng)的API函數(shù)來實現(xiàn)觸摸數(shù)據(jù)的上報,下面是常用的API函數(shù)。
2.3.1 input_mt_init_slots
該函數(shù)用于初始化MT的輸入slots,其函數(shù)原型如下:
/**
* dev: MT設(shè)備對應(yīng)的input_dev
* num_slots: 設(shè)備要使用的slot的數(shù)量,也就是觸摸點的數(shù)量
* flags: 其他一些flags信息
* return: 0-成功 負值-失敗
*/
int input_mt_init_slots(struct input_dev *dev,
unsigned int num_slots,
unsigned int flags)
其中第3個參數(shù),可設(shè)置的flags包括:
#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */
#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */
#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */
#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */
#define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */
可以使用‘|’運算來同時設(shè)置多個flags標(biāo)識
2.3.2 input_mt_slot
該函數(shù)用于Type B類型,用于產(chǎn)生 ABS_MT_SLOT事件,其函數(shù)原型如下:
/**
* dev: MT設(shè)備對應(yīng)的input_dev
* slot: 當(dāng)前發(fā)送的是哪個slot的坐標(biāo)信息,也就是哪個觸摸點
* return: 無
*/
void input_mt_slot(struct input_dev *dev, int slot)
2.3.3 input_mt_report_slot_state
該函數(shù)用于Type B類型,用于產(chǎn)生ABS_MT_TRACKING_ID和ABS_MT_TOOL_TYPE事件,其函數(shù)原型如下:
/**
* dev: MT設(shè)備對應(yīng)的input_dev
* tool_type: 觸摸類型
* active: 觸摸或抬起
* return: 無
*/
void input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type,
bool active)
其中第2個參數(shù),tool_type包括:
MT_TOOL_FINGER:手指
MT_TOOL_PEN:筆
MT_TOOL_PALM:手掌
其中第3個參數(shù),active包括:
true: 連續(xù)觸摸, input子系統(tǒng)內(nèi)核會自動分配一個ABS_MT_TRACKING_ID給slot
false:觸摸點抬起,表示某個觸摸點無效了,input子系統(tǒng)內(nèi)核會分配一個-1給slot
2.3.4 input_report_abs
該函數(shù)用于上報觸摸點坐標(biāo),TypeA和TypeB類型都使用此函數(shù)上報觸摸點坐標(biāo)信息,其函數(shù)原型如下:
/**
* dev: MT設(shè)備對應(yīng)的input_dev
* code: 要上報的是什么數(shù)據(jù)
* value: 要上報的數(shù)據(jù)值
* return: 無
*/
void input_report_abs(struct input_dev *dev,
unsigned int code,
int value)
其中第2個參數(shù),code包括:
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
2.3.5 input_mt_report_pointer_emulation
如果追蹤到的觸摸點數(shù)量多于當(dāng)前上報的數(shù)量,驅(qū)動程序使用 BTN_TOOL_TAP 事件來通知用戶空間當(dāng)前追蹤到的觸摸點總數(shù)量,然后調(diào)用 input_mt_report_pointer_emulation 函數(shù)將use_count 參數(shù)設(shè)置為 false,否則的話將 use_count 參數(shù)設(shè)置為 true。
/**
* dev: MT設(shè)備對應(yīng)的input_dev
* use_count: true-有效的觸摸點數(shù)量 false-追蹤到的觸摸點數(shù)量多于當(dāng)前上報的數(shù)量
* return: 無
*/
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
3 input子系統(tǒng)上報數(shù)據(jù)含義講解
3.1 input子系統(tǒng)簡介
在Linux中,對于輸入設(shè)備,例如按鍵、 鼠標(biāo)、 鍵盤、 觸摸屏等,為了更加方便統(tǒng)一的管理, Linux內(nèi)核為此專門做了一個input子系統(tǒng)的框架來處理輸入事件。
input是輸入的意思,就是管理輸入的子系統(tǒng),和 pinctrl、gpio 子系統(tǒng)一樣,都是 Linux 內(nèi)核針對某一類設(shè)備而創(chuàng)建的框架。input 子系統(tǒng)框架圖如下:
3.2 input輸出事件
3.2.1 事件類型
evbit 表示輸入事件類型,可選的事件類型定義在 include/uapi/linux/input.h 文件中,事件類型如下:
各個的含義為:
#define EV_SYN 0x00 /* 同步事件 */
#define EV_KEY 0x01 /* 按鍵事件 */
#define EV_REL 0x02 /* 相對坐標(biāo)事件 */
#define EV_ABS 0x03 /* 絕對坐標(biāo)事件 */
#define EV_MSC 0x04 /* 雜項(其他)事件 */
#define EV_SW 0x05 /* 開關(guān)事件 */
#define EV_LED 0x11 /* LED */
#define EV_SND 0x12 /* sound(聲音) */
#define EV_REP 0x14 /* 重復(fù)事件 */
#define EV_FF 0x15 /* 壓力事件 */
#define EV_PWR 0x16 /* 電源事件 */
#define EV_FF_STATUS 0x17 /* 壓力狀態(tài)事件 */
例如,如果要使用按鍵的inpu件功能,就需要注冊EV_KEY事件,若還要使用連按功能,需要注冊EV_REP事件。
如果要使用觸摸屏的inpu件功能,就需要注冊EV_KEY事件,
3.2.2 按鍵值類型
evbit、keybit、relbit 等等都是存放不同事件對應(yīng)的值,Linux 內(nèi)核定義了很多按鍵值:
#define KEY_RESERVED 0
#define KEY_ESC 1
#define KEY_1 2
#define KEY_2 3
#define KEY_3 4
#define KEY_4 5
//......
#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
#define BTN_TOUCH 0x14a
#define BTN_STYLUS 0x14b
//......
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_Z 0x02
#define ABS_RX 0x03
#define ABS_RY 0x04
#define ABS_RZ 0x05
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
具體的定義在input.h文件中:
3.3 觸摸數(shù)據(jù)上報實例分析
上篇文章只是將觸摸坐標(biāo)打印到了屏幕,實際是使用觸摸屏?xí)r,需要將坐標(biāo)數(shù)據(jù)通過input子系統(tǒng)上報應(yīng)用層,現(xiàn)在來具體分析一下input子系統(tǒng)上報的這些數(shù)據(jù)的含義,例如按下觸摸鍵后,串口會有如下打?。?/p>
將數(shù)據(jù)內(nèi)容摘出來看:
/*****************input_event 類型********************/
/*編號*/ /*tv_sec*/ /*tv_usec*/ /*type*/ /*code*/ /*value*/
0000000 00f6 0000 e539 0003 0003 0039 0000 0000
0000010 00f6 0000 e539 0003 0003 0035 009d 0000
0000020 00f6 0000 e539 0003 0003 0036 00c1 0000
0000030 00f6 0000 e539 0003 0001 014a 0001 0000
0000040 00f6 0000 e539 0003 0003 0000 009d 0000
0000050 00f6 0000 e539 0003 0003 0001 00c1 0000
0000060 00f6 0000 e539 0003 0000 0000 0000 0000
0000070 00f6 0000 11ad 0005 0003 0039 ffff ffff
0000080 00f6 0000 11ad 0005 0001 014a 0000 0000
0000090 00f6 0000 11ad 0005 0000 0000 0000 0000
type 為事件類型
0000:EV_SYN,同步事件
0001:EV_KEY,按鍵事件
0003:EV_ABS,絕對坐標(biāo)事件
code 為事件編碼,也就是按鍵號
0000:ABS_X,單點觸摸上報X坐標(biāo)值
0001:ABS_Y,單點觸摸上報Y坐標(biāo)值
0035:ABS_MT_POSITION_X,多點觸摸上報X坐標(biāo)值
0036:ABS_MT_POSITION_Y,多點觸摸上報Y坐標(biāo)值
0039:ABS_MT_TRACKING_ID,觸摸點的track id
014a:BTN_TOUCH,觸摸按鍵
value 就是按鍵值, 為 1 表示按下, 為 0 的話表示松開
來分析一下每行輸出的含義:
第1行:絕對坐標(biāo)事件,觸摸點的track id,id=0
第2行:絕對坐標(biāo)事件,多點觸摸X坐標(biāo)值,X=0x9d (157)
第3行:絕對坐標(biāo)事件,多點觸摸Y坐標(biāo)值,Y=0xc1 (193)
第4行:按鍵事件,觸摸按鍵,1表示按鍵按下
第5行:絕對坐標(biāo)事件,單點觸摸X坐標(biāo)值,X=0x9d (157)
第6行:絕對坐標(biāo)事件,單點觸摸Y坐標(biāo)值,Y=0xc1 (193)
第7行:同步事件,由input_sync函數(shù)上報
第8行:絕對坐標(biāo)事件,觸摸點的track id,id=0xffffffff=-1,即觸摸點離開了屏幕
第9行:按鍵事件,觸摸按鍵,0表示沒有按鍵
第10行:同步事件,由input_sync函數(shù)上報
注:上面的打印,有多點觸摸和單點觸摸的上報,實際上如果使用了多點觸摸,可以將單點觸摸的上報去掉,如下:
去掉后,再次測試,可以看到只有多點觸摸數(shù)據(jù)的上報:
4 將觸摸驅(qū)動編譯到內(nèi)核
自己編寫的觸摸驅(qū)動,每次系統(tǒng)啟動后,都要手動加載驅(qū)動模塊后才能使用,比較麻煩,現(xiàn)在驅(qū)動文件不需要再改了,就可以將自己的驅(qū)動直接編譯到內(nèi)核中。方法如下:
將自己寫的觸摸屏驅(qū)動文件拷貝到Linux內(nèi)核的drivers/input/touchscreen/目錄下:
cp gt911.c ../../kernel/nxp_kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga/drivers/input/touchscreen/ -f
修改 drivers/input/touchscreen 目錄下的 Makefile,在最下面添加下面一行:
obj-y += gt911.o
然后(使用之前編寫的編譯腳本)重新編譯linux內(nèi)核
再將zImage拷貝到板子中,重新啟動板子。
正常情況下,在內(nèi)核啟動的時候就打印出觸摸驅(qū)動的event編號信息,我這里確實也打印了,只是隨后一直刷IIC錯誤:
暫時看不出來是什么原因,才這居打印看,觸摸開始讀數(shù)據(jù)時才會進到這里,感覺像是觸摸驅(qū)動剛加載完成,就觸發(fā)了中斷,但在中斷里通過IIC讀取觸摸數(shù)據(jù)時,又出現(xiàn)了問題。。。
一個暫時的替代方式是,可以在開機自啟動文件中進行觸摸驅(qū)動的加載,在/etc/init.d/rcS文件中補充如下語句即可:
cd /lib/modules/4.1.15
depmod
modprobe gt911.ko
cd /
5 總結(jié)
本篇首先介紹了測試觸摸是庫——tslib,使用它可以進行圖形化的觸摸測試。隨后,又分析觸摸協(xié)議上報的原理以及通過input子系統(tǒng)上報的數(shù)據(jù)的具體含義。
附:演示視頻
https://www.bilibili.com/video/BV1XL4y1t7kf
-
嵌入式
+關(guān)注
關(guān)注
5060文章
18976瀏覽量
302220 -
驅(qū)動
+關(guān)注
關(guān)注
12文章
1821瀏覽量
85121 -
Linux
+關(guān)注
關(guān)注
87文章
11213瀏覽量
208736 -
電容觸摸
+關(guān)注
關(guān)注
0文章
70瀏覽量
16436 -
i.MX6
+關(guān)注
關(guān)注
1文章
37瀏覽量
16272
發(fā)布評論請先 登錄
相關(guān)推薦
評論