You are on page 1of 38

觸控面板驅動實作

與應用
指導老 師: 李 志賢 組長
孫文駿 老師
黃馨臻 老師

組長: 黃熠 样
組員: 王奕 晨 林承 毅 黃 秀蕙 魏 韶
羿
研究動 機
本組藉由這次專題實作的機會,練習寫觸控面板
的 usb 驅動程式並移植在 ARM 板上控制
QT/embedded 滑鼠游標,增進驅動程式撰寫經驗
,以利未來職場上的應用。
電阻 式觸控 面板 原理
電阻式的驅動原理是用電壓降的方式來找座標軸,由下圖可以看出, X
軸和 Y 軸各由一對 0∼5V 的電壓來驅動,當電阻式觸控螢幕被 Touch 到
的時
候,由於迴路被導通,而會產生電壓降,而控制器則會算出電壓降所佔
的比例然後 更進一步算出座標軸。
運作原 理

電壓值 USB OR
控制器 RS232

ADC Interface IC

電阻 式觸控 面板 電腦

根據電壓值
轉換座標
Usb Core
USB CORE 是所有 USB 裝置的介面 ,USB 裝置透過 USB CORE 跟
USB DRIVER 溝通

URB 是 USB DRIVER 和 USB CORE 間 , 傳輸資料的方式 ,URB 有下


面這 4 種

控制傳輸( control urb )


中斷傳輸( interrupt urb )
巨量傳輸( bulk urb )
等時傳輸( isochronous urb )
(vendor 1391 prod ID 1000 )
(vendor ID 1391 prod ID 1000 )
If vid=1391 and pid=1000 ?
(Load driver)
Touch panel Touch panel
urb driver

Usb 隨身碟 Usb core

Usb 等等裝置
Usb 驅動介 紹
第一步 :

Fill in vendor 1391 and prod ID 1000 into the structure

static struct usb_device_id skel_table [] = {


{ USB_DEVICE(1391,1000) },
{}
};
MODULE_DEVICE_TABLE(usb, skel_table);

#cat /proc/bus/usb/devices
Usb 驅動 介紹
第二步 :

Set up the function name in this structure :

將 driver 所需功能填入此 file_operations 結構中 , 上層 ap 呼叫


open 時則 driver 會執行 skel_open , read 時會執行 skel_read write
時會執行 skel_write , ioctl 時會執行 skel_ioctl

static struct file_operations skel_fops = {


.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
.open = skel_open,
.release = skel_release,
.ioctl = skel_ioctl,
};
Usb 驅動 介紹
第三步 :

Set up device file into structure :

設定裝置檔案名稱 , 填入 file_operations 結構名稱 , 設定 minor


number

static struct usb_class_driver skel_class = {


.name = "skel%d",
.fops = &skel_fops,
.minor_base =196,
};
Usb 驅動 介紹
第四步 :

Set up structure usb_driver for this driver

static struct usb_driver skel_driver = {


.name = “skeleton”, //driver 名稱
.id_table = skel_table, //usb id table 表
.probe = skel_probe, // 裝置插入會執行
.disconnect = skel_disconnect, // 裝置拔出會執行
};

第五步 :

Register the usb_driver into usb core

static int __init usb_skel_init(void)


{
usb_register(&skel_driver); // 註冊 driver 到 usb core

}
Usb 驅動 介紹
第六步

Write program in this functions


skel_probe() skel_release()
skel_disconnect() skel_ioctl()
skel_read()
skel_write()
skel_open()
skel_probe()
裝置插 入會 執行
static int skel_probe(struct usb_interface *interface, const struct usb_device_id
*id)
{
………………………..

struct usb_skel *dev = NULL; // 此 driver 的資源結構


usb_register_dev(interface, &skel_class); // 註冊 /dev 底下的裝置檔案
dev->interface = interface; // 取得 interface 儲存進資源結構裡
dev->urb = usb_alloc_urb(0, GFP_KERNEL); // 設定 urb
usb_fill_int_urb(…………..) // 初始化 read 中斷 urb
usb_submit_urb(dev->urb, GFP_KERNEL); // 提交 urb
usb_set_intfdata(interface, dev); // 把資源結構儲存進 interface 裡 , 供往
後使

………………………….
}
skel_open()
上層 ap open 時會執 行
static int skel_open(struct inode *inode, struct file *file)
{

……………………………..

struct usb_skel *dev; // 資源結構


dev = usb_get_intfdata(interface); // 從 interface 取得之前儲存的資源結構
file->private_data = dev; // 把資源結構儲存進 file 指標裡 , 供往後 read write
使用
kref_get(&dev->kref); // 驅動使用權 +1 動作

………………………………….

}
skel_irq()
中斷 urb 完工函 式
static void skel_irq(struct urb *urb, struct pt_regs *regs)
{

struct usb_skel *dev = urb->context; // 從 urb 裡取得資源結構


……………………………….
解析 5byte 座標資訊 , 完成後儲存進 kernel space buf 裡
……………………………….
usb_submit_urb (urb, GFP_ATOMIC);

// 重新提交 read 中斷 urb 到 usb core 裡 , 排定下次傳輸

}
skel_read()
上層 ap read 時會 執行
static ssize_t skel_read(struct file *file, char __user *user_buf, size_t count, loff_t
*ppos)
{
………………………….

struct usb_skel *dev; // 資源結構


dev = (struct usb_skel *)file->private_data; // 取得 file 指標指的資源結構

………………………….

copy_to_user(user_buf,_kernel_buffer,byteread); // 把座標資訊丟到 user space

…………………………..
}
skel_write()
上層 ap write 時會執行
static ssize_t skel_write(struct file *file, const char __user *user_buffer, size_t count,
loff_t *ppos)
{

struct usb_skel *dev; // 資源結構


dev = (struct usb_skel *)file->private_data; // 取得 file 指標指的資源結構
……………………………
copy_from_user(kernel_buf,user_buffer,count) // 取得 user sapce 送進來的資訊
usb_control_msg(…………….) // 把 user space 送進來的資訊使用 urb 寫進 user
space 裡
…………………………...

}
skel_ioctl()
供上層 ap 呼叫的 ioctl
static int skel_ioctl(struct inode *inode, struct file * file,unsigned int cmd,
unsigned long arg)
{
struct usb_skel *dev; // 資源結構
dev=(struct usb_skel *)file->private_data; // 取的資源結構
switch (cmd)
{

case SCR_IOCTL_CLEAR_BUFF:

memset(kernel_buf,0x00,sizeof(kernel_buf));// 清空 kernel space


buf
return 1;

}
skel_release()
上層 ap close 呼叫 會執行

static int skel_release(struct inode *inode, struct file *file)


{

struct usb_skel *dev; // 資源結構


dev = (struct usb_skel *)file->private_data;// 取得資源結構
kref_put(&dev->kref, skel_delete);// 驅動使用權 -1 動作

}
skel_disconnect()
裝置拔 出會 執行

static void skel_disconnect(struct usb_interface *interface)


{
………………………………….

usb_set_intfdata(interface, NULL); // 取消資源結構的儲存


usb_deregister_dev(interface, &skel_class); // 解除 /dev 裝置檔案
usb_unlink_urb(dev->urb); // 取消 urb
usb_free_urb(dev->urb);// 取消 urb
……………………………………
}
usb_skel_exit(void)
rmmod usb.ko 會執行

static void __exit usb_skel_exit(void)


{
usb_deregister(&skel_driver); // 解除驅動的註冊
}
驅動程 式流 程
5 1
Skel_irq() Skel_probe() AP
3 11
Skel_ioctl() skel_disconnect() Open()
2
Skel_open() read()
4 8
interrupt urb 7 Skel_read() Copy_to_user()
Usb core /dev/skel
write()
Skel_write() Copy_from_user(
control urb )

10 Skel_release( close()
)

6 9
Kernel_buf[130] user_buf[130]

Kernel space user space


Usb Device Driver 最後結果 :
Insmod usb. ko 和插入 裝置後

查看 /dev 是否 有裝 置檔案 查看裝 置是 否有載 入驅 動

Cat /proc/bus/usb/devices
座標資 訊

同一點 3 筆資 3 筆取平均數

1200 1133
(C8 or 88) 6a 60 7a 70 1202 1120 / 3 = 1204 1121
公式轉換
Up or down 1212 1111
high low high low

X 座標 14bit y 座標 14bit
Driver porting to ARM
ARM 軟硬體架 構
• ARM9 + 3.5 吋 LCD
• 10 吋電阻式 USB 觸控式面板 ( 接在 ARM9 的 USB 接口
)
• Linux kernel 2.6
• QT/embedded 3.3.8
• Touch panel Usb driver
• QT 程式
QT/embedded 介紹
Trolltech 針對嵌入式環境推出 Qt/Embedded 產
品。與桌上出版本不同, Qt/Embedded 已經直
接取代了 X Server 及 X Library 等角色,將所有
的功能全部整合在一起。

Qt/Embedded 的底層圖形引擎採用
FrameBuffer
的方式顯示 gui 介面
PC & ARM GUI

PC 與 ARM 在視窗介面的差異性比較
PC ARM

GNOME or KDE QT 任意程式

X Server QT/Embedded
(x window driver) (QT touch driver)

Touch panel Usb driver Touch panel Usb driver


QT/embedded 移植
1. 為了讓 QT 支援 touch panel usb driver 修改
qte/src/embedded/qmouselinuxtp_qws.cpp (QT touch driver)

2. 修改 qte/mkspecs/qws/linux-arm-g++/qmake.conf
把原本的 gcc and g++ 改成
arm-linux-gcc arm-linux-g++
3. 開始編譯 :
./configure -thread -embedded ipaq -shared -depths 16 -no-cups -no-ipv6
-thread -no-gfx-qvfb -no-freetype -disable-opengl -disable-xml -disable-
canvas -qt-libjpeg -qt-mouse-linuxtp -xplatform qws/linux-arm-g++
4.Configure 成功後開始 make sub-src

成功後會產生 4 個 .so 檔
libqte-mt.so, libqte-mt.so.3, libqte-mt.so.3.3, libqte-mt.so.3.3.8

最後在使用 NFS server 跟板子連線的方式把這 4 個檔放進 ARM 裡就成功完成


移植
qmouselinuxtp_qws.cpp

• 要修改的有裝置檔案名稱 , 還有 read 方式
( 改成 touch panel usb driver 的 device file /dev/skel0)

void QWSLinuxTPMouseHandlerPrivate::readMouseData()
{

改成可以讀取 touch panel usb driver 的座標


加入兩點校正公式 , 讀取校正檔案

samples[currSample] = QPoint( x, y);


…………………………………
handler->mouseChanged(mousePos,0); // 實際控制 QT 鼠標的函式

}
USB driver 移植
1. 要先在 PC 上用 cross compile 成 arm 可以用的 driver
2. 利用 NFS server 跟板子做連線 , 放進 ARM 板後試試看有沒有作用
利用一隻簡單的 ap 跑看看

1. 最後試者跟 QT/embedded 做結合

寫個簡單的 QT 程式試試看

在終端機打入 ./myqt –qws (FrameBuffer 來執行 )

( 執行後會找尋這 4 個檔案 libqte-mt.so, libqte-mt.so.3, libqte-mt.so.3.3, libqte-


mt.so.3.3.8, load 這些檔案後 , 成功就會跑出 gui 介面 )
ARM QT

900,900

100,100 samples[currSample] = QPoint( x, y);

測試出來 (100,100) 鼠標在左下 (900,900) 鼠標在右上


座標轉 換
(4 byte 座標合併公式 )
X=((byte2<<1) | ((byte1)<<7)) X=(X/20)+100
Y=((byte4<<1) | ((byte3)<<7)) Y=(Y/20)+100

( 原始面 板座 標 ) (16376,16376) ( 轉換 QT 對應座 (900,900)


標)

(0,0)
(0,0)
兩點校正 公式
(X1,Y1) 為 touch panel 左下座標 (X2,Y2) 為 touch panel 右上座
標,
900,900 為 QT 鼠標最大座標

X=900-(900 * ( X-X2) / (X1 – X2) )


Y=900-(900 * ( Y- Y2) / (Y1 – Y2) )
(touch panel 校正前 ) (900,900) (touch panel 校正完後 )

(X2,Y2) (900,900)

(X2,Y2) (900,900)

(X1,Y1) (X1,Y1) (0,0) (0,0)


(0,0)
校正程 式

白色紙表示校正的區域
校正程 式
終端機打入 ./2Pcail_QT -qws 執行 QT 校正程式

點擊畫面上 1 左下座標 2 右上座標


校正程 式
校正完成後 , 畫面會顯示校正完成

程式會把兩點的座標存到檔案裡面 , 供 QT touch driver 使用


運作結 果
• 已經可以利用選定的 3.5 區域來控制鼠標了 , 現在可以點擊和移動鼠

但移動還是會有點誤差
參考資 料
Linux device driver 3/e 第 13 章
謝謝您 耐心聆 聽

You might also like