S3C2440 触摸屏touch screen驱动程序(十七)

发布者:Yuexiang666最新更新时间:2020-07-17 来源: eefocus关键字:S3C2440  触摸屏  touch  screen  驱动程序 手机看文章 扫描二维码
随时随地手机看文章

1、先来回忆之前第12节分析的输入子系统(请点击这里)


其中输入子系统层次如下图所示:

其中事件处理层的函数是通过input_register_handler()函数注册到input_handler_list链表中


搜索input_register_handler注册函数,就可以看到都是事件处理层里的函数:

所以最终如下图所示:

右边的驱动事件处理,内核是已经写好了的,所以我们的触摸屏只需要写具体的驱动设备,然后内核会与触摸屏驱动tsdev.c自动连接。


 


2、本节需要用到的结构体成员如下:


struct input_dev {     

       void *private;

       const char *name;  //设备名字

       const char *phys;  //文件路径,比如 input/buttons

       const char *uniq;  

       struct input_id id;

 

       unsigned long evbit[NBITS(EV_MAX)];  //表示支持哪类事件,常用有以下几种事件(可以多选)

       //EV_SYN      同步事件,当使用input_event()函数后,就要使用这个上报个同步事件

       //EV_KEY       键盘事件

       //EV_REL       (relative)相对坐标事件,比如鼠标

       //EV_ABS       (absolute)绝对坐标事件,比如摇杆、触摸屏感应

       //EV_MSC      其他事件,功能

       //EV_LED       LED灯事件

       //EV_SND      (sound)声音事件

       //EV_REP       重复键盘按键事件

       //(内部会定义一个定时器,若有键盘按键事件一直按下/松开,就重复定时,时间一到就上报事件)  

 

       //EV_FF         受力事件

       //EV_PWR      电源事件

       //EV_FF_STATUS  受力状态事件

 

       unsigned long keybit[NBITS(KEY_MAX)];   //存放支持的键盘按键值

       //键盘变量定义在:include/linux/input.h, 比如: KEY_L(按键L)、BTN_TOUCH(触摸屏的按键)

 

       unsigned long relbit[NBITS(REL_MAX)];    //存放支持的相对坐标值

       unsigned long absbit[NBITS(ABS_MAX)];   //存放支持的绝对坐标值,存放下面4个absxxx[]

       unsigned long mscbit[NBITS(MSC_MAX)];   //存放支持的其它事件,也就是功能

       unsigned long ledbit[NBITS(LED_MAX)];    //存放支持的各种状态LED

       unsigned long sndbit[NBITS(SND_MAX)];    //存放支持的各种声音

       unsigned long ffbit[NBITS(FF_MAX)];       //存放支持的受力设备

       unsigned long swbit[NBITS(SW_MAX)];     //存放支持的开关功能

         ... ...

 

 

/*以下4个数组都会保存在上面成员absbit[]里,数组号为:ABS_xx ,位于include/linux/input.h */

/*比如数组0,标志就是ABS_X,以下4个的absXXX[0]就是表示绝对位移X方向的最大值、最小值... */

/*对于触摸屏常用的标志有:

ABS_X(X坐标方向), ABS_Y(Y坐标方向), ABS_PRESSURE(压力方向,比如绘图,越用力线就越粗)* / 

       int absmax[ABS_MAX + 1];      //绝对坐标的最大值

       int absmin[ABS_MAX + 1];      //绝对坐标的最小值

       int absfuzz[ABS_MAX + 1];     //绝对坐标的干扰值,默认为0,

       int absflat[ABS_MAX + 1];     //绝对坐标的平焊位置,默认为0

... ...

 


3、本节需要用到的函数:


struct input_dev *input_allocate_device(void);  //向内存中分配input_dev结构体

 

input_free_device(struct input_dev *dev);   //释放内存中的input_dev结构体

 

input_register_device(struct input_dev *dev);   //注册一个input_dev,若有对应的驱动事件,

则在/sys/class/input下创建这个类设备

 

input_unregister_device(struct input_dev *dev);   //卸载/sys/class/input目录下的

input_dev这个类设备

 

 

set_bit(nr,p);                  //设置某个结构体成员p里面的某位等于nr,支持这个功能

/* 比如:

set_bit(EV_KEY,buttons_dev->evbit);   //设置input_dev结构体buttons_dev->evbit支持EV_KEY

set_bit(KEY_S,buttons_dev->keybit);  //设置input_dev结构体buttons_dev->keybit支持按键”S”

*/

 

input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat); 

