关键词:android 电容屏 tp 工作队列 中断 坐点计算 电容屏主要参数
平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0

平台:S5PV310(samsung exynos 4210)

转载:http://blog.csdn.net/xubin341719/article/details/7833383

android 电容屏(一):电容屏基本原理篇

android 电容屏(二):驱动调试之基本概念篇

android 电容屏(三):驱动调试之驱动程序分析篇

以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

软件部分,整体流程如下:


三、IIC配置

设备到芯片的数据、初始化值都是从这条总线上传输的,首先我们要配置这个条总线,

/linux/arch/arm/mach-exynos/mach-smdkv310.c,这个因平台而已,地址右移也跟情况而定,如果本来就是7bit的地址就不用移位。

[cpp] view plain copy
  1. staticstructi2c_board_infoi2c_devs5[]__initdata={
  2. #ifCONFIG_TOUCHSCREEN_GT8105
  3. {
  4. I2C_BOARD_INFO("Goodix-TS",(0xaa>>1)),
  5. .irq=IRQ_EINT(5),
  6. }
  7. #endif
  8. };

四、电源、复位(使能脚)

1、电源

3.3V的电源是一直有的,这个硬件上给就行了。

2、复位(时能脚),这个因触摸屏而已,gt8105工作时要高电平。

在:linux3.0/drivers/input/touchscreen/goodix_touch.h

[cpp] view plain copy
  1. #defineRESETPIN_CFGs3c_gpio_cfgpin(EXYNOS4_GPB(4),S3C_GPIO_OUTPUT)
  2. #defineRESETPIN_SET0gpio_direction_output(EXYNOS4_GPB(4),0)
  3. #defineRESETPIN_SET1gpio_direction_output(EXYNOS4_GPB(4),1)
  4. staticvoidgoodix_reset(void)
  5. {
  6. interr;
  7. err=gpio_request(EXYNOS4_GPB(4),"GPX1");
  8. if(err)
  9. printk(KERN_ERR"####failedtorequestGPB_4####\n");
  10. RESETPIN_CFG;//配置管脚功能
  11. RESETPIN_SET0;//管脚拉低
  12. mdelay(20);//延时
  13. RESETPIN_SET1;//管脚拉高
  14. mdelay(60);
  15. gpio_free(EXYNOS4_GPB(4));
  16. }

五、中断配置

在:linux3.0/drivers/input/touchscreen/goodix_touch.h

