学习笔记 --- LINUX触摸屏原理与驱动分析
来源:互联网 发布:淘宝网店操作 编辑:程序博客网 时间:2024/05/29 15:36
电阻式触摸屏的原理:
触摸屏定位过程:
输入子系统之前已经分析了一个按键,这里写一个触摸屏,也是一个输入,可以用到输入子系统,我们只要实现device端就可以了,按照以下步骤:
1 分配
2 设置
3 注册
4 硬件设置
前面三步都是软件操作,后面就是配置硬件平台的寄存器,看代码:
#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/serio.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/clk.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/plat-s3c24xx/ts.h>#include <asm/arch/regs-adc.h>#include <asm/arch/regs-gpio.h>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;}//进入测量xy电压模式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();enter_measure_xy_mode();//按下触屏,测量xy电压start_adc();}return IRQ_HANDLED;}//xy电压测完,产生中断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); //100ms定时}else{enter_measure_xy_mode();start_adc();}}return IRQ_HANDLED;}static int s3c_ts_init(void){struct clk* clk;/* 1. 分配一个input_dev结构体 */s3c_ts_dev = input_allocate_device();/* 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);/* 3. 注册 */input_register_device(s3c_ts_dev);/* 4. 硬件相关的操作 *//* 4.1 使能时钟(CLKCON[15]) */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;}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);}module_init(s3c_ts_init);module_exit(s3c_ts_exit);MODULE_LICENSE("GPL");
0 0
- 学习笔记 --- LINUX触摸屏原理与驱动分析
- 学习笔记 --- LINUX LCD显示原理与驱动分析
- Linux驱动学习笔记之触摸屏驱动
- Linux驱动学习笔记之触摸屏驱动
- Linux驱动学习笔记之触摸屏驱动
- Linux驱动学习笔记之触摸屏驱动
- Linux驱动学习笔记----------触摸屏驱动
- linux 触摸屏驱动分析
- linux 触摸屏驱动分析
- Linux 触摸屏驱动分析
- linux触摸屏驱动分析
- linux 触摸屏驱动分析
- linux 触摸屏驱动分析
- linux 触摸屏驱动分析
- linux 触摸屏驱动分析
- 嵌入式linux驱动-触摸屏笔记
- 触摸屏驱动学习笔记 一
- Linux触摸屏驱动学习,mini2440
- 关于android的ScrollView套listView展示不全的问题
- Android使用Application总结
- jsp backspace 重新登录
- cocos2d-x游戏开发 跑酷(一)开始界面
- input type为checkbox或radio时的click默认事件
- 学习笔记 --- LINUX触摸屏原理与驱动分析
- iOS 邮件
- 10.5. Accessing VMs
- des 填充信息的保护,正确加密与解密,中文签名错误异常原因
- 信仰
- python判断当前系统,使用platform模块
- sql 如何应对子查询返回数据有多条 我就是要返回数据有多条
- 古代 经典问题之鸡兔同笼
- win7系统用vmware虚拟机打开mac系统