触摸屏驱动

硬件配置

硬件原理

ADC AND TOUCH SCREEN INTERFACE SPECIAL REGISTERS

 

 

 

 

 

 

 

   

   

 

   

   

   

程序框架

软件架构:输入子系统

 

   

优化措施

①问题: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)\n", (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

   

posted @ 2019-11-17 20:51  Lilto  阅读(576)  评论(0编辑  收藏  举报