//设置绝对位移的支持参数

//dev: 需要设置的input_dev结构体

//axis : 需要设置的数组号,常用的有: ABS_X(X坐标方向), ABS_Y(Y坐标方向), ABS_PRESSURE(压力方向)//min: axis方向的最小值, max:axis方向的最大值, fuzz: axis方向的干扰值, flat:axis方向的平焊位置

 

 

input_report_abs(struct input_dev *dev, unsigned int code, int value);   

//上报EV_ABS事件

//该函数实际就是调用的input_event(dev, EV_ABS, code, value);

//*dev :要上报哪个input_dev驱动设备的事件

// code: EV_ABS事件里支持的哪个方向,比如X坐标方向则填入: ABS_X

//value:对应的方向的值,比如X坐标126

 

input_report_key(struct input_dev *dev, unsigned int code, int value);  

//上报EV_KEY事件 

 

input_sync(struct input_dev *dev); //同步事件通知,通知系统有事件上报

 

struct  clk *clk_get(struct device *dev, const char *id);    

//获得*id模块的时钟,返回一个clk结构体

//*dev:填0即可,     *id:模块名字, 比如"adc","i2c"等,名字定义在clock.c中

 

clk_enable(struct clk *clk);   

//开启clk_get()到的模块时钟,就是使能CLKCON寄存器的某个模块的位

 


4、电阻式触摸屏介绍:


如下图所示,2440开发板使用的是4线触摸屏,该4线连接在2440的AIN4~AIN7引脚上,该引脚专门是用来接收模拟输入信号

引脚说明:


YM:(Y Minus)触摸屏的Y坐标的负线,也可以用Y-表示


YP:(Y Power)触摸屏的Y坐标的正线,也可以用Y+表示


XM:(X Minus)触摸屏的X坐标的负线,也可以使用X-表示


YP:(X Power)触摸屏的Y坐标的正线,也可以使用X+表示


4.1 4线触摸屏包含了两个阻性层,如下图所示:

当没有触摸按下时,X和Y层是分离的,此时就测不到电压


4.2 测X坐标方向时:


如下图,把XP接3.3V,XM接0V,YP和YM悬空,我们以按压X坐标的中间位置,X层和Y层便闭合了,此时YP就会输出当前X坐标值的1.66V给CPU

4.3 测Y坐标方向时:


如下图,把YP接3.3V,YM接0V,XP和XM悬空,我们以按压X坐标的中间位置,X层和Y层便闭合了,此时XP就会输出当前X坐标值的1.66V给CPU

5、接下来开始看2440手册


如下图,2440的ADC分辨率为10位(0~0X3FFF)

如下图,若工作在普通ADC模式,则通过寄存器ADCCON->SEL_MUX来选择转换哪个引脚的模拟信号


当设置为ADC等待中断模式时,测到有屏幕笔尖触摸,就会产生INT_TC中断


其中ADC的工作频率最大为2.5MHz,需要设置寄存器ADCCON->PRSCVL更改分频系数

5.1 获取笔尖触摸按下/松开使用的是ADC等待中断模式:


当笔尖落下时,触摸屏控制器产生中断(INT_TC)信号。需要设置寄存器


ADCTSC=0xd3/0x1d3


设置寄存器ADCTSC=0x0d3/0x1d3(X 1101 0011)时(如下图):

开启YM开关,使能XP上拉,开启等待中断模式


当有笔尖按下时,X层和Y层闭合,然后会拉低XP和XM电平,输出低电平


设置为0x0d3是检测触摸低电平,设置为0x1d3是检测触摸上拉电平


(PS:ADCDAT0的bit15位用来标志笔尖是按下还是松开)


5.2 获取XY坐标时,使用的是自动X/Y方向转换模式


当ADC转换成功,X坐标值到ADCDAT0和Y坐标值到ADCDAT1后,就会产生INT_ADC中断


