天天看点

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

http://www.cnblogs.com/lifexy/p/7628889.html

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

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

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

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

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

所以最终如下图所示:

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

右边的驱动事件处理,内核是已经写好了的,所以我们的触摸屏只需要写具体的驱动设备,然后内核会与触摸屏驱动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引脚上,该引脚专门是用来接收模拟输入信号

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

引脚说明:

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

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

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

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

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

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

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

4.2 测X坐标方向时:

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

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

4.3 测Y坐标方向时:

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

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

5、接下来开始看2440手册

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

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

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

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

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

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

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

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

ADCTSC=0xd3/0x1d3

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

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

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

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

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

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

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

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

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

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

设置寄存器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 <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>

#include <asm/plat-s3c24xx/ts.h>

#include <asm/arch/regs-adc.h>
#include <asm/arch/regs-gpio.h>

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-松开,0-按下
	if (s3c_ts_regs->adcdat0 & (1<<15))//如果已经松开
	{
		//printk("pen up\n");		
		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); //表示s3c_ts_dev这事件上报完毕
		enter_wait_pen_down_mode();//等待按下模式,这样才可以处理下一次
	}
	else//按下
	{
		//printk("pen down\n");
		//enter_wait_open_up_mode();//等待松开模式,这样才可以处理下一次
		enter_measure_xy_mode();//进入测量x、y模式
		start_adc();//转换成功启动ADC,ADC不可能瞬间完成
	}
	return IRQ_HANDLED;
}

