收稿日期:2005-09-22作者简介:朱华生(1965-),男,江西临川人,副教授.文章编号:1006-4869(2005)04-0051-03基于Linux 系统的HHARM9电机驱动程序设计朱华生,胡凯利(南昌工程学院计算机科学与技术系,江西南昌330099)摘 要:对嵌入式Linux 操作系统驱动程序的组成进行分析,讨论了驱动程序的基本框架,以HHARM9电机控制为实例,详细论述了电机驱动程序的实现过程.关键词:嵌入式;Linux;驱动程序中图分类号:TP316 文献标识码:ALinux System -Based Design of HHARM 9Electromotor DriverZHU Hua -sheng,HU Ka-i li(Department of Computer and Science,Nanchang Institute of Technology,Nanchang 330099,China)Abstract:The paper analyses the composition of driver in embedded linux system,disuses its basic frame of driver,and illustrales the process of driver design of HHARM9electromotor in detail.Key words:Embedded;Linux;driver嵌入式Linux 操作系统因具有免费、开放源代码、强大的网络功能等特点,在嵌入式产品中得到越来越广泛的应用.基于Linux 操作系统的嵌入式产品结构[1]如图1所示.本文主要探讨嵌入式系统驱动程序的设计.1 嵌入式Linux 操作系统驱动程序简介1)驱动程序和应用程序的区别驱动程序的设计和应用程序的设计有很大的区别[2].首先,驱动程序的设计要对硬件的结构、信号的工作流程十分清楚,而在应用程序的设计中,一般不需要了解这些.其次,应用程序一般有一个main 函数,从头到尾执行一个任务;驱动程序却不同,它没有main 函数,通过使用宏module _init(初始化函数名),将初始化函数加入内核全局初始化函数列表中,在内核初始化时执行驱动的初始化函数,从而完成驱动的初始化和注册,之后驱动便停止等待被应用软件调用.应用程序可以和GLIB C 库连接,因此可以包含标准的头文件,比如<stdio.h>、<stdlib.h>等;在驱动程序中,不能使用标准C 库,因此不能调用所有的C 库函数,比如输出打印函数只能使用内核的printk 函数,包含的头文件只能是内核的头文件,比如<linux/module.h>.2)Linux 系统设备文件为了方便应用程序的开发,在Linux 操作系统中,使用了设备文件这一概念来管理硬件设备.Linux 操 第24卷 第4期2005年12月南昌工程学院学报Journal of Nanchang Institute of Technology Vol.24No.4Dec.2005作系统把设备映射成为一个特殊的设备文件.每个设备都对应一个设备文件,设备文件保存在系统的/dev 目录下.应用程序要操作硬件设备,只需对相应的设备文件进行操作就可以.硬件设备文件是在安装驱动程序时,由驱动程序向内核注册后生成的.3)驱动程序的组成设备驱动程序的作用是应用程序与硬件之间的一个中间软件层.它由3部分组成:(1)自动配置和初始化子程序,负责检测所要驱动的硬件设备是否存在和能否正常工作.(2)服务于I/O 请求的子程序.这部分程序在执行时,系统认为是和进行调用的进程属于同一进程,只是由用户态变成了内核态.(3)中断服务子程序.在Linux 系统中,并不直接从中断向量表中调用设备驱动程序的中断服务子程序,而是由Linux 系统来接收硬件中断,再由系统调用中断服务子程序.2 嵌入式Linux 操作系统驱动程序的设计方法驱动程序的作用是隐藏硬件设备的具体细节,对不同的设备提供一致的接口,这些接口通过file _oper -ations 结构[3]来定义,设计驱动程序的大部分工作就是根据硬件设计来/填写0结构体中定义的函数.在设计驱动程序时,首先要分析硬件的工作原理,了解电路的工作时序,各种寄存器的地址及各位的功能等信息.然后结合硬件电路设计并实现open 、read 、write 、ioctl 、release 、init 等函数.(1)设计open 函数 open 函数的主要功能是提供给驱动程序初始化能力.在设计时,要根据硬件电路,设置好控制、状态和数据寄存器,为以后的设备操作做好准备.(2)设计read 函数 read 函数的主要功能是从设备上读数据.在设计时,要根据读操作的流程,按顺序设置寄存器,然后再根据响应结果判断是否读取寄存器或总线上的数据.(3)设计write 函数 write 函数的主要功能是往设备上写数据.在设计时,要根据写操作的流程,按顺序设置寄存器,再根据响应结果将要写的数据按顺序写入寄存器或总线.(4)设计ioctl 函数 ioctl 函数的主要功能是执行读、写之外的操作,如:配置设备、进入或退出某种操作模式,实现对设备的控制.(5)release 函数 release 函数功能与open 函数相反,它的主要功能是释放open 分配的file->private_data 中的所有内容.(6)init 函数 init 函数的主要功能是完成寄存器的地址映射和设备向内核注册.3 嵌入式Linux 操作系统驱动程序设计实例以HHARM9实验箱为例,介绍电机驱动程序的设计过程.1)硬件控制结构在设计驱动程序之前,必须对硬件的结构和工作流程十分清楚.在实验箱中,CPU 利用CPLD(95144)逻辑来控制直流电机的工作,如图2所示,其中ULN2803AP 是一个电流放大器.硬件电路的控制逻辑如下:C PLD 判断到nGCS2选中,并且地址线MA5-MA0为000110b 时,读取数据线的低四位D3-D0,并作为M4-M1的输出.寄存器GPACON 的地址是:0x56000000,寄存器GPADAT 的地址是0x56000004.2)驱动程序的设计驱动程序的设计主要分如下几步:(1)给file )operations 结构赋初值赋值语句如下:52南昌工程学院学报2005年第4期static struct file _operations elec tromotor _fops={open: electromotor _open,read: electromotor _read,write: electromotor _write,release: electromotor _release,};本结构的主要作用是:将不同的设备提供一致的接口.如在应用程序中,对不同设备进行读操作时,都使用read 函数,写操作时,都使用write 函数.(2)设计electromotor _open 函数electromotor _open 函数的功能是选中指定设备,即选中nGC S2片选.实现方法是:先将GPACON 寄存器的第13位置1,再将GPADAT 寄存器的第13位置0.函数设计如下:int electromotor _open(struct inode *inode,struct file *filp){ electromotor _sle |=0x2000; //将GPAC ON 寄存器的第13位置1electromotor _sle _data &=(0x2000);//将GPADAT 寄存器的第13位置0printk(/open ok \n 0);return 0;}(3)设计electromotor _write 函数electromotor _write 函数的功能是实现设备的写操作.它首先通过get _user 函数得到用户传送过来的数据,接着写地址M5-M0为000110,即让CPLD 进入控制逻辑.然后将应用程序中传来的值的低四位传送给M4-M1.函数设计如下:ssize _t electromotor _write(struct file*fp,char*buf,size _t size){ char key;if (get _user(key,buf)) //将用户态数据转为内核态return -EFAULT;(*(volatile unsigned char *)ELEC TROMOTOR_6)=key;return 1;}(4)设计electromotor _init 函数electromotor _init 函数主要是完成映射nGC S2地址和CPLD 逻辑控制的入口地址,以及向内核申请注册设备.函数设计如下:int -init electromotor _init(void){ printk(d **************electromotor _init**********\n d );ELEC TROMOTOR _GPACON=ioremap(0x56000000,4);ELEC TROMOTOR _GPADATA=ioremap(0x56000004,4);ELEC TROMOTOR _1=iore map(0x10000000,8);/*******向内核注册设备驱动文件**********/devfs _electromotor =devfs _register (NULL,d electromotor d ,DE VFS _FL _DEFAULT,ELEC TROMOTOR _MA -JOR,0,S _IFC HR |S _IRUSR |S _IW USR |S _IRGRP |S _I WGRP,&electromotor _fops,NULL);return 0;}(5)设计module _init 函数该函数是驱动程序的模块入口,通过调用module _init(electromotor _init)来实现.因为电机没有反馈信息,所以本驱动程序可以把electromotor _read 函数写成一个空的函数.驱动程序设计完成后,再编写Makefile 文件,通过make 命令生成目标文件,最后利用insmod 命令向内核加载驱动程序,这时在/dev 就会新增一个设备文件.说明驱动程序加载成功.(下转第62页)53第4期朱华生,等:基于Linu x 系统的HHARM9电机驱动程序设计z =Q 2K .(5)3 比较与分析在圆孔的夫琅和费衍射时,由衍射积分得出的最小距离为z =k 2Q 2=PQ 2K .(6)与波带法得出的式(5)进行比较,两者在数量级上是相同的,而具体数值上两式相差P .进一步分析不难发觉,为了得出夫琅和费衍射条件,在波带法中,圆孔对P 0点所张面积正好为一个波带,即P 0点到圆孔边缘相对P 0到圆孔中心的光程差为K 2,相应的相位差是P .在衍射积分中,采用的是式(2),此式中大括号里与振幅U 1(x 1,y 1)相乘的平方项相位因子在夫琅和费衍射时必须被忽略,在圆孔边缘处其相位为k Q 22z =PQ 2K z,当把分析衍射积分中的观察屏上P 点取在轴线上的P 0点时,此项正是P 0点到圆孔边缘((x 21+y 21)max =Q 2)相对P 0点到圆孔中心(x 1=0,y 1=0)的相位差.在文献[1]中要求这个相位差远远小于1从而忽略其影响,得出了夫琅和费衍射条件.当然可以认为这个条件是严格的,然而为了与波带法比较,可以将这个条件放宽至P ,若在式(3)中也采用波带法的标准,即在衍射积分中夫琅和费衍射条件下的最小距离要求上述相位差k Q 22z =P ,此时对应的光程差为Q 22z =K 2,得出z =Q 2K,在这种条件下两种分析方法结果一致.虽然在讨论中采用了圆孔衍射屏,显然分析得出的结果与衍射孔径的形状无关.通过以上分析可知,由衍射积分和波带法都可以得出夫琅和费衍射条件的表达式,而波带法的分析具有物理图像清楚、方法简单直观的优点,有助于学生对无透镜夫琅和费衍射条件的深入理解.参考文献:[1]J.W.顾得门.傅里叶光学导论[M].北京:科学出版社,1976.[2]赵凯华,钟锡华.光学[M ].北京:北京大学出版社,1983.[3]姚启钧.光学教程[M].高等教育出版社,1999.(上接第53页)4 结束语由于设备驱动是沟通底层硬件与上层应用程序的桥梁,它所涉及的内容相当多.要设计出一个好的驱动程序,不仅要对硬件设备及工作原理相当熟悉,同时还必须具备一定的内核结构知识.参考文献:[1]王田苗.嵌入式系统设计与实例开发[M].北京:清华大学出版社,2003.[2]ALESSANDRO RUBINI.LINUX 设备驱动程序(第二版)[M ].北京:中国电力出版社,2002.[3]姜明华,周敬利,黄晓涛.Linux 下加密卡驱动程序的开发与性能分析[J].计算机工程,2004,(8):185-187.62南昌工程学院学报2005年第4期。