这是几个月以前的东西了,在彻底遗忘之前拿出来好好写写。做个笔记,也算是造福后来人了。在做这个项目之前,没有做过电容屏的驱动,印象中的电容触摸屏是不需要校正的。IC支持多大的屏就要配多大的屏。但是拿到需求,发现要用FT5406做10寸屏,可是FT5406手册上明明写了,最大支持到8.9寸。由于经验不足,感到略懵。就去核实这个需求方案是不是搞错了?!得到的答案:蓝魔的平板也是这个搭配。这样, 那需求应该就没问题了。先看现象再说:
硬件搭起来看现象,如下图:
红色区域是FT5406上报有效数据的范围(1280*600),以左上角为原点 ,X轴方向上报数据的最大值1280,Y轴方向上报的最大数据是600.。但是我用的LG的10.1寸屏,分辨率为1366*768。若想把触摸IC上报的数据和像素点的值一一对应起来,只能通过校正了。开始做校正的时候有点犯抽。竟然自己写校正算法,代码冗长不说,校准误差也特别大。 还好,后来想起了tslib这个东西。tslib是专门为电阻屏设计的一个校正库,只能校正单点触摸数据。而FT5406是支持5点触摸的。 不过只需要校正一点就可以了,这个点与其他四个点的上报数据的偏差大小无区别,只需要在驱动中做相同的消除偏差处理即可。思路有了,下面就从驱动开始说起:
1.FT5406 在Linux 3.5 中的驱动要点----数据上报过程
FT5406是通过IIC总线同CPU进行数据交互的,内核中的驱动框架符合一个典型IIC设备驱动+输入子系统(默认大家是了解IIC设备驱动和输入子系统驱动的)。硬件I/O的初始化和寄存器配置就不在这里赘述了, 照着手册来就可以了。重点看一下,数据上报过程,先看一个FT5406 原理图(图中标的是5206 ,没关系接口是一样的)::
原理图上可以看到,用到了EINT14这根中断线。通过这条中断线,差不多就能猜到上报流程了吧:当用户触摸到触摸板以后,产生中断,在中断服务程序中读IIC。这样就完成了一次数据的上报。下面就看看内核源码的实现,先看一个流程图:
中断代码实现如下:
[cpp]view plaincopystaticvoidft5x0x_ts_pen_irq_work(structwork_struct*work){//底半部中断structft5x0x_ts_data*ts=container_of(work,structft5x0x_ts_data,work);if(!ft5x0x_read_data(ts)){ft5x0x_ts_report(ts);}enable_irq(this_client->irq);}staticirqreturn_tft5x0x_ts_interrupt(intirq,void*dev_id){//顶半部中断structft5x0x_ts_data*ts=dev_id;disable_irq_nosync(this_client->irq);if(!work_pending(&ts->work)){queue_work(ts->queue,&ts->work);}returnIRQ_HANDLED;}
从IC中读取触摸数据:[cpp]view plaincopystaticintft5x0x_read_data(structft5x0x_ts_data*ts){structft5x0x_event*event=&ts->event;u8buf[32]={0};intret;#ifdefCONFIG_FT5X0X_MULTITOUCHret=ft5x0x_i2c_rxdata(buf,31);#elseret=ft5x0x_i2c_rxdata(buf,7);#endifif(ret<0){printk("%s:readtouchdatafailed,%d\n",__func__,ret);returnret;}memset(event,0,sizeof(structft5x0x_event));event->touch_point=buf[2]&0x07;if(!event->touch_point){ft5x0x_ts_release(ts);return1;}#ifdefCONFIG_FT5X0X_MULTITOUCHswitch(event->touch_point){case5:event->x[4]=(s16)(buf[0x1b]&0x0F)<<8|(s16)buf[0x1c];event->y[4]=(s16)(buf[0x1d]&0x0F)<<8|(s16)buf[0x1e];case4:event->x[3]=(s16)(buf[0x15]&0x0F)<<8|(s16)buf[0x16];event->y[3]=(s16)(buf[0x17]&0x0F)<<8|(s16)buf[0x18];case3:event->x[2]=(s16)(buf[0x0f]&0x0F)<<8|(s16)buf[0x10];event->y[2]=(s16)(buf[0x11]&0x0F)<<8|(s16)buf[0x12];case2:event->x[1]=(s16)(buf[0x09]&0x0F)<<8|(s16)buf[0x0a];event->y[1]=(s16)(buf[0x0b]&0x0F)<<8|(s16)buf[0x0c];case1:event->x[0]=(s16)(buf[0x03]&0x0F)<<8|(s16)buf[0x04];event->y[0]=(s16)(buf[0x05]&0x0F)<<8|(s16)buf[0x06];break;default:printk("%s:invalidtouchdata,%d\n",__func__,event->touch_point);return-1;}#elseif(event->touch_point==1){event->x[0]=(s16)(buf[0x03]&0x0F)<<8|(s16)buf[0x04];event->y[0]=(s16)(buf[0x05]&0x0F)<<8|(s16)buf[0x06];}#endifevent->pressure=200;return0;}
上报过程代码:[cpp]view plaincopystaticvoidft5x0x_ts_report(structft5x0x_ts_data*ts){structft5x0x_event*event=&ts->event;intx,y;inti;#ifdefCONFIG_FT5X0X_MULTITOUCHfor(i=0;i<event->touch_point;i++){if(swap_xy){x=event->y[i];y=event->x[i];}else{x=event->x[i];y=event->y[i];}if(scal_xy){x=(x*ts->screen_max_x)/TOUCH_MAX_X;y=(y*ts->screen_max_y)/TOUCH_MAX_Y;}input_report_abs(ts->input_dev,ABS_MT_POSITION_X,x);input_report_abs(ts->input_dev,ABS_MT_POSITION_Y,y);input_report_abs(ts->input_dev,ABS_MT_PRESSURE,event->pressure);input_report_abs(ts->input_dev,ABS_MT_TOUCH_MAJOR,event->pressure);input_report_abs(ts->input_dev,ABS_MT_TRACKING_ID,i);input_mt_sync(ts->input_dev);}#elseif(event->touch_point==1){if(swap_xy){x=event->y[i];y=event->x[i];}else{x=event->x[i];y=event->y[i];}if(scal_xy){x=(x*ts->screen_max_x)/TOUCH_MAX_X;y=(y*ts->screen_max_y)/TOUCH_MAX_Y;}input_report_abs(ts->input_dev,ABS_X,x);input_report_abs(ts->input_dev,ABS_Y,y);input_report_abs(ts->input_dev,ABS_PRESSURE,event->pressure);}input_report_key(ts->input_dev,BTN_TOUCH,1);#endifinput_sync(ts->input_dev);}
IC驱动的大致工作流程就是这样的,下面就来看看该怎么去做校正:
一、这个电容屏是往exynos4412 核心 Android4.2设备上移植的,所以第一步要做的是往Anroid移植TSlib1.4库。简述移植过程
1.生成configure
./autogen.sh
安装tslib中遇到的错误:./autogen.sh: 4: autoreconf: not found
是因为在不同版本的tslib下执行autogen.sh产生。它们产生的原因一样,是
因为没有安装 automake工具, (ubuntu 13.10)用下面的命令安装好就可以了。
sudo apt-get install autoconf automake libtool
2./configure --host=交叉编译器路径(注意要用对应Android平台自带的bionic c编译器而不是配套开发板的GNU C编译器)
ac_cv_func_malloc_0_nonnull=yes -static
在tslib/config.h文件中加入如下定义: #define TS_CONF "/system/etc/ts.conf" #define PLUGIN_DIR "/system/lib" #define TS_POINTERCAL "/data/etc/pointercal"
另外由于bionic c 和GNU c的差异,需要修改几个tslib的头文件编译才能通过将下面路径文件 tslib/src/ts_open.c tslib/tests/ts_calibrate.c tslib/tests/fbutils.c 中的 #include <sys/fcntl.h> 修改成 #include <fcntl.h> 将tslib/tests/ts_calibrate.c文件中 static int clearbuf(struct tsdev *ts) 修改为 static void clearbuf(struct tsdev *ts)
将etc/ts.conf的参考配置:
修改tslib/etc/ts.conf内容如下:
module_raw input
module pthres pmin=1
module variance delta=30
module dejitter delta=100
module linear
4.在android源代码init.rc中声明tslib相关环境变量如下:
# touchscreen parameters
export TSLIB_FBDEVICE /dev/graphics/fb0
export TSLIB_CALIBFILE /data/etc/pointercal
export TSLIB_CONFFILE /system/etc/ts.conf
export TSLIB_TRIGGERDEV /dev/input/event0
export TSLIB_TSDEVICE /dev/input/event1
5.将/src/.lib 中生成的库文件,分别全部拷贝开发板的根文件系统对应/system/lib 目录中,将tests目录中的ts_calibrate cp到system/bin中
到此完成对tslib的移植。
在运行ts_calibrate前首先要取消内核对多点触摸的支持,因为tslib只能处理单点的数据格式,而且单点的数据,必须要满足以下上报顺寻:
input_report_abs(ts->input_dev, ABS_X, x); input_report_abs(ts->input_dev, ABS_Y, y); input_report_abs(ts->input_dev, ABS_PRESSURE, event->pressure);
通过运行ts_calibrate,获得校正参数,存放在/data目录下的pointercal文件中
最后要做的就是修改内核驱动/drivers/input/touchscreen/ft5x06_ts.c,添加校正算法(如下)并添加获得的校正参数(红色标注即为获得的校正参数)。如下:
[cpp]view plaincopy#ifdefCONFIG_INPUT_TS_LINEARstaticintts_linear_scale(int*x,int*y,intswap_xy){intxtemp,ytemp;inta[7]={<spanstyle="color:rgb(255,0,0);">87701,-382,-420352,-89,84218,-936128,65536</span>};xtemp=*x;ytemp=*y;if(a[6]==0)return-EINVAL;*x=(a[2]+a[0]*xtemp+a[1]*ytemp)/a[6];*y=(a[5]+a[3]*xtemp+a[4]*ytemp)/a[6];if(swap_xy){inttmp=*x;*x=*y;*y=tmp;}return0;}#endif
static void ft5x0x_ts_report(struct ft5x0x_ts_data *ts) {
struct ft5x0x_event *event = &ts->event;
int x, y;
int i;
#ifdef CONFIG_FT5X0X_MULTITOUCH
for (i = 0; i < event->touch_point; i++) {
if (swap_xy) {
x = event->y[i];
y = event->x[i];
} else {
x = event->x[i];
y = event->y[i];
}
if (scal_xy) {
x = (x * ts->screen_max_x) / TOUCH_MAX_X;
y = (y * ts->screen_max_y) / TOUCH_MAX_Y;
}
#ifdef CONFIG_INPUT_TS_LINEAR
ts_linear_scale(&x, &y, swap_xy);
#endif
在上报过程 首先通过static int ts_linear_scale(int *x, int *y, int swap_xy)函数将从IC获得的触摸点坐标消除偏差。
FT5X06 如何应用在10寸电容屏(linux-3.5电容屏驱动简析移植10寸电容屏驱动到Android4.2) (by liukun321咕唧咕唧)