当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

12.触摸屏驱动

来源:本站原创 浏览:20次 时间:2021-12-07

触摸屏子系统是通过input子系统来实现,对应设备节点 /dev/input/eventn,熟悉套路后重点放在硬件程序的编写

一、内核自带触摸屏驱动S3c2410_ts的简单分析

S3c2410_ts.c (drivers\input\touchscreen) 内核自带三星的触摸屏驱动
(1)入口函数:

/*注册一个平台driver*/static int __init s3c2410ts_init(void){//     init_MUTEX(&gADClock);   returnplatform_driver_register(&s3c2410ts_driver);}

(2)platform_driver结构体

static struct platform_drivers  3c2410ts_driver = {  .driver         = {  .name  = "s3c2410-ts",  .owner = THIS_MODULE,  },  .probe         = s3c2410ts_probe,  .remove         = s3c2410ts_remove,};/*内核中有同名设备的时候,probe函数s3c2410ts_probe会被调用*/

(3)static int __init s3c2410ts_probe(structplatform_device *pdev)做什么了呢?

  /*分配一个 input_dev结构体*/input_dev =input_allocate_device();

/*设置    能产生哪些事件 按键类事件,绝对位置类事件*/ts.dev =input_dev;ts.dev->evbit[0]= BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);ts.dev->keybit[LONG(BTN_TOUCH)]= BIT(BTN_TOUCH);/*设置绝对位置的参数*/   input_set_abs_params(ts.dev,ABS_X, 0, 0x3FF, 0, 0);//绝对位移方向   input_set_abs_params(ts.dev,ABS_Y, 0, 0x3FF, 0, 0);   input_set_abs_params(ts.dev,ABS_PRESSURE, 0, 1, 0, 0);   ts.dev->private= &ts;   ts.dev->name= s3c2410ts_name;   ts.dev->id.bustype= BUS_RS232;   ts.dev->id.vendor= 0xDEAD;   ts.dev->id.product= 0xBEEF;   ts.dev->id.version= S3C2410TSVERSION;/*注册*/   input_register_device(ts.dev);

(4)touch_timer_fire 当事件发生的时候,上报事件

/*上报事件*/input_report_abs--》input_event

二、参考S3c2410_ts从零写S3C2440触摸屏驱动

触摸屏使用流程
a.按下,产生中断
b.在中断处理程序中,启动ADC转换坐标。
c.ADC结束,产生ADC中断。
d.在ADC中断处理函数中,上报(input_event),启动定时器。
e.定时器时间到(处理长按,滑动操作。)
f.松开
具体触摸屏的测量坐标的原理可以参考https://blog.csdn.net/qq_16933601/article/details/102749277

  1. 分配input_dev结构体
static struct input_dev *s3c_ts_dev;/* 1. 分配一个input_dev结构体 */s3c_ts_dev = input_allocate_device();

  1. 设置
/* 2. 设置 *//* 2.1 能产生哪类事件 */set_bit(EV_KEY, s3c_ts_dev->evbit);/*触摸屏绝对位移事件*/set_bit(EV_ABS, s3c_ts_dev->evbit);/* 2.2 能产生这类事件里的哪些事件 */set_bit(BTN_TOUCH, s3c_ts_dev->keybit);input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);

  1. 注册
/* 3. 注册 */input_register_device(s3c_ts_dev);

  1. 硬件相关操作
/* 4. 硬件相关的操作 *//* 4.1 使能时钟(CLKCON[15]) *//*内核启动时,会把不相关的模块关掉。CLKCON启动各种模块*/clk = clk_get(NULL, "adc");clk_enable(clk);/* 4.2 设置S3C2440的ADC/TS寄存器 */s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));/* bit[14]  : 1-A/D converter prescaler enable * bit[13:6]: A/D converter prescaler value, *            49, ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz * bit[0]: A/D conversion starts by enable. 先设为0 */s3c_ts_regs->adccon = (1<<14)|(49<<6);request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);/* 优化措施1:  * 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断 */s3c_ts_regs->adcdly = 0xffff;/* 优化措施5: 使用定时器处理长按,滑动的情况 *  */init_timer(&ts_timer);ts_timer.function = s3c_ts_timer_function;add_timer(&ts_timer);enter_wait_pen_down_mode();return 0;}

  1. 其他相关子函数
