天天看點

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

上篇文章介紹了電容觸摸驅動的編寫,包括裝置樹的修改和驅動程式(IIC驅動+中斷+input子系統),并通過将觸摸坐标值實時列印出來的方式,對觸摸功能進行測試。

本篇,先來介紹一會測試觸摸是庫——tslib,使用它可以進行圖形化的觸摸測試。之後,再回頭來分析分析觸摸協定上報的原理以及通過input子系統上報的資料的具體含義。

文章目錄

  • ​​1 tslib的使用​​
  • ​​1.1 tslib庫移植​​
  • ​​1.1.1 ubuntu上編譯tslib​​
  • ​​1.1.2 開發闆上配置tslib​​
  • ​​1.2 tslib庫測試​​
  • ​​1.2.1 螢幕校準​​
  • ​​1.2.2 多點觸摸拖拽測試​​
  • ​​1.2.3 多點觸摸劃線測試​​
  • ​​2 多點觸摸(MT)協定講解​​
  • ​​2.1 TypeA協定​​
  • ​​2.2 TypeB協定​​
  • ​​2.3 多點觸摸API函數​​
  • ​​2.3.1 input_mt_init_slots​​
  • ​​2.3.2 input_mt_slot​​
  • ​​2.3.3 input_mt_report_slot_state​​
  • ​​2.3.4 input_report_abs​​
  • ​​2.3.5 input_mt_report_pointer_emulation​​
  • ​​3 input子系統上報資料含義講解​​
  • ​​3.1 input子系統簡介​​
  • ​​3.2 input輸出事件​​
  • ​​3.2.1 事件類型​​
  • ​​3.2.2 按鍵值類型​​
  • ​​3.3 觸摸資料上報執行個體分析​​
  • ​​4 将觸摸驅動編譯到核心​​
  • ​​5 總結​​
  • ​​附:示範視訊​​

1 tslib的使用

Tslib是一個開源的程式,能夠為觸摸屏驅動獲得的采樣提供諸如濾波、去抖、校準等功能,通常作為觸摸屏驅動的适配層,為上層的應用提供了一個統一的接口。

1.1 tslib庫移植

首先下載下傳tslib庫的源碼:​​https://github.com/libts/tslib/tags​​

目前最新的是1.22,不過本篇先使用1.21版本

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

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      
【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

編譯完成後,make install會将編譯成果複制到指定的tslib目錄中:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

可以看到最終編譯生成的是5個檔案夾。

1.1.2 開發闆上配置tslib

将編譯出的5個檔案夾整個複制到開發闆的根檔案系統中:

sudo cp * -rf ~/myTest/nfs/rootfs/      

然後打開闆子的**/etc/ts.conf** 檔案,找到下面這一行:

module_raw input      

如果這句前面有“#”注釋,就删除掉“#“,我這個預設是沒有的,是以不用修改

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

打開闆子的**/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檔案即可

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

1.2.2 多點觸摸拖拽測試

使用如下指令:

ts_test_mt      

然後會出現一個觸摸測試界面,先測試Drag功能,手指接觸螢幕後進行移動,螢幕上的十字标記就會跟着移動:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

1.2.3 多點觸摸劃線測試

還是剛才的指令,再來測試Draw功能,手指接觸螢幕後進行移動,螢幕上就會出現滑過的軌迹線:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

2 多點觸摸(MT)協定講解

多點觸摸協定,即Multi-touch (MT) Protocol,該協定的介紹,在linux核心源碼中有對應的文檔,如下圖:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

多點電容觸摸的協定分為兩種類型:TypeA和TypeB,目前基本都是使用TypeB協定。

  • TypeA協定适用于觸摸點不能被區分或者追蹤,此類裝置上報原始資料。
  • TypeB協定适用于有硬體追蹤并能區分觸摸點的觸摸裝置,此類型裝置通過slot更新某一個觸摸點的資訊。

觸摸點的資訊通過一系列的 ABS_MT事件上報給linux核心,這些事件的定義在include/uapi/linux/input.h中:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

比較常用的有:

  • 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      

總結對比一下兩個觸摸協定的差別:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

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 子系統架構圖如下:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

3.2 input輸出事件

3.2.1 事件類型

evbit 表示輸入事件類型,可選的事件類型定義在 include/uapi/linux/input.h 檔案中,事件類型如下:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

各個的含義為:

#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檔案中:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

3.3 觸摸資料上報執行個體分析

上篇文章隻是将觸摸坐标列印到了螢幕,實際是使用觸摸屏時,需要将坐标資料通過input子系統上報應用層,現在來具體分析一下input子系統上報的這些資料的含義,例如按下觸摸鍵後,序列槽會有如下列印:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

将資料内容摘出來看:

/*****************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函數上報

注:上面的列印,有多點觸摸和單點觸摸的上報,實際上如果使用了多點觸摸,可以将單點觸摸的上報去掉,如下:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

去掉後,再次測試,可以看到隻有多點觸摸資料的上報:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

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      
【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

然後(使用之前編寫的編譯腳本)重新編譯linux核心

再将zImage拷貝到闆子中,重新啟動闆子。

正常情況下,在核心啟動的時候就列印出觸摸驅動的event編号資訊,我這裡确實也列印了,隻是随後一直刷IIC錯誤:

【i.MX6ULL】驅動開發13——電容觸摸驅動實踐(下)

暫時看不出來是什麼原因,才這居列印看,觸摸開始讀資料時才會進到這裡,感覺像是觸摸驅動剛加載完成,就觸發了中斷,但在中斷裡通過IIC讀取觸摸資料時,又出現了問題。。。

一個暫時的替代方式是,可以在開機自啟動檔案中進行觸摸驅動的加載,在/etc/init.d/rcS檔案中補充如下語句即可:

cd /lib/modules/4.1.15
depmod
modprobe gt911.ko
cd /      

5 總結

本篇首先介紹了測試觸摸是庫——tslib,使用它可以進行圖形化的觸摸測試。随後,又分析觸摸協定上報的原理以及通過input子系統上報的資料的具體含義。

附:示範視訊

繼續閱讀