嵌入式操作系统驱动程序编写基础课件

上传人:我*** 文档编号:144683648 上传时间:2020-09-13 格式:PPT 页数:123 大小:7.54MB
返回 下载 相关 举报
嵌入式操作系统驱动程序编写基础课件_第1页
第1页 / 共123页
嵌入式操作系统驱动程序编写基础课件_第2页
第2页 / 共123页
嵌入式操作系统驱动程序编写基础课件_第3页
第3页 / 共123页
嵌入式操作系统驱动程序编写基础课件_第4页
第4页 / 共123页
嵌入式操作系统驱动程序编写基础课件_第5页
第5页 / 共123页
点击查看更多>>
资源描述

《嵌入式操作系统驱动程序编写基础课件》由会员分享,可在线阅读,更多相关《嵌入式操作系统驱动程序编写基础课件(123页珍藏版)》请在金锄头文库上搜索。

1、嵌入式操作系统 -驱动程序编写基础,李春杰,主要内容,设备驱动硬件基础 内核模块 中断服务例程 驱动程序组成,设备驱动的作用,驱动是应用软件和硬件的桥梁 它使得应用软件只需要调用系统软件的应用编程接口(API)就可让硬件去完成要求的工作。 驱动程序沟通着硬件和应用软件,而驱动工程师沟通着硬件工程师和软件工程师。,无操作系统的程序架构,在这样的系统中,虽然不存在操作系统,但设备驱动程序一般存在。一般情况下,驱动程序都会定义为一个软件模块,包含.h文件和.C文件,前者定义该设备驱动程序的数据结构并声明外部函数,后者进行驱动的具体实现。,无操作系统时驱动和应用程序的关系,在没有操作系统时,设备的接口

2、被直接提交给用用软件。 应用软件直接调用、访问设备驱动的接口 设备驱动的接口函数与硬件的功能直接吻合,没有任何附加功能。 两种不合理设计 驱动中存在部分应用,或应用中包含驱动都会导致程序移植性和复用性变差,有操作系统的设备驱动,有操作系统的设备驱动的变化 无操作系统时设备驱动的硬件工作仍然必不可少,没有它们驱动不可能与硬件打交道 需要把驱动融入内核。为了实现这种融合,需要在驱动程序中设计面向系统内核的接口。 这样的接口有操作系统规定,对一类设备而言结构一致,独立于具体的设备。 设备驱动程序成为硬件和内核的桥梁-要写一部分内核接口,多出来两层结构,有利有弊,屏蔽了底层的差异,Linux的设备驱动

3、,Linux设备 字符设备 块设备 网络设备,无操作系统的LED驱动,Linux的led驱动,Linux设备驱动的重点、难点,Linux设备驱动设计的硬件基础,计算机系统的硬件主要由CPU、存储器和外设组成。驱动针对的对象是存储器和外设(包括CPU内部集成的存储器和外设)。 注意不是针对CPU核,Linux设备驱动设计的硬件基础,1、处理器,Linux设备驱动设计的硬件基础,2、存储器,Linux设备驱动设计的硬件基础,3、总线与接口 串口 电器特性、时序特性(掌握)、信号分类 I2C有时序,无协议 SPI CAN有协议,有时序 USB PCI 网口,Linux设备驱动设计的硬件基础,Linu

4、x设备驱动设计的硬件基础,原理图分析:确定设备使用的相关资源 时序分析: 芯片手册 芯片结构、整体性能、管件个数、电气性能 寄存器编程 外设控制器的编程流程,Linux设备驱动设计的硬件基础,仪器仪表使用 万用表 示波器 等等,内核模块概述,Linux的内核模块机制给内核提供了很强的灵活性,用户通过加载内核模块可以方便的给内核添加功能;同样用户也可以将内核不需要用的功能卸载。 驱动程序可以静态编译进内核,但由于外设众多,内核不可能包含所有设备的驱动。 用户通过内核模块机制可以把需要用到的驱动程序动态地加入内核。,内核模块的概述,内核模块在内核空间运行,内核模块编程是在内核空间编程。 内核模块可

