摘要:在便携式的电子类产品中,
触摸屏由于其便、灵活、占用空间少等优点,已经逐渐取代键盘成为嵌入式计算机系统常选用的人机交互输入设备。触摸屏输入系统由触摸屏、触摸屏控制器、微控制器及其相应的驱动程序构成。本文从触摸屏控制器的驱动程序设计着手,介绍触摸屏控制器ADS7843的内部结构及工作原理和在嵌入式Linux操作系统中基于PXA255微处理器的ADS7843驱动程序设计。
1、触摸屏控制器ADS7843的介绍
1.1ADS7843的内部结构
ADS7843内驻一个多路低导通电阻模拟开关组成的供电-测量电路网络、12bit逐次逼近A/D转换器和异步串行数据输入输出,ADS7843根据微控制器发来的不同测量命令导通相应的模拟开关,以便向触摸屏电极对提供电压,并把相应电极上的触点坐标位置所对应的电压模拟量引入A/D转换器,图1为ADS7843内部结构图。X+、Y+、X-、Y-为触摸屏电极模拟电压输入;CS为ADS7843的片选输入信号,低电平有效;DCLK接外部时钟输入,为芯片进行A/D转换和异步串行数据输入/输出提供时钟;DIN串行数据输入端,当CS低电平时,输入数据在时钟的上升沿将串行数据锁存;DOUT串行数据输出端,在时钟下降沿数据由此移位输出,当CS为高电平时,DOUT呈高阻态。BUSY为系统忙标志端,当CS为低电平,且BUSY为高电平时,表示ADS7843正在进行数据转换;VREF参考电压输入端,电压值在+1V到+VCC之间变化;PENIRQ为笔触中断,低电平有效;IN3、IN4为辅助ADC转换输入通道;+VCC为电源输入。
图1ADS7843内部结构
1.2ADS7843的转换时序
ADS7843完成一次数据转换需要与微控制器进行3次通信,*次微处理器通过异步数据传送向ADS843发送控制字,其中包括起始位、通道选择、8/12位模式、差分/单端选择和掉电模式选择,其后的两次数据传送则是微控制器从ADS7843取出16bitA/D转换结果数据(zui后四位自动补零),每次通信需要8个时钟周期,完成一次数据转换共需24个时钟周期,图2为ADS7843转换时序。
图2ADS7843转换时序
2、ADS7843与PXA255硬件接口
PXA255微处理器是In公司生产的第二代基于32位XScale微架构的集成系统芯片(ISOC),PXA255具有高性能、低功耗等优点,它除了XScale微内核外,还集成了许多适用于手持设备市场需要的外围设备。图3为ADS7843触摸屏控制器与PXA255微处理器的硬件连线示意图。当屏触发生时ADS7843向PXA255发出中断请求,由PXA255响应该中断请求,启动通信过程,读取ADS7843的转换结果,从而得到触摸点的坐标。ADS7843各信号的时序受外部输入时钟信号频率的影响,一旦外部输入时钟频率固定,各信号的时序便*确定,因此需要配置PXA255的接口信号时序,使之*符合ADS7843的时序。
图3ADS7843触摸屏控制器与PXA255微处理器的连线示意图
3、ADS7843驱动程序的设计
Linux作为一个宏内核操作系统,其设备驱动都在内核,即系统空间实现,实现方式有两种,一种是将有关的设备驱动程序和数据结构静态地连接在内核映像中;另一种是将具体的设备驱动程序和数据结构独立加以编译,成为可安装的模块,需要时由应用程序通过系统调用动态地予以安装或拆卸。设备驱动的实现方法也有两种,一种是轮询(polling)方式,另一种是中断(inter-rupt)方式,轮询方式对设备的操作*由CPU掌握,外部设备则*处于被动状态。中断方式是由外部设备主动提出申请,CPU响应申请后对外部设备进行处理,是现在常用的设备驱动方式。Linux的设备驱动具有两个显著的特点,其一是把所有的设备视为一种设备文件,每个设备都呈现于文件系统的/dev目录下,设备驱动与文件操作具有相同的界面和语义,并通过同一组系统调用进行操作;另一个显著特点是Linux的设备驱动有着分明的层次和结构。
Linux内核的新近版本为设备入口提供了一种特殊的文件系统,即设备文件系统devfs(devicefilesystem)。新的devfs机制的优点在于:①各种设备驱动模块动态地向系统登记,设备初始化时在/dev目录下创建设备入口点,移除设备时将其删除。②设备驱动程序可以设备名、所有者和权限位。③不需要为设备驱动程序分配主设备号以及次设备号。④当装载和卸载模块时,不再需要运行脚本来创建设备文件,驱动程序自主地管理其设备文件。采用devfs机制的设备驱动程序调用下面的函数来处理设备的创建和删除工作。
devfs_hander_tdevfs_mk_dir(devfs_han2der_tdir,constchar3name,void3info)
devfs_hander_tdevfs_register(devfs_han2der_tdir,constchar3name,unsignedintflags,unsignedintmajor,unsignedintminor,umode_tmode,void3ops,void3info)
voiddevfs_unregister(devfs_hander_tde)
在Linux操作系统编写设备驱动程序时有几个固定的功能模块:向Linux内核注册该设备时的初始化设备驱动程序模块;用于系统卸载模块时删除设备驱动程序的模块;提供用户使用该设备驱动程序的文件操作接口模块。对于各类具体设备编写驱动程序时还应具有对该设备进行操作的应用函数。下面就以ADS7843驱动程序设计为例分析以上几个功能模块。
1)ADS7843向Linux内核注册设备时的初始化函数
int__initads7843_ts_init(void)//设备初始化函数
{intret;
if((ret=devfs_register_chrdev(TS_MAJOR,TS_NAME,&ads7843_ts_fops))!=0)
{printk(“registeringof”TS_NAME“isfailedn”);returnret;}
devfs_ts_dir=devfs_mk_dir(NULL,“touchscreen”,NULL);//建立触摸屏设备目录
devfs_handle=devfs_register(devfs_ts_dir,“ts”,DEVFS_FL_DEFAULT,TS_MAJOR,0,S_IFCHR|S_IRUSR|S_IWUSR,&ads7843_ts_fops,NULL);//注册设备
if((ret=request_irq(IRQ_GPIO_ADS7843,ads7843_ts_inter-rupt,
SA_SHIRQ|SA_INTERRUPT,TS_NAME,dev_id)))//申请中断
{printk(“ads7843_ts_init:failedtoregisterIRQn”);
free_irq(IRQ_GPIO_ADS7843,dev_id);returnret;}
if((ret=ads7843_init())!=0)//初始化触摸屏
{free_irq(IRQ_GPIO_ADS7843,dev_id);returnret;}
GPDR0&=~GPIO_bit(ADS7843_BUSY);
GPDR0&=~GPIO_bit(ADS7843_DOUT);
Ads7843_Enable_IRQ();//开启中断
printk(“ads7843touchscreendriverinitializedn”);
return0;}
2)系统卸载ADS7843驱动程序功能函数
void__exitads7843_ts_cleanup(void)//卸载驱动程序函数
{if(in_timehandle)
del_timer(&timer);
free_irq(IRQ_GPIO_ADS7843,dev_id);//释放中断
devfs_unregister_chrdev(TS_MAJOR,TS_NAME);//从系统中删除设备驱动程序
printk(“ads7843touchscreendriverremovedn”);}
3)在驱动程序zui后用于模块初始化和删除驱动的功能函数
module_init(ads7843_ts_init);//初始化驱动模块函数
module_exit(ads7843_ts_cleanup);//删除驱动模块函数
4)ADS7843设备文件操作结构体
staticstructfile_operationsads7843_ts_fops={
read:ads7843_ts_read,//从设备中读数据操作
poll:ads7843_ts_poll,//查询设备操作
ioctl:ads7843_ts_ioctl,//设备IO控制操作
fasync:ads7843_ts_fasync,//异步通知操作
open:ads7843_ts_open,//打开设备操作
release:ads7843_ts_release,};//当文件结构被释放时,调用释放操作
由于文章篇幅所限,对设备文件操作的功能函数不再一一列出。
5)ADS7843具体操作函数
①ADS7843串行输出控制字函数
voidADS7843_din(charcommand)
udelay(DELAY);//延时
for(inti=0;i<8;i++)//从串行输入端输入8位控制字
{ADS7843_ClearBit(0,ADS7843_CLK);//时钟变低,下降沿输出
if((command>>i)&0x1)
ADS7843_SetBit(0,ADS7843_DIN);//数据位为1
else
ADS7843_ClearBit(0,ADS7843_DIN);//数据位为0
udelay(DELAY);
ADS7843_SetBit(0,ADS7843_CLK);}}//时钟变高
②微处理器读取X坐标值函数(读取Y坐标值函数相类似,控制字为0x90)
intADS7843_ts_measure_x(void)
{chari,inttouch_data=0;
ADS7843_ClearBit(0,ADS7843_CS);//片选端置低电平
udelay(DELAY);
ADS7843_din(0xD0);//向ADS7843发送读X坐标控制字0xD0
ADS7843_ClearBit(0,ADS7843_CLK);
udelay(DELAY);
while(!(GPLR0&GPIO_bit(ADS7843_BUSY)))printk(“BUSY1n”);
ADS7843_ClearBit(0,ADS7843_CLK);
for(i=0;i<15;i++)//读取坐标值
{touch_data<<=1;
if(GPLR0&GPIO_bit(ADS7843_DOUT))
touch_data|=0x01;
else
touch_data&=0xffffe;
ADS7843_SetBit(0,ADS7843_CLK);
udelay(DELAY);
ADS7843_ClearBit(0,ADS7843_CLK);}
touch_data>>=3;//对zui后4位自动置0处理
return(touch_data&0xfff);}