触摸屏驱动

摘要:
硬件配置硬件原理ADANDTOUCHSCREENNINTERFFACESPECIALLREGISTERS程序框架软件架构:输入子系统的优化措施① 问题:ADC转换的值变化太大且不稳定;原因1:触摸屏被“触摸”,触摸点的电压值尚未稳定,已被ADC转换为数字量;改进1:将ADC转换延迟(reg:ACDLY)设置为最大值;原因2:如果在ADC转换完成之前触摸屏已“触摸释放”,则转换后的值将不会

硬件配置

硬件原理

触摸屏驱动第1张

ADC AND TOUCH SCREEN INTERFACE SPECIAL REGISTERS

触摸屏驱动第2张

触摸屏驱动第3张

触摸屏驱动第4张

触摸屏驱动第5张

 

触摸屏驱动第6张

触摸屏驱动第7张

   

触摸屏驱动第8张

   

触摸屏驱动第9张

触摸屏驱动第10张触摸屏驱动第11张

   

触摸屏驱动第12张

   

触摸屏驱动第13张

   

程序框架

软件架构:输入子系统

 触摸屏驱动第14张

   

优化措施

①问题:ADC转换出来的值变化太大,不稳定;

原因1:触摸屏被"触摸",触摸点电压值尚未稳定,已经被ADC转换成数字量;

改善1:设置ADC转换延时(reg:ADCDLY),把延时值设为最大;

   

原因2:假设在ADC转换结束之前,触摸屏已"触摸松开",那么转换出来的值将不正确;

改善2ADC转换完成,判断触摸屏状态,如果已经"松开",则认为转换无效,丢弃已转换数据;

   

②为了使ADC转换出来的数据稳定可靠,可增加软件滤波算法;

   

驱动程序

driver.c

