天天看點

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

繼續閱讀