引言
目前,随着手机和平板电脑的广泛使用,电容式触摸屏已成为电子产品的重要组成部分,电容触摸屏的多点触摸功能是红外式、电阻式触摸屏所不具备的,其线性度、透明度和耐久度也有着明显优势。苹果公司的多点触摸技术使人们的生活方式有了极大变化,且随着嵌入式设备和技术的成熟,电容触摸屏作为新兴的输入设备必将得到广泛应用。
SP5V210是基于CortexA8架构的32位处理器,带有内存管理单元MMU,最高主频为1.0 GHz,内部集成图像处理器可以高效显示与处理图像,且可以十分流畅地运行Linux和Android高级系统;GT811为5点电容屏控制芯片,其内部触摸检测网络由 10路感应通道与16路驱动通道构成,通过内部的数模转化模块、模拟放大电路和 MPU 采集实时的触摸信息,并由I2C总线传输到主控处理器。本设计以SP5V210处理器和Linux2.6.25内核为系统的硬件与软件平台,用GT811作为电容式触摸屏的控制器,设计了一种基于SP5V210的嵌入式多点电容触摸屏驱动。
1 电容式触摸屏
目前大部分电容屏是投射式互容电容屏。本文以投射式电容触摸屏为例,应用OGS方案,即将氧化铟锡(ITO)导电膜直接镀在保护玻璃上形成传感器,此时保护玻璃具有了触摸传感功能。该电容触摸屏采用单层ITO(SITO)结构,水平X和垂直Y电极通过蚀刻ITO层形成,电极交叉处有绝缘层,这样X电极与Y电极之间形成了耦合电容CM 。
通过检测触摸屏整个二维平面的互电容大小来计算触摸位置,首先触摸屏控制器会控制X电极依次发出激励信号,Y电极同时接收,得到所有XY电极交叉处的电容值,当手指触摸时会使触摸位置局部电容CM减小,这样根据二维电容数据变化量就可以计算出每个触摸位置的真实坐标。
本设计采用三星公司的SP5V210处理器作为主机,通过I2C总线接口与电容式触摸屏控制芯片GT811相连,GT811集成在柔性线路板上通过绑定技术连接到7寸电容触摸屏屏体上。图1为系统硬件连接示意图。触摸屏控制器GT811驱动端依次从drv00到drv15发出激励脉冲,感应端sens00~sens09同时接收,并转换为数字信号,此时为原始数据rawdata,经数据处理后再由内部MPU通过I2C总线与处理器SP5V210完成触摸坐标信息的交互。

图1 电容触摸屏硬件连接图
2 触摸屏驱动程序设计
本文利用处理器SP5V210、触摸屏控制器GT811和Linux输入子系统来实现多点电容触摸屏的驱动,程序流程如图2所示。

图2 电容触摸屏驱动程序流程图
2.1 I2C总线设备注册
GT811是一个I2C设备,需向Linux内核注册才可被使用。注册GT811的I2C模块先在Linux内核文件arch/arm/machs5pv210/machtq210.c的I2C通道2结构体中加入TC的I2C地址,也就是0x5d,添加后如下:
static struct IIC_board_info tq210_devs2[] __initdata = {
{IIC_BOARD_INFO ("tq210tc", 0x5d),}
};
然后注册此设备:
IIC_register_board_info(2,IIC_devs2,ARRAY_SIZE(IIC_devs2));
系统初始化时会根据板级I2C总线设备配置信息,创建I2C总线客户端设备I2C_client,并将其添加到I2C子系统中。
2.2 I2C总线设备驱动注册
I2C总线设备需要两个结构体:struct IIC_driver表示I2C设备驱动,struct IIC_client用于描述I2C设备:
static struct IIC_driver tc_driver = {
.sd = tc_suspend, /*电源休眠管理函数*/
.res = tc_resume,/*电源唤醒管理函数*/
.probe = tc_probe,/*探测函数*/
.ud = tc_unload,/*卸载函数*/
.id_table = tc_id,/*该变量将驱动与已定义的I2C设备
/*联系起来*/
.driver = {
.name = "tq210tc",
.owner = THIS_MODULE,
},
};
注册和注销I2C总线设备需建立_init函数和_exit函数。
static int tc_init (void) {
IIC_add_driver(&tc_driver);
return 0;
}
static void tc_exit (void) {
IIC_del_driver(&tc_driver);
}
2.3 驱动入口函数
检查到I2C总线设备进入探测函数static int sp5v210_tc_probe (struct IIC_client *client, const struct dev_id*id),该函数的主要工作如下:
(1) 分配goodix_data和input结构内核空间
struct goodix_data
tc = (struct goodix_data *) kzalloc (sizeof (struct goodix_data), GFP_KERNEL);
(2) 探测设备
IIC_client用于描述一个真实的I2C物理设备,在其访问IIC_adapter适配器时,需要先检测其所需要的功能是否支持。
if (IIC_function (client-﹥adp, IIC_FUN_IIC)= =0) {
dev_err (&client->dev, "Have IIC_FUN_IIC ");
ret = -ENODEV;
goto free_tc;
}
触摸屏控制器GT811初始化,通过初始化函数static int tc_init_panel (struct IIC_client *client)配置各相关寄存器,检测是否工作在正常模式。
for (retry = 0; retry!= 5; ++ retry) {
ret = tc_init_panel (client);
if (ret ==0)
break;
}
注册输入设备:
ret = input_register_device (tc_input);
(3) 中断函数
设定中断引脚,触发时电平会被拉低:
client-﹥irq = IRQ_EINT (14);
通过以下函数进行中断申请,其中tc_irq_handler为中断处理函数。
if(request_irq(IRQ_EINT(14),tc_irq_handler,IRQF_TRIGGER_FALLING, "gt811int", NULL) < 0){
printk ("Request irq forGT811 failed!\\n");
ret =ENOMEM;
goto free_wq;
}
手指按下时中断引脚被拉低,处理器SP5V210调用中断处理函数tc_irq_handler,首先该处理函数将提交任务&ts-﹥work给工作队列tc_wq,然后进入工作队列tc_wq中的tc_work_fun函数。
2.4 触摸屏工作函数设计
手指触摸时电容控制器首先会采集多帧原始数据进行平均值处理并存储,再进行数据处理得到实时的坐标信息,通过I2C总线传输触点坐标给CPU,并在触摸屏工作函数中完成坐标点的修正、