1 /*
2 * 参考s3c2410_ts.c
3 */
4
5 #include <linux/errno.h>
6 #include <linux/kernel.h>
7 #include <linux/module.h>
8 #include <linux/slab.h>
9 #include <linux/input.h>
10 #include <linux/init.h>
11 #include <linux/serio.h>
12 #include <linux/delay.h>
13 #include <linux/platform_device.h>
14 #include <linux/clk.h>
15 #include <asm/io.h>
16 #include <asm/irq.h>
17
18 #include <asm/plat-s3c24xx/ts.h>
19
20 #include <asm/arch/regs-adc.h>
21 #include <asm/arch/regs-gpio.h>
22
23
24 struct s3c_ts_regs{
25         unsigned long ADCCON;
26         unsigned long ADCTSC;
27         unsigned long ADCDLY;
28         unsigned long ADCDAT0;
29         unsigned long ADCDAT1;
30         unsigned long ADCUPDN;
31 };
32
33 static struct timer_list ts_timer;
34 static struct input_dev *ts_dev;
35 static struct s3c_ts_regs *ts_regs;
36
37 static void enter_wait_pen_down(void)
38 {
39         //设置电阻屏"点击"触发中断
40         ts_regs->ADCTSC = 0xd3;
41 }
42
43 static void enter_wait_pen_up(void)
44 {
45         //设置电阻屏"松开"触发中断        
46         ts_regs->ADCTSC = 0x1d3;
47 }
48
49 static void enter_measure_xy_mode(void)
50 {
51         //测量"被点击"的坐标
52         ts_regs->ADCTSC &= ~((1<<3) | (1<<2));
53         ts_regs->ADCTSC |= ((1<<3) | (1<<2));
54 }
55
56 static void start_adc(void)
57 {
58         //启动ADC
59         ts_regs->ADCCON |= 1;
60 }
61
62 /*
63 * 电阻屏"点击"或"松开"中断事件处理函数
64 */
65 static irqreturn_t pen_down_up_irq(int irq, void* dev_id)
66 {
67         //电阻屏松开状态
68         if (ts_regs->ADCDAT0 & (1<<15))
69         {
70                 //上报"松开"事件
71                 input_report_abs(ts_dev, ABS_PRESSURE, 0);
72                 input_report_key(ts_dev, BTN_TOUCH, 0);
73                 input_sync(ts_dev);
74                 enter_wait_pen_down();
75         }
76         //电阻屏点击状态
77         else {
78                 //"被点击",测量"被点击"坐标
79                 enter_measure_xy_mode();
80                 start_adc();
81         }
82         return IRQ_HANDLED;
83 }
84
85 /*
86 * 软件过滤
87 */
88 static int filter_ts(int sadcdat0, int sadcdat1)
89 {
90         //滤波算法
91         return 1;
92 }
93
94 /*
95 * ADC转换中断处理函数:
96 * 条件:ADC中断处理完成,进入中断
97 * 处理:
98 * ①如果已"松开",丢弃转换结果,上报"松开时间",并进入等待"点击";
99 * ②否则,获取转换值:
100 * 连续记录转换出来的坐标值,如果不能连续获得4次坐标值,认为本次获取的坐标值是不准确的,丢弃结果;
101 * 如果成功测得4组数据,则进行软件滤波处理;通过滤波,上报坐标,否则丢弃结果;
102 */
103 static irqreturn_t adc_irq(int irq, void* dev_id)
104 {
105         static int cnt;
106         static int sadcdat0[4], sadcdat1[4];
107         int adcdat0, adcdat1;
108
109         adcdat0 = ts_regs->ADCDAT0;
110         adcdat1 = ts_regs->ADCDAT1;
111         if (ts_regs->ADCDAT0 & (1<<15))
112         {
113                 cnt = 0;
114                 input_report_abs(ts_dev, ABS_PRESSURE, 0);
115                 input_report_key(ts_dev, BTN_TOUCH, 0);
116                 input_sync(ts_dev);
117                 enter_wait_pen_down();
118         }
119         else {
120                 sadcdat0[cnt] = adcdat0 & 0x3ff;
121                 sadcdat1[cnt] = adcdat1 & 0x3ff;
122                 cnt ++;
123                 if (cnt == 4)
124                 {
125                         if(filter_ts(sadcdat0, sadcdat1))
126                         {
127                                 //printk("(%d, %d) ", (sadcdat0[0]+sadcdat0[1]+sadcdat0[2]+sadcdat0[3])/4 , (sadcdat1[0]+sadcdat1[1]+sadcdat1[2]+sadcdat1[3])/4);
128                                 //上报事件
129                                 input_report_abs(ts_dev, ABS_X, (sadcdat0[0]+sadcdat0[1]+sadcdat0[2]+sadcdat0[3])/4);
130                                 input_report_abs(ts_dev, ABS_Y, (sadcdat1[0]+sadcdat1[1]+sadcdat1[2]+sadcdat1[3])/4);
131                                 input_report_abs(ts_dev, ABS_PRESSURE, 1);
132                                 input_report_key(ts_dev, BTN_TOUCH, 1);
133                                 input_sync(ts_dev);
134                         }
135                         cnt = 0;
136                         enter_wait_pen_up();
137
138                         //启动定时器,处理长按、滑动的情况
139                         mod_timer(&ts_timer, jiffies + HZ/100);                //定时10ms
140                 }
141                 else {
142                         enter_measure_xy_mode();
143                         start_adc();
144                 }
145         }
146         return IRQ_HANDLED;
147 }
148
149 /*
150 * 定时器超时处理函数
151 */
152 static void ts_timer_fun(unsigned long data)
153 {
154         if (ts_regs->ADCDAT0 & (1<<15))
155         {
156                 //已经"松开"
157                 input_report_abs(ts_dev, ABS_PRESSURE, 1);
158                 input_report_key(ts_dev, BTN_TOUCH, 1);
159                 input_sync(ts_dev);
160                 enter_wait_pen_down();
161         }
162         else {
163                 //长按、滑动状态,继续测量坐标值
164                 enter_measure_xy_mode();
165                 start_adc();
166         }
167
168         return;
169 }
170
171 /* 1、出入口函数 */
172 static __init int sc_init(void)
173 {
174         struct clk *clk;
175
176         /* 1.1、分配一个input_dev结构体 */
177         ts_dev = input_allocate_device();
178         /******** 1.1 end ********/
179
180         /* 1.2、设置 */
181         //1.2.1 事件类设置
182         set_bit(EV_KEY, ts_dev->evbit);
183         set_bit(EV_ABS, ts_dev->evbit);
184
185         //1.2.2 具体事件的产生
186         set_bit(BTN_TOUCH, ts_dev->keybit);
187
188         input_set_abs_params(ts_dev, ABS_X, 0, 0x3FF, 0, 0);
189         input_set_abs_params(ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
190         input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
191         /******** 1.2 end ********/
192
193         /* 1.3 注册 */
194         input_register_device(ts_dev);
195         /******** 1.3 end ********/
196
197         /* 1.4 硬件相关的操作 */
198         //1.4.1 使能ADC外设时钟(CLKCON[15])
199         clk = clk_get(NULL, "adc");
200         clk_enable(clk);
201
202         //1.4.2 设置s3c2440的ADC/TS寄存器
203         ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
204
205         ts_regs->ADCCON = ((1<<14) | (49<<6));//设置预分频
206
207         //模数转换延时,使电压值更稳定
208         ts_regs->ADCDLY = 0xffff;
209
210         //1.4.3 注册中断
211         request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
212         request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
213         enter_wait_pen_down();
214
215         //1.4.4 使用定时器处理长按、滑动
216         init_timer(&ts_timer);
217         ts_timer.function = ts_timer_fun;
218         add_timer(&ts_timer);
219         /******** 1.4 end ********/
220         return 0;
221 }
222
223 static __exit void sc_exit(void)
224 {
225         free_irq(IRQ_TC, NULL);
226         free_irq(IRQ_ADC, NULL);
227         iounmap(ts_regs);
228         input_unregister_device(ts_dev);
229         input_release_device(ts_dev);
230         del_timer(&ts_timer);
231         return;
232 }
233
234 module_init(sc_init);
235 module_exit(sc_exit);
236
237 MODULE_LICENSE("GPL");
238 /******** 1 end ********/

   

Makefile

1 KERN_DIR = /work/system/linux-2.6.22.6
2
3 all:
4         make -C $(KERN_DIR) M=`pwd` modules
5

6 clean:
7         make -C $(KERN_DIR) M=`pwd` modules clean
8
        rm -rf modules.order

9
10 obj-m        += ts.o

   

   

调试

pc-linux:

cd /work/system/linux-2.6.22.6/

make menuconfig(屏蔽触摸屏驱动)

make uImage

cp arch/arm/boot/uImage /work/nfs_root/uImage_nots

   

board-uboot:

nfs 30000000 192.168.0.103:/work/nfs_root/uImage_nots

bootm 30000000

   

board-linux:

ls /dev/event*

insmod ts.ko

ls /dev/event*

hexdump /dev/event

   

触摸屏驱动第15张

免责声明:文章转载自《触摸屏驱动》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Android-LogCat日志工具(一)CSS遮罩mask下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Stm32ADC-内部温度传感器的使用

搞完了ADC的基本配置步骤,下面就是ADC配合一些外设的应用了,首先就是stm32f1内部的温度传感器通过adc采集获得温度; 内部温度传感器在ADC1的通道16上,所以只需要初始化以下ADC1就好了,然后再写两个函数来获得ADC转换之后的值并根据公式将该值转换为温度即可. 温度公式: 公式中的 Avg_Slope 的典型值 4.3 的单位是 mv/C,...

Stm32 ADC学习

stm32 ADC 简介 stm32的ADC是 12位逐次逼近型 模拟数字转换器;它包括18个通道,可以用来测量16个外部通道和2个内部通道.ADC转换的结果存放在16位数据寄存器(ADC规则数据寄存器,ADC_DR 和 ADC注入数据寄存器,ADC_JDCx)中,这个数据寄存器可以设置对齐方式为左对齐或右对齐. ADC通道与GPIO对应表(图片来自整点...

常见类型ADC原理探秘,选型必知

[导读] 上文总结了主要常见的重要ADC的技术指标,本文来梳理两个方面的内容,常见的ADC类型及原理,以及可能容易掉进去的坑。 谈谈我为什么整理这个文章吧,工程师往往关注点更多在于功能,而忽略了性能。为什么会忽略性能呢?因为可能缺少对于原理的深入探究,那么使用时可能失之毫厘,谬以千里。性能往往不好,稳定性也可能不佳。帽子扣大点说是缺少匠心,其实这也是大学...

(stm32f103学习总结)—ADC模数转换实验

一、STM32F1 ADC介绍  TM32F103 系列一般都有 3 个 ADC,这些 ADC 可以独立使用,也可 以使用双重(提高采样率)。STM32F1 的 ADC 是 12 位逐次 逼近型的模拟数字转换器。它具有多达 18个复用通道,可测量来自16 个外部源、2 个内部源信号。 这些通道的 A/D 转换可 以单次、连续、扫描或间断模式执行。ADC 的...

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

关键词:android 电容屏 tp ITO平台信息:内核:linux2.6/linux3.0系统:android/android4.0平台:S5PV310(samsung exynos 4210) 作者:xubin341719(欢迎转载,请注明作者) android 电容屏(一):电容屏基本原理篇 android 电容屏(二):驱动调试之基本概念篇 and...

STM32F1库函数初始化系列:DMA—ADC采集

1 void ADC_Configure(void) 2 { 3 ADC_InitTypeDef ADC_InitStructure; 4   GPIO_InitTypeDef GPIO_InitStructure; 5 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); 6   RCC_AHBPer...