struct s3c_ts_regs {unsigned long adccon;unsigned long adctsc;unsigned long adcdly;unsigned long adcdat0;unsigned long adcdat1;unsigned long adcupdn;};static struct input_dev *s3c_ts_dev;static volatile struct s3c_ts_regs *s3c_ts_regs;static struct timer_list ts_timer;static void enter_wait_pen_down_mode(void){s3c_ts_regs->adctsc = 0xd3;}static void enter_wait_pen_up_mode(void){s3c_ts_regs->adctsc = 0x1d3;}static void enter_measure_xy_mode(void){s3c_ts_regs->adctsc = (1<<3)|(1<<2);}static void start_adc(void){s3c_ts_regs->adccon |= (1<<0);}static int s3c_filter_ts(int x[], int y[]){#define ERR_LIMIT 10int avr_x, avr_y;int det_x, det_y;avr_x = (x[0] + x[1])/2;avr_y = (y[0] + y[1])/2;det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))return 0;avr_x = (x[1] + x[2])/2;avr_y = (y[1] + y[2])/2;det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);det_y = (y[3] > avr_y) ? (y[3] - avr_y����,�ٶ�) : (avr_y - y[3]);if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))return 0;return 1;}static void s3c_ts_timer_function(unsigned long data){if (s3c_ts_regs->adcdat0 & (1<<15)){/* 已经松开 */input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);input_report_key(s3c_ts_dev, BTN_TOUCH, 0);input_sync(s3c_ts_dev);enter_wait_pen_down_mode();}else{/* 测量X/Y坐标 */enter_measure_xy_mode();start_adc();}}static irqreturn_t pen_down_up_irq(int irq, void *dev_id){if (s3c_ts_regs->adcdat0 & (1<<15)){//printk("pen up\n");input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);input_report_key(s3c_ts_dev, BTN_TOUCH, 0);input_sync(s3c_ts_dev);enter_wait_pen_down_mode();}else{//printk("pen down\n");//enter_wait_pen_up_mode();/*测量xy*/enter_measure_xy_mode();start_adc();}return IRQ_HANDLED;}static irqreturn_t adc_irq(int irq, void *dev_id){static int cnt = 0;static int x[4], y[4];int adcdat0, adcdat1;/* 优化措施2: 如果ADC完成时, 发现触摸笔已经松开, 则丢弃此次结果 */adcdat0 = s3c_ts_regs->adcdat0;adcdat1 = s3c_ts_regs->adcdat1;if (s3c_ts_regs->adcdat0 & (1<<15)){/* 已经松开 */cnt = 0;input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);input_report_key(s3c_ts_dev, BTN_TOUCH, 0);input_sync(s3c_ts_dev);enter_wait_pen_down_mode();}else{// printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);/* 优化措施3: 多次测量求平均值 */x[cnt] = adcdat0 & 0x3ff;y[cnt] = adcdat1 & 0x3ff;++cnt;if (cnt == 4){/* 优化措施4: 软件过滤 */if (s3c_filter_ts(x, y)){//printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);input_report_key(s3c_ts_dev, BTN_TOUCH, 1);input_sync(s3c_ts_dev);}cnt = 0;enter_wait_pen_up_mode();/* 启动定时器处理长按/滑动的情况 */mod_timer(&ts_timer, jiffies + HZ/100);}else{enter_measure_xy_mode();start_adc();}}return IRQ_HANDLED;}

  1. 退出
static void s3c_ts_exit(void){free_irq(IRQ_TC, NULL);free_irq(IRQ_ADC, NULL);iounmap(s3c_ts_regs);input_unregister_device(s3c_ts_dev);input_free_device(s3c_ts_dev);del_timer(&ts_timer);}

  1. 注册初始化和退出函数
module_init(s3c_ts_init);module_exit(s3c_ts_exit);MODULE_LICENSE("GPL");

  1. 测试
    a. ls /dev/event*
    b. insmod s3c_ts.ko
    c. ls /dev/event*
    d. hexdump /dev/event0
              秒     微秒   type   code   value
    0000000 29a4 0000 8625 0008 0003 0000 0172 0000
    0000010 29a4 0000 8631 0008 0003 0001 027c 0000
    0000020 29a4 0000 8634 0008 0003 0018 0001 0000
    0000030 29a4 0000 8638 0008 0001 014a 0001 0000
    0000040 29a4 0000 863c 0008 0000 0000 0000 0000
    0000050 29a4 0000 c85e 0008 0003 0000 0171 0000
    0000060 29a4 0000 c874 0008 0003 0001 027d 0000
    0000070 29a4 0000 c87b 0008 0000 0000 0000 0000
    0000080 29a4 0000 ed37 0008 0003 0018 0000 0000
    0000090 29a4 0000 ed48 0008 0001 014a 0000 0000
    00000a0 29a4 0000 ed4a 0008 0000 0000 0000 0000

  2. 编译tslib

export TSLIB_TSDEVICE=/dev/event1       //触摸屏是哪一个export TSLIB_CALIBFILE=/etc/pointercal   // 校验文件位置    校验后在  /etc/pointercal 生成校验文件export TSLIB_CONFFILE=/etc/ts.conf     // 配置文件位置export TSLIB_PLUGINDIR=/lib/ts               //插件位置export TSLIB_CONSOLEDEVICE=none export TSLIB_FBDEVICE=/dev/fb0             //显示屏

到此触摸屏驱动移植成功。

  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net