Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2262557
  • 博文数量: 218
  • 博客积分: 5767
  • 博客等级: 大校
  • 技术积分: 5883
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-01 14:44
文章存档

2012年(53)

2011年(131)

2009年(1)

2008年(33)

分类: LINUX

2008-03-01 20:15:13

#define mode_x_axis_n() { ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | \

XP_PULL_UP_DIS | XP_PST(NOP_MODE); }

/*基本配置和上面相同,就是不进行x 坐标的转换*/

#define mode_y_axis() { ADCTSC = XP_AIN | XM_HIZ | YP_EXTVLT | YM_GND | \

XP_PULL_UP_DIS | XP_PST(Y_AXIS_MODE); }

/*Y 坐标开始进行测量

*/

#define start_adc_x() { ADCCON = PRESCALE_EN | PRSCVL(49) | \

ADC_INPUT(ADC_IN5) | ADC_START_BY_RD_EN | \

ADC_NORMAL_MODE; \

ADCDAT0; }

/*首先设置ADCCON 寄存器,开始转换x 坐标,因为在ADCCON 寄存器中,已经设置通

过读取数据寄存器来启动转换,所以在执行ADCDAT0 宏时(该宏从ADCDATA0 寄存器中

读取数据),A/D 转换器即开始转换数据。

ADCDAT0 定义为:

#define ADCDAT0 bADC_CTL(oADCDAT0)

。。。。。

#define bADC_CTL(Nb) __REG(ADC_CTL_BASE + (Nb))

*/

#define start_adc_y() { ADCCON = PRESCALE_EN | PRSCVL(49) | \

ADC_INPUT(ADC_IN7) | ADC_START_BY_RD_EN | \

ADC_NORMAL_MODE; \

ADCDAT1; }

/*

首先设置ADCCON 寄存器,开始转换y 坐标,因为在ADCCON 寄存器中,已经设置

通过读取数据寄存器来启动转换,所以在执行ADCDAT1 宏时(该宏从ADCDATA1 寄存器

中读取数据),A/D 转换器即开始转换数据。

ADCDAT1 定义为:

#define ADCDAT1 bADC_CTL(oADCDAT1)

。。。。。

#define bADC_CTL(Nb) __REG(ADC_CTL_BASE + (Nb))

49

*/

#define disable_ts_adc() { ADCCON &= ~(ADCCON_READ_START); }

/*

停止转换

*/

static unsigned int adc_state = 0;

static unsigned int x, y; /* touch screen coorinates */

static unsigned int time=0;

#define CHEAT_NUMBER 40

static unsigned int cheat = 0;

static unsigned int cheat_y[CHEAT_NUMBER] = {0,};

static unsigned int cheat_diff_y = 0;

static unsigned int cheat_x[CHEAT_NUMBER] = {0,};

static unsigned int cheat_diff_x = 0;

49

static void tsEvent_raw(void)

{

if (tsdev.penStatus == PEN_DOWN)

{

#ifdef UP_TS

BUF_HEAD.x = x;

BUF_HEAD.y = y;

#endif

#ifdef DOWN_TS

BUF_HEAD.x = y;//x;

BUF_HEAD.y = x;//y;

#endif

BUF_HEAD.pressure = PEN_DOWN;

/*

将结果存放到环形缓冲区的head 指针所指向的位置。

*/

#ifdef HOOK_FOR_DRAG

ts_timer.expires = jiffies + TS_TIMER_DELAY;

add_timer(&ts_timer);

#endif

}

else

{

#ifdef HOOK_FOR_DRAG

del_timer(&ts_timer);

#endif

BUF_HEAD.x = 0;

BUF_HEAD.y = 0;

BUF_HEAD.pressure = PEN_UP;

}

tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);

/*

在触摸屏设备的环形队列中,将head 指针向下移动一位

*/

wake_up_interruptible(&(tsdev.wq));

/*

如果有相关的设备被阻塞在这个队列的时候,就去唤醒它。

比如,在应用程序中,我们首先打开触摸屏设备,然后用read 函数去读其中的内容,

但是由于还没有点击触摸屏,所以应用进程就会被阻塞,等到用户点击触摸屏后,会调用

wake_up_interruptible()通知被阻塞的用户解除阻塞。

*/

#ifdef USE_ASYNC

if (tsdev.aq)

kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);

#endif

#ifdef CONFIG_PM

pm_access(tsdev.pm_dev);

#endif

}

static int tsRead(TS_RET * ts_ret)

{

spin_lock_irq(&(tsdev.lock));

ts_ret->x = BUF_TAIL.x;

ts_ret->y = BUF_TAIL.y;

ts_ret->pressure = BUF_TAIL.pressure;

tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);

spin_unlock_irq(&(tsdev.lock));

/*

从环形缓冲区的尾部取数据

*/