static irqreturn_t adc_irq(int irq, void *dev_id)//ADC完成后,发生中断,进入adc中断处理函数
{
	//坐标值x、y是电压的数字表示而已,与实际的坐标没有关系
	//x坐标值存放在ADCDAT0[9:0],最低10位
	//y坐标值存放在ADCDAT1[9:0]
	static int cnt = 0;
	static int x[4],y[4];//多次测量的值放在这里
	int adcdat0, adcdat1;
	
	/* 优化措施2:如果ADC完成时,发现触摸笔已经松开,则丢弃此次结果 */
	/* adcdat0、adcdat1的bit[15]判断松开还是按下 */
	adcdat0 = s3c_ts_regs->adcdat0;
	adcdat1 = s3c_ts_regs->adcdat1;
	if (s3c_ts_regs->adcdat0 & (1<<15))//松开
	{
		/* 如果已经松开,就等待触摸笔按下模式,丢弃结果,不打印结果 */		
		cnt = 0;		
		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); //表示s3c_ts_dev这事件上报完毕
		enter_wait_pen_down_mode();//等待按下模式,这样才可以处理下一次
	}
	else//按下
	{
		//printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);		
		/* 优化措施3:多次测量求平均值 */
		x[cnt] = adcdat0 & 0x3ff;
		y[cnt] = adcdat1 & 0x3ff;
		++cnt;
		if (cnt==4)	//记录4次后
		{
			/* 优化措施4:软件过滤 */
			if (s3c_filter_ts(x, y))
			{
				//printk("x = %d, y = %d\n", (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_event()),X方向的位移,X方向的坐标
				input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);	//上报事件(实质:input_event()),X方向的位移,X方向的坐标
				input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);	//上报事件(实质:input_event()),按下的压力值,1--按下
				input_report_key(s3c_ts_dev, BTN_TOUCH, 1);	//按键类事件(实质:input_event()),1--按下
				input_sync(s3c_ts_dev);	//表示s3c_ts_dev这事件上报完毕
			}		
			cnt = 0;			
			enter_wait_pen_up_mode();//测量后,等待触摸笔松开

			/* 启动定时器处理长按/滑动的情况 */
			mod_timer(&ts_timer, jiffies + HZ/100);//HZ=1秒,1秒/100=10毫秒
		}
		else
		{
			//如果还没到达4次,则再让它再测量一次
			enter_measure_xy_mode();//进入测量x、y模式
			start_adc();//转换成功启动ADC,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->keybit);	//能产生按键类里的触摸屏按键

	input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);	//X方向,最小值0,最大值0x3FF(10位)
	input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);	//Y方向,最小值0,最大值0x3FF(10位)
	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));

	/* bit[14]  :1-A/D converter prescaler enable 预分频使能
     * bit[13:6]: A/D converter prescaler value 预分频系数
     *			  49,ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz
     * bit[0]:A/D conversion starts by enable.先设置为0
	 */
	s3c_ts_regs->adccon = (1<<14) | (49<<6);

	request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);//IRQ_TC,按下触摸屏则产生中断
	request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);	//adc中断

	/* 优化措施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_LICENSE("GPL");
           

7、测试运行

7.1 重新设置编译内核(去掉默认的触摸屏驱动和LCD驱动)

进入linux内核代码:cd /work/system/linux-2.6.22.6

输入命令:make menuconfig,进入menu菜单,重新设置内核参数:

去掉默认的触摸屏驱动:

-> Device Drivers
  -> Input device support
    -> Generic input layer
      -> Touchscreens
      <>   S3C2410/S3C2440 touchscreens //将自带的触摸屏驱动去掉,不编进内核和模块
           

去掉默认的LCD驱动:

进入-> Device Drivers
  	-> Graphics support
		<M> S3C2410 LCD framebuffer support//以模块的方式编进内核
           

(上面“<*>s3c2410 LCD framebuffer support”是之前自带的驱动程序,这里去掉后以<M>模块方式编译进内核)

(<M>模块方式编译进内核)

然后make uImage编译内核。编译好的uImage在 linux-2.6.22.6/arch/arm/boot/uImage目录下。

将新的触摸屏驱动模块和新的uImage,放入/work/rootnfs文件系统目录中:

7.2 烧写内核

使用新的的uImage来启动开发板:

7.2.1 启动开发板,进入uboot界面,然后输入q退出菜单,进入uboot的命令行

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

7.2.2 使用nfs来从linux虚拟机中(服务器192.168.1.3)下载uImage

nfs 30000000 192.168.1.3:/work/nfsroot/uImage_nots/uImage

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

7.2.3 输入bootm 30000000,开发板从地址3000 0000开始启动内核。

7.3 装载触摸屏驱动模块和LCD驱动模块

7.3.1 使用nfs网络文件系统挂载,输入命令:

mount -t nfs -o intr,nolock,rsize=1024,wsize=1024 192.168.1.3:/work/nfsroot /mnt

7.3.2 装载驱动模块(LCD驱动模块、触摸屏驱动模块)

    装载完后,可以使用ls -l /dev/fb0,查看到LCD设备;使用ls -l /dev/event0,查看到触摸屏设备。

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

7.3.3 如果出现一下错误:Segmentation fault,

则需要配置内核,make menuconfig:Device Drivers->Graphics support->Console display driver support-><>Framebuffer Console support把这一项给去掉。

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

7.4 使用hexdump命令调试代码:

(hexdump详解:https://blog.csdn.net/xiaodingqq/article/details/80807145)

测试效果如下:

# hexdump /dev/event0	//触摸屏驱动
//hexdump序列号     秒            微妙         绝对坐标事件 code=ABS_X      x坐标值
    0000000 	0d92 0000 	d3f1 000a         0003 	     0000 	    0255 0000
    0000010 	0d92 0000 	d40a 000a         0003 	     0001 	    01cc 0000
    0000020 	0d92 0000 	d40d 000a         0003 	     0018 	    0001 0000
    0000030 	0d92 0000 	d412 000a         0001 	     014a 	    0001 0000
    0000040 	0d92 0000 	d416 000a         0000       0000 	    0000 0000
    0000050 	0d92 0000 	127a 000b         0003 	     0000 	    0259 0000
    0000060 	0d92 0000 	1292 000b         0003 	     0001 	    01d0 0000
    0000070 	0d92 0000 	129a 000b         0000 	     0000 	    0000 0000
    0000080 	0d92 0000 	6068 000b         0003 	     0000 	    025c 0000
    0000090 	0d92 0000 	607c 000b         0003 	     0001 	    01d2 0000
    00000a0 	0d92 0000 	6083 000b         0000 	     0000 	    0000 0000
    00000b0 	0d92 0000 	c3dc 000b         0003 	     0018 	    0000 0000
    00000c0 	0d92 0000 	c3ef 000b         0001 	     014a 	    0000 0000
    00000d0 	0d92 0000 	c3f1 000b         0000 	     0000 	    0000 0000
           

(code=0,x方向。code=1,y方向。code=18,压力。code=14a,哪一个按键)

7.5 使用tslib测试:

(tslib详解:https://blog.csdn.net/xiaodingqq/article/details/80807553)

(tslib:为触摸屏驱动获得的采样提供诸如滤波、去抖、校准等功能,通常作为触摸屏驱动的适配层,为上层的应用提供了一个统一的接口)

7.5.1、先在网上下载tslib-1.4.tar.gz压缩包

7.5.2、然后在虚拟机Ubuntu编译:(输入以下命令)

7.5.2-1   tar xzf tslib-1.4.tar.gz

7.5.2-2   cd tslib

7.5.2-3   ./autogen.sh

7.5.2-4   mkdir tmp(创建安装目录)

7.5.2-5   echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache(设置参数)

7.5.2-6   ./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp(配置到tmp目录下)

7.5.2-7   make(编译)

7.5.2-8   mae install(安装到tmp目录下)

7.5.2-9   cd tmp(进入tmp目录,将tmp里面的bin,etc,include,lib4个目录拷贝到rootnfs文件系统下)

7.5.2-10   cp * /文件系统根目录/ -rfd(强制拷贝tmp下所有文件到文件系统根目录,-d:保持链接,原来的是连接,复制过来的也是链接)

7.5.3、进入开发板,使nfs:

7.5.3-1 修改参数:

vi /etc/ts.conf:将# module_raw input 改为 module_raw input(注意前面的空格也要删掉)

7.5.3-2 然后装载驱动,再配置LCD和触摸屏的环境:(输入以下命令)

export TSLIB_TSDEVICE=/dev/event0(ts设备文件(触摸屏):event0)

export TSLIB_CALIBFILE=/etc/pointercal(检验文件(calibrate file),存放校验值)

export TSLIB_CONFFILE=/etc/ts.conf(配置文件)

export TSLIB_PLUGINDIR=/lib/ts(插件文件)

export TSLIB_CONSOLEDEVICE=none(终端控制台设置为NULL)

export TSLIB_FBDEVICE=/dev/fb0(fb设备文件(LCD):fb0)

7.5.3-3 校验测试:(输入命令)

ts_calibrate(运行校验,屏幕会出现5次十字架让用户触摸,然后生成/etc/pointercal,并存5个小十字架的值)

7.5.3-4 校验界面如下图所示:

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

7.5.3-5 运行测试:

ts_test(测试,可以随意画图测试)

7.5.3-6 运行测试如下图所示:

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

7.5.3-7 测试:

ts_print:打印坐标

ts_print_raw:打印原始数据,x、y坐标

OK...........OK

继续阅读