电容触摸屏驱动分析
电容触摸屏硬件原理
电容触摸屏利用人体电流感应现象,在手指和屏幕之间形成一个电容,手指触摸时吸走一个微小电流,这个电流会导致触摸板上 4 个电极上发生电流流动,控制器通过计算这 4 个电流的比例就能算出触摸点的坐标。
电容触摸屏代码分析
电容触摸屏设备是一个字符设备,以 GT9xx 系列的电容触摸屏为例,该电容触摸屏常见采用 I2C 接口连接到主控芯片。
应用程序只需通过 read 函数读取触摸屏设备,即可获取到填充有触摸坐标信息的 mouse_event_notify 结构体。
电容触摸屏初始化
安装触摸屏驱动的逻辑如下:
INT touchDrv (VOID)
{
struct file_operations fileOper;
INT iDrvNum;
lib_memset(&fileOper, 0, sizeof(struct file_operations));
fileOper.owner = THIS_MODULE;
fileOper.fo_create = __touchOpen;
fileOper.fo_open = __touchOpen;
fileOper.fo_close = __touchClose;
fileOper.fo_read = __touchRead;
fileOper.fo_lstat = __touchLstat;
fileOper.fo_ioctl = __touchIoctl;
iDrvNum = iosDrvInstallEx2(&fileOper, LW_DRV_TYPE_NEW_1);
return (iDrvNum);
}
创建触摸屏设备的逻辑如下:
iError = iosDevAddEx(&pTouchDev->TOUCH_devHdr, pcName, iDrvNum, DT_CHR);
if (iError) {
_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY);
__SHEAP_FREE(pTouchDev);
printk(KERN_ERR "Failed to create touch device %s!\n", pcName);
return (PX_ERROR);
}
最终,调用 GT9xx 硬件初始化操作:
- 通过 I2C 接口设置触摸屏扫描数据间隔寄存器、最大支持 TOUCH 点数寄存器。
- 初始化 GT9xx 中断,其采用 GPIO 作为外部中断,当手指触摸到屏幕时,会产生 GPIO 中断。
电容触摸屏事件上抛线程
GT9xx 的触摸事件提交分为上下半程处理,下半程线程会阻塞等待触摸中断事件产生。当产生了触摸中断时,会调用 __touchHandleEvents 获取坐标值,并将获取到的坐标值填入 mouse_event_notify 结构体,最终通过消息队列传送到触摸屏定义的 read 函数中。用户调用触摸驱动的 read 函数时,即可获取到触摸事件信息。
GT9xx 的下半程线程逻辑如下:
static PVOID __touchThread (PVOID pvArg)
{
INT iEventNum;
PTOUCH_DEV pTouchDev = (PTOUCH_DEV)pvArg;
while (!pTouchDev->TOUCH_bQuit) {
API_SemaphoreBPend(pTouchDev->TOUCH_hSignal, LW_OPTION_WAIT_INFINITE);
if (pTouchDev->TOUCH_bQuit) {
break;
}
iEventNum = __touchHandleEvents(pTouchDev);
if (iEventNum == PX_ERROR) {
printk(KERN_ERR "touch: handle touch event fail!\n");
} else if (iEventNum > 0) {
SEL_WAKE_UP_ALL(&pTouchDev->TOUCH_selList, SELREAD);
}
}
return (LW_NULL);
}
__touchHandleEvents 获取坐标值时会调用到 GT9xx 定义的 getevent 函数,在其中读取 GT9xx 的坐标寄存器,并填充为 mouse_event_notify 结构体。当用户手指离开屏幕时,GT9xx 产生 release 事件,getevent 返回值为 TOUCH_RELEASE_NUM ,其实现如下:
static INT __touchHandleEvents (PTOUCH_DEV pTouchDev)
{
mouse_event_notify events[TOUCH_MAX_INPUT_POINTS];
INT iEvents;
INT i = 0;
iEvents = pTouchDev->pDrvFunc->getevent(pTouchDev, events);
if (iEvents == TOUCH_RELEASE_NUM) {
API_MsgQueueSend(pTouchDev->TOUCH_hEventQueue,
(PVOID)&events[0],
(ULONG)sizeof(mouse_event_notify));
i = 1;
} else {
if (iEvents > TOUCH_MAX_INPUT_POINTS) {
iEvents = TOUCH_MAX_INPUT_POINTS;
}
for (i=0; i<iEvents; i++) {
API_MsgQueueSend(pTouchDev->TOUCH_hEventQueue,
(PVOID)&events[i],
(ULONG)sizeof(mouse_event_notify));
}
}
return (i);
}
电容触摸屏触摸中断产生
手指触摸时中断处理逻辑如下:
static irqreturn_t __touchIsr (PTOUCH_DEV pTouchDev, ULONG ulVector)
{
irqreturn_t irqreturn;
irqreturn = API_GpioSvrIrq(pTouchDev->TOUCH_data.T_uiIrq);
if (irqreturn == LW_IRQ_HANDLED) {
API_GpioClearIrq(pTouchDev->TOUCH_data.T_uiIrq);
API_SemaphoreBPost(pTouchDev->TOUCH_hSignal);
}
return (irqreturn);
}