Linux驱动学习笔记之触摸屏驱动

发布者:美好回忆最新更新时间:2023-02-02 来源: elecfans关键字:Linux驱动  触摸屏驱动  中断 手机看文章 扫描二维码
随时随地手机看文章

触摸屏归纳为输入子系统,这里主要是针对电阻屏,其使用过程如下

当用触摸笔按下时,产生中断。

在中断处理函数处理函数中启动ADC转换x,y坐标。

ADC结束,产生ADC中断

在ADC中断处理函数里上报(input_event)启动定时器

再次启动定时器(可以处理滑动、长按)

松开按键

 

其驱动程序的写法和之前写输入子系统的写法基本上一致。

写出入口函数,出口函数并加以修饰,加入相关头文件,然后开始完善各函数,在入口函数中分配input_dev结构体,设置(能产生哪类事件,能产生这类事件中的哪些事件),注册设备,硬件相关的操作等。出口函数中主要对之前注册、分配的一些资源进行释放。

还应根据2440数据手册ADC转换和触摸屏那一章,对相关寄存器根据实际需要进行设置。

 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

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;

void enter_wait_pen_down_mode(void)  /* 进入等待触摸笔按下模式 */

{

    s3c_ts_regs->adctsc = 0xd3;      /* 进入等待中断模式 bit[8]为0 2440手册P442 */

}

void enter_wait_pen_up_mode(void)       /* 进入等待触摸笔松开模式 */

{

    s3c_ts_regs->adctsc = 0x1d3;        /* 进入等待中断模式 bit[8]为1 2440手册P442 */

}

static void enter_measure_xy_mode(void) /* 进入xy测量模式 */

{

    s3c_ts_regs->adctsc = (1<<3) | (1<<2);

}

static void start_adc(void)

{

    s3c_ts_regs->adccon |= (1<<0);       /* 启动ADC */

}

static int s3c_filter_ts(int x[, int y[)      /* 软件过滤 */

{

#define ERR_LIMIT 10      /* 经验值,容差值 */

    int 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 1;

}

static void s3c_ts_timer_functions(unsigned long data)

{

    if (s3c_ts->adcdat0 & (1<<15))   /* 假设时间到 */

    {

        /* 如果触摸已经松开 */

        input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);   /* 上报事件,压力值为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->adcdat0 & (1<<15))   /* 2440手册P447 ADCDAT0寄存器 */

    {

        printk("pen upn");

        enter_wait_pen_down_mode();

    }

    else

    {

        //printk("pen downn");

        //enter_wait_pen_up_mode();

        enter_measure_xy_mode();

        start_adc();

    }

    return IRQ_HANDLED;

}

static irqreturn_t adc_irq(int irq, void *dev id)

{

    static int cnt = 0;

    static int x[4, y[4;

    int adcdat0, adcdat1;

    /* 优化措施2

     * 如果ACD完成时,发现触摸笔已松开,则丢弃此次结果

     */

    adcdat0 = s3c_ts_regs->adcdat0;

    adcdat1 = s3c_ts_regs->adcdat1;

    if (s3c_ts->adcdat0 & (1<<15))     /* bit[15判断是否松开 */

    {

        /* 如果已经松开则丢弃结果 */

        cnt = 0;

        input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);   /* 上报事件,压力值为0 */

        input_report_key(s3c_ts_dev, BTN_TOUCH, 0);

        input_sync(s3c_ts_dev);

        enter_wait_pen_up_mode();

    }

    else

    {

        /* 如果还是按下,则打印结果并进入等待松开模式 */

        //printk("adc_irq cnt = %d,x = %d, y = %dn", ++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 = %dn", (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;    /* cnt计数清0 */

            enter_wait_pen_up_mode();       /* 测量完后要进入等待松开模式,这样才能连续操作 */

            /* 启动定时器处理长按/滑动的情况 */

            mod_timer(&ts_timer, jiffies + HZ/100);  /* 1HZ/100 = 10ms */

        }

        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->evbit); /* 能够产生按键类里面的触摸屏事件 */

    input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);   /* X方向 0xFF是因为触摸屏ADC是10位 */

    input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);   /* Y方向 */

    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));

    /* ADCCON

     * bit[14   : 1 预分频使能

     * bit[13:6 :   预分频系数

     *               49 ,ADCCLK = PCLK/(49+1) = 50MHz/(49+1)=1MHz

     * bit[5:3  : 多路选择

     * bit[2    : 省电模式选择

     * bit[1    : AD启动方式,通过读来启动

     * bit[0    : 启动AD转换,启动后会自动清零

     */

    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_DEscriptION("s3c_ts driver for the s3c2440");

