硬件配置

硬件原理

android8 触摸屏 驱动 触摸屏幕驱动_#include

ADC AND TOUCH SCREEN INTERFACE SPECIAL REGISTERS

android8 触摸屏 驱动 触摸屏幕驱动_linux_02

 

android8 触摸屏 驱动 触摸屏幕驱动_linux_03

 

android8 触摸屏 驱动 触摸屏幕驱动_#include_04

 

 

android8 触摸屏 驱动 触摸屏幕驱动_3c_05

 

android8 触摸屏 驱动 触摸屏幕驱动_linux_06

 

 

android8 触摸屏 驱动 触摸屏幕驱动_3c_07

   

android8 触摸屏 驱动 触摸屏幕驱动_#include_08

   

android8 触摸屏 驱动 触摸屏幕驱动_linux_09

 

android8 触摸屏 驱动 触摸屏幕驱动_#include_10

android8 触摸屏 驱动 触摸屏幕驱动_#include_11

   

android8 触摸屏 驱动 触摸屏幕驱动_linux_12

   

android8 触摸屏 驱动 触摸屏幕驱动_3c_13

   

程序框架

软件架构:输入子系统

 

android8 触摸屏 驱动 触摸屏幕驱动_linux_14

   

优化措施

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

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

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

   

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

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

   

②为了使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*
 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
 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*
104 {
105         static int
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
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 =
 2			
 3 all:
 4         make -C $(KERN_DIR) M=`pwd`
 5
 6 clean:
 7         make -C $(KERN_DIR) M=`pwd`
 8
 9			
10 obj-m        +=

  

  

调试

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

android8 触摸屏 驱动 触摸屏幕驱动_3c_15