[cpp] view plain copy
  1. #defineINT_PORTEXYNOS4_GPX0(5)
  2. #ifdefINT_PORT
  3. #defineTS_INTIRQ_EINT(5)//中断引脚,中断号
  4. #defineINT_CFGS3C_GPIO_SFN(0x0F)
  5. #else
  6. 在:linux3.0/drivers/input/touchscreen/goodix_touch.h中中断申请
  7. #ifdefINT_PORT
  8. client->irq=TS_INT;
  9. if(client->irq)
  10. {
  11. ret=request_irq(client->irq,goodix_ts_irq_handler,IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,client->name,ts);
  12. #endif
上面三部完成了触摸屏工作的最基本配置,保证IIC 、上电、INT正常,触摸屏就可以工作。

六、驱动程序分析(完整代码见goodix_touch.c/goodix_touch.h)

驱动有几个比较重要的部分:probe函数分析;中断申请、工作队列调度;中断下半部函数的执行,坐标值计算、上报。

1、probe函数分析

[cpp] view plain copy
  1. staticintgoodix_ts_probe(structi2c_client*client,conststructi2c_device_id*id)
  2. {
  3. structgoodix_ts_data*ts;
  4. …………
  5. //1,分配触摸屏结构内核空间;
  6. ts=kzalloc(sizeof(*ts),GFP_KERNEL);
  7. …………
  8. //2,初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;
  9. INIT_WORK(&ts->work,goodix_ts_work_func);
  10. …………
  11. //3,触摸芯片初始化;
  12. for(retry=0;retry<3;retry++)
  13. {
  14. ret=goodix_init_panel(ts);
  15. …………
  16. }
  17. //4、触摸屏复位,拉高;
  18. goodix_reset();
  19. #ifdefINT_PORT
  20. //5,中断申请,TS_INT就是我们所设定的中断脚;
  21. client->irq=TS_INT;
  22. ret=request_irq(client->irq,goodix_ts_irq_handler,IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
  23. client->name,ts);
  24. ………………
  25. #endif
  26. //6、分配input驱动内核空间;
  27. ts->input_dev=input_allocate_device();
  28. //7,input初始化参数设定,我们在前面提到Linux与Android多点触摸协议里有对这部分说明;
  29. ts->input_dev->evbit[0]=BIT_MASK(EV_SYN)|BIT_MASK(EV_KEY)|BIT_MASK(EV_ABS);
  30. ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)]=BIT_MASK(BTN_TOUCH);
  31. ts->input_dev->absbit[0]=BIT(ABS_X)|BIT(ABS_Y)|BIT(ABS_PRESSURE);//absolutecoor(x,y)
  32. #ifdefHAVE_TOUCH_KEY
  33. for(retry=0;retry<MAX_KEY_NUM;retry++)
  34. {
  35. input_set_capability(ts->input_dev,EV_KEY,touch_key_array[retry]);
  36. }
  37. #endif
  38. input_set_abs_params(ts->input_dev,ABS_X,0,ts->abs_x_max,0,0);
  39. input_set_abs_params(ts->input_dev,ABS_Y,0,ts->abs_y_max,0,0);
  40. input_set_abs_params(ts->input_dev,ABS_PRESSURE,0,255,0,0);
  41. //8、这部分针对触摸屏参数设定;
  42. #ifdefGOODIX_MULTI_TOUCH
  43. input_set_abs_params(ts->input_dev,ABS_MT_WIDTH_MAJOR,0,255,0,0);
  44. input_set_abs_params(ts->input_dev,ABS_MT_TOUCH_MAJOR,0,255,0,0);
  45. input_set_abs_params(ts->input_dev,ABS_MT_POSITION_X,0,ts->abs_x_max,0,0);
  46. input_set_abs_params(ts->input_dev,ABS_MT_POSITION_Y,0,ts->abs_y_max,0,0);
  47. input_set_abs_params(ts->input_dev,ABS_MT_TRACKING_ID,0,ts->max_touch_num,0,0);
  48. #endif
  49. //9、触摸屏版本信息设定;
  50. sprintf(ts->phys,"input/ts");
  51. ts->input_dev->name=goodix_ts_name;
  52. ts->input_dev->phys=ts->phys;
  53. ts->input_dev->id.bustype=BUS_I2C;
  54. ts->input_dev->id.vendor=0xDEAD;
  55. ts->input_dev->id.product=0xBEEF;
  56. ts->input_dev->id.version=10427;//screenfirmwareversion
  57. //10,对于input子系统来说,这个是重头戏了,只有注册了input子系统,其他的才有做用;
  58. ret=input_register_device(ts->input_dev);
  59. ………………
  60. //11,对睡眠唤醒操作;
  61. #ifdefCONFIG_HAS_EARLYSUSPEND
  62. ts->early_suspend.level=EARLY_SUSPEND_LEVEL_BLANK_SCREEN+1;
  63. ts->early_suspend.suspend=goodix_ts_early_suspend;
  64. ts->early_suspend.resume=goodix_ts_late_resume;
  65. register_early_suspend(&ts->early_suspend);
  66. #endif
  67. ………………
  68. }

(1)、分配触摸屏结构内核空间;

[cpp] view plain copy
  1. structgoodix_ts_data{
  2. uint16_taddr;
  3. uint8_tbad_data;
  4. structi2c_client*client;
  5. structinput_dev*input_dev;
  6. intuse_reset;//useRESETflag
  7. intuse_irq;//useEINTflag
  8. intread_mode;//readmoudlemode,20110221byandrew
  9. structhrtimertimer;
  10. structwork_structwork;
  11. charphys[32];
  12. intretry;
  13. structearly_suspendearly_suspend;
  14. int(*power)(structgoodix_ts_data*ts,inton);
  15. uint16_tabs_x_max;
  16. uint16_tabs_y_max;
  17. uint8_tmax_touch_num;
  18. uint8_tint_trigger_type;
  19. uint8_tgreen_wake_mode;
  20. };

(2)、初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;这个和中断申请一起分析;

(3)、触摸芯片初始化;

对触摸芯片寄存器的初始化,这里面对中断方式设定等,一般芯片厂的FAE在调试的时候会修改这里面的值,这个也是因芯片而异,有的在驱动里做,可以直接改;有的直接做成固件了,那部分要FAE帮忙了。

[cpp] view plain copy
  1. uint8_tcfg_info_group1[]=
  2. {
  3. 0x65,0x00,0x25,0x80,0x19,0x00,0x00,0x2C,0x11,0x11,0x32,0x02,0x08,0x10,0x20,0x00,
  4. 0x00,0x88,0x88,0x88,0x03,0x13,0x32,0x64,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
  5. 0x08,0x09,0x0A,0x0B,0x0C,0xFF,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
  6. 0x17,0x18,0x19,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  7. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  8. 0x00,0x00,0x00,0x00
  9. };

(4)、触摸屏复位,拉高;

gt8015在工作时要拉高,所以我们做一个拉低—延时--拉高的操作;

(5)、中断申请,TS_INT就是我们所设定的中断脚,和(2)一起后面分析;

(6)、分配input驱动内核空间;

