- 573.57 KB
- 10页
- 1、本文档共5页,可阅读全部内容。
- 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
- 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
- 文档侵权举报电话:19940600175。
'项目报告:嵌入式系统I/O口驱动设计与实现连云港职业技术学院信息工程学院陈海峰Linux以模块的形式加载设备类型,通常来说一个模块对应一个设备驱动,因此是可以分类的。将模块分成不同的类型或者类并不是一成不变的,开发人员町以根据实际工作需耍在一个模块中实现不同的驱动程序。一般情况,一个设备驱动对应一类设备的模块方式,这样便于多个设备的协调工作也利于应用程序的开发和扩展。设备驱动在准备好以后可以编译到内核屮(参考实验四的内容),在系统启动时和内核一起启动,这种方法在嵌入式Linux系统屮经常被采川。通常情况下设备驱动的动态加载更为普遍(参考实验七的内容),开发人员不必在调试过程中频繁启动机器就能完成设备驱动的开发工作。设备驱动在加载时首先调川入口函数init_module(),该函数完成设备驱动的初始化工作,比如寄存器置位、结构体赋值等一系列工作,其中最重要的一个工作就是向内核注册该设备,对丁•字符设备调丿LIregister_chrdev()5i-成注册,对丁-块设备需:要调用register_blkdev()完成注册。注册成功后,该设备获得了系统分配的主设备号、口定义的次设备号,并建立起于文件系统的关联。设备在卸载吋需要冋收相应的资源,令设备的响应寄存器复位并从系统中注销该设备,字符设备调用unregister—ChnlevO、块设备调用unregister—blkdevO。系统调用部分则是对设备的操作过程,比如open、read、write、ioctl等。图1为一个设备驱动模块动态挂载、卸载和系统调用的全过程。图1设备驱动在内核中的挂载、卸载和系统调川过程
设备驱动程序负责将应丿IJ程序如读、写等操作正确无误的传递给相关的硕件,并使破件
能够做汨正确反应的代码,因此在编写设备驱动程序吋,必须要了解相应的碾件设备的寄存器、10口及内存的配置参数。1、硬件接口电路(1)、LED和八段数码显示接口电路目标板LED和八段数码显示接口电路如图2所示,74HC574为D锁存器,在时钟信号CLK作用下,该锁存器将输入信号进行锁存,叩xQ=xD(x=l~8)。从图中可以看出,LED和八段数码显示电路将74HC574的时钟信号输入端作为片选信号,其屮LED显示的片选信号为LED_CS4、八段数码显示的片选信号为LED.CSlo在八段数码显示电路中,8位数据的高位(D7、D15:即数码管的小数点dp段)用作八段数码的公共选通信号,通过控制PNP三极管來控制数码管的显示。LEDFB1680图2LED和八段数码显示接口电路显示电路屮的片选信号LED.CSx,由D标板系统的PXA270xCPU的地址信号BA22〜
BA20通过3・8译码器LC138产生(如图3际)。VCC.3.3TVCC_3.3_0R77TP5ElTP6U25888012222AAABBB20A3ABCCJN02A2BR8400>01234567YYYYYYYY1311ADCS1LED-CSILED・CS2‘LED-CS3LED-CS4IDECSRTCCSADCS2TP7R26710KTP8图3片选信号产生电路由图可知,当BA22、BA21、BA20=101吋产生LED显示电路的片选信号LED_CS4,当BA22、BA21、BA20=010、011、100时分别产生八段数码显示电路的片选信号LED_CS1、LED_CS2、LED.CS3(另外2组八段显示电路参考系统提供的总电路图)。(2)、键盘接口电路目标平台提供了阵列键盘(如图匕4所示)和单按键键盘(如图8・5所示)两种键盘接口电路,其中阵列键盘中行控制信号线KP-MKIN0-2分别由CPU的通用IOIIGPIO100〜102控制,列控制信号线KP-MKOUTO-5分别由CPU的通川10口GPIO103〜105和GPIO108控制。单按键键盘的控制信号线KP-DKIN1~2,KP-DKIN5-6分别山CPU的通用10口GPIO94〜95和GPIO98〜99控制。图4阵列键盘接II
[1]KP-CKIN6[1]KP-CKIN1[1]KP-DKIN2[1]KP-DKIN5KP-DK1N6图5单按键键盘接口(3)、步进电机控制接口步进电机控制电路如图6所示,步进电机的转动方向控制信号和步进输入信号GP1、GP2分别山CPU的通用IO口GPIO83和GPIO84控制。R1630>宀5601110R16210KVCCOEDRI-INDRI-OUTSTATE-AOUT-ATIME/OUTOUT-BDICOUT-CMONOOUT-DSTEP-INKSTEP-ENGNDU53678UCN4202£24R2350轩45VCC12图6步进电机控制接口电路2、I/O驱动程序设备驱动程序运行在内核空间,而应川程序则运行在用八空间,Linux操作系统通过系统调川和硕件屮断完成从川户空问到内核空间的控制转移,执行系统调川的内核代码在进程的上下文中执行,也就是说代表调用进程操作而口可以访问进稈地址空间的数据,中断处理程序相对进程而言是异步的,而且与任何一个进程都无关。
设备驱动模块的功能就是扩展内核的功能,主要完成两部分任务:一个是系统调用,另一个是中断处理。下面分别以八段数码显示驱动模块为例介绍如何在一个字符驱动设备实现对I/O驱动程序的编写方法和过程(源码实验文件为XSB_EDR_8SEG..c)o1)模块初始化模块初始化module_init(Emdoor_8Seg_init)函数中的参数Emdoor_8Seg_init实际上为八段数码显示驱动模块的初始化函数staticint—initEmdoor_8Seg_init(void),该函数主要完成将产生数码显示的片选控制信号的BA22~BA20通过void*ioremap(unsignedlongoffset,unsignedlongsi須函数为I/O内存区域分配虚拟地址,这样设备菠动程序就能访问I/O内存地址,同时在模块初始化函数中,rcgistcr_chrdcv()R数完成字符设备在内核系统中的注册并建立与文件系统(Emdoojfops)的关联。staticint_initEmdoor_8Seg_init(void){intret;csl_address=ioremap(SEG_CSh32);//distributeI/Omemorymapaddresscs2_address=ioremap(SEG_CS2,4);cs3_address=ioremap(SEG_CS3,4);ret=register_chrdev(61,DEVICE_NAME,&Emd(x)r_fops);//registerdevicenameif(ret<0){printk(DEVICE_NAME"cantgetmajornumbern");returnret;}return0;其中数码片选信号SEG_CS1〜3和设备文件名在程序中采用#define宏定义进行定义。#defineDEVICE.NAMEnemdoor_8segH#defineSEG.CS1#defineSEG_CS2#defineSEG_CS30x102000000x103000000x10400000〃A22,A21,A20=010->LED_CS1〃A22,A21,A20=011->LED_CS2〃A22,A21,A20=100->LED_CS32)模块的卸载模块的卸Scmodule_exit(Emdoor_8Seg_exit)函数屮参数Emdoor_8Seg_exit实际上是模块的从内核卸载吋所调用的staticvoid_exitEmdoor_8Seg_exit(void);设备在卸载吋需要冋收相应的资源,并利用unregister_chrdev()函数从内核中将设备注销。staticvoid_exitEmdoor_8Seg_exit(void){iounmap(csl_address);//releaseI/Omemorymap,reclaimsystemresourceiounmap(cs2_address);iounmap(cs3_address);unregister_chrdev(61,DEVICE_NAME);//unregisterdevice3)设备文件操作接口定义设备文件操作接口定义是用户使用该设备的关键,合理的定义可简化应用程序设计,缩短项R的整体开发周期。八段数码显示驱动模块定义了open、write,releaseioctl等四种设备文件操作,内容如下所示:staticstructfilc_opcrationsEmdoor_fops={open:write:Emdoor_8Seg_open,//openoperationfunctionEmdoor_8Seg_write,//writeoperationfunctionrelease:ioctl:Emdoor_8Seg_release,//releaseoperationfunctionEmdoor_8Seg_ioctl,//IOcontroloperationfunctionowner:THIS_MODULE,};
1)设备文件操作根据设备文件操作接口定义,每一个设备文件操作对应一个系统调用,在用户程序中利川系统调用对设备文件进行诸如open/write等操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取设备文件操作接口定义的相应的函数指针,接着把控制权交给该操作函数。在八段数码显示驱动模块定义了open、write、release>ioctl筹四种设备文件操作。①.打开设备操作staticintEmdoor_8Seg_open(structinode*inode,structfile*filp){structseg*seg_7;seg_7=kmalloc(sizeof(structseg),GFP_KERNEL);//distributememoryinkernelspaceseg_7->negative=LED_MODULE;fi1p->private_data=se^.7;//privatedatapointerpointtoseg_7MOD_INC_USE_COUNT;//currentmodulecounteradd1return0;②.写设备操作staticssize_tEmdoor_8Seg_write(structfile水file,constchar*buffer,size_tcount,loff_t*ppos){inti;structseg*seg_7=file->private_data;charled_forall[6];if(count!=6)//LEDamount{printk(KERN_EMERG"thecountofinputisnotsix!!");return0;}copy_from_user(led_forall,buffer,6);//copydatafromuserspacetokernelspacefor(i=l;i<=6;i++){value_seting(seg_7,i,LED[i-l]);}Updateled(seg_7);//lightentheLEDreturn6;}③.I/O控制操作staticintEmdoor_8Se^ioctl(structinode*ip,structfile*fp,unsignedintcmd,unsignedlongarg){charval=0x00;structseg*seg_7=fp・>private_data;讦(!arg)return-EINVAL;if(copy_from_user(&val,(int*)arg,sizeof(char)))return-EFAULT;switch(cmd){//controltheLEDcommandwordcase1:value_seting(seg_7,1,val);//controlthefirst8LEDbreak;case2:value_seting(seg_7,2,val);//controlthesecond8LED
break;case3:value_seting(seg_7,3,val)//controlthethird8LEDbreak;case4:value_seting(seg_7,4,val);break;case5:value_seting(seg_7,5,val);break;case6:value_seting(seg_7,6,val);//controlthesixth8LEDbreak;case0://clearallLEDseg_7->negative=LED_MODULE;break;default:printk(KERN_EMERGHioct1parameterinputerror,pleaseinputnumber0-6"1);break;}Updateled(seg_7);//lightenLEDreturn0;}①.释放设备操作staticintEmdoor_8Seg_release(structinode*inode,structfile*filp){kfree(filp->private_data);//releasememorywhichdistributedbykmallocMOD_DEC_USE_COUNT;//currentmodulecountersubtract1return0;}1)内部自定义函数在八段数码显示驱动程序中,自定义了一个点亮数码管的函数Updateled(stirictseg*scg_7)staticvoidUpdateled(structseg*seg_7){unsignedshortbuff=0x00;buff=seg_7->ledl_val;buff=buffl(seg_7->led2_val«8);writew(buff,csl_address);//write16bitsdataintoI/Omemorybuff=OxOO;buff=seg_7->led3_val;buff=buffl(seg_7->led4_val«8);writew(buff,cs2_address);
buff=OxOO;buff=seg_7->led5_val;buff=buffl(seg_7->led6_val«8);writew(buff,cs3_address);return;和设置数码管所显示数值的函数value_seting(structseg*seg_7,charposition,charvalue)ovoidvalue_seting(structseg*seg_7,charposition,charvalue){if(seg_7->negative==0)value=-value&〜(0xl«7);elsevalue=(0x1«7)lvalue;if(position==l)seg_7->ledl_val=value;elseif(position==2)seg_7->led2_val=value;elseif(position==3)seg_7・>led3_val=value;elseif(position==4)seg_7->led4_val=value;elseif(position==5)seg_7->led5_val=value;elseif(position==6)segJ7・>led6_val=value;}3、驱动模块的编译在编译驱动模块程序时,应当编写适合于特定口标平台的Makefile编译文件(具体参考实验七和实验二的内容),下而为八段数码显示驱动模块的Makefile内容,,必须注意的是交叉编译工具变量CC和模块将耍使用和运行的内核源码的include变量INCLUDEDIR两个变量的设定必须根据编译平台的实际路径进行修改。CC=/opt/xscalevl/bin/arm-linux-gccINCLUDEDIR=/XSBase270/2.4/Kernel/xsbase/linux-2.4.21-emdoor_EDR/includeCFLAGS=-DKERNEL_-DMODULE-Wall-02CFLAGS+=-1..-1$(INCLUDEDIR)#8SEGTARGET_8SEG=XSB_EDR_8SEG0BJ_8SEG=$(TARGET_8SEG).oS0URCE_8SEG=$(TARGET_8SEG).call:$(OBJ8SEG)$(0BJ_8SEG):$(S0URCE_8SEG)
$(CC)$(CFLAGS)-c-o$(0BJ_8SEG)$(S0URCE_8SEG)clean:rm-rf$(0BJ_8SEG)4、驱动模块的加载将编译好的驱动模块下载到目标上,进入目标板系统后,利JIJmkiiod命令在/devn录下建立该设备的节点。然后利用insmod命令装载驱动模块,最后在目标平台中运行驱动模块的测试程序driverTestC测试程序的下载过程参考实验六的内容),检杏驱动模块的止确性。[root@51BoarcT]$inknod/dev/xsb_edr_8segc611[root@51BoarcT]$insmodXSB_EDR_8SEG.o通过在开发平台上的验证实现八段数码显示的编译和加载过程,将8LED和键盘驱动模块编译并加载到目标平台的内核中;然后将测试程序下载到1=1标平台,测试设备菠动模块的正确性。'
您可能关注的文档
- PC-ABS市场报告、PC-ABS投资报告、PC-ABS项目报告、
- 单片机实训项目报告
- 《互换性与测量技术》三级项目报告 轴类零件的精度与检测
- 光纤网络光信号实时监测系统项目报告
- 教育素质子项目报告(第一稿)
- 新建年产600吨食用菌栽培项目报告书
- 课程设计项目报告-李伟男11160400411
- 电力系统稳态分析报告课程项目报告材料
- 质量标准研究项目报告
- 陶瓷精品艺术销售项目商业方案计划书(项目报告)
- 热镀锌项目报告表
- 物联网系统项目报告
- 物业公司聘请物业顾问项目报告
- 土地增值税项目报告材料表-附件1
- 山东德源泵业有限公司年产6000台(套)潜水电泵和隔爆泵、泵用电机高压电机技改项目报告表
- 生物颗粒及环保炭生产项目报告表文本
- 陕西通用润滑科技有限公司年产10000吨润滑油调制项目报告表
- 衡水中润商砼有限公司扩建1th燃气锅炉项目报告表