分类: LINUX
2014-04-05 18:35:52
好了,一旦释放了锁,那么我们触摸屏事件的一个生命周期才真正算分析结束了,不过在此还有一个问题没有解决,就是当我们触摸屏按键被释放后,其实也会产生一个按键中断,执行触摸中断程序,不过在这个程序中起初是为了获得一个信号量,由于信号量是等待锁,所以,程序一直在试图获取这个信号量,当我们的信号量在上面这个touch_timer_fire中被释放后,我们就会再次获取这个信号量,继续跟踪这个触摸中断函数stylus_updown
static irqreturn_t stylus_updown(int irq, void *dev_id) { unsigned long data0; unsigned long data1; int updown; if (down_trylock(&ADC_LOCK) == 0) { //再次获取锁 OwnADC = 1; data0 = ioread32(base_addr+S3C2410_ADCDAT0); data1 = ioread32(base_addr+S3C2410_ADCDAT1); updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN)); if (updown) { //因为是释放操作,所以updowm=0 touch_timer_fire(0); } else { OwnADC = 0; up(&ADC_LOCK); //释放锁 } } return IRQ_HANDLED; } |
好了,这样我们就真正结束了一次触摸时间的周期。
总结下触摸屏控制的整个运行过程:
Step1:软件开启INT_ADC和INT_TS中断,设置ADCCON以确定AD转换需要的时钟频率,设置ADCDLY以确定从得到命令到开始转换坐标的延时时长,设置ADCTSC使得触摸屏处于等待触笔按下状态
Step2:当触笔按下,产生INT_TC中断,执行stylus_updown,stylus_updown首先判断中断产生的原因是不是触笔按下,是的话就调用定时函数touch_timer_fire,在touch_timer_fire中设置ADCTSC使得触摸屏准备进行自动X/Y轴转换状态,然后设置ADCCON启动坐标转换,结束stylus_updown。
Step3:触摸屏在延迟指定时间后开始转换X/Y坐标,并将转换的结果保存到ADCDAT0和ADADAT1中,完成后发出INT_ADC中断,表示转换完成。
Step4:进入INT_ADC中断处理程序stylus_action,获取X/Y轴坐标,然后进行四次坐标转换以求平均值,最后设置ADCTSC使得触摸屏处于等待触笔释放状态,同时当下一个节拍到来时,调用touch_timer_fire向input子系统报告坐标。
Step5:当触笔释放,还会产生INT_TC中断,进入其中断处理程序,得到触笔释放的消息,最后设置ADCTSC使得触摸屏处于下一次等待触笔按下状态。
三、触摸屏驱动测试
由于mini2440的触摸屏驱动是基于input子系统的,而input子系统给用户层提供的是input_event结构体,我们主要是在应用层接收这个结构体,然后对其类型进行分类,取出我们需要的数值。
struct input_event { struct timeval time; unsigned short type; //支持的类型,如EV_ABS unsigned short code; //支持的具体事件,如坐标事件的ABS_X unsigned int value; //值 }; |
测试触摸屏驱动的应用层代码如下
#include #include #include #include #include int main(int argc, char *argv[]) { int fd = -1; int num; size_t rb; int version; char name[20]; struct input_event ev; int i=0; if ((fd = open("/dev/input/event0", O_RDONLY)) < 0) //打开设备 { perror("open error"); exit(1); } while(1) { rb = read(fd, &ev, sizeof(struct input_event)); //读取设备 if (rb < (int)sizeof(struct input_event)) //读取错误 { perror("read error"); exit(1); } if (EV_ABS==ev.type) //读取按键内容 { printf("event=%s,value=%d\n",ev.code==ABS_X?"ABS_X":ev.code==ABS_Y?"ABS_Y":ev.code==ABS_PRESSURE?"ABS_PRESSURE":"UNKNOWEN",ev.value); }else{ printf("not ev_abs\n"); } } close(fd); return 0; } |
编译测试程序test.c
arm-linux-gcc test.c –o test
超级终端:
./test
测试结果:(触笔按下触摸屏)
event=ABS_X, value=505
event=ABS_Y, value=334
event=ABS_PRESSURE, value=1