[cpp] view plain copy
  1. ts->input_dev=input_allocate_device();

(7)、input初始化参数设定,我们在前面提到Linux与Android 多点触摸协议里有对这部分说明;(8)、这部分针对触摸屏参数设定;

(9)、触摸屏版本信息设定;

[cpp] view plain copy
  1. cat/proc/bus/input/devices时可以看到下面信息(这个是pixcir的触摸屏)
  2. I:Bus=0018Vendor=0000Product=0000Version=0000
  3. N:Name="pixcir-ts"
  4. P:Phys=
  5. S:Sysfs=/devices/platform/s3c2440-i2c.5/i2c-5/5-005c/input/input3
  6. U:Uniq=
  7. H:Handlers=kbdevent3
  8. B:PROP=0
  9. B:EV=b
  10. B:KEY=40000001000400008000000
  11. B:ABS=26500001000000

(10)、对于input子系统来说,这个是重头戏了,驱动注册到input子系统;

[cpp] view plain copy
  1. input_register_device(ts->input_dev);

(11),触摸屏睡眠唤醒操作,这部分不做详细说明,感兴趣的可以看下……

2、中断申请、工作队列调度

(1)、中断申请

[cpp] view plain copy
  1. ret=request_irq(client->irq,goodix_ts_irq_handler,IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
  2. client->name,ts);
  3. 第一个参数:中断号,client->irq,client->irq=TS_INT;
  4. #defineTS_INTIRQ_EINT(5)对应到我们要申请的中断;
  5. 第二个参数:中断执行函数,goodix_ts_irq_handler;
  6. 第三个参数:中断触发方式:上升沿触发、下降沿触发、高电平触发、低电平触发
  7. IRQ_TYPE_EDGE_RISING,
  8. IRQ_TYPE_EDGE_FALLING,
  9. IRQ_TYPE_LEVEL_LOW,
  10. IRQ_TYPE_LEVEL_HIGH
  11. 第四个参数:
  12. 第五个参数:

(2)、中断处理函数 goodix_ts_irq_handler

[cpp] view plain copy
  1. staticirqreturn_tgoodix_ts_irq_handler(intirq,void*dev_id)
  2. {
  3. structgoodix_ts_data*ts=dev_id;
  4. queue_work(goodix_wq,&ts->work);
  5. returnIRQ_HANDLED;
  6. }

看下queue_work()这个函数中的两个参数:

a、goodix_wq

[cpp] view plain copy
  1. goodix_wq=create_singlethread_workqueue("goodix_wq");//createaworkqueueandworkerthread

在函数 goodix_ts_init中,创建工作队列和工作线程,初始化时创建线程。

b、&ts->work

在函数goodix_ts_probe()中:

[cpp] view plain copy
  1. 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()函数

这就是核心部分,坐标点的计算、上报、多点处理都在这个函数中执行。