5、以引用内核空间导出的全局符号,因此内核模块编程与内核的版本密切相关。 内核模块只能调用和使用内核提供的函数,不能使用相关的应用程序库函数。,模块编程举例-一个简单的hello 模块,为何不用printf函数语句?,上面例子是一个完整的内核模块,该模块被载入内核时会向系统的日志中写入Hello,world;当模块被卸载时,该模块会向系统日志写入一条Goodbye,cruel world的信息。,内核模块的基本结构1,一个典型的内核模块包含以下几部分: 头文件声明:头文件module.h和init.h是必须的。 module.h包含了加载模块需要的函数和符号的定义; init.h包含了模块初始化和

6、清理函数的定义;如果模块在加载时允许用户传递参数,模块还应该包含moduleparam.h头文件。,内核模块的基本结构2,模块许可声明:MODULE_LICENSE宏声明此模块的许可证,否则在模块被加载时,内核会显示警告。 初始化、清理函数声明:在2.6内核模块必须调用宏module_init和module_exit去注册初始化与清理函数,需要注意的是初始化清理函数必须在宏module_init和module_exit使用前定义 满足以上基本结构,模块就可以正常工作了,在驱动程序中除包含模块的三个基本部分以外,还会包含文件操作及其它内容。 可以在模块中包含的其他描述性定义有 MODULE_AU

7、THOR ( 声明谁编写了模块 ), MODULE_DESCRIPION( 一个人可读的关于模块做什么的声明 ), 等其它MODULE_宏;各种 MODULE_ 声明可以出现在你的源码文件的任何函数之外的地方. 但是, 一个内核代码中相对近期的惯例是把这些声明放在文件末尾.,模块的初始化与关闭,模块初始化函数注册模块提供的相关功能. 这些功能, 我们指的是新功能, 可以由应用程序存取的或者一整个驱动或者一个新软件抽象. 实际的初始化函数定义常常如: static int _init initialization_function(void) /* Initialization code her

8、e */ module_init(initialization_function); 每个非试验性的模块也要求有一个清理函数, 它注销接口, 在模块被去除之前返回所有资源给系统. 这个函数定义为: static void _exit cleanup_function(void) /* Cleanup code here */ module_exit(cleanup_function); 如果你的模块没有定义一个清理函数, 内核不会允许它被卸载.,初始化中的错误处理 如果在你注册工具时发生任何错误, 首先第一的事情是决定模块是否能够无论如何继续初始化它自己. 常常, 在一个注册失败后模块可以继续

9、操作, 如果需要可以功能降级. 在任何可能的时候, 你的模块应当尽力向前, 并提供事情失败后具备的能力. 如果证实你的模块在一个特别类型的失败后完全不能加载, 你必须取消任何在失败前注册的动作.,清理注册,另一种编程如下:,模块的编译,在linux2.6内核中,模块的编译需要配置过的内核源代码,没有源代码无法进行内核模块编译工作。编译、链接后生成的内核模块后缀为.ko。 编译过程中首先会到内核源码目录下,读取顶层的makefile文件,然后返回模块源代码所在的目录编译。,模块的编译,模块的makefile二,模块的加载,编译好模块后用户可以利用超级用户的身份可以将内核模块加载到内核中。常见的实

10、用程序insmod、rmmod、lsmod、modprobe,直接在内核源码树下完成模块的构建,直接在内核源码树下完成模块的构建,对于上面的示例建立模块的步骤,接下来在内核的配置文件中增加新的选项:在./driver/char/kconfig文件中增加针对example的配置选项 当设置完kconfig文件并且保存在./driver/char/子目录下后,上述的代码片段最终在当前的操作系统内核配置选项中增加了新的一项config_examples 相应的配置程序需要通过下面的命令进行调用,然后进行相关配置完成相关配置选项的配置工作,接下来修改./driver/char/子目录的makefile

11、,添加example选项,指导内核配置选项config_example完成example的构建工作。,驱动模块的生成,完成上述工作以后,构建example设备驱动程序的基础设施就准备好了,利用上述步骤完成构建的好处是,不管何时调用内核构建工作,相应的驱动程序都会自动被构建。只要在相应配置选项中进行相应选择,就可以完成设备驱动程序的构建 相应的命令行举例:,把驱动程序模块安装在文件系统相应的目录中。 命令举例(把模块装在coyote-target目录),加载设备驱动模块,对外设的操作-1.轮询,2.中断,外设的操作时间一般较长,并且具有时间的不确定性,驱动程序向外设发出操作指令后,驱动程序采用两

