android 电容屏(三):驱动调试之驱动程序分析篇
平台信息:
内核:linux3.4.39
系统:android4.4
平台:S5P4418(cortex a9)
作者:瘋耔(欢迎转载,请注明作者)
欢迎指正错误,共同学习、共同进步!!
关注博主新浪博客:http://weibo.com/cpjphone
以goodix的gt8105为例
一、总体架构
硬件部分:先看一个总体的图吧,其实触摸屏原理也比较简单,触摸屏和主控芯片间的联系,如下主要有三部分:
1、IIC部分,初始化gt8105的数据和传回主控制的坐标位置信息就是通过IIC这条线传输的;
2、INT,当gt8105初触摸时,会发出中断通知主控接收信息(坐标数据);
3、gt8105电源、复位这一部分,不同芯片有所不同,可以根据触摸屏芯片来配置。
软件部分:
二、电容触摸屏的主要参数(这部分面试的时候也许有人会问的)
记得刚出来找工作时有人问我一些问题,我答不上来,现在感觉很清晰(那时候刚毕业IIC我都说不全)
1、IIC
(1)、clk370KHz~400KHz;
(2)、触摸屏工作在从模式,这个比较简单;
2、电容检测频率,也就是每秒检测的次数:(大概)
(1)、单指≥100Hz;
(2)、五指≥80Hz;
(3)、十指≥60Hz。
3、手指按下,没抬起时触发多少中断?
中断个数也就是检测频率,按下没提起一直有中断。这样我们就可有判断单点、划线之类的操作;
4、校准功能、自动校准(有个别电容屏没有的,用软件校准)
(1)、初始化校准
不同的温度、湿度及物理空间结构均会影响到电容传感器在闲置状态的基准值。一般电容触摸屏会在初始化的 200ms内根据环境情况自动获得新的检测基准。完成触摸屏检测的初始化。
(2)、 自动温漂补偿
温度、湿度或灰尘等环境因素的缓慢变化,也会影响到电容传感器在闲置状态的基准值。实时检测各点数据的变化,对历史数据进行统计分析,由此来修正检测基准。从而降低环境变化对触摸屏检测的影响。
5、推荐工作条件(环境温度为 25°C,VDD=2.8V)
参数 |
最小值 |
典型值 |
最大值 |
单位 |
模拟AVDD(参考AGND) |
2.5 |
2.8 |
3.6 |
V |
数字DVDD(参考DGND) |
2.5 |
2.8 |
3.6 |
V |
电源纹波 |
50(注意电池、充电器的影响) |
mV |
||
工作温度 |
-20 |
+25 |
+85 |
度 |
工作湿度 |
- |
- |
95 |
% |
三、硬件接口电路:
如下图:
SDA |
IIC数据 要上拉电阻,为1K; |
SCL |
IIC 时钟(400KHz) |
TP_EN |
使能脚(gt8105为高电平) |
INT |
中断(一直点到触摸屏时中断是一直发出的) |
VCC |
3.3V 这个电压一直有 |
GND |
地 |
对于S5P4418电路:
与LCD接口部分;
与主控触摸屏中断输入管脚;
与主控I2C数据传递引脚连接;
复位控制引脚与主控连接;
-------
软件部分,整体流程如下:
三、IIC配置
设备到芯片的数据、初始化值都是从这条总线上传输的,首先我们要配置这个条总线,
/linux/arch/arm/mach-exynos/mach-smdkv310.c,这个因平台而已,地址右移也跟情况而定,如果本来就是7bit的地址就不用移位。
static struct i2c_board_info i2c_devs5[] __initdata = {
#if CONFIG_TOUCHSCREEN_GT8105
{
I2C_BOARD_INFO("Goodix-TS", (0xaa>>)),
.irq = IRQ_EINT(),
}
#endif
};
四、电源、复位(使能脚)
1、电源
3.3V的电源是一直有的,这个硬件上给就行了。
2、复位(时能脚),这个因触摸屏而已,gt8105工作时要高电平。
在:linux3.0/drivers/input/touchscreen/goodix_touch.h中
#define RESETPIN_CFG s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT)
#define RESETPIN_SET0 gpio_direction_output(EXYNOS4_GPB(4),0)
#define RESETPIN_SET1 gpio_direction_output(EXYNOS4_GPB(4),1)
static void goodix_reset(void)
{
int err;
err = gpio_request(EXYNOS4_GPB(), "GPX1");
if (err)
printk(KERN_ERR "#### failed to request GPB_4 ####\n");
RESETPIN_CFG; //配置管脚功能
RESETPIN_SET0;//管脚拉低
mdelay(); //延时
RESETPIN_SET1;//管脚拉高
mdelay();
gpio_free(EXYNOS4_GPB());
}
4418:在:linux3.0/drivers/input/touchscreen/goodix_tool.h中
五、中断配置
在:linux3.0/drivers/input/touchscreen/goodix_touch.h中
#define INT_PORT EXYNOS4_GPX0(5)
#ifdef INT_PORT
#define TS_INT IRQ_EINT(5)//中断引脚,中断号
#define INT_CFG S3C_GPIO_SFN(0x0F)
#else 在:linux3./drivers/input/touchscreen/goodix_touch.h中 中断申请
#ifdef INT_PORT
client->irq=TS_INT;
if (client->irq)
{
ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,client->name, ts);
#endif
上面三部完成了触摸屏工作的最基本配置,保证IIC、上电、INT正常,触摸屏就可以工作。
六、驱动程序分析(完整代码见 goodix_touch.c/goodix_touch.h)
驱动有几个比较重要的部分:probe函数分析;中断申请、工作队列调度;中断下半部函数的执行,坐标值计算、上报。
1、probe函数分析
static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct goodix_ts_data *ts;
…………
// 1,分配触摸屏结构内核空间;
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
…………
// 2,初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;
INIT_WORK(&ts->work, goodix_ts_work_func);
…………
// 3, 触摸芯片初始化;
for(retry=; retry<; retry++)
{
ret=goodix_init_panel(ts);
…………
}
//4、触摸屏复位,拉高;
goodix_reset();
#ifdef INT_PORT
// 5,中断申请,TS_INT就是我们所设定的中断脚;
client->irq=TS_INT;
ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
client->name, ts);
………………
#endif // 6、分配input驱动内核空间;
ts->input_dev = input_allocate_device();
// 7,input初始化参数设定,我们在前面提到Linux与Android 多点触摸协议里有对这部分说明;
ts->input_dev->evbit[] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
ts->input_dev->absbit[] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); // absolute coor (x,y)
#ifdef HAVE_TOUCH_KEY
for(retry = ; retry < MAX_KEY_NUM; retry++)
{
input_set_capability(ts->input_dev,EV_KEY,touch_key_array[retry]);
}
#endif input_set_abs_params(ts->input_dev, ABS_X, , ts->abs_x_max, , );
input_set_abs_params(ts->input_dev, ABS_Y, , ts->abs_y_max, , );
input_set_abs_params(ts->input_dev, ABS_PRESSURE, , , , );
//8、这部分针对触摸屏参数设定;
#ifdef GOODIX_MULTI_TOUCH
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, , , , );
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, , , , );
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, , ts->abs_x_max, , );
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, , ts->abs_y_max, , );
input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, , ts->max_touch_num, , );
#endif
//9、触摸屏版本信息设定;
sprintf(ts->phys, "input/ts");
ts->input_dev->name = goodix_ts_name;
ts->input_dev->phys = ts->phys;
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0xDEAD;
ts->input_dev->id.product = 0xBEEF;
ts->input_dev->id.version = ; //screen firmware version
//10,对于input子系统来说,这个是重头戏了,只有注册了input子系统,其他的才有做用;
ret = input_register_device(ts->input_dev);
………………
// 11,对睡眠唤醒操作;
#ifdef CONFIG_HAS_EARLYSUSPEND
ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + ;
ts->early_suspend.suspend = goodix_ts_early_suspend;
ts->early_suspend.resume = goodix_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
………………
}
(1)、分配触摸屏结构内核空间;
struct goodix_ts_data {
uint16_t addr;
uint8_t bad_data;
struct i2c_client *client;
struct input_dev *input_dev;
int use_reset; //use RESET flag
int use_irq; //use EINT flag
int read_mode; //read moudle mode,20110221 by andrew
struct hrtimer timer;
struct work_struct work;
char phys[];
int retry;
struct early_suspend early_suspend;
int (*power)(struct goodix_ts_data * ts, int on);
uint16_t abs_x_max;
uint16_t abs_y_max;
uint8_t max_touch_num;
uint8_t int_trigger_type;
uint8_t green_wake_mode;
};
(2)、初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;这个和中断申请一起分析;
(3)、触摸芯片初始化;
对触摸芯片寄存器的初始化,这里面对中断方式设定等,一般芯片厂的FAE在调试的时候会修改这里面的值,这个也是因芯片而异,有的在驱动里做,可以直接改;有的直接做成固件了,那部分要FAE帮忙了。
uint8_t cfg_info_group1[] =
{
0x65,0x00,0x25,0x80,0x19,0x00,0x00,0x2C,0x11,0x11,0x32,0x02,0x08,0x10,0x20,0x00,
0x00,0x88,0x88,0x88,0x03,0x13,0x32,0x64,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
0x08,0x09,0x0A,0x0B,0x0C,0xFF,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
0x17,0x18,0x19,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};
(4)、触摸屏复位,拉高;
gt8015在工作时要拉高,所以我们做一个拉低—延时--拉高的操作;
(5)、中断申请,TS_INT就是我们所设定的中断脚,和(2)一起后面分析;
(6)、分配input驱动内核空间;
ts->input_dev= input_allocate_device();
(7)、input初始化参数设定,我们在前面提到Linux与Android 多点触摸协议里有对这部分说明;(8)、这部分针对触摸屏参数设定;
(9)、触摸屏版本信息设定;
cat /proc/bus/input/devices时可以看到下面信息(这个是pixcir的触摸屏)
I: Bus= Vendor= Product= Version=
N: Name="pixcir-ts"
P: Phys=
S: Sysfs=/devices/platform/s3c2440-i2c./i2c-/-005c/input/input3
U: Uniq=
H: Handlers=kbd event3
B: PROP=
B: EV=b
B: KEY=
B: ABS=
(10)、对于input子系统来说,这个是重头戏了,驱动注册到input子系统;
input_register_device(ts->input_dev);
(11),触摸屏睡眠唤醒操作,这部分不做详细说明,感兴趣的可以看下……
2、中断申请、工作队列调度
(1)、中断申请
(2)、中断处理函数 goodix_ts_irq_handler
static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
{
struct goodix_ts_data *ts = dev_id;
queue_work(goodix_wq, &ts->work);
return IRQ_HANDLED;
}
看下queue_work()这个函数中的两个参数:
a、goodix_wq
goodix_wq=create_singlethread_workqueue("goodix_wq"); //createa work queue and worker thread
在函数 goodix_ts_init中,创建工作队列和工作线程,初始化时创建线程。
b、&ts->work
在函数goodix_ts_probe()中:
INIT_WORK(&ts->work,goodix_ts_work_func);
在工作队列&ts->work中增加 goodix_ts_work_func任务。
也就是当中断函数触发时,执行中断函数goodix_ts_irq_handler(),中断函数里面对队列调度,调用队列中的goodix_ts_work_func()函数。
3、中断下半部函数的执行goodix_ts_work_func()函数
这就是核心部分,坐标点的计算、上报、多点处理都在这个函数中执行。
static void goodix_ts_work_func(struct work_struct *work)
{
int ret=-;
int tmp = ;
uint8_t point_data[(-READ_COOR_ADDR)+++*MAX_FINGER_NUM+]={ }; //read address(1byte)+key index(1byte)+point mask(2bytes)+5bytes*MAX_FINGER_NUM+coor checksum(1byte)
uint8_t check_sum = ;
uint16_t finger_current = ;
uint16_t finger_bit = ;
unsigned int count = , point_count = ;
unsigned int position = ;
uint8_t track_id[MAX_FINGER_NUM] = {};
unsigned int input_x = ;
unsigned int input_y = ;
unsigned int input_w = ;
unsigned char index = ;
unsigned char touch_num = ; struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work); if(g_enter_isp)return; COORDINATE_POLL:
if((ts->int_trigger_type> )&& (gpio_get_value(INT_PORT) != (ts->int_trigger_type&0x01)))
{
goto NO_ACTION;
} if( tmp > ) { dev_info(&(ts->client->dev), "I2C transfer error,touchscreen stop working.\n");
goto XFER_ERROR ;
} if(ts->bad_data)
msleep(); point_data[] = READ_COOR_ADDR; //read coor address
//1、读取触摸屏值,手指数、坐标值等;
ret=i2c_read_bytes(ts->client, point_data, ((-READ_COOR_ADDR)+++*ts->max_touch_num+));
…………
//2、判断是否有手指按下;
finger_current = (point_data[ - READ_COOR_ADDR]<<) + point_data[ – READ_COOR_ADDR]; if(finger_current)//3、如果有手指按下
{
point_count = , finger_bit = finger_current;
//3,循环判断有多少手指按下;
for(count = ; (finger_bit != ) && (count < ts->max_touch_num); count++)//cal how many point touch currntly
{
if(finger_bit & 0x01)
{
track_id[point_count] = count;
point_count++;
}
finger_bit >>= ;
}
//4、把按下手指数赋给touch_num;
touch_num = point_count;
//5、计算坐标值;
check_sum = point_data[ - READ_COOR_ADDR] + point_data[ - READ_COOR_ADDR]; //cal coor checksum
count = - READ_COOR_ADDR;
for(point_count *= ; point_count > ; point_count--)
check_sum += point_data[count++];
check_sum += point_data[count];
if(check_sum != ) //checksum verify error
{
printk("coor checksum error!\n");
if(ts->int_trigger_type> )
goto COORDINATE_POLL;
else
goto XFER_ERROR;
}
}
//6、读取值坐标值上报;
if(touch_num)
{
//7、touch_num为按下手指个数,依次循环读取;
for(index=; index<touch_num; index++)
{
position = - READ_COOR_ADDR + *index;
//8、读出X的值;
input_x = (unsigned int) (point_data[position]<<) + (unsigned int)( point_data[position+]);
//9、读出Y的值;
input_y = (unsigned int)(point_data[position+]<<) + (unsigned int) (point_data[position+]);
input_w =(unsigned int) (point_data[position+]);
//10、如果读出值超出范围,退出;
if((input_x > ts->abs_x_max)||(input_y > ts->abs_y_max))
continue;
//11、下面的函数依次上报坐标, input_mt_sync单点同步
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, track_id[index]);
input_mt_sync(ts->input_dev);
}
}
//12、没有触摸时,初始值为0;
else
{
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, );
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, );
input_mt_sync(ts->input_dev);
}
//13、同步多点值;
input_sync(ts->input_dev); if(ts->int_trigger_type> )
{
msleep(POLL_TIME);
goto COORDINATE_POLL;
}
goto END_WORK_FUNC; NO_ACTION:
END_WORK_FUNC:
XFER_ERROR: return;
}
总的来数,当我们手指按下是,不管是单个手指,还是多个手指,坐标值和一些信息存储到触摸芯片的相应寄存器中,然后再通过IIC读出,送到主控中就可以了,其他事情就是android去处理了。
如下图所示,规格书中坐标及重量:XY坐标缓存寄存器的高低位:
中断触发--中断函数--工作队列调度--功能函数执行
android 电容屏(三):驱动调试之驱动程序分析篇的更多相关文章
- 【转】android 电容屏(三):驱动调试之驱动程序分析篇
关键词:android 电容屏 tp 工作队列 中断 坐点计算 电容屏主要参数平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV310( ...
- android 电容屏(四):驱动调试之驱动程序分析篇 -- FocalTech
本人用的触摸屏IC是FocalTech公司的ft5306,是一款i2c的电容屏多点触控芯片.对于它的整体驱动官方已经给了,我们就触摸屏和按键部分的代码做相关说明.说明其中应该注意的地方. 对于所有的i ...
- 【转】android 电容屏(二):驱动调试之基本概念篇
关键词:android 电容屏 tp 工作队列 中断 多点触摸协议平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV310(samsung ...
- Android 电容屏驱动
Android 电容屏(一):电容屏基本原理篇 Android 电容屏(二):驱动调试之基本概念篇 Android 电容屏(三):驱动调试之驱动程序分析篇
- 【转】android 电容屏(一):电容屏基本原理篇
关键词:android 电容屏 tp ITO 平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:S5PV310(samsung exynos 42 ...
- Android电容屏(一)【转】
本文转载自:http://blog.csdn.net/xubin341719/article/details/7820492 关键词:Android 电容屏 tp ITO 平台信息:内核:linu ...
- android 电容屏(二):驱动调试之基本概念篇
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
- Android电容屏(二):驱动调试分析【转】
本文转载自:http://blog.csdn.net/xubin341719/article/details/7833383 以goodix的gt8105为例 一.总体架构 硬件部分:先看一个总体的图 ...
- android 电容屏(一):电容屏基本原理篇
平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博 ...
随机推荐
- apache重写
---- 本文旨在提供如何用Apache重写规则来解决一些常见的URL重写方法的问题,通过常见的实例给用户一些使用重写规则的基本方法和线索. 一.为什么需要用重写规则 ---- 网站的生命在于不断地进 ...
- TweenMax动画库学习(五)
目录 TweenMax动画库学习(一) TweenMax动画库学习(二) TweenMax动画库学习(三) Tw ...
- java集合的互转
List<-->数组.List<-->Set.数组<-->Set.Map将键转化为Set.Map将值转化为Set.Map将值转化为List等集合常 public c ...
- [原创] linux课堂-学习笔记-目录及概况
本学习笔记基于:网易云课堂-linux课堂 课时1Centos 6.4安装讲解46:14 课时2Centos 6.4桌面环境介绍与网络连接04:30 课时3 Linux目录结构介绍及内核与shell分 ...
- PHP服务器负载判断
<?php header("content-type:text/html;charset=utf-8"); // echo PHP_OS;exit; // echo get_ ...
- CentOS-6.3安装配置Nginx
安装说明 系统环境:CentOS-6.3软件:nginx-1.2.6.tar.gz安装方式:源码编译安装 安装位置:/usr/local/nginx 下载地址:http://nginx.org/en/ ...
- Inside Microsoft SQL Server 2008: T-SQL Querying 读书笔记1
(5)SELECT (5-2) DISTINCT (5-3)TOP(<top_specifications>) (5-1)<select_list> (1)FRO ...
- Demo学习: FileUpload
FileUpload 文件上传,学习TUniFileUpload控件的使用 TUniFileUpload主要属性: Filter: 文件类型过滤,这个属性在web模式下是无效的,UniGUI目前版本还 ...
- Spark Streaming揭秘 Day32 WAL框架及实现
Spark Streaming揭秘 Day32 WAL框架及实现 今天会聚焦于SparkStreaming中非常重要的数据安全机制WAL(预写日志). 设计要点 从本质点说,WAL框架是一个存储系统, ...
- 64位Python安装PIL
写个小程序需要安装PIL,但是官网只有32位,无法找到64位安装路径.根据网上教程自行编译,但是由于VS版本问题总是提示“Python error: Unable to find vcvarsall. ...