图3 触摸位置
上报以及多点处理功能。由于电容触摸屏XY电极上一般会蚀刻成菱形的感应块(对角线长约4~6 mm),这样手指操作时会触摸到4个感应块(如图3所示),需要采用算法定位坐标。
采用重心法计算触点坐标位置(Px,P,y):

其中,Sn为第n个感应块交叉处的信号值,Nx和Ny分别为X、Y电极方向上感应块个数,R为触摸屏的逻辑分辨率。再由工作函数tc_work_fun (struct work_struct* work)进行数据的读取与事件上报。
触摸屏触点坐标信息会保存在控制器GT811的输出信息寄存器中,如表1所列。中断触发后进入tc_work_fun()函数。该函数的主要工作:读取GT811输出信息寄存器中的坐标信息;向上层报告对应的事件和坐标信息。
表1 GT811输出信息寄存器

首先根据输出信息存储器中的数据计算出触点坐标值input_x和input_y,再利用input_report_abs()函数报告相应事件与坐标值。
if(touch_number){//其中touch_number为触摸手指的个数
for(indx)
for(indx=0; indx<touch_number; indx++){ //依次循环读取
position=4-read_coor-addr+indx*5;
input_x=( uint16_t)(point_data[position]<<8)+( uint16_t)(point_data[position]+1);//读x坐标的值
input_y = (uint16_t)(point_data[position+2]<<8) + (uint16_t) (point_data[position+3]); //读出Y的值
//用下面的函数将触点坐标信息和对应事件依次上报给CPU
input_report_abs(tc_input,ABS_MT_MT_TRACK_ID,track_id[indx]);
input_report_abs(tc_input,ABS_MT_TOUCH_MAJOR,input_w);
input_report_abs(tc_input,ABS_MT_POSITION_X,input_x);
input_report_abs(tc_input,ABS_MT_POSITION_Y,input_y);
input_mt_sync(tc_input); //为单点的同步
}
}
input_sync (tc_input); //最后为多点的同步,结束报告
3 触摸屏驱动测试
本文应用两种方法进行驱动测试。第一种是移植编译后通过开源的tslib程序直接对触摸屏进行测试,运行tc_test可以自由画线,测试结果如图4所示。

图4 电容触摸屏测试图
第二种为在驱动函数中通过printk函数和串口工具SecureCRT来显示触摸坐标,触摸的同时显示x,y坐标,如图5所示。虽然该方法没有第一种直观,但通过该方法可以检测出驱动过程中是否工作正常。

图5 电容触摸屏测试图
结语
本设计应用SP5V210处理器和电容触摸屏控制器GT811作为系统硬件,通过两种方法的测试表明,成功地在Linux系统上实现电容触摸屏的驱动。本文分析了电容触摸屏的硬件设计、驱动程序流程和触点坐标定位方法,并详细讨论了触摸屏入口函数与工作函数的设计。只需对底层驱动进行适当修改,就可以将本设计移植到多种嵌入式Linux系统平台上,简化了系统调试与开发。