自动获取XY坐标时(如下图):

设置寄存器ADCTSC=0X0C(关闭XP上拉、启动自动XY方向转换)


设置寄存器ADCCON的位[0]=1(开启一次ADC转换,当ADC转换成功该位清0)


6、编写代码


步骤如下:

6.1 在init入口函数


1)分配一个input_dev结构体


2)设置input_dev的成员


    ->2.1)设置input_dev->ebit支持按键时间,绝对位移时间


            (触摸屏:通过按键BTN_TOUCH获取按下/松开,通过绝对位移获取作弊啊)


    ->2.2)设置input_dev->keybit支持BTN_TOUCH触摸屏笔尖按下


    ->2.3)设置input_dev->absbit支持ABS_X、ABS_Y、ABS_PRESSURE


                input_set_abs_params(ts.dev,ABS_X,0,0x3FF,0,0);


                input_set_abs_params(ts.dev,ABS_Y,0,0x3FF,0,0);     //0x3FF:最大值为10位ADC


                input_set_abs_params(ts.dev,ABS_PRESSURE,0,1,0,0);    //压力最多就是1


3)注册input_dev驱动设备到内核中


4)设置触摸屏相关的硬件


    ->4.1)开启ADC时钟,使用clk_get()和clk_enable()函数


    ->4.2)ioremap获取寄存器地址,设置寄存器ADCCON=(1<<14)|(49<<6),分频


    ->4.3)设置寄存器ADCDLY=0xffff,ADC启动延时时间设为最大值,使触摸按压更加稳定


    ->4.4)开启IRC_TC笔尖中断、开启IRQ_ADC中断获取XY坐标


    ->4.5)初始化定时器,增加触摸滑动功能


    ->4.6)最后设置寄存器ADCTSC=0x0d3,开启IRQ_TC中断


6.2 在出口函数中:


1)注销内核里的input_dev


2)释放中断、删除定时器、iounmap注销地址


3)释放input_dev


6.3 在IRQ_TC中断函数中:


1)若判断笔尖为松开,设置寄存器ADCTSC=0xD3(按下中断)


2)若判断笔尖按下,设置为XY自动转换模式,启动一次ADC转换,ADC转换成功,会进入ADC中断


6.4 在IRQ_ADC中断函数中:


1)获取ADCDAT0的位[9:0],来算出XY方向坐标值


2)测量n次值保存在数组中,然后再次设置为XY自动转换模式,启动ADC


    (PS:要启动ADC转换之前,必须设置一次XY为自动转换模式,不然获取的数据会不准)


3)采集完毕,使用快速排序将n次值排序后,以最小值为基准,如有误差非常大的数,则舍弃,如果没有则打印数组的中间值,实现中值滤波。


4)打印数据后,必须设置寄存器ADCTSC=0x1D3(松开中断IRQ_TC)


(PS:在ADC采样模式下是判断不到ADCDAT0的bit15位的,因为ADCDAT0已被自动设置为X坐标的采样值)


5)设置定时器10ms超时时间


6.5 在定时器超时函数中:


1)判断ADCDAT0的bit15位,若还在按下再次启动ADC转换(实现触摸滑动功能)


2)若松开,设置寄存器ADCTSC=0xD3(按下中断)


最终代码如下:


#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;//定时器

 

static void enter_wait_pen_down_mode(void)

{

//bit[8]:0-检测按下

s3c_ts_regs->adctsc = 0xd3; //等待触摸笔按下模式

}

 

static void enter_wait_pen_up_mode(void)

{

//bit[8]:1-检测松开

s3c_ts_regs->adctsc = 0x1d3; //等待触摸笔松开模式

}

 

static void enter_measure_xy_mode(void)//测量xy模式

{

s3c_ts_regs->adctsc = (1<<3) | (1<<2);//禁止上拉,自动测量x、y

}

 

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;//误差值

 

/* 第一个数与第二数求平均值,如果第三个数比平均值大10则认为是错误值 */

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; //如果x或者y的差值大于10,则认为它是一个错误的值

 

/* 第二个数与第三数求平均值,如果第四个数比平均值大10则认为是错误值 */

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 0; //如果x或者y的差值大于10,则认为它是一个错误的值

 

