FT5X06 如何应用在10寸电容屏(linux-3.5电容屏驱动简析&移植10寸电容屏驱动到Android4.2) (by liukun321咕唧咕唧)
这是几个月以前的东西了,在彻底遗忘之前拿出来好好写写。做个笔记,也算是造福后来人了。在做这个项目之前,没有做过电容屏的驱动,印象中的电容触摸屏是不需要校正的。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。这样就完成了一次数据的上报。下面就看看内核源码的实现,先看一个流程图:
中断代码实现如下:
- static void ft5x0x_ts_pen_irq_work(struct work_struct *work) { //底半部中断
- struct ft5x0x_ts_data *ts = container_of(work, struct ft5x0x_ts_data, work);
- if (!ft5x0x_read_data(ts)) {
- ft5x0x_ts_report(ts);
- }
- enable_irq(this_client->irq);
- }
- static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id) {//顶半部中断
- struct ft5x0x_ts_data *ts = dev_id;
- disable_irq_nosync(this_client->irq);
- if (!work_pending(&ts->work)) {
- queue_work(ts->queue, &ts->work);
- }
- return IRQ_HANDLED;
- }
从IC中读取触摸数据:
- static int ft5x0x_read_data(struct ft5x0x_ts_data *ts) {
- struct ft5x0x_event *event = &ts->event;
- u8 buf[32] = { 0 };
- int ret;
- #ifdef CONFIG_FT5X0X_MULTITOUCH
- ret = ft5x0x_i2c_rxdata(buf, 31);
- #else
- ret = ft5x0x_i2c_rxdata(buf, 7);
- #endif
- if (ret < 0) {
- printk("%s: read touch data failed, %d\n", __func__, ret);
- return ret;
- }
- memset(event, 0, sizeof(struct ft5x0x_event));
- event->touch_point = buf[2] & 0x07;
- if (!event->touch_point) {
- ft5x0x_ts_release(ts);
- return 1;
- }
- #ifdef CONFIG_FT5X0X_MULTITOUCH
- switch (event->touch_point) {
- case 5:
- event->x[4] = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
- event->y[4] = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
- case 4:
- event->x[3] = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
- event->y[3] = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
- case 3:
- event->x[2] = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
- event->y[2] = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
- case 2:
- event->x[1] = (s16)(buf[0x09] & 0x0F)<<8 | (s16)buf[0x0a];
- event->y[1] = (s16)(buf[0x0b] & 0x0F)<<8 | (s16)buf[0x0c];
- case 1:
- 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: invalid touch data, %d\n", __func__, event->touch_point);
- return -1;
- }
- #else
- if (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];
- }
- #endif
- event->pressure = 200;
- return 0;
- }
上报过程代码:
- 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;
- }
- 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);
- }
- #else
- if (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);
- #endif
- input_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编译器)
在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)
3.编译make
将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,添加校正算法(如下)并添加获得的校正参数(红色标注即为获得的校正参数)。如下:
- #ifdef CONFIG_INPUT_TS_LINEAR
- static int ts_linear_scale(int *x, int *y, int swap_xy)
- {
- int xtemp, ytemp;
- int a[7] = {<span style="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) {
- int tmp = *x;
- *x = *y;
- *y = tmp;
- }
- return 0;
- }
- #endif
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咕唧咕唧)的更多相关文章
- 背水一战 Windows 10 (113) - 锁屏: 将 Application 的 Badge 通知和 Tile 通知发送到锁屏, 将 secondary tile 的 Badge 通知和 Tile 通知发送到锁屏
[源码下载] 背水一战 Windows 10 (113) - 锁屏: 将 Application 的 Badge 通知和 Tile 通知发送到锁屏, 将 secondary tile 的 Badge ...
- google 分屏 横屏模式 按home键界面错乱故障分析(二) 分屏的启动过程
google 进入分屏后在横屏模式按home键界面错乱(二) 你确定你了解分屏的整个流程? imageMogr2/auto-orient/strip%7CimageView2/2/w/1240&quo ...
- 索尼Sony ATI显卡驱动 Win7 Win8 Win8.1 视频黑屏 解决方法
索尼ATI显卡驱动 Win7 Win8 Win8.1 视频 黑屏 完美解决方法: 下载这个补丁 安装 即可 解决 ! baidu pan: http://pan.baidu.com/s/1gd ...
- linux 下 取进程占用内存(MEM)最高的前10个进程
# linux 下 取进程占用 cpu 最高的前10个进程ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head # linux 下 取进程占用内存 ...
- 【转】Linux 下取进程占用 cpu/内存 最高的前10个进程
# Linux 下 取进程占用 cpu 最高的前10个进程ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head # linux 下 取进程占用内存 ...
- DELPHI 10.2 TOKYO搭建LINUX MYSQL开发环境
DELPHI 10.2 TOKYO搭建LINUX MYSQL开发环境 笔者使用ubuntu64位LINUX 首先必须保证LINUX可以连互联网. 安装MYSQLsudo apt-get update ...
- DELPHI 10.2(TOKYO) FOR LINUX的兼容性说明
DELPHI 10.2(TOKYO) FOR LINUX的兼容性说明 自DELPHI 10.2(TOKYO) 始开始支持Linux . Delphi Linux 编译器 64 位 Linux 平台支持 ...
- 简析hotjar录屏功能实现原理
简析hotjar录屏功能实现原理 众所周知,hotjar中录屏功能是其重要的一个卖点,看着很牛X酷炫的样子,今天就简单的分析一下其可能实现(这里只根据其请求加上个人理解分析,并不代表hotjar中真实 ...
- linux shell编程,先等10秒再判断是否有进程存在,存在就再等10秒再杀了进程才运行
linux shell编程,先等10秒再判断是否有进程存在,存在就再等10秒再杀了进程才运行 crontab每分钟执行一次,但5秒以上才有更新数据,有时候一分钟可能跑不完上一个进程,需要先等10秒再判 ...
随机推荐
- Python 元组内置函数
Python元组包含了以下内置函数 序号 方法及描述 1 cmp(tuple1, tuple2)比较两个元组元素. 2 len(tuple)计算元组元素个数. 3 max(tuple)返回元组中元素最 ...
- Zookeeper Api
如何使用 Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储 ...
- dimens.xml详解
本文联合两篇博文和自身理解写下 其中一篇:http://blog.csdn.net/hnzcdy/article/details/50628993 另一篇:暂不知原作者 Android中官方建议的屏幕 ...
- WiFi文件上传框架SGWiFiUpload
背景 在iOS端由于文件系统的封闭性,文件的上传变得十分麻烦,一个比较好的解决方案是通过局域网WiFi来传输文件并存储到沙盒中. 简介 SGWiFiUpload是一个基于CocoaHTTPServer ...
- Linux 下不经过BIOS重启(i386)
前段时间有个项目,要求在Linux下不经过BIOS重启,i386平台. 一.可行性分析 众所周知,BIOS中包含了CPU及其他各种设备的初始化代码,Linux系统运行之后是否能够将各种用到的设备返回到 ...
- GIF动态图制作
GIF动态图制作 博客写了也有一阵了,一直好奇大牛的博客里demo的动态图是怎么做的,今天抽空研究了一下,找了一个软件,以后再发现有好的工具再继续推荐 GIF制作工具--LICEcap 效果要比下面的 ...
- hive 压缩全解读(hive表存储格式以及外部表直接加载压缩格式数据);HADOOP存储数据压缩方案对比(LZO,gz,ORC)
数据做压缩和解压缩会增加CPU的开销,但可以最大程度的减少文件所需的磁盘空间和网络I/O的开销,所以最好对那些I/O密集型的作业使用数据压缩,cpu密集型,使用压缩反而会降低性能. 而hive中间结果 ...
- SpriteKit中为何不要在update方法中测试碰撞
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们若要在游戏中做碰撞检测有2种办法,一是利用物理引擎,二是自 ...
- 剑指offer-面试题7:俩个栈实现队列(java)
详细分析请参照C语言版,这里仅仅给出实现代码,注释很详细,不得不说java各种api用起来真是爽飞了 1 package com.xsf.SordForOffer; 2 3 import java.u ...
- lucene索引库的增删改查操作
1. 索引库的操作 保持数据库与索引库的同步 说明:在一个系统中,如果索引功能存在,那么数据库和索引库应该是同时存在的.这个时候需要保证索引库的数据和数据库中的数据保持一致性.可以在对数据库进行增.删 ...