⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 touchscreen(完善版,哈哈).c

📁 S3C44B0x下的ADS7843触摸屏驱动资料与代码
💻 C
字号:
/*
***************************************
* linux/driver/touch/touchscreen.c
* touchscreen driver for my S3C44b0X board
* copyright by kom118@163.com
***************************************
*/

#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/wait.h>  /*等待队列*/

#include <asm/uaccess.h>
#include <asm/arch-S3C44B0X/s3c44b0x.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch-S3C44B0X/irqs.h>

#define  TOUCH_MAJOR        67
#define  TOUCH_DEVNAME   "touchscreen_kmf"
#define  TS_IRQ   S3C44B0X_INTERRUPT_EINT2

#define  TOUCHSTATUS_UP          0
#define  TOUCHSTATUS_DOWN     1

#define  MASK_BIT(bit)       (1<<(bit))
#define  BIT_EINT2      (1<<23)
#define  MAX_TS_BUF   16  //校准用
#define  TOUCH_TIMER_DELAY1    (HZ)/100

static int    touch_users = 0;  /* number of connected users; only one is allowed */
static int    touch_event=0;    /* is there an event pending? */
static int    j,flags=0;
static unsigned char rtmp=0;

/*该值校正用*/
//static int   xres = 640;
//static int   yres = 240;

// A/D 通道选择命令字和工作寄存器
#define	CHX 	0x90	//通道Y+的选择控制字	//0x9c   0x94
#define	CHY 	0xD0	//通道X+的选择控制字	//0xDc  0xD4

#define TP_DCLK(a)           outw((inw(S3C44B0X_PDATF) &(~(1<<8)) ) | ((a&1)<<8),S3C44B0X_PDATF)   //----GPF8  ,output
#define TP_CS(a)		      outw((inw(S3C44B0X_PDATF) &(~(1<<7)) ) | ((a&1)<<7),S3C44B0X_PDATF)   //-----GPF7 , output
#define TP_DIN(a)            outw((inw(S3C44B0X_PDATF) &(~(1<<6)) ) | ((a&1)<<6),S3C44B0X_PDATF)   //------GPF6 ,output


//读ADS7843的I/O控制口
//#define TP_BUSY	
#define TP_DOUT	       ((inw(S3C44B0X_PDATF)>>5) & 0x1)	       //-------GPF5
#define TP_IRQ		((inb(S3C44B0X_PDATG)>>2) & 0x1)        //TP_IRQ--------ExINT2(GPG2)


/*打算在中断中使用定时器队列,定义定时器链表*/
static struct timer_list  touch_timer;  /* be used for polling */

struct  TS_RET
{
 	unsigned short x; //The x position
  	unsigned short y;//The y position	
} ;
//static  struct TS_RET  touchstate;

typedef struct {
   	 unsigned int Status;                          //触摸屏状态
   	 struct TS_RET  buf[MAX_TS_BUF];   //触摸屏缓冲区
    	 unsigned int head,tail;                           //触摸屏缓冲区头和尾
    	 wait_queue_head_t  wq;                        //等待队列
} TS_DEV;
static TS_DEV touchdev;

#define BUF_HEAD         touchdev.buf[touchdev.head]    //缓冲区头
#define BUF_TAIL           touchdev.buf[touchdev.tail]       //缓冲区尾
#define INCBUF(x,mod)   ((++(x)) & ((mod)-1))            //移动缓冲区指针

static void (*TouchEvent)(void);
static void TouchEvent_dummy(void) {}
static int  IS_DOWN(void);
static void bubble_sort(unsigned short *array, int n)/*采用冒泡排序*/
{
	 int j, k, h; 
	 unsigned short temp;
  
 	for (h=n-1; h>0; h=k) /*循环到没有比较范围*/
	 {
  		for (j=0, k=0; j<h; j++) /*每次预置k=0,循环扫描后更新k*/
 			 {
 				  if (*(array+j) > *(array+j+1)) /*大的放在后面,小的放到前面*/
  				 {
    					 temp= *(array+j);
   					 *(array+j) = *(array+j+1);
   					 *(array+j+1) =temp; /*完成交换*/
    					  k = j; /*保存最后下沉的位置。这样k后面的都是排序排好了的。*/
   				}
  			}
 	}
}


static void ads7843_Start( void )
{
       TP_CS(1);
	TP_DCLK(0);
	TP_CS(0);	
	TP_DIN(1);
    	//TP_DCLK(1);
       		
}

