《嵌入式系统设计ppt课件 第8章.pptx》由会员分享,可在线阅读,更多相关《嵌入式系统设计ppt课件 第8章.pptx(37页珍藏版)》请在三一办公上搜索。
1、第8章 设备驱动程序开发,驱动激励硬件设备开启,赋予硬件设备能量,1,本章内容,2,8.1 设备驱动概述,1,8.2 设备驱动程序的开发过程,2,8.3 驱动程序开发的常见问题,3,目的和要求,了解驱动程序的功能理解驱动程序开发过程掌握各类设备驱动程序设计方法掌握驱动程序开发过程中的常见问题掌握直流电机驱动程序设计实例,3,8.1 设备驱动概述,主要完成以下的功能:(1)对设备初始化和释放;(2)把操作数据从内核传送到硬件和从硬 件读取数据;(3)读取应用程序传送给硬件设备的数据 和回送应用程序请求的数据;(4)检测和处理硬件设备出现的错误。,4,8.1.1 驱动程序和应用程序的区别,设备驱动
2、程序就工作在“内核空间” ;应用程序则是在“用户空间”中运行 。驱动程序的优先级高于应用程序。 驱动程序可以对硬件进行直接访问和对内存的访问。应用程序则不能。,5,应用程序与驱动程序的关系图,6,Linux的设备管理,字符设备(Character Device) 块设备(Block Device) 网络设备驱动(Network interface),7,字符设备,Linux下的字符设备接口支持面向字符的I/O操作,是以字节为单位顺序读写; 字符设备无需缓存且被直接读写 ;字符设备可以访问/dev目录下的文件系统节点,8,字符设备驱动程序示意图,9,块设备,Linux系统下的块设备是指对信息存取
3、以“块”为单位 ;块设备对于I/O请求有对应的缓冲区,块设备具有随机访问特性;块设备和字符设备一样也是通过/dev目录下的文件系统节点被访问的;块驱动程序除了给内核提供和字符设备驱动程序一样的接口以外,还提供了专门面向块设备的接口 ;块设备的接口还必须支持挂装(mount)文件系统。,10,块设备驱动程序数据结构示意图,11,网络设备驱动,网络驱动的体系结构包括网络协议接口层、网络设备接口层、网络驱动接口层和设备媒介层。,12,网络驱动的体系结构,13,8.2 设备驱动程序的开发过程,8.2.1 字符设备驱动程序的设计,驱动程序的接口流程图,14,Linux为所有的设备文件都提供了统一的操作函
4、数接口,具体操作方法是使用数据结构struct file_operations。,struct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char *, size_t, loff_t *);ssize_t (*write) (struct file *, const char *, size_t, loff_t *);int (*readdir) (struct file *, void *, filldir
5、_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);,15,在嵌入式系统的开发中,我们一般仅仅实现其中几个接口函数:read、write、ioctl、open、releas
6、e,就可以完成应用系统需要的功能。open接口 Open 接口提供给驱动程序初始化设备的能力,从而为以后的设备操作做好准备。release接口 与 open函数相反 ;read 和write 接口 read 函数完成将数据从内核拷贝到应用程序空间,write函数则相反,将数据从应用程序空间拷贝到内核。,16,ioctl 接口 ioctl 接口主要用于对设备进行读写之外的其他控制。,例:LED驱动程序: S3C2410上的4个LED指示灯由4个I/O端口控制,他们分别是GPF4GPF7,当GPF4GPF7分别输出低电平时候,LED指示灯亮,输出高电平的时候,LED指示灯灭,17,1、LED驱动需
7、要的头文件 # include /配置头文件# include /内核头文件# include /用户定义模块初始函数需引用的头文件# include /模块加载的头文件# include /延时头文件 # include # include /用户的硬件配置文件# include ,18,2、LED驱动需要的宏定义 # define GPIO_LED_MAJOR 220 /定义主设备号/声明4个LED灯的I/O端口; GPFDAT 是端口F的数据寄存器# define LED1_ON()(GPFDAT & = 0 x10) /GPF4输出0# define LED2_ON()(GPFDAT
8、& = 0 x20) /GPF5输出0# define LED3_ON()(GPFDAT & = 0 x40) /GPF6输出0# define LED4_ON()(GPFDAT & = 0 x80) /GPF7输出0# define LED1_OFF()(GPFDAT | = 0 x10) /GPF4输出1# define LED2_OFF()(GPFDAT | = 0 x20) /GPF5输出1# define LED3_OFF()(GPFDAT | = 0 x40) /GPF6输出1# define LED4_OFF()(GPFDAT | = 0 x80) /GPF7输出1/定义LED灯
9、的状态# define LED_ON 0 /低电平点亮LED# define LED_OFF 1 /高电平熄灭LED,19,3、file_operations 结构体的设计 struct file_operations GPIO_LED_ctl_ops= open: GPIO_LED_open, read: GPIO_LED_read, write: GPIO_LED_write, ioctl: GPIO_LED_ioctl, release: GPIO_LED_release, ;,20,4、LED驱动程序的读写函数实现 在本例中,LED的读写操作不做任何操作,可以省略。本例仅给出了读写操作
10、函数的框架。/-READ-ssize_t GPIO_LED_read(struct file * file ,char * buf , size_t count, loff_t * f_ops) return count;/-WRITE-ssize_t GPIO_LED_write(struct file * file ,const char * buf , size_t count, loff_t * f_ops) return count;,21,ssize_t GPIO_LED_ioctl(struct inode * inode, struct file * file,unsigned
11、 int cmd,long data) Switch (cmd) case LED_ON: LED1_ON(); / 点亮LED1udelay(0 x500000); /延时LED2_ON(); / 点亮LED2udelay(0 x500000); /延时LED3_ON(); / 点亮LED3udelay(0 x500000); /延时LED4_ON(); / 点亮LED4udelay(0 x500000); /延时break; case LED_OFF:,LED1_OFF(); / LED1灭 udelay(0 x500000); /延时LED2_OFF(); / LED2灭udelay(0
12、 x500000); /延时LED3_OFF(); / LED3灭udelay(0 x500000); /延时LED4_OFF(); / LED4灭udelay(0 x500000); /延时break; default: printk (LED control:no cmd run.n ); return -1; return 0;,5、LED驱动程序ioctl控制模块的实现:对设备I/O控制操作,22,6、驱动程序的open()、close()函数:设备文件的打开、关闭操作。 /-OPEN-Ssize_t GPIO_LED_open(struct inode * inode , struc
13、t file * file) MOD_INC_USE_COUNT; /模块数量增1 return 0; /-RELEASE/CLOSE-Ssize_t GPIO_LED_release(struct inode * inode , struct file * file) MOD_DEC_USE_COUNT; /模块数量减1 return 0;,23,7、驱动程序的init、exit函数:模块加载功能的函数实现 /-INIT-static int GPIO_LED_CTL_init(void) int ret=0;GPFCON = 0 x55aa; /设置端口为I/O输出模式GPFUP = 0
14、xff; / 关闭上拉功能GPFDAT = 0 xff; / 初始值为高电平熄灭LED灯/注册设备ret=register_chrdev(GPIO_LED_MAJOR, GPIO_LED_CTL, ,24,static int _init S3C2410_GPIO_LED_CTL_init(void) int ret=0; / 调用函数GPIO_LED_CTL_init() ret= GPIO_LED_CTL_init(); if (ret) return -1; return 0; static void _exit cleanup_GPIO_LED_ctl(void) unregister
15、_chrdev(GPIO_LED_MAJOR, GPIO_LED_CTL); /注销LED设备module_init(S3C2410_GPIO_LED_init);module_exit(cleanup_GPIO_LED_ctl);,25,8.2.2 块设备驱动程序设计,块设备可以在一次I/O操作中传送固定大小的数据块,可以随机访问设备中所存放的块。所有对块设备的读写操作都是通过调用generic_file_read ( )和generic_file_write ( ) 函数实现 。,26,8.2.3 网络设备驱动程序设计,网络设备的驱动程序接口函数 :1.初始化(initialize):主要
16、完成检测设备、配置和初始化硬件 、申请资源等。 2. 打开(open):网络设备被激活的时候调用 。3. 关闭(close):释放资源以减少系统负担 。4. 发送(hard_start_xmit) 5. 接收(reception)6. 硬件帧头(hard_header) 7. 地址解析(xarp) 8. 参数设置和统计数据,27,8.2.4 驱动程序的注册,设备驱动程序的注册和取消注册应分别在模块的初始化函数和析构函数中完成。1字符设备驱动程序的注册 注册函数: register_chrdev(unsigned int major, const char * name, struct file
17、_operations *fops) major:主设备号; name:设备名称; fops: 指向文件操作表的一个指针。如果major=0,系统自动分配一个主设备号。 注册成功返回0,否则返回负值。 取消注册的函数为unregister_chrdev( register_chrdev(unsigned int major, const char * name),28,2块设备驱动程序的注册,注册函数:register_blkdev(unsigned int major, const char * name, struct block_device_operations *bdops) maj
18、or:主设备号; name :设备名称; bdops:指向具体设备操作的指针。如果major=0,系统自动分配一个主设备号。注册成功返回0,否则返回负值。 删除块注册函数: unregister_blkdev(unsigned int major, const char * name),29,3网络设备驱动程序注册,注册函数:register_netdev(struct device *)卸载设备: unregister_netdev(struct device *) 函数,30,8.2.5 设备驱动程序的编译,在Linux下要运行驱动程序需要用Makefile文件进行编译,Makefile
19、文件定义了一系列的编译规则。,31,8.2.6驱动程序的加载,动态加载: 动态加载在系统启动后,用insmod命令把驱动程序添加上去,在不需要的时候用rmmod命令来卸载 。静态加载: 静态加载就是把驱动程序直接编译到内核里,系统启动后可以直接调用。,32,8.2.7 驱动程序的调用,在嵌入式系统中应用程序对驱动程序的调用实质就是使用数据结构struct file_operations中成员函数的指针 。这个结构的每一个成员函数的名字都对应着一个系统调用 。用户进程利用系统调用在对设备文件进行诸如读写read/write操作时,首先通过设备文件的主设备号找到相应的设备驱动程序,然后再读取这个数
20、据结构相应的函数指针,接着把控制权交给该函数。,33,8.3 驱动程序开发的常见问题,驱动程序开发过程中主要考虑三个方面。提供尽量多的选项给用户;提高驱动程序的速度和效率;尽量使驱动程序简单,使之易于维护。,34,比较常见的问题有,阻塞型IO的处理: read函数调用时会出现当前没有数据可读,但马上就会有数据到达的情况,这时采用睡眠并等待数据的方式,这就是阻塞型IO。 解决阻塞型IO ,一般采用进程睡眠、唤醒,在阻塞的情况查看是否有数据等方式。,35,并发访问与数据保护 当应用程序使用多线程操作时,需要数据共享使用,在驱动程序中可以使用循环缓冲区并且避免使用共享变量。中断处理 在使用请求中断函数时,如果有几个设备共享同一个中断的话,申请时要指明共享方式 。网络驱动程序中对硬件发送忙时的处理 在Linux系统中网络设备驱动程序一般不做数据缓存,不能发送的数据都要通知系统发送不成功,所以必须要有一个机制在硬件不忙时及时通知系统接着发送后续剩余的数据。,36,37,Thank You !,