MODULE_LICENSE("GPL");

 

 

 

 

测试方法主要是检测上报事件是否正常,要想更好的测试,需要移植ts_lib这方面的资料网上都可以找到。

以tslib-1.4.tar.gz为例

sudo apt-get install autoconf

sudo apt-get install automake

sudo apt-get install libtool

 

 

 

 

编译:

tar xzf tslib-1.4.tar.gz

cd tslib

./autogen.sh 

 

mkdir tmp      // 安装目录

echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache

[1] [2]
关键字:Linux驱动  触摸屏驱动  中断 引用地址:Linux驱动学习笔记之触摸屏驱动

上一篇:ARM芯片基于linux嵌入式操作系统实现的CMU控制器方案
下一篇:基于ARM9嵌入式的RS485总线接口设计

推荐阅读最新更新时间:2024-11-08 10:25

TQ2440按键中断
有几点需要注意: 1、需要调用MMU函数,实现内存的映射; 2、在中断触发跳入中断处理函数后,首先要清除SRCPND和INTPND相应的位,如果用到次级中断源,如这里用到了EINT4_7中的EINT4,就要清除EINTPEND相应的位。一般来说,应该先清除次级中断源相应的位,再清除中断源,否则中断源会发生多次中断。在完成清除后再进行具体的处理。 #include def.h #include option.h #include 2440addr.h #include 2440lib.h #include 2440slib.h #include mmu.h #define LED1 (1 5) //must be (
[单片机]
Part5核心初始化_lesson4---关闭中断
1、关闭cpsr寄存器里面的I(中断)和F(快速中断)位; 2、设置中断屏蔽寄存器。 针对2440: 这是中断处理过程,当有中断源(没有子中断源)来的时候,它会把这个中断记录在SRCPND里面;它还要经过MASK屏蔽寄存器,如果我们对对应位屏蔽了,那么它就无法进入到IRQ这里来处理。对于有子中断源的同理。 其代码: 针对6410: 打开S3C6410X文件,进入到Vectored Interrupt Controller这个章节, 6410和210采用的是向量中断的方式, 在6410要去屏蔽一个寄存器应该用那个寄存器呢?在6410里面中断源被分为了两组,第0组,VIC0和第1组,VIC1; 往这两个寄存器里面写入全1,
[单片机]
Part5核心初始化_lesson4---关闭<font color='red'>中断</font>
51单片机内核的中断基础知识
51内核的最基础的中断源请求有外部中断、定时器中断和串口中断,这也是学习和开发者最长用的。当然还有其他的中断源,比如ADC、SPI、PWM等。以外部中断0为例,在编程中常使用的方式为: void INT0()interrupt 0 using 1 { …… } 在这里特别做上笔记:其中前面的void INT0() 只是代表一个普通没有形参的函数而已,函数名写成什么都是可以的,这个到不重要。那么后面的就一个一个词的扣把:(2-1-i-c-中国-电子网,防抓取) 其中 interrupt n 组成一组,n用来指明中断号,在函数后使用了interrupt关键字后,就会自动的生成中断向量,51内核中断号如下图,这是
[单片机]
51单片机内核的<font color='red'>中断</font>基础知识
PIC C语言编程_PICC中断函数的实现
PICC可以实现C语言的中断服务程序。中断服务程序有一个特殊的定义方法: voidinterruptISR(void); 其中的函数名“ISR”可以改成任意合法的字母或数字组合,但其入口参数和返回参数类型必须是“void”型,亦即没有入口参数和返回参数,且中间必须有一个关键词“interrupt”。 中断函数可以被放置在原程序的任意位置。因为已有关键词“interrupt”声明,PICC在最后进行代码连接时会自动将其定位到0x0004中断入口处,实现中断服务响应。编译器也会实现中断函数的返回指令“retfie”。一个简单的中断服务示范函数如下: voidinterruptISR(void)//中断服务程序 {
[单片机]
STM8S bootloader中断向量重定向 INTVEC exceeds maximum size 问题解决
最近重装了系统,然后重装了IAR for STM8软件(由于找不到之前的安装软件,就用了剑齿虎开发板提供的IAR安装包),发现以前正常编译的bootloader工程文件,再次编译时出现如下问题: Error : actual size (0x100) exceeds maximum size (0x80) for block “INTVEC” 在icf文件中,INTVEC块确定定义为0x80大小,这是单片机固定的,不能修改,因此应该是编译产生的中断向量代码超出了实际范围。 define block INTVEC with size = 0x80 { ro section .intvec }; 中断向量的重定向的代码如下:
[单片机]
STM8S bootloader<font color='red'>中断</font>向量重定向 INTVEC exceeds maximum size 问题解决
STM8S003定时器1中断服务程序(PWM)中开启定时器2定时计数
STM8S003定时器1中断服务程序(PWM)中开启定时器2定时定时功能,那么在定时器1中断服务程序退出时,立即就产生了定时器2更新中断,但是轴定时器2中断服务程序中(PWM),开启定时器2定时功能,却工作正常,何故? 这是定时器1中断服务程序的开启定时器2的代码: //TIM2_Cmd(DISABLE); TIM2- CR1 &= (uint8_t)(~TIM2_CR1_CEN); //TIM1_Cmd(DISABLE); TIM1- CR1 &= (uint8_t)(~TIM1_CR1_CEN); gsMOTOR.ucPulseCnt = 0;
[单片机]
基于ARM9芯片S3C2410异常中断程序设计
引言 计算机体系结构中,异常或者中断是处理系统中突发事件的一种机制,几乎所有的处理器都提供这种机制。异常主要是从处理器被动接受的角度出发的一种描述,指意外操作引起的异常。而中断则带有向处理器主动申请的意味。但这两种情况具有一定的共性,都是请求处理器打断正常的程序执行流程,进入特定程序的一种机制。若无特别说明,对“异常”和“中断”都不作严格的区分。本文结合经过实际验证的代码对ARM9中断处理流程进行分析,并设计出基于S3C2410芯片的外部中断处理程序。 1.异常中断响应和返回 系统运行时,异常可能会随时发生。当一个异常出现以后,ARM微处理器会执行以下几步操作: 1) 将下一条指令的地址存入相应连接寄存器LR,以便程序在处
[单片机]
基于ARM9芯片S3C2410异常<font color='red'>中断</font>程序设计
51单片机的中断,有些乱
几个与中断有关的寄存器: 1. TCON:中断标志寄存器,内容为 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 2. SCON:串行口控制寄存器,内容为 SM0 SM1 SM2 REN TB8 RB8 TI RI TI:发送数据前应复位,发完一帧数据时,由硬件置位。 RI:接收中断标志,与TI类似 中断响应后,RI和TI不能自动清除,须由软件来清除。 IT0,1:外部中断的触发方式,=1时为下降沿有效 IE0,1:外部中断中断请求标志位 TF0,1:定时器溢出中断请求 3. IP:中断优先级控制寄存器 自然优先级的排列顺序(由高到低):外部中断0(INT0)、定时器T0、外部中断1
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved