armlinux学习笔记--触摸屏驱动程序分析
- 格式:wps
- 大小:103.00 KB
- 文档页数:19
【学习笔记】TSlib校准原理#export CVSROOT=:pserver:cvs@:/mnt/src/cvsroot#cvs login#cvs co tslib获得Tslib 的源代码后,需要⾸先进⾏编译,下⾯以Tslib 1.4 为例介绍Tslib 的编译过程:#cd ../tslib1.4//指定交叉编译⼯具# export CC=/usr/local/ arm-Linux-4.1.1 /bin/arm-Linux-gcc//⽣成config ⽂件#export PATH=/usr/local/ arm-Linux-4.1.1/bin:$PATH//避免检查ac_cv_func_malloc_0_nonnull#echo "ac_cv_func_malloc_0_nonnull=yes" >arm-Linux.cache//配置⽬标机、缓冲、安装路径#./configure --host=arm-Linux --cache-file=arm-Linux.cache --prefix=/opt/tslib1.4# make# make install这样就可以在/opt/tslib1.4 ⽬录下看到相关的应⽤程序、共享库、配置⽂件等了,需要说明的是在嵌⼊式中,由于触摸屏的种类多样、质量不⼀,采⽤Tslib 的参考配置往往⽆法获得较好的触摸屏触摸效果,同样需要经过⼤量的测试才能得到满意的配置参数,恶劣情况下,甚⾄需要对Tslib 的算法进⾏进⼀步的优化。
下⾯就Tslib 的环境变量、配置⽂件等进⾏简要的介绍。
1. 环境变量为了实现Tslib 的正确运⾏,需要对如下的Tslib 的环境变量进⾏配置:TSLIB_TSDEVICE //触摸屏设备⽂件名。
Default (no inputapi): /dev/touchscreen/ucb1x00Default (inputapi): /dev/input/event0TSLIB_CALIBFILE //校准的数据⽂件,由ts_calibrate 校准程序⽣成。
触摸屏驱动学习/embeddedlong/article/details/6112623第一:四线式电阻式触摸屏原理S3C2440而言:在直接试用触摸屏的是时,引脚XP、XM、XP和YM被用于和触摸屏直接相连。
只剩下AIN[3:0]共4个引脚用于一般的ADC输入;当不使用的时候,XP、XM、XP和YM也可用于一般的ADC输入。
S3C2440的触摸屏接口可以驱动成四线电阻触摸屏,四线触摸屏的等效电路如图:14.4所示。
图中粗线表示相互绝缘的两层导电层,当按下时,他们触点处相连;不同的触点在x,y方向电压值不一样,将这两个值经过A/D转换后即可得到X,Y的坐标。
触摸屏工作过程:1.触摸屏没有被按下时,等效电路如14.5所示S4,S5闭合,S1,S2,S3断开,即YM接地、XP上拉、XP作为模拟输入(对CPU而言),YP 作为模拟输入(对CPU而言),XM高阻。
触摸屏没有按下的时候,Y_ADC因为上拉,为高电平,当X轴和Y轴受挤压而接触导通后,Y_ADC的电压由于连通到地变为低电平,此低电平可作为中断触发信号来通知CPU发生“Pen Down”事件,称为等待中断模式。
Pen Down/Up:就是触摸屏按下(松开),都产生INT_TC中断信号,在ADCTSC寄存器的位【8】为0或者1时,表示等待Pen Down/Up中断。
2.采集X_ADC电压,得到X坐标,等效电路如14.6所示。
S1,S3闭合,S2,S4,S5断开,即XP接上电源,XM接地,YP作为输入(对CPU而言)、YM高祖、XP禁止上拉。
这时,YP即X_ADC就是X轴的分压点,进行A/D转换后就得到X坐标。
3.采集Y_ADC电压,得到Y坐标,等效电路如14.7所示。
S2、S4闭合,S1,S3,S5断开,即YP接上电源、YM接地、XP作为模拟输入(对CPU而言),XM高祖,XP禁止上拉,这时,XP即Y_ADC就是y轴的分压点,进行A/D转换后就得到y坐标。
S3C2410触摸屏驱动程序原理图本文介绍了基于三星S3C2410X微处理器,采用SPI接口与ADS7843触摸屏控制器芯片完成触摸屏模块的设计。
具体包括在嵌入式Linux操作系统中的软件驱动开发,采用内核定时器的下半部机制进行了触摸屏硬件中断程序设计,采用16个时钟周期的坐标转换时序,实现触摸点数据采集的方法,给出了坐标采集的流程。
设计完成的触摸屏驱动程序在博创公司教学实验设备UP-NETARM2410-S平台上运行效果良好。
引言随着信息家电和通讯设备的普及,作为与用户交互的终端媒介,触摸屏在生活中得到广泛的应用。
如何在系统中集成触摸屏模块以及在嵌入式操作系统中实现其驱动程序,都成为嵌入式系统设计者需要考虑的问题。
本文主要介绍在三星S3C2410X微处理器的硬件平台上进行基于嵌入式Linux的触摸屏驱动程序设计。
硬件实现方案SPI接口是Motorola推出的一种同步串行接口,采用全双工、四线通信系统,S3C2410X是三星推出的自带触摸屏接口的ARM920T内核芯片,ADS7843为Burr-Brown生产的一款性能优异的触摸屏控制器。
本文采用SPI接口的触摸屏控制器ADS7843外接四线电阻式触摸屏,这种方式最显著的特点是响应速度更快、灵敏度更高,微处理器与触摸屏控制器间的通讯时间大大减少,提高了微处理器的效率。
ADS7843与S3C2410的硬件连接如图1所示,鉴于ADS7843差分工作模式的优点,在硬件电路中将其配置为差分模式。
图1触摸屏输入系统示意图嵌入式Linux系统下的驱动程序设备驱动程序是Linux内核的重要组成部分,控制了操作系统和硬件设备之间的交互。
Linux 的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,成为设备文件。
应用程序可以打开、关闭、读写这些设备文件,对设备的操作就像操作普通的数据文件一样简便。
为开发便利、提高效率,本设计采用可安装模块方式开发调试触摸屏驱动程序。
一、开发环境∙主机:VMWare--Fedora 9∙开发板:Mini2440--64MB Nand, Kernel:2.6.30.4∙编译器:arm-linux-gcc-4.3.2二、前提知识1、Linux输入子系统(Input Subsystem):在Linux中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入子系统事件处理层(Event Handler)组成。
其中设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层;而核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口;而事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。
所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。
下面用图形来描述一下这三者的关系吧!另外,又找了另一幅图来说明Linux输入子系统的结构,可能更加形象容易理解。
如下:2、输入子系统设备驱动层实现原理:在Linux中,Input设备用input_dev结构体描述,定义在input.h中。
设备的驱动只需按照如下步骤就可实现了。
①、在驱动模块加载函数中设置Input设备支持input子系统的哪些事件;②、将Input设备注册到input子系统中;③、在Input设备发生输入操作时(如:键盘被按下/抬起、触摸屏被触摸/抬起/移动、鼠标被移动/单击/抬起时等),提交所发生的事件及对应的键值/坐标等状态。
Linux中输入设备的事件类型有(这里只列出了常用的一些,更多请看linux/input.h中):1.EV_SYN 0x00 同步事件2.EV_KEY 0x01 按键事件3.EV_REL 0x02 相对坐标(如:鼠标移动,报告的是相对最后一次位置的偏移)4.EV_ABS 0x03 绝对坐标(如:触摸屏和操作杆,报告的是绝对的坐标位置)5.EV_MSC 0x04 其它6.EV_LED 0x11 LED7.EV_SND 0x12 声音8.EV_REP 0x14 Repeat9.EV_FF 0x15 力反馈用于提交较常用的事件类型给输入子系统的函数有:1.void input_report_key(struct input_dev *dev, unsigned int code, int value);2.//提交按键事件的函数3.void input_report_rel(struct input_dev *dev, unsigned int code, int value);4.//提交相对坐标事件的函数5.void input_report_abs(struct input_dev *dev, unsigned int code, int value);6.//提交绝对坐标事件的函数注意,在提交输入设备的事件后必须用下列方法使事件同步,让它告知input系统,设备驱动已经发出了一个完整的报告:1.void input_sync(struct input_dev *dev)三、触摸屏驱动的实现步骤1、硬件原理图分析:S3c2440芯片内部触摸屏接口与ADC接口是集成在一起的,硬件结构原理图请看:S3C2440上ADC驱动实例开发讲解中的图,其中通道7(XP或AIN7)作为触摸屏接口的X坐标输入,通道5(YP或AIN5)作为触摸屏接口的Y坐标输入。
/*触摸屏驱动程序及分析*/#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 <plat/regs-adc.h>#include <mach/regs-gpio.h>/* For ts.dev.id.version */#define S3C2410TSVERSION 0x0101#define WAIT4INT(x) (((x)<<8) | \S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \S3C2410_ADCTSC_XY_PST(3))#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))static char *s3c2410ts_name = "s3c2410 TouchScreen";static struct input_dev *dev;static long xp;static long yp;static int count;extern struct semaphore ADC_LOCK;static int OwnADC = 0;static void __iomem *base_addr;/*把GPG12~15 设置为保留模式*/static inline void s3c2410_ts_connect(void){s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);}/*求坐标的平均值,报告坐标,当还是按下状态时,再次调用ADC转换,如果抬起则让触摸屏设置为等待中断模式*/static void touch_timer_fire(unsigned long data){unsigned long data0;unsigned long data1;int updown;/*用于读取ADCDA T数据*/data0 = ioread32(base_addr+S3C2410_ADCDA T0);data1 = ioread32(base_addr+S3C2410_ADCDA T1);/*判断是按下还是送开*/updown = (!(data0 & S3C2410_ADCDA T0_UPDOWN)) && (!(data1 & S3C2410_ADCDA T0_UPDOWN));/*如果按下*/if (updown) {if (count != 0) {/*转换四次后进行事件汇报*/long tmp;tmp = xp;xp = yp;yp = tmp;/* 求平均值*/xp >>= 2;yp >>= 2;/* 报告x、y的绝对坐标值*/input_report_abs(dev, ABS_X, xp);input_report_abs(dev, ABS_Y, yp);/* 报告按键事件,键值为1(代表触摸屏对应的按键被按下) */input_report_key(dev, BTN_TOUCH, 1);/* 报告触摸屏的状态,1表明触摸屏被按下*/input_report_abs(dev, ABS_PRESSURE, 1);/* 同步*/input_sync(dev);}xp = 0;yp = 0;count = 0;/*自动X/Y轴坐标转换模式的设置,自动地进行X轴和Y轴的转换操作,随后产生相应的INT_ADC中断通知转换完毕*/iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);/*如果还没有启动ADC或者ADC转换四次完毕后则启动ADC*/iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);} else {count = 0;/* 如果触摸笔是弹起状态,则提出报告,并让触摸屏处于等待触摸的阶段*//* 报告按键事件,键值为0(代表触摸屏对应的按键被释放) */input_report_key(dev, BTN_TOUCH, 0);/* 报告触摸屏的状态,0表明触摸屏未被按下*/input_report_abs(dev, ABS_PRESSURE, 0);/*同步*/input_sync(dev);/* 设置触摸屏为等待中断模式,等待触摸笔按下*/iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);if (OwnADC) {OwnADC = 0;up(&ADC_LOCK);}}}static struct timer_list touch_timer =TIMER_INITIALIZER(touch_timer_fire, 0, 0);/*当触摸按下时,产生INT_TC中断,会进入到stylus_updown中断处理函数当有中断产生时,会使OwnADC=1,然后读取数据,并判断是抬起还是按下,按下则调用touch_timer_fire()函数,抬起则释放锁,并使OwnADC=0*/static irqreturn_t stylus_updown(int irq, void *dev_id){unsigned long data0;unsigned long data1;int updown;/*注意在触摸屏驱动模块中,这个ADC_LOCK的作用是保证任何时候都只有一个驱动程序使用ADC的中断线,因为在mini2440的adc模块中也会使用到ADC,这样只有拥有了这个锁,才能进入到启动ADC代码部分,注意尽管LDD3中说过信号量因为休眠不适合使用在ISR中,但down_trylock是一个例外,它不会休眠*/if (down_trylock(&ADC_LOCK) == 0) {OwnADC = 1;//获取ADC转换的数据data0 = ioread32(base_addr+S3C2410_ADCDA T0);data1 = ioread32(base_addr+S3C2410_ADCDA T1);updown = (!(data0 & S3C2410_ADCDA T0_UPDOWN)) && (!(data1 & S3C2410_ADCDA T0_UPDOWN));/*判断目前触摸笔的状态updown = 1 触摸笔按下;updown = 0 触摸笔弹起;*/if (updown) {//当触摸笔按下时touch_timer_fire(0); /*这是一个定时器函数,当然在这里只是作为普通函数调用,用来启动ADC*/} else {//当笔弹起时,释放锁OwnADC = 0;up(&ADC_LOCK);}}return IRQ_HANDLED;}/*INT_ADC 中断处理函数读取四次AD转换的值,然后求和,超过四次后执行touch_time_fire()函数*/static irqreturn_t stylus_action(int irq, void *dev_id){unsigned long data0;unsigned long data1;if (OwnADC) {data0 = ioread32(base_addr+S3C2410_ADCDA T0);data1 = ioread32(base_addr+S3C2410_ADCDA T1);xp += data0 & S3C2410_ADCDA T0_XPDA TA_MASK;yp += data1 & S3C2410_ADCDA T1_YPDA TA_MASK;count++;if (count < (1<<2)) { /*如果小于四次重新启动ADC转换*/iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);iowrite32(ioread32(base_addr+S3C2410_ADCCON)|S3C2410_ADCCON_ENABLE_STAR T, base_addr+S3C2410_ADCCON);} else {/*如果超过四次,启动1个时间滴答的定时器,停止ADC,然后调用定时器处理函数touch_timer_fire进行数据上报*/mod_timer(&touch_timer, jiffies+1);iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);}}return IRQ_HANDLED;}static struct clk *adc_clock;/*初始化主要做的工作为:1、获取ADC时钟并使时钟使能2、申请IO虚拟地址3、设置ADCCON,ADCDLY,ACDTSC4、申请input设备5、设置input事件类型,事件值,X,Y坐标的最大最小值6、中断申请7、注册input设备*/static int __init s3c2410ts_init(void){struct input_dev *input_dev; //定义input结构体指针/*获取时钟,触摸屏是挂载在APB BUS上的外围设备,需要时钟控制,见数据手册第7章*/adc_clock = clk_get(NULL, "adc");if (!adc_clock) {//如果时钟获取失败时printk(KERN_ERR "failed to get adc clock source\n");return -ENOENT;}//时钟使能clk_enable(adc_clock);/*I/O内存不要直接进行访问的,最好对其进行映射*/base_addr=ioremap(S3C2410_PA_ADC,0x20);if (base_addr == NULL) {printk(KERN_ERR "Failed to remap register block\n");return -ENOMEM;}/* Configure GPIOs 把YPON,YMON,XPON,XMOND都设置成11,保留模式*/s3c2410_ts_connect();/*使能预分频和设置分频系数S3C2410_ADCCON_PRSCEN:使AD转换使能,是ADCCON的第14位PRSCENS3C2410_ADCCON_PRSCVL(0xFF):预分频系数,取值为0~255:,AD时钟=PCLK/(PRSCVL+1),且必须小于1/5的PCKL*/iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),base_addr+S3C2410_ADCCON);/*设置ADC延时,在等待中断模式下表示产生INT_TC的间隔时间,ADC转换周期等待定时器*/iowrite32(0xffff, base_addr+S3C2410_ADCDLY);/*ADCTSC = 0xd3 ,将触摸屏置为等待中断模式,等待触摸屏被按下产生INT_TC中断*/iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);/* 以下配置2.6内核划分出来的输入设备*//* 分配一个input输入设备*/input_dev = input_allocate_device();if (!input_dev) {//分配input输入设备不成功时printk(KERN_ERR "Unable to allocate the input device !!\n");return -ENOMEM;}dev = input_dev;/*evbit字段用来定义该输入设备可以支持的(产生和响应)的事件的类型,触摸屏设置为支持同步(EN_SYN)、按键(EN_KEY)、绝对坐标(EV_ABS)事件*/dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);/* 设置所支持的按键(键值),触摸屏可以看成只有一个按键的设备*/dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);/* 设置绝对坐标x的最小最大值(0-0x3FF) */input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);/* 设置绝对坐标y的最小最大值(0-0x3FF) */input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);dev->name = s3c2410ts_name;dev->id.bustype = BUS_RS232;dev->id.vendor = 0xDEAD;dev->id.product = 0xBEEF;dev->id.version = S3C2410TSVERSION;/*INT_TC, INT_ADC中断注册,问题:两种中断的产生时机?哪种中断会先产生?答案:INT_TC会先产生,并不断的产生*//* Get irqs *///中断处理函数if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM, "s3c2410_action", dev)) {printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");iounmap(base_addr);return -EIO;}if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,"s3c2410_action", dev)) {printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");iounmap(base_addr);return -EIO;}printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);/* All went ok, so register to the input system *//*注册输入设备*/input_register_device(dev);return 0;}/*主要完成:1、中断的释放2、注销input设备3、释放虚拟内存*/static void __exit s3c2410ts_exit(void){disable_irq(IRQ_ADC);disable_irq(IRQ_TC);free_irq(IRQ_TC,dev);free_irq(IRQ_ADC,dev);if (adc_clock) {clk_disable(adc_clock);clk_put(adc_clock);adc_clock = NULL;}input_unregister_device(dev);iounmap(base_addr);}module_init(s3c2410ts_init);module_exit(s3c2410ts_exit);MODULE_LICENSE("GPL");。
mini2440驱动分析系列之---------------------------------------Mini2440触摸屏程序分析By JeefJiang July,8th,2009这是mini2440驱动分析系列的第三篇文章,本文分为三个部分,第一部分讲叙硬件知识,包括触摸屏的原理以及SCC2440 SOC上的触摸屏是如何工作的。
第二部分分析输入设备子系统的框架,并进行相应的代码分析。
第三部分利用上述的原理来分析mini2440的触摸屏驱动。
第四部分介绍了测试和校准。
1.需要准备的硬件知识1.1电阻式触摸屏工作原理原理触摸屏附着在显示器的表面,与显示器相配合使用,如果能测量出触摸点在屏幕上的坐标位置,则可根据显示屏上对应坐标点的显示内容或图符获知触摸者的意图。
触摸屏按其技术原理可分为五类:矢量压力传感式、电阻式、电容式、红外线式、表面声波式,其中电阻式触摸屏在嵌入式系统中用的较多。
电阻触摸屏是一块4层的透明的复合薄膜屏,如图2所示,最下面是玻璃或有机玻璃构成的基层,最上面是一层外表面经过硬化处理从而光滑防刮的塑料层,中间是两层金属导电层,分别在基层之上和塑料层内表面,在两导电层之间有许多细小的透明隔离点把它们隔开。
当手指触摸屏幕时,两导电层在触摸点处接触。
触摸屏的两个金属导电层是触摸屏的两个工作面,在每个工作面的两端各涂有一条银胶,称为该工作面的一对电极,若在一个工作面的电极对上施加电压,则在该工作面上就会形成均匀连续的平行电压分布。
如图4所示,当在X方向的电极对上施加一确定的电压,而Y方向电极对上不加电压时,在X平行电压场中,触点处的电压值可以在Y+(或Y-)电极上反映出来,通过测量Y+电极对地的电压大小,便可得知触点的X 坐标值。
同理,当在Y电极对上加电压,而X电极对上不加电压时,通过测量X+电极的电压,便可得知触点的Y坐标。
电阻式触摸屏有四线和五线两种。
四线式触摸屏的X工作面和Y工作面分别加在两个导电层上,共有四根引出线,分别连到触摸屏的X电极对和Y电极对上。
linux学习心得总结范文linux学习心得总结【1】学习Linux,应该怎样学,主要学些什么,一位Linux热心学习者,一段学习Linux的风云经验,历时十二个小时的思考总结,近十位网络Linux学习者权威肯定,为您学习Linux指明方向,学习效率,掌握程度,熟悉操作是日常学习Linux中的三大法宝。
以下是作者学习Linux的一些个人经验,供参考:1,应对Linux的发展历史和特点有所了解,Linux是抢占式多任务多用户操作系统,Linux最大的优点在于其作为服务器的强大功能,同时支持多种应用程序及开发工具。
2,熟悉并掌握安装Linux,安装是学习的前提。
目前较常见的安装方法有二种:硬盘安装及光盘安装,清楚了解安装Linux应注意的有关问题,如安装Linux应在最后一个分区内,至少分二个分区,在系统检测不到与Linux兼容的显卡,那么此次安装就可能不支持图形化界面安装,而只能用文本模式安装等等。
3,掌握硬件配置,如显卡,声卡,网卡等,硬件只要不是太老或太新一般都能被支持,作为一名Linux系统管理员建议多阅读有关硬件配置文章,对各种不支持或支持不太好的硬件有深刻的了解。
4,熟悉系统的基本操作,Linux的图形界面直观,操作简便,多加上机练习就可熟悉操作,在Linux下学习办公软件等常用软件,永中office2004增强版安装只需要默认安装即可使用并操作大多与win系统雷同,打印机的配置和管理,记录光盘等。
5,一定要学好命令,shell是命令语言,命令解释程序及程序设计语言的统称,shell也负责用户和操作系统之间的沟通,把用户下达的命令解释给系统去执行,并将系统传回的信息再次解释给用户,估shell也称为命令解释器,有关命令的学习可参考论坛相关文章,精通英文也是学习Linux的关键。
6,掌握在Linux系统中安装软件,在安装Linux工具盘后大致日常所需的软件都会有,一般网络提供下载的软件都会有安装说明。
armlinux学习笔记--触摸屏驱动程序分析//*******************************************************//* 2007.6.26//*******************************************************Linux 下的触摸屏驱动程序主要都在/kernel/drivers/char/s3c2410-ts.c 文件中。
触摸屏的file_operations 结构定义如下:static struct file_operations s3c2410_fops = {owner: THIS_MODULE,open: s3c2410_ts_open,read: s3c2410_ts_read,release: s3c2410_ts_release,#ifdef USE_ASYNCfasync: s3c2410_ts_fasync,#endifpoll: s3c2410_ts_poll,};在触摸屏设备驱动程序中,全局变量struct TS_DEV tsdev 是很重要的,用来保存触摸屏的相关参数、等待处理的消息队列、当前采样数据、上一次采样数据等信息,数据结构struct TS_DEV 的定义如下:typedef struct {unsigned int penStatus; /* PEN_UP, PEN_DOWN, PEN_SAMPLE */TS_RET buf[MAX_TS_BUF]; /* protect against overrun(环形缓冲区)*/unsigned int head, tail;/* head and tail for queued events (环形缓冲区的头尾)*/wait_queue_head_t wq; //* 等待队列数据结构spinlock_t lock; //* 自旋锁#ifdef USE_ASYNCstruct fasync_struct *aq;#endif#ifdef CONFIG_PMstruct pm_dev *pm_dev;#endif} TS_DEV;static TS_DEV tsdev;在/kernel/include/asm-arm/linuette_ioctl.h 文件中:typedef struct {unsigned short pressure; //* 压力,这里可定义为笔按下,笔抬起,笔拖曳unsigned short x; //* 横坐标的采样值unsigned short y; //* 纵坐标的采样值unsigned short pad; //* 填充位} TS_RET;在/kernel/include/linux/wait.h 文件中:struct __wait_queue_head {wq_lock_t lock;struct list_head task_list;#if WAITQUEUE_DEBUGlong __magic;long __creator;#endif};typedef struct __wait_queue_head wait_queue_head_t;TS_RET结构体中的信息就是驱动程序提供给上层应用程序使用的信息,用来存储触摸屏的返回值。
上层应用程序通过读接口,从底层驱动中读取信息,并根据得到的值进行其他方面的操作。
TS_DEV结构用于记录触摸屏运行的各种状态,PenStatus包括PEN_UP、PEN_DOWN和PEN_FLEETING。
buf [MAX_TS_BUF]是用来存放数据信息的事件队列,head、tail分别指向事件队列的头和尾。
程序中的笔事件队列是一个环形结构,当有事件加入时,队列头加一,当有事件被取走时,队列尾加一,当头尾位置指针一致时读取笔事件的信息,进程会被安排进入睡眠。
wq等待队列,包含一个锁变量和一个正在睡眠进程链表。
当有好几个进程都在等待某件事时,Linux会把这些进程记录到这个等待队列。
它的作用是当没有笔触事件发生时,阻塞上层的读操作,直到有笔触事件发生。
lock使用自旋锁,自旋锁是基于共享变量来工作的,函数可以通过给某个变量设置一个特殊值来获得锁。
而其他需要锁的函数则会循环查询锁是否可用。
MAX_TS_BUF的值为16,即在没有被读取之前,系统缓冲区中最多可以存放16个笔触数据信息。
(关于自旋锁的作用和概念可以参考一篇《Linux内核的同步机制》文章的相关章节。
)------------------------------------------------------------------------模块初始化函数是调用s3c2410_ts_init 函数来实现的,主要完成触摸屏设备的内核模块加载、初始化系统I/O、中断注册、设备注册,为设备文件系统创建入口等标准的字符设备初始化工作。
static int __init s3c2410_ts_init(void)ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);tsMajor = ret;这里首先对字符设备进行注册,将触摸屏的file_operations 结构中的函数接口传入内核,注册成功后获得系统自动分配的主设备号。
set_gpio_ctrl(GPIO_YPON);set_gpio_ctrl(GPIO_YMON);set_gpio_ctrl(GPIO_XPON);set_gpio_ctrl(GPIO_XMON);在/kernel/include/asm-arm/arch-s3c2410/smdk.h 文件中:#define GPIO_YPON (GPIO_MODE_nYPON | GPIO_PULLUP_DIS | GPIO_G15)#define GPIO_YMON (GPIO_MODE_YMON | GPIO_PULLUP_EN | GPIO_G14)#define GPIO_XPON (GPIO_MODE_nXPON | GPIO_PULLUP_DIS | GPIO_G13)#define GPIO_XMON (GPIO_MODE_XMON | GPIO_PULLUP_EN | GPIO_G12)GPIO 口的Port G 端口有4个管脚对应触摸屏的控制接口,分别是:GPG15 --- nYPON Y+ 控制信号GPG14 --- YMON Y- 控制信号GPG13 --- nXPON X+ 控制信号GPG12 --- XMON X- 控制信号需要通过配置GPGCON 寄存器来设定该端口管脚的输出模式,对应位如下:[31:30] [29:28] [27:26] [25:24]GPG15 GPG14 GPG13 GPG12 ...参考S3C2410 芯片datasheet 的I/O口章节,都要设为11(二进制)。
ADCDLY = 30000;配置ADCDLY寄存器,对自动转换模式来说是设定ADC 开始转换时的延时时间,以及对X 轴和Y轴转换的时间间隔,对正常模式来说仅设定对X轴和Y轴转换的时间间隔。
注意该值不能为0。
在/kernel/arch/arm/kernel/irq.c 文件中:/*** request_irq - allocate an interrupt line* @irq: Interrupt line to allocate* @handler: Function to be called when the IRQ occurs* @irqflags: Interrupt type flags* @devname: An ascii name for the claiming device* @dev_id: A cookie passed back to the handler function** This call allocates interrupt resources and enables the* interrupt line and IRQ handling. From the point this* call is made your handler function may be invoked. Since* your handler function must clear any interrupt the board* raises, you must take care both to initialise your hardware* and to set up the interrupt handler in the right order.** Dev_id must be globally unique. Normally the address of the* device data structure is used as the cookie. Since the handler* receives this value it makes sense to use it.** If your interrupt is shared you must pass a non NULL dev_id* as this is required when freeing the interrupt.** Flags:** SA_SHIRQ Interrupt is shared** SA_INTERRUPT Disable local interrupts while processing** SA_SAMPLE_RANDOM The interrupt can be used for entropy**/int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),unsigned long irq_flags, const char * devname, void *dev_id)其中handler 函数指针的具体参数为:void (*handler)(int irq, void *dev_id, struct pt_regs *regs)函数request_irq 是Linux 系统中驱动程序注册中断的方法。
irq 为所要申请的硬件中断号,handler 为系统所注册的中断处理子程序,irq_flags 为申请时的选项,devname 为指向设备名称的字符指针,dev_id 为申请时告诉系统的设备标识。