return 1;

}

 

static void s3c_ts_timer_function(unsigned long data) //定时器处理函数

{

//ADCDAT0的第15位可以判断按下或者松开的模式

//1-松开,0-按下

if (s3c_ts_regs->adcdat0 & (1<<15))//如果已经松开

{

/* 已经松开 */

input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); //上报事件(实质:input_event()),按下的压力值,0--松开

input_report_key(s3c_ts_dev, BTN_TOUCH, 0); //按键类事件(实质:input_event()),0--松开

input_sync(s3c_ts_dev);

enter_wait_pen_down_mode();//等待按下模式,这样才可以处理下一次

}

else 

{

/* 测量X/Y坐标 */

enter_measure_xy_mode();//进入测量x、y模式

start_adc();//转换成功启动ADC,ADC不可能瞬间完成

}

}

 

 

static irqreturn_t pen_down_up_irq(int irq, void *dev_id)//按下触摸笔中断处理函数

{

//ADCDAT0的第15位可以判断按下或者松开的模式

[1] [2]
关键字:S3C2440  触摸屏  touch  screen  驱动程序 引用地址:S3C2440 触摸屏touch screen驱动程序(十七)

上一篇:S3C2440 USB总线驱动分析(十八)
下一篇:S3C2440 热拔插驱动 hotplug_uevent机制 (三十三)

推荐阅读最新更新时间:2024-11-23 06:28

s3c2440裸机-电阻触摸屏编程(7.触摸屏校准测试 及优化)
1,防止点击一个点,显示出5个点 Isr_Adc中同理也许要上报数据。 这里在touchscreen.c中还补充了上报压力值,当isr_adc上报data时,同时上报了压力值, 这样在ts_read_raw时能够读到压力值讯息。 分析下面这个函数: 当用户点击校准点A时,进入isr_Tc(), 检测到按下,启动adc,adc转换结束产生adc中断,进入isr_adc。然后adc上报坐标和压力值数据。 补充了rs_read_raw时,只有当松开时,也就是read raw读出来的压力值=0的时候才会返回数据。最上面的do while (pressure == 0)是为了过滤掉上一次松开后,下一次还没来得及点击就进入了get_
[单片机]
<font color='red'>s3c2440</font>裸机-电阻<font color='red'>触摸屏</font>编程(7.<font color='red'>触摸屏</font>校准测试 及优化)
Touch Bar都有?苹果iPhone 8概念图脑洞大开
关注苹果笔记本的朋友,对Touch Bar应该不陌生,在Mac Book Pro上我们已经见到了Touch Bar带来的惊喜。之前有消息称,苹果很有可能将这项功能带到新一代的iPhone上去。尽管这也是猜测,但毕竟是已经实现的功能,对于苹果来说,在手机中加入也并非难事。近日,有苹果粉丝还专门为下一代iPhone制作了一张加入Touch Bar功能的渲染图。 加入Touch Bar的新iPhone   之前传闻称,新的iPhone将会采用全新的设计,而且它还会变得更加的纤薄,也许是这个传言给了网友灵感,此前我们见到最多的概念设计,就是扬声器被移动到iPhone顶端的位置,而此次的概念设计中,Touch Bar也带到了iPhone
[手机便携]
ARM9(S3C2440) Touch Screen
触摸屏工作原理 触摸屏分为:电阻式,电容式,声表面波式,红外线扫描式等类型,使用的最多的是4线电阻式的触摸屏。 触摸屏工作流程 (1)、设置触摸屏接口为等待中断模式,等待触摸屏被按下。 (2)、如果中断(INT_TC)发生,选择X,Y坐标转换模式(X/Y坐标分别转换模式,X/Y坐标自动转换模式),启动AD转换。 (3)、当AD转换完毕后,通过中断(INT_ADC),获取X/Y坐标,ADCDAT0 bit -x坐标,ADCDAT1 bit -Y坐标。 (4)、设置触摸屏接口为等待中断模式,等待触摸笔离开触摸屏。 (5)、返回步骤1,等待下次触摸笔被按下。 实验主要代码 main
[单片机]
STM32开发笔记92: SX1268驱动程序设计(时钟)
单片机型号:STM32L053R8T6 本系列开发日志,将详述SX1268驱动程序的整个设计过程,本篇介绍时钟的相关内容。 一、RC频率参考 Two RC oscillators are available: 64 kHz and 13 MHz RC oscillators. The 64 kHz RC oscillator (RC64k) is optionally used by the circuit in SLEEP mode to wake-up the transceiver when performing periodic or duty cycled operations. Several commands
[单片机]
STM32开发笔记92: SX1268<font color='red'>驱动程序</font>设计(时钟)
传苹果推新iPod touch:升级处理器 适配iOS 12
新浪手机讯 3月20日上午消息,来自外媒MacRumors的消息,苹果公司可能在明天发布第七代iPod touch,升级处理器以运行最新的iOS系统。   外媒MacRumors这个月早些时候收到了一个爆料,爆料声称苹果公司将在本周一、周二和周三发布新的iPad,iMac和iPod。到目前为止,随着周一的新iPad Air和iPad mini以及今天的新iMac的推出,这些信息已经被证实。自然,我们现在希望苹果公司明天推出一款新的iPod touch。   如果消息准确的话,本周的一系列硬件发布表明苹果公司可能会在3月25日史蒂夫·乔布斯剧院的活动中发布其新闻和视频服务。   上个月,经验丰富的分析师郭明
[手机便携]
传苹果推新iPod <font color='red'>touch</font>:升级处理器 适配iOS 12
融入iPod设计经验?苹果iPhone拆解之后仍神秘
加拿大反向工程公司Semiconductor Insights(SI)的供应链经理Allan Yogasingam为得到一款最新推出的苹果iPhone手机,毅然排了12小时的长队。他和他的“勇敢”团队用照相机记录下他们拆解iPhone并探究其内部奥妙的全过程。SI的这份拆解报告昭示了苹果公司强势进入手机市场的举措。 截至美国当地时间6月29日下午6点,共有约300万部iPhone售出。iPhone所激发的消费热潮是苹果公司的市场营销策略、iPhone有趣的交互式用户界面,以及iPhone整合iTunes功能等因素综合作用的结果。 “市面上有比iPhone功能更强大的产品,但就象同样也有MP3播放器比iPod更好一样,iPhon
[焦点新闻]
基于ARM7和VC平台的高分辨率红外触摸屏设计
  触摸屏是结合显示器使用的一种透明的绝对定位系统,透明和优良的定位原理是它的技术特征。目前应用在各场合的触摸屏主要有四种:电阻式触摸屏、电容式触摸屏、表面声波触摸屏和红外触摸屏。其中红外触摸屏的视觉效果和定位原理都优于其它触摸屏技术,而且不受电流、电压和静电干扰,可以适宜恶劣的环境条件。但是,与其它三种触摸屏相比,红外触摸屏也存在分辨率低的问题,这一点严重影响了红外触摸屏的实际应用。   为此,本文采用ARM7和VC提出了一种高分辨率的红外触摸屏的实现方案。该方法通过ARM7对接收管和发射管的控制,来实时采集与发射管一一对应的接收管的光通量,然后计算鼠标位置,最后通过VC编程来实现在Windows下的鼠标驱动。   1硬件平
[单片机]
触摸屏“退隐江湖”之后,谁将成为新一代手机输入接口“新秀”?
专家指出,声音识别是手机业界是继触摸屏之外下一个被关注的技术。 如今,很多用户在使用手机时感觉到的不便:“手机按键太多”、“手机按键太小又挤在一起,很不方便”。设计也是降低手机使用便利性的因素之一。如果要体现超薄设计,那么手机按键的使用会更难,而如果要体现多媒体潮流,那么LCD显示屏会扩大,从而削弱手机的携带特性。 为了更加方便地使用手机复杂多样的功能和进行革新的设计,手机业界正极力寻找继触摸屏之后的下一代手机输入接口。声音是人最直观和方便的输入方式之一,任何功能可以不用经过好几个菜单操作而直接启动。 LG电子PRADA手机的开发者称,“随着手机设计的日益重要和简约主义的体现,对新一代接口的担忧越来越大,能够超过触摸屏界限的
[焦点新闻]
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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