上篇文章介紹了電容觸摸驅動的編寫,包括設備樹的修改和驅動程序(IIC驅動+中斷+input子系統),并通過將觸摸坐標值實時打印出來的方式,對觸摸功能進行測試。
本篇,先來介紹一會測試觸摸是庫——tslib,使用它可以進行圖形化的觸摸測試。之后,再回頭來分析分析觸摸協議上報的原理以及通過input子系統上報的數據的具體含義。
1 tslib的使用
Tslib是一個開源的程序,能夠為觸摸屏驅動獲得的采樣提供諸如濾波、去抖、校準等功能,通常作為觸摸屏驅動的適配層,為上層的應用提供了一個統一的接口。
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 中創建一個名為“tslib”的目錄存放編譯結果,然后執行以下指令進行編譯:
cd tslib-1.21/
./autogen.sh
./configure --host=arm-linux-gnueabihf --prefix=/home/xxpcb/myTest/imx6ull/otherlib/tslib/tslib/
make
make install
編譯完成后,make install會將編譯成果復制到指定的tslib目錄中:
可以看到最終編譯生成的是5個文件夾。
1.1.2 開發板上配置tslib
將編譯出的5個文件夾整個復制到開發板的根文件系統中:
sudo cp * -rf ~/myTest/nfs/rootfs/
然后打開板子的/etc/ts.conf 文件,找到下面這一行:
module_raw input
如果這句前面有“#”注釋,就刪除掉“#“,我這個默認是沒有的,所以不用修改
打開板子的/etc/profile文件,我的板子此時沒有這個文件,所以我新建了一個該文件,然后在里面加入如下內容:
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 :觸摸設備文件,要根據具體情況設置為/dev/input/event1還是event2(如果接口鼠標鍵盤,這個編號可能還會變,比如我接了無線鍵盤后,觸摸就又變成了event)
TSLIB_CALIBFILE :校準文件,此文件可以不存在,校準的時候會自動生成
TSLIB_CONFFILE :觸摸配置文件,在移植 tslib 的時候會生成
TSLIB_PLUGINDIR :tslib 插件目錄位置
TSLIB_CONSOLEDEVICE :控制臺設置,這里不設置,設為none
TSLIB_FBDEVICE:FB 設備,也就是屏幕,也要根據實際情況配置設置為/dev/fb0或是其它
1.2 tslib庫測試
1.2.1 屏幕校準
電容屏可以不用校準,不過也可以看看tslib的校準測試用例,輸入如下指令:
ts_calibrate
校準完成以后如果不滿意,刪除掉/etc/pointercal文件即可
1.2.2 多點觸摸拖拽測試
使用如下指令:
ts_test_mt
然后會出現一個觸摸測試界面,先測試Drag功能,手指接觸屏幕后進行移動,屏幕上的十字標記就會跟著移動:
1.2.3 多點觸摸劃線測試
還是剛才的指令,再來測試Draw功能,手指接觸屏幕后進行移動,屏幕上就會出現滑過的軌跡線:
2 多點觸摸(MT)協議講解
多點觸摸協議,即Multi-touch (MT) Protocol,該協議的介紹,在linux內核源碼中有對應的文檔,如下圖:
多點電容觸摸的協議分為兩種類型:TypeA和TypeB,目前基本都是使用TypeB協議。
TypeA協議適用于觸摸點不能被區分或者追蹤,此類設備上報原始數據。
TypeB協議適用于有硬件追蹤并能區分觸摸點的觸摸設備,此類型設備通過slot更新某一個觸摸點的信息。
觸摸點的信息通過一系列的 ABS_MT事件上報給linux內核,這些事件的定義在include/uapi/linux/input.h中:
比較常用的有:
ABS_MT_SLOT :上報觸摸點ID
ABS_MT_POSITION_X:上報觸摸點的X坐標信息
ABS_MT_POSITION_Y:上報觸摸點的Y坐標信息
ABS_MT_TRACKING_ID:TypeB區分觸摸點
下面具體介紹兩種協議的區別。
2.1 TypeA協議
TypeA協議適用于觸摸點不能被區分或者追蹤,此類設備上報原始數據。
TypeA協議發送觸摸點信息的時序如下(以 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
依次循環上報其它點
所有的點上報完后,再上報一個SYN_REPORT
當第一個觸點離開后,上報的時序如下(就是只上報剩下的那一個):
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_MT_REPORT
SYN_REPORT
當第二個觸點也離開后,上報的時序如下(就是上報空數據):
SYN_MT_REPORT
SYN_REPORT
如果驅動除了ABS_MT事件外還上報BTN_TOUCH或ABS_PRESSURE之一,則最后一個SYN_MT_REPORT事件可能被忽略。另外,最后的SYN_REPORT會被輸入內核放棄,從而導致沒有空觸事件到達用戶層。
2.2 TypeB協議
TypeB協議適用于有硬件追蹤并能區分觸摸點的觸摸設備,此類型設備通過slot更新某一個觸摸點的信息。
TypeA協議發送觸摸點信息的時序如下(以 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
每個數據點前,先上報ABS_MT_SLOT事件,帶上一個觸摸點ID,此ID由觸摸IC提供
TypeB要求每個SLOT須關聯一個ABS_MT_TRACKING_ID,這個ID由linux內核自動分配
然后上報一個點的x和y
依次循環上報其它點
所有的點上報完后,再上報一個SYN_REPORT。
當觸點45在X方向上移動后,上報的時序如下:
ABS_MT_SLOT 0
ABS_MT_POSITION_X x[0]
SYN_REPORT
當slot 0中觸點離開后,上報的時序如下:
ABS_MT_TRACKING_ID -1
SYN_REPORT
由于slot被修改為0,因此這個ABS_MT_SLOT被忽略。這條信息移除了slot 0和觸點45的聯系,因此銷毀觸點45同時釋放slot 0給另外的觸點再次使用。
當第二個觸點離開后,上報的時序如下:
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID -1
SYN_REPORT
總結對比一下兩個觸摸協議的區別:
2.3 多點觸摸API函數
了解了兩種觸摸協議,在編程時,就要使用其相應的API函數來實現觸摸數據的上報,下面是常用的API函數。
2.3.1 input_mt_init_slots
該函數用于初始化MT的輸入slots,其函數原型如下:
/**
* dev: MT設備對應的input_dev
* num_slots: 設備要使用的slot的數量,也就是觸摸點的數量
* flags: 其他一些flags信息
* return: 0-成功 負值-失敗
*/
int input_mt_init_slots(struct input_dev *dev,
unsigned int num_slots,
unsigned int flags)
其中第3個參數,可設置的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 */
可以使用‘|’運算來同時設置多個flags標識
2.3.2 input_mt_slot
該函數用于Type B類型,用于產生 ABS_MT_SLOT事件,其函數原型如下:
/**
* dev: MT設備對應的input_dev
* slot: 當前發送的是哪個slot的坐標信息,也就是哪個觸摸點
* return: 無
*/
void input_mt_slot(struct input_dev *dev, int slot)
2.3.3 input_mt_report_slot_state
該函數用于Type B類型,用于產生ABS_MT_TRACKING_ID和ABS_MT_TOOL_TYPE事件,其函數原型如下:
/**
* dev: MT設備對應的input_dev
* tool_type: 觸摸類型
* active: 觸摸或抬起
* return: 無
*/
void input_mt_report_slot_state(struct input_dev *dev,
unsigned int tool_type,
bool active)
其中第2個參數,tool_type包括:
MT_TOOL_FINGER:手指
MT_TOOL_PEN:筆
MT_TOOL_PALM:手掌
其中第3個參數,active包括:
true: 連續觸摸, input子系統內核會自動分配一個ABS_MT_TRACKING_ID給slot
false:觸摸點抬起,表示某個觸摸點無效了,input子系統內核會分配一個-1給slot
2.3.4 input_report_abs
該函數用于上報觸摸點坐標,TypeA和TypeB類型都使用此函數上報觸摸點坐標信息,其函數原型如下:
/**
* dev: MT設備對應的input_dev
* code: 要上報的是什么數據
* value: 要上報的數據值
* return: 無
*/
void input_report_abs(struct input_dev *dev,
unsigned int code,
int value)
其中第2個參數,code包括:
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
2.3.5 input_mt_report_pointer_emulation
如果追蹤到的觸摸點數量多于當前上報的數量,驅動程序使用 BTN_TOOL_TAP 事件來通知用戶空間當前追蹤到的觸摸點總數量,然后調用 input_mt_report_pointer_emulation 函數將use_count 參數設置為 false,否則的話將 use_count 參數設置為 true。
/**
* dev: MT設備對應的input_dev
* use_count: true-有效的觸摸點數量 false-追蹤到的觸摸點數量多于當前上報的數量
* return: 無
*/
void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
3 input子系統上報數據含義講解
3.1 input子系統簡介
在Linux中,對于輸入設備,例如按鍵、 鼠標、 鍵盤、 觸摸屏等,為了更加方便統一的管理, Linux內核為此專門做了一個input子系統的框架來處理輸入事件。
input是輸入的意思,就是管理輸入的子系統,和 pinctrl、gpio 子系統一樣,都是 Linux 內核針對某一類設備而創建的框架。input 子系統框架圖如下:
3.2 input輸出事件
3.2.1 事件類型
evbit 表示輸入事件類型,可選的事件類型定義在 include/uapi/linux/input.h 文件中,事件類型如下:
各個的含義為:
#define EV_SYN 0x00 /* 同步事件 */
#define EV_KEY 0x01 /* 按鍵事件 */
#define EV_REL 0x02 /* 相對坐標事件 */
#define EV_ABS 0x03 /* 絕對坐標事件 */
#define EV_MSC 0x04 /* 雜項(其他)事件 */
#define EV_SW 0x05 /* 開關事件 */
#define EV_LED 0x11 /* LED */
#define EV_SND 0x12 /* sound(聲音) */
#define EV_REP 0x14 /* 重復事件 */
#define EV_FF 0x15 /* 壓力事件 */
#define EV_PWR 0x16 /* 電源事件 */
#define EV_FF_STATUS 0x17 /* 壓力狀態事件 */
例如,如果要使用按鍵的inpu件功能,就需要注冊EV_KEY事件,若還要使用連按功能,需要注冊EV_REP事件。
如果要使用觸摸屏的inpu件功能,就需要注冊EV_KEY事件,
3.2.2 按鍵值類型
evbit、keybit、relbit 等等都是存放不同事件對應的值,Linux 內核定義了很多按鍵值:
#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 觸摸數據上報實例分析
上篇文章只是將觸摸坐標打印到了屏幕,實際是使用觸摸屏時,需要將坐標數據通過input子系統上報應用層,現在來具體分析一下input子系統上報的這些數據的含義,例如按下觸摸鍵后,串口會有如下打印:
將數據內容摘出來看:
/*****************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,絕對坐標事件
code 為事件編碼,也就是按鍵號
0000:ABS_X,單點觸摸上報X坐標值
0001:ABS_Y,單點觸摸上報Y坐標值
0035:ABS_MT_POSITION_X,多點觸摸上報X坐標值
0036:ABS_MT_POSITION_Y,多點觸摸上報Y坐標值
0039:ABS_MT_TRACKING_ID,觸摸點的track id
014a:BTN_TOUCH,觸摸按鍵
value 就是按鍵值, 為 1 表示按下, 為 0 的話表示松開
來分析一下每行輸出的含義:
第1行:絕對坐標事件,觸摸點的track id,id=0
第2行:絕對坐標事件,多點觸摸X坐標值,X=0x9d (157)
第3行:絕對坐標事件,多點觸摸Y坐標值,Y=0xc1 (193)
第4行:按鍵事件,觸摸按鍵,1表示按鍵按下
第5行:絕對坐標事件,單點觸摸X坐標值,X=0x9d (157)
第6行:絕對坐標事件,單點觸摸Y坐標值,Y=0xc1 (193)
第7行:同步事件,由input_sync函數上報
第8行:絕對坐標事件,觸摸點的track id,id=0xffffffff=-1,即觸摸點離開了屏幕
第9行:按鍵事件,觸摸按鍵,0表示沒有按鍵
第10行:同步事件,由input_sync函數上報
注:上面的打印,有多點觸摸和單點觸摸的上報,實際上如果使用了多點觸摸,可以將單點觸摸的上報去掉,如下:
去掉后,再次測試,可以看到只有多點觸摸數據的上報:
4 將觸摸驅動編譯到內核
自己編寫的觸摸驅動,每次系統啟動后,都要手動加載驅動模塊后才能使用,比較麻煩,現在驅動文件不需要再改了,就可以將自己的驅動直接編譯到內核中。方法如下:
將自己寫的觸摸屏驅動文件拷貝到Linux內核的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內核
再將zImage拷貝到板子中,重新啟動板子。
正常情況下,在內核啟動的時候就打印出觸摸驅動的event編號信息,我這里確實也打印了,只是隨后一直刷IIC錯誤:
暫時看不出來是什么原因,才這居打印看,觸摸開始讀數據時才會進到這里,感覺像是觸摸驅動剛加載完成,就觸發了中斷,但在中斷里通過IIC讀取觸摸數據時,又出現了問題。。。
一個暫時的替代方式是,可以在開機自啟動文件中進行觸摸驅動的加載,在/etc/init.d/rcS文件中補充如下語句即可:
cd /lib/modules/4.1.15
depmod
modprobe gt911.ko
cd /
5 總結
本篇首先介紹了測試觸摸是庫——tslib,使用它可以進行圖形化的觸摸測試。隨后,又分析觸摸協議上報的原理以及通過input子系統上報的數據的具體含義。
附:演示視頻
https://www.bilibili.com/video/BV1XL4y1t7kf
-
嵌入式
+關注
關注
5087文章
19153瀏覽量
306394 -
驅動
+關注
關注
12文章
1844瀏覽量
85405 -
Linux
+關注
關注
87文章
11326瀏覽量
209959 -
電容觸摸
+關注
關注
0文章
70瀏覽量
16464 -
i.MX6
+關注
關注
1文章
37瀏覽量
16325
發布評論請先 登錄
相關推薦
評論