static void ads7843_Write ( unsigned char  cmd )/*实际上写命令字*/
{
	unsigned char  i,temp;

	temp=0x80;
	//printk("TP_DCLK=");
      // TP_DCLK(0);
	for( j = 0; j < 5; j++ );   //Tcss-Tds
	
	for( i = 0; i < 8; i++ )
	{
		/*将控制字分解成位传入ads7843,从而ads7843发送命令*/
		if(cmd&temp)  
				TP_DIN(1);
		else
				TP_DIN(0);
	
	

		for( j = 0; j < 15; j++ );
		/*软件模拟一个CLK,将一位送出,总共送8位,所以总共循环产生了8格时钟*/
		TP_DCLK(1);  /*DCLK置高*/
		for( j = 0; j < 10; j++ );	//200ns

		TP_DCLK(0); /*DCLK清0*/
		for( j = 0; j < 25; j++ );	//200ns	
		//为送下一位准备
		temp=temp>>1;   
	}

	TP_DIN(0); /*DIN清0,准备读数据了*/
	
       /*接下来可以读数据了,直接调用ads7843_read()函数*/
       return ;
}

/*读数据*/
static unsigned short  ads7843_Read ( void )
{
	unsigned short ack = 0 ;
	unsigned char i;

	for( i = 0; i < 11; i++ )
	{
		TP_DCLK(1); 
		for( j = 0; j < 25; j++ );	//200ns
		
		TP_DCLK(0); 
		for( j = 0; j < 10; j++ );	/*时钟下降沿读取*/

		if(TP_DOUT)
			ack +=1;
		
		for( j = 0; j < 15; j++ ); //120ns
		ack=ack<<1;
	}
	
       TP_DCLK(1); 
	for( j = 0; j < 25; j++ );	//200ns
	TP_DCLK(0); 
	for( j = 0; j < 10; j++ ); //80ns
	
      //接收最后一位,第12位
	if(TP_DOUT)
			ack +=1;
		

	for( j = 0; j < 15; j++ );	

	for( i = 0; i < 4; i++ )
	{
		TP_DCLK(1); 
		for( j = 0; j < 25; j++ );	//200 ns
		
		TP_DCLK(0); 
		for( j = 0; j < 25; j++ );	
	
	}
	
	//最后将~CS 置高,ads7843禁止
	TP_CS(1);
	
	return ack;
}

static void ads7843_get_XY(void)
{	
	int sum,i;
	unsigned short  tempx,tempy,val[20];
	sum=0;
	/*----------------X  坐标与读取处理---------------*/
	for(i=0;i<20;i++)
	{
		ads7843_Start() ;
		for( j = 0; j < 5; j++ ); //40ns
		ads7843_Write(CHX) ;
		//延时400ns等待数据转换
		for( j = 0; j < 50; j++ ); //200ns
       	val[i]= ads7843_Read();
		
		for( j = 0; j < 100; j++ );
	}

	/*对val进行排序*/
       bubble_sort(val, 20);
       
	/*采用中值平均滤波发处理数据*/
	for(i=3;i<17;i++)
	{
		sum+=val[i];
	}
	/*求平均值*/
       tempx=(unsigned short)(sum/14);
	   
	/*----------------Y  坐标与读取处理---------------*/
	sum=0;
	
	for(i=0;i<20;i++)
	{
		 ads7843_Start() ;
		 for( j = 0; j < 5; j++ ); //40ns
		 ads7843_Write(CHY) ;
		 for( j = 0; j <50; j++ ); //200ns
		 val[i]= ads7843_Read() ;

		 for( j = 0; j < 100; j++ );
	}
	
	/*对val进行排序*/
       bubble_sort(val, 20);
       
	/*采用中值平均滤波发处理数据*/
	for(i=3;i<17;i++)
	{
		sum+=val[i];
	}
	
	/*求平均值*/
	tempy=(unsigned short)(sum/14);

      /*坐标转换*/

	BUF_HEAD.x=(3853-tempx)*640/(3853-264);
	BUF_HEAD.y=(tempy-650)*240/(3638-650);

	printk("X=%d ,  Y=%d\n",BUF_HEAD.x,BUF_HEAD.y);
	
	touchdev.tail=INCBUF(touchdev.tail,MAX_TS_BUF);

}