12、种方式等待操作完成。 轮询模式(polling mode)CPU重复检查(轮询)设备的状态寄存器,直到寄存器的值表明I/O操作已经完成为止 中断模式(interrupt mode)如果I/O控制器能够通过IRQ线发出I/O操作结束的信号,就可以使用中断模式,轮询模式的简单例子不好,可以用来粗略的判断超时,若时间比较长,比如ms级,可以在每次轮询操作之后调用schedule主动放弃CPU,直到下次被调度再次轮询,中断模式好处,外部设备通过中断线将产生的中断通知处理器,在驱动程序采用中断模式工作前必须要申请注册一个中断号。 要注册给外设注册一个外部中断号,必须要确定外设使用的那个中断号,确定中断号

13、可以通过: 指定外设中断号 通过检测函数检测中断号,从而确定要注册的外部中断号 编写相关的中断服务例程ISR,确定外部中断号,自动检测IRQ: 内核在中声明了两个用于自动检测IRQ的函数,两个函数使用结构如下:,检测IRQ函数举例,注册外部中断,中断程序的注册 一个模块被希望来请求一个中断通道(或者 IRQ, 对于中断请求), 在使用它之前要注册它, 并且当结束时释放它. 函数声明在 , 实现中断注册接口:,中断处理程序:一个中断处理的角色是给它的设备关于中断接收的回应并且读或写数据, 根据被服务的中断的含义. 第一步常常包括清除接口板上的一位; 让大部分硬件设备不产生别的中断直到它们的“中断

14、挂起”位被清除. 即action. 中断处理程序与普通c代码没有太大不同,不同的是中断程序在中断期间运行,有如下限制: 不能向用户空间发送或接收数据-发生中断的上下文是当前的用户空间,如果发数据,会污染用户空间 不能执行有睡眠操作的函数 不能调用调度函数-中断优先级很高,内核不支持中断中调度,每一个中断服务例程都应该尽快地释放处理器,把能够推迟的工作尽量后推。 中断处理程序的上半部和下半部 上半部分会立即被内核执行 下半部分会被推迟执行:下半部的执行并不需要指明一个确切时间,只要把这些任务推迟,让它们在系统不太繁忙并且中断恢复后执行就可以了。,中断处理程序的上半部和下半部的划分: 如果一个任务

15、对时间非常敏感,将其放在上半部执行 如果一个任务和硬件相关,将其放在上半部中执行 如果一个任务要保证不被其他中断(特别是相同的中断)打断,将其放在上半部中执行 其他所有任务,考虑放置在下半部执行,中断处理程序下半部的实现机制: 软中断 Tasklet:基于软中断来实现,但比软中断接口简单,同步要求较低;软中断保留给执行频率及时间要求高的下半部使用。 工作队列,1、软中断(32g)的主要数据结构,在softirq_vec中定义 在softirq_vec数组中每一项对应一个软中断,系统中最多可以有32个软中断。,优先级对应于softirq_vec的 下标,软中断函数 及其参数,kernel/sof

16、tirq.c,include/linux/interrupt.h,内核只预定义了6个中断,优先级0:处理高优先级的 tasklet和下半部分,优先级2:把数据包传送到网卡,优先级3:从网卡接受数据包,优先级5:处理tasklet,优先级1:与时钟中断相关的tasklet,优先级4:块设备相关,优先级6:调度SMP相关,include/linux/interrupt.h,软中断的初始化,初始化软中断函数 软中断初始注册函数 open_softirq接受三个参数,软中断的序号(如nr置为0)、软中断处理函数以及传递给软中断处理函数的参数,软中断的触发与执行,软中断处理程序被注册后,触发软中断的函数为raise_softirq;该函数接受要被激活的软中断序号最为参数。例如: raise_softirq(NET_TX_SOFTIRQ)使该软中断的处理函数net_tx_action处于可运行状态 该软中断处理函数net_tx_action会在内核下次执行软中断do_softirq()时被执行 自学linux内核的软中断机制?,2、Task

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > PPT模板库 > PPT素材/模板

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号