• 触摸屏驱动


    硬件配置

    硬件原理

    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) ", (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

       

  • 相关阅读:
    python split的用法
    大学排名爬虫
    一直在报错:ModuleNotFoundError: No module named 'bs4'.
    微信小程序部署到线上环境
    mybatis关联三张表查询对应字段名
    WPF图像裁剪控件
    git创建标签并推送到远程
    Windows7、10的热键屏蔽
    WPF使用SVG简单整理
    Visual Studio 注册码和下载
  • 原文地址:https://www.cnblogs.com/lilto/p/11878187.html
Copyright © 2020-2023  润新知