资讯详情

linux驱动之电阻触摸屏驱动开发与滤波算法

NS2009是一款带I2C接口的4线电阻触摸屏控制电路包含12位分辨率A/D转换器。NS2009能通过执行两次A/D此外,还可以测量触摸屏上添加的压力。在2.7V在典型的工作状态下,功耗可小于0.75mW。可用于手机(手机等)、触摸屏显示器、个人数字助理(PDA)便携式设备,POS机器终端设备等。

开发平台:Linux操作系统

内核版本:3.10

摘要:本文基于ns2009驱动程序,主要内容是ns采样、滤波2009电阻触摸屏。

1.ns相关数据结构

struct ns2009_ts  {   spinlock_t irq_lock;  struct i2c_client *client;  struct input_dev *input_dev;  wait_queue_head_t irq_wait;   struct timer_list timer;  int (*get_pen_status)(void);   int irq_is_disable;  bool stopped;  unsigned int irq;  };

该结构包含i2c子系统、输入子系统、定时器系统、定时器和中断,是实现按键坐标从采集到报告到应用层的重要组成部分。

struct ns2009_data {  unsigned int x;  unsigned int y;  unsigned int z; };

输入子系统将结构保存的内容报告到应用层,以保存按键坐标和压力值。

为了保证接触的准确性,需要对收集到的坐标进行过滤。这里的过滤方案如下:一次接触取5个坐标,然后冒泡排序,过滤丢弃漂移较大的坐标,从头到尾寻求平均值。相关代码如下:

(1)冒泡排序算法

/*根据从小到大的冒泡排序*/ static inline void bubble_sort(int a[], int n) {  int i = 0,j = 0;  int temp = 0;  for(i=0; i<n-1; i  )  {   int isSorted = 1;   for(j = 0; j<n-1-i; j  )   {       if(a[j] > a[j 1])       {     isSorted = 0;     temp = a[j];     a[j] = a[j 1];     a[j 1]=temp;       }   }   if(isSorted)     break;   } }

(2)滤波算法

static inline int tsc_filter(const u32 *x, const u32 *y, const int cread) {  int tmp = 0;  int new_value, i = 0;  int value = 0;  for(i= 1; i < cread; i  ) {   value = x[i-1];   new_value = x[i];   tmp  = new_value - value;    if (tmp > ERR_LIMIT)///直接丢弃漂移较大的点     return 0;  }    tmp = 0;  value = 0;  new_value = 0;   for(i= 1; i < cread; i  ) {   value = y[i-1];   new_value = y[i];    tmp  = new_value - value;    if (tmp > ERR_LIMIT)///直接丢弃漂移较大的点     return 0;  }  return 1; }

(3)用滤波算法读取坐标函数

static int ns2009_read_coordinates(struct ns2009_ts *ts, struct ns2009_data *data, unsigned int *z1, unsigned int *z2) {   int i = 0;  unsigned int temp_x = 0, temp_y = 0;  //unsigned int xsum = 0, ysum = 0;  unsigned int yvals[READ_NUM], xvals[READ_NUM];  //unsigned int cread = READ_NUM;  //u8 ADC_ON = PWRDOWN;  u8 ADC_OFF = PWRUP;  rtp_i2c_write_bytes(ts->client, &ADC_OFF, 1);  //usleep_range(50, 80);   for(i = 0; i < READ_NUM; i  ) {   xvals[i] = ns2009_xfer(ts, READ_X);    yvals[i] = ns2009_xfer(ts, READ_Y);     if (!is_valid_coor(xvals[i], yvals[i]))      continue;  }   bubble_sort(xvals, READ_NUM);  bubble_sort(yvals, READ_NUM);  if(!tsc_filter(xvals, yvals, READ_NUM)) {   ns2009_dbg("Coor quality too bad\n");   return -1;  }   if (READ_NUM <= 3) {   for (i = 0; i < READ_NUM; i  ) {    temp_x  = xvals[i];    temp_y  = yvals[i];   }   temp_x /= READ_NUM;   temp_y /= READ_NUM;  } else {   for(i = 1; i < READ_NUM - 1; i  ) {    temp_x  = xvals[i];    temp_y  = yvals[i];   }     temp_x /= READ_NUM - 2;      temp_y /= READ_NUM - 2;  }  //data->x = XADC_MAX - temp_x;  data->x = temp_x;  data->y = temp_y;  *z1 = ns2009_xfer(ts, READ_Z1);  *z2 = ns2009_xfer(ts, READ_Z2);  return 0; }

由于读取触摸屏坐标是一个复杂而耗时的过程,因此不能直接在硬中断中读取。在linux为了在中断执行时间尽可能短和中断处理之间找到平衡, Linux 将中断处理程序分为两个半部分:上半部分( top half)和底半部( bottom half)。在顶部完成尽可能少的紧急功能,它通常只是读取寄存器中的中断状态,并在注册中断工作后清除中断标志。底部几乎所有的事情都被中断了,可以被新的中断打断,这是底部和顶部之间最大的区别,因为顶部通常被设计成不可中断的。底部相对不是很紧急,相对耗时,不在硬件中断服务程序中执行。linux实现底半部的机制主要包括tasklet、工作队列和软中断。

因此,电阻触摸屏驱动读取触摸屏坐标的函数应放在软中断中。在本触摸屏驱动代码中,注册中断函数为:

int request_threaded_irq(unsigned int irq, irq_handler_t handler,     irq_handler_t thread_fn, unsigned long irqflags,     const char *devname, void *dev_id)

参数说明

irq:中断号

handler:硬件中断处理函数

thread_fn:软件中断处理函数,thread_fn将在内核线程中执行

irqflag:触发标志中断

devname:设备名

dev_id:传参中断函数

可参考此驱动Linux内核ts2007.c写驱动程序,基本添加上述滤波和读取,然后改变注册中断的方式。

标签: 设备数字电阻屏

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台