[cpp] view plain copy
  1. staticvoidgoodix_ts_work_func(structwork_struct*work)
  2. {
  3. intret=-1;
  4. inttmp=0;
  5. uint8_tpoint_data[(1-READ_COOR_ADDR)+1+2+5*MAX_FINGER_NUM+1]={0};//readaddress(1byte)+keyindex(1byte)+pointmask(2bytes)+5bytes*MAX_FINGER_NUM+coorchecksum(1byte)
  6. uint8_tcheck_sum=0;
  7. uint16_tfinger_current=0;
  8. uint16_tfinger_bit=0;
  9. unsignedintcount=0,point_count=0;
  10. unsignedintposition=0;
  11. uint8_ttrack_id[MAX_FINGER_NUM]={0};
  12. unsignedintinput_x=0;
  13. unsignedintinput_y=0;
  14. unsignedintinput_w=0;
  15. unsignedcharindex=0;
  16. unsignedchartouch_num=0;
  17. structgoodix_ts_data*ts=container_of(work,structgoodix_ts_data,work);
  18. if(g_enter_isp)return;
  19. COORDINATE_POLL:
  20. if((ts->int_trigger_type>1)&&(gpio_get_value(INT_PORT)!=(ts->int_trigger_type&0x01)))
  21. {
  22. gotoNO_ACTION;
  23. }
  24. if(tmp>9){
  25. dev_info(&(ts->client->dev),"I2Ctransfererror,touchscreenstopworking.\n");
  26. gotoXFER_ERROR;
  27. }
  28. if(ts->bad_data)
  29. msleep(20);
  30. point_data[0]=READ_COOR_ADDR;//readcooraddress
  31. //1、读取触摸屏值,手指数、坐标值等;
  32. ret=i2c_read_bytes(ts->client,point_data,((1-READ_COOR_ADDR)+1+2+5*ts->max_touch_num+1));
  33. …………
  34. //2、判断是否有手指按下;
  35. finger_current=(point_data[3-READ_COOR_ADDR]<<8)+point_data[2–READ_COOR_ADDR];
  36. if(finger_current)//3、如果有手指按下
  37. {
  38. point_count=0,finger_bit=finger_current;
  39. //3,循环判断有多少手指按下;
  40. for(count=0;(finger_bit!=0)&&(count<ts->max_touch_num);count++)//calhowmanypointtouchcurrntly
  41. {
  42. if(finger_bit&0x01)
  43. {
  44. track_id[point_count]=count;
  45. point_count++;
  46. }
  47. finger_bit>>=1;
  48. }
  49. //4、把按下手指数赋给touch_num;
  50. touch_num=point_count;
  51. //5、计算坐标值;
  52. check_sum=point_data[2-READ_COOR_ADDR]+point_data[3-READ_COOR_ADDR];//calcoorchecksum
  53. count=4-READ_COOR_ADDR;
  54. for(point_count*=5;point_count>0;point_count--)
  55. check_sum+=point_data[count++];
  56. check_sum+=point_data[count];
  57. if(check_sum!=0)//checksumverifyerror
  58. {
  59. printk("coorchecksumerror!\n");
  60. if(ts->int_trigger_type>1)
  61. gotoCOORDINATE_POLL;
  62. else
  63. gotoXFER_ERROR;
  64. }
  65. }
  66. //6、读取值坐标值上报;
  67. if(touch_num)
  68. {
  69. //7、touch_num为按下手指个数,依次循环读取;
  70. for(index=0;index<touch_num;index++)
  71. {
  72. position=4-READ_COOR_ADDR+5*index;
  73. //8、读出X的值;
  74. input_x=(unsignedint)(point_data[position]<<8)+(unsignedint)(point_data[position+1]);
  75. //9、读出Y的值;
  76. input_y=(unsignedint)(point_data[position+2]<<8)+(unsignedint)(point_data[position+3]);
  77. input_w=(unsignedint)(point_data[position+4]);
  78. //10、如果读出值超出范围,退出;
  79. if((input_x>ts->abs_x_max)||(input_y>ts->abs_y_max))
  80. continue;
  81. //11、下面的函数依次上报坐标,input_mt_sync单点同步
  82. input_report_abs(ts->input_dev,ABS_MT_POSITION_X,input_x);
  83. input_report_abs(ts->input_dev,ABS_MT_POSITION_Y,input_y);
  84. input_report_abs(ts->input_dev,ABS_MT_TOUCH_MAJOR,input_w);
  85. input_report_abs(ts->input_dev,ABS_MT_WIDTH_MAJOR,input_w);
  86. input_report_abs(ts->input_dev,ABS_MT_TRACKING_ID,track_id[index]);
  87. input_mt_sync(ts->input_dev);
  88. }
  89. }
  90. //12、没有触摸时,初始值为0;
  91. else
  92. {
  93. input_report_abs(ts->input_dev,ABS_MT_TOUCH_MAJOR,0);
  94. input_report_abs(ts->input_dev,ABS_MT_WIDTH_MAJOR,0);
  95. input_mt_sync(ts->input_dev);
  96. }
  97. //13、同步多点值;
  98. input_sync(ts->input_dev);
  99. if(ts->int_trigger_type>1)
  100. {
  101. msleep(POLL_TIME);
  102. gotoCOORDINATE_POLL;
  103. }
  104. gotoEND_WORK_FUNC;
  105. NO_ACTION:
  106. END_WORK_FUNC:
  107. XFER_ERROR:
  108. return;
  109. }

总的来数,当我们手指按下是,不管是单个手指,还是多个手指,坐标值和一些信息存储到触摸芯片的相应寄存器中,然后再通过IIC读出,送到主控中就可以了,其他事情就是android去处理了。

如下图所示,规格书中坐标及重量:XY坐标缓存寄存器的高低位:



中断触发--中断函数--工作队列调度--功能函数执行

更多相关文章

  1. Android三角函数
  2. [android] PhoneGap 在 android 下的实现原理
  3. ISurfaceComposer接口有13个成员函数
  4. Android签名验证简介
  5. Android(安卓)中屏幕点击事件的实现
  6. android 电容屏(二):驱动调试之基本概念篇
  7. android 纯c/c++开发
  8. Android的IPC机制Binder的详解(转发)
  9. Android中Message机制的灵活应用

随机推荐

  1. My Android(安卓)Bugs
  2. android 多点触摸 放大 缩小 图片
  3. android工具详解
  4. Android(安卓)自动化测试工具Robotium 之
  5. android生命周期研究
  6. android监听当前应用
  7. Android(安卓)studio 常见错误以及问题
  8. android 自定义相册 多选
  9. Android版本及API等级关系
  10. java.lang.NullPointerException: Attemp