1. 司机的角色
本文参考地址:
任何计算机系统的运行都是系统中软件和硬件配合的结果。 没有硬件的软件就是空中楼阁,没有软件的硬件只是一堆废铁。 硬件是底层的基础,是所有软件运行的平台。 代码最终将在硬件上实现为组合逻辑和时序逻辑; 软件实现特定的应用,根据各种业务需求进行设计,以满足用户的需求。 。 硬件相对固定,而软件则非常灵活,可以适应各种复杂多变的应用。 可以说,计算机系统的软件和硬件相辅相成。
然而,软件和硬件之间也存在一个悖论,那就是软件和硬件不应该渗透对方的领地。 为了尽快完成设计,应用软件工程师不想也不需要关心硬件,而硬件工程师也很少有足够的闲暇和能力来关心软件。 例如,当应用软件工程师调用套接字发送和接收数据包时,他不需要关心中断、寄存器、存储空间、I/O端口、片选以及网卡上的任何其他硬件词汇; 当使用 printf() 函数输出信息时,他不需要知道底层如何将相应的信息输出到屏幕或串口。
也就是说,应用软件工程师需要看到一个没有硬件的纯软件世界,硬件必须透明地呈现给他们。 谁将使硬件对应用软件工程师不可见? 这项艰巨的任务就落在了驱动工程师的肩上。
对设备驱动程序最通俗的解释是“驱动硬件设备行动”。 设备驱动程序直接与底层硬件打交道,根据硬件设备的具体工作方式读写设备寄存器,完成设备轮询、中断处理、DMA通信、将物理内存映射到虚拟内存,最终使通信设备能够发送和接收数据。 显示设备可以显示文本和图像,存储设备可以记录文件和数据。
可见,设备驱动程序充当了硬件和应用软件之间的纽带。 它使得应用软件只需调用系统软件的应用程序编程接口(API)即可让硬件完成所需的工作。 当系统中没有操作系统时,工程师可以根据硬件设备的特点定义自己的接口,例如为串口定义SerialSend()和SerialRecv(); 为 LED 定义 LightOn() 和 LightOff(); 并为Flash定义FlashWrite()。 )、FlashRead()等。对于操作系统来说,设备驱动程序架构由相应的操作系统定义。 驱动工程师必须根据相应的架构来设计设备驱动程序,这样设备驱动程序才能很好地集成到操作系统的内核中。
驱动程序与硬件和应用软件进行通信,驱动工程师与硬件工程师和应用软件工程师进行通信。 随着通信和电子工业的快速发展,全世界每天都有大量的新芯片被生产出来,大量的新电路板被设计出来。 因此,需要开发大量的设备驱动程序。 这些设备驱动程序要么运行在简单的单任务环境中,要么运行在VxWorks、Linux、Windows等多任务操作系统环境中,发挥着不可替代的作用。
2、有操作系统和无操作系统的区别
1)无操作系统的设备驱动程序(即裸机)
并非每个计算机系统都必须运行操作系统。 在许多情况下,不需要操作系统。 对于功能相对单一、控制不复杂的系统,如公交刷卡机、冰箱、微波炉、简单的手机、小灵通等,不需要多任务调度、文件系统、内存管理等复杂功能。 单任务架构完全支持他们的工作。 与检测设备中断或轮询设备混合的无限循环是此类系统中的典型软件架构。 裸机的实现有点类似于微控制器(MCU)。 虽然单片机的寄存器没有那么多,但是如果你能驱动裸机,我想你应该能胜任单片机的工作了,哈哈。
在这样的系统中,虽然没有操作系统,但是设备驱动程序必须存在。 通常,每个设备驱动程序被定义为一个软件模块,包括.h文件和.c文件。 前者定义设备驱动程序的数据结构并声明外部函数,后者实现设备驱动程序。 书中给出了一个串口驱动serial.cserial.h的例子,主要配置GPIO、串口控制寄存器、串口收发(读写)寄存器。 这些配置都是通过自定义函数实现的,比如串口写入。 (发送)SerialSend函数等
当其他模块需要使用该设备时,只需包含设备驱动程序的头文件serial.h,然后调用其中的外部接口函数即可。 如果我们想从串口发送字符串“HelloWorld”,请使用函数SerialSend(“HelloWorld”,11)。
可见,在没有操作系统的情况下,设备驱动接口直接提交给应用软件工程师,应用软件直接访问设备驱动接口,不跨越任何层级。 设备驱动程序中包含的接口函数也直接与硬件的功能相匹配,无需任何附加功能。
一些工程师设计单任务系统时,使设备驱动程序和特定应用软件模块处于同一级别(即应用程序也是在例如serial.c中实现的)。 这显然是不合理的,也不符合软件设计中的高内聚、低耦合。 要求。
另一种不合理的设计是在应用程序中直接操作硬件寄存器(单个main.c,所有功能都在一个函数中实现,没有使用其他接口/函数),而不单独设计驱动模块。 设计意味着系统中不存在或未充分利用可重用的驱动程序代码。
2)有操作系统时的设备驱动程序
无操作系统的设备驱动程序中的设备驱动程序直接运行在硬件上,不与任何操作系统关联。 当操作系统包含在系统中时,设备驱动程序会发生什么?
首先,在没有操作系统的情况下,设备驱动程序的硬件操作工作仍然是必不可少的。 如果没有这部分,设备驱动程序就无法与硬件打交道。
其次,我们还需要将设备驱动程序集成到内核中。 为了实现这种集成,所有设备驱动程序中都必须设计面向操作系统内核的接口。 这些接口是由操作系统指定的,对于某种类型的设备具有一致的结构,并且与具体设备无关。
可见,当系统中存在操作系统时,设备驱动程序就成为连接硬件和内核的桥梁。 操作系统的存在必然要求设备驱动程序增加更多的代码和功能(在我看来,主要是提供了很多结构),将单一的“驱动硬件设备动作”变成了与操作系统交互的模块。操作系统内部的硬件,对外呈现为操作系统的API,不再直接向应用软件工程师提供接口。 随着操作系统的到位,设备驱动程序变得更加复杂。 那么操作系统是做什么的呢?
首先,一个复杂的软件系统需要处理多个并发任务。 如果没有操作系统,想要完成多任务并发是非常困难的。
其次,操作系统为我们提供了内存管理机制。 一个典型的例子是,对于大多数包含MMU的处理器来说,Windows和Linux等操作系统可以允许每个进程独立访问4GB的内存空间。
上述优点似乎并没有在设备驱动中体现出来。 操作系统的存在给设备驱动程序带来什么好处呢?
总之,操作系统通过给设备驱动程序制造麻烦来达到给上层应用程序提供方便的目的。 如果按照操作系统提供的与设备无关的接口来设计设备驱动程序,应用程序将能够使用统一的系统调用接口来访问各种设备。 对于类UNIX的VxWorks、Linux等操作系统,应用程序可以通过write()、read()等函数读写文件来访问各种字符设备和块设备,而与设备的具体类型和工作模式无关。 很方便。
无论有没有操作系统,无论是SerialSend还是write,访问设备都需要读写寄存器。 例如串口在dev目录下有一个ttys0节点。 我们可以通过ioctl函数来读写它。 当然,写和读更直接。上层应用程序可以封装这些功能,定义不同的接口来实现更多的功能。