static  void  s3c44b0_IO_init(void)
{
       /*配置与ADS7843 相连的I/O端口 output : PF5,PG3;      input:PF6,PF7,PF8   ;ads7843  busy  线没用*/
	unsigned int val32;
	unsigned short  val16;

      /*配置F  端口*/
	/*-------------------------*/
	/* configuration of PCONF  */
	/*-------------------------*/
	val32=inl(S3C44B0X_PCONF);
	outl((val32&0xFFC003FF)|0xFFC923FF, S3C44B0X_PCONF);  /* config GPF5 input  ; GPF6  GPF7  GPE8 output */
	
	/*-------------------------*/
	/* configuration of PUPF */
	/*-------------------------*/
	val16 =inb(S3C44B0X_PUPF)&0xFFEF;
	outw(val16, S3C44B0X_PUPF); /* config GPF5 activate pull up   GPF5 上拉电阻使能,GPF6,GPF7,GPF8  disable */
}

static int  IS_DOWN(void)
{
       rtmp=inb(S3C44B0X_PDATG);

        //读入GPG端口数据,若没键按下,GPG2 为1 
	if ((rtmp &0x04)==0) 
	{   
	      //延时一段时间再判断,延时消除抖动
  		for( j= 0; j< 5000; j++ );	 //10ms
  		
		 rtmp=inb(S3C44B0X_PDATG); 
		 
	       if ((rtmp&0x04)==0) 
	 	 {
	 	 	//确实有键按下
	 	 	 touchdev.Status=TOUCHSTATUS_DOWN;
			 flags=1;
	 	 	 return  1;
	        }
		else 
		{
			return 0;
		}
	}
	return 0;     
}

void touch_task_handler (unsigned long irq)   /*中断程序下半部*/
{    
      
	 //延时10ms后,判断按键状态
	if(IS_DOWN()==1)
	{	
		 /*获取X , Y 坐标*/
              ads7843_get_XY();	
		
		/*触摸屏仍然被按下, 继续轮询*/
		while((rtmp&0x04)==0)
		rtmp=inb(S3C44B0X_PDATG);
		
		touch_event=1;
     		wake_up_interruptible(&(touchdev.wq));   /* wake any reading process */ 

	}

	
	//重新将G端口GPG2 设置为中断模式
	outw(inw(S3C44B0X_PCONG)|0x30, S3C44B0X_PCONG); 
	  
	//开中断
	outl(inl(S3C44B0X_INTMSK)&(~BIT_EINT2),S3C44B0X_INTMSK); 
	
	  //清中断请求寄存器
	 outl(inl(S3C44B0X_I_ISPC)|(BIT_EINT2),S3C44B0X_I_ISPC);	
	  
	/*-------------------------*/
	/* enable irq          		     */
	/*-------------------------*/
	//enable_irq(irq);
	
	touchdev.Status=TOUCHSTATUS_UP;
	
	return ;
} 

static void touch_interrupt(int irq, void *dev_id, struct pt_regs *regs)  /*中断程序上半部*/
{ 
	  //关中断
	outl(inl(S3C44B0X_INTMSK)|(BIT_EINT2),S3C44B0X_INTMSK);
	
	  //清中断请求寄存器
	 outl(inl(S3C44B0X_I_ISPC)|(BIT_EINT2),S3C44B0X_I_ISPC);
	
	for( j= 0; j< 5000; j++ );	 	//10ms
	
	 /*-------------------------*/
	/* disable irq          		      */
	/*-------------------------*/
	//disable_irq(irq);
	if (touchdev.Status==TOUCHSTATUS_UP)
	{      //printk(KERN_INFO "get in interrupt  ...:):)\n");
       
		//设置GPG2为输入模式
	       outw(inw(S3C44B0X_PCONG)&0xFFCF,S3C44B0X_PCONG);
		
		//初始化定时器
		init_timer(&touch_timer);
		touch_timer.function = touch_task_handler;
		touch_timer.data = irq;
		touch_timer.expires = jiffies+TOUCH_TIMER_DELAY1;
		add_timer(&touch_timer);
	}
	
	return;

}

static ssize_t touchscreen_read(struct file *file, char *buffer,
			  size_t count, loff_t *pos)
{    
      retry:
		
	 	if (touchdev.head != touchdev.tail) //当前循环队列中有数据
		{ 
			//把数据从内核空间传送到用户空间返回
			if(copy_to_user(buffer,(struct  TS_RET *)&BUF_HEAD,sizeof(struct  TS_RET)))
			{
				printk("error reading, copy_to_user\n");
				return  -EFAULT;
			}
                     touchdev.head=INCBUF(touchdev.head,MAX_TS_BUF);
			return sizeof(struct  TS_RET);
		}
		else
		{
	  		 if(file->f_flags & O_NONBLOCK)//若用户采用非阻塞方式读取
        		  return   -EAGAIN;
			 
	   		 // printk("sleep ..... \n");
	 		  wait_event_interruptible(touchdev.wq,flags);
			  flags=0;
			  //printk("sleep after .....\n");
		}
		
     	goto retry;

     return  sizeof(unsigned char) ;
       	
	  
}