return sizeof(TS_RET);

}

static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)

{

TS_RET ts_ret;

retry:

if (tsdev.head != tsdev.tail) {

int count;

count = tsRead(&ts_ret);

if (count) copy_to_user(buffer, (char *)&ts_ret, count);

return count;

} else {

if (filp->f_flags & O_NONBLOCK)

return -EAGAIN;

interruptible_sleep_on(&(tsdev.wq));

if (signal_pending(current))

return -ERESTARTSYS;

goto retry;

}

/*

首先调用tsdev.head != tsdev.tail 判断环形缓冲区中是否有数据,如果有则执行tsRead()

函数从环形缓冲区中读出其里面的一项值,并把结果通过copy_to_user()返回到用户空间中。

如果环形缓冲区中没有数据,则首先判断用户程序中的打开该设备文件时是否使用阻塞

方式(默认为阻塞方式),还是非阻塞方式(如打开时使用fd=open(“/dev/s3c2410-ts”,

O_RDONLY|O_NONBLOCK))。如果采用非阻塞方式,返回EAGAIN 错误码。采用阻塞方

式时,则会调用interruptible_sleep_on()函数通知应用进程进入睡眠状态,而内核中

s3c2410_ts_read()函数会不停的测试相应的位,直到环形缓冲区中有数据为止。

*/

return sizeof(TS_RET);

}

#ifdef USE_ASYNC

static int s3c2410_ts_fasync(int fd, struct file *filp, int mode)

{

return fasync_helper(fd, filp, mode, &(tsdev.aq));

}

#endif

static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)

{

poll_wait(filp, &(tsdev.wq), wait);

return (tsdev.head == tsdev.tail) ? 0 : (POLLIN | POLLRDNORM);

}

static inline void start_ts_adc(void)

{

adc_state = 0;

/*

标识一次触摸屏转换的开始

*/

mode_x_axis();

start_adc_x();

/*

首先调用mode_x_axis()函数来完成x 坐标转换的前期准备工作,然后调用start_adc_x()

来完成x 坐标正在转换的开始。

start_adc_x()函数中会触发一次触摸屏中断,这是由于在该函数中设置了启动触摸屏

AD 转换的方式是读取AD 数据寄存器的值,而且在该函数的最后读取AD 数据寄存器0

值,所以引发一次AD 转换中断。

*/

time = 0;

/*

主要用于时间测量,在很多触摸屏驱动中,都会定义一个定时器,该定时器能够处理触

摸笔抖动问题

*/

}

static inline void s3c2410_get_XY(void)

{

const int TIMES = 60;

unsigned int i, tmp,j;

static unsigned int max, min;

static unsigned int data[60];

if (adc_state == 0)

{

if (time == 0)

{

y = 0;

//max = 0;

//min = 0xffffffff;

}

if (time < TIMES)

{

disable_ts_adc();

data[time] = (ADCDAT0 & 0x3ff);

//if (tmp > max) max = tmp;

//if (tmp < min) min = tmp;

//y += tmp;

start_adc_x();

time++;

/*

红颜色标注的代码被执行60 次,因为第一次被执行的时候time 值为0adc_state 0

其中会执行start_adc_x()函数一次,即发生AD 中断一次,time 变量变为1。第二次中断再

次执行这段代码,重复刚才的步骤,一直等到执行60 次,即time 变量值等于60 时,才会

去执行下面蓝颜色标识的代码。每次中断时都会重新执行一次有关X 坐标的转换,所以

X 坐标被转换了60 次,每次转换的值存放在data 数组中。

*/

}

else

{

for (i = 0; i < TIMES; i++)

{

for (j = 0; j < TIMES - i; j++)

{

if (data[j] > data[j+1])

{

tmp = data[j];

data[j] = data[j+1];

data[j+1] = tmp;

}

}

}

/*

将刚才转换的60 x 坐标进行排序,采用冒泡排序,排序后data 数组的

值由小到大排列。

*/

time = 0;

y = 0;

for (i = TIMES / 6; i < TIMES*5/6; i++)

{

y += data[i];

}

/*

把刚才转换后的第10 次~49 次的值相加,存放到变量y 中,其实就是40

次转换的结果相加。

*/

y /= (TIMES*2/3);

/*

把刚才转换的结果除以40,得到本次转换的最终结果。

*/

y &= 0x3ff;

if (cheat < 400)

{

for (i = 0; i < CHEAT_NUMBER; i++)

{

if (y > cheat_y[i])

{

cheat_diff_y = y - cheat_y[i];

}

else

{

cheat_diff_y = cheat_y[i] - y;

}

if (cheat_diff_y < 20)

{

y = cheat_y[i];

break;

}

else if (cheat_y[i] == 0)

{

cheat_y[i] = y;

break;

}

}

}

阅读(1447) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~