static unsigned int touchscreen_poll(struct file *file, poll_table *wait)
{
	poll_wait(file, &(touchdev.wq), wait);
	if(touch_event)
		return (POLLIN | POLLRDNORM);  /* readable */

	return 0;
}

static int touchscreen_open(struct inode *inode, struct file *file) 
{
	if(!touch_users) /* only one user is allowed!! */
		touch_users++;
	else
		return -EBUSY;
		
       //开中断
	outl(inl(S3C44B0X_INTMSK)&(~BIT_EINT2),S3C44B0X_INTMSK); 
	printk("opened  normally :):):):):):)!\n");
	
	for( j= 0; j< 10000; j++ );	 
	touchdev.head = touchdev.tail = 0; //清空按键动作缓冲区
	enable_irq(TS_IRQ);
	
	return 0;
}

static int touchscreen_close(struct inode * inode, struct file * file)	
{
	TouchEvent = TouchEvent_dummy; //函数指针指向空函数
	if(touch_users<1)
	{	
		printk("release  touchdevice error\n");
	       return -ENODEV;
	}
       touch_users--;
	if(!touch_users) /* must be also true since we allow only one user */
	{	disable_irq(TS_IRQ);
		//关中断
	     outl(inl(S3C44B0X_INTMSK)|BIT_EINT2,S3C44B0X_INTMSK); 
	}
	return 0;

}

struct file_operations  ts_fops = {
	read: touchscreen_read,  
	poll: touchscreen_poll,   //查询设备
	open: touchscreen_open,
	release: touchscreen_close, //释放设备
};


int s3c44b0x_ts_init(void)
{     
	int ret,val32;
	
	printk("s3c44b0x_touch: initializing...\n");
	
       /*-------------------------------*/
	/* configure s3c44b0x   I/O    		 */
	/* s3c44b0_IO_init();				 */
	/*-------------------------------*/
	s3c44b0_IO_init(); 
	   
	//TP_CS(1);/*ads7843芯片禁止*/
       /*-------------------------------*/
	/* configure interrupt          			 */
	/*-------------------------------*/
	
	// 将多功能端口GPG2设置为中断模式
	outw(inw(S3C44B0X_PCONG)|0x30, S3C44B0X_PCONG); 	
	//INT2上拉使能
	outb(inb(S3C44B0X_PUPG)&(0<<2),S3C44B0X_PUPG);
	
	val32=inl(S3C44B0X_EXTINT);
	outl((val32&0xFFFFF8FF)|0x200, S3C44B0X_EXTINT);	/* 下降沿触发*/

	 //设置中断控制器INTMOD
	val32=inl(S3C44B0X_INTMOD);
	val32&=~MASK_BIT(23);
	outl(val32, S3C44B0X_INTMOD); 	  /* normal IRQ */

	 //设置中断控制器INTCON
	outb( 0x5,S3C44B0X_INTCON);

	//注册设备
	if((ret = register_chrdev(TOUCH_MAJOR,TOUCH_DEVNAME ,&ts_fops))<0)
	{
		printk("touch_rw. unable to get major %d for led write\n", TOUCH_MAJOR);
		return ret;
	}
	
	//注册中断
  	if(request_irq(TS_IRQ, touch_interrupt,SA_INTERRUPT, "44b0_touchscreen",NULL))
	{
		printk("s3c44b0: unable to get IRQ\n");
		return -EBUSY;
	}	
	
	touchdev.head = touchdev.tail = 0;  //初始化结构体touchdev
	touchdev.Status = TOUCHSTATUS_UP;
       
       //初始化等待队列
	 init_waitqueue_head(&(touchdev.wq));
	   
        return 0;

}


int  s3c44b0x_ts_exit(void)
{
	int ret;

	//注销中断
	free_irq(TS_IRQ, NULL);
	//注销设备
	if((ret = unregister_chrdev(TOUCH_MAJOR,TOUCH_DEVNAME ))<0)
	       printk("TOUCH DEV. unable to release major %d for read  \n",TOUCH_MAJOR);
		return ret;
	
	printk(KERN_INFO "touchscreen uninstalled\n");
	return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -