嵌入式软件开发人员需要掌握的一项基本技能是理解如何编写驱动程序。在嵌入式系统中,通常有两种类型的驱动程序:微控制器外围驱动程序和通过I2C、SPI或UART等接口连接的外部设备驱动程序。在今天的许多情况下,微控制器供应商为他们的芯片提供了示例驱动程序,这些驱动程序可以按原样使用,或者可能需要修改以用于生产。外部驱动程序可能包括伪代码,但嵌入式开发人员几乎总是自己负责编写驱动程序。
重要的是要认识到,编写驱动程序的方法不止一种,而且它的编写方式会极大地影响系统性能、能耗以及我们在开发产品时喜欢跟踪的许多其他因素。在本文中,我们将研究几种常见的驱动程序设计模式,以及它们如何影响应用程序代码。我们将从基本模式开始,并致力于更复杂的模式。
技术1:轮询驱动程序
第一种技术,也是最基本的技术,是开发一个驱动程序,轮询外围设备(或外部设备),查看它是否准备好发送或接收信息。轮询驱动程序非常容易实现,因为它们通常只轮询一个标志。例如,模数转换器(ADC)驱动程序可能启动转换序列,然后简单地阻止处理器执行,并不断检查ADC完成标志。此代码类似于以下内容:
首先,当我们有一个使用轮询的驱动程序时,在大多数实现中,该驱动程序将是一个阻塞驱动程序。这意味着一旦我们调用驱动程序,它将不会从驱动程序返回,直到我们得到所需的结果。还有其他一些实现,我们可以让驱动程序检查一次结果,然后返回。在这种情况下,应用程序负责轮询驱动程序,我们将考虑驱动程序是非阻塞的。从设计的角度来看,应该由嵌入式开发人员来决定轮询应该在哪里进行。在驱动程序中,可以减少应用程序不得不这样做,但如果应用程序这样做,则可以灵活地执行其他活动并以较低的速率轮询驱动程序。
其次,一般来说,轮询非常容易实现。通常,开发人员所需要做的就是观察寄存器中的一些位并监视它们,以决定何时与设备交互。最后,虽然轮询很容易实现,但通常被认为效率低下。其他技术,例如使用中断,可以在需要执行某些操作时通知CPU,这使得轮询效率相当低。
这给我们带来了一个更高效但稍微复杂的驱动程序实现,即使用中断。
技术:2–中断驱动程序
在驱动程序中使用中断非常棒,因为它可以极大地提高代码的执行效率。中断告诉处理器驱动程序现在准备好了,我们跳起来处理中断,而不是不断地检查是否该做某事。通常,我们可以使用两种类型的中断驱动机制:事件驱动和调度。当外设中发生需要处理的事件时,事件驱动驱动程序将触发中断。例如,我们可能有一个UART驱动程序,当缓冲区中接收到一个新字符时,该驱动程序将触发一个中断。另一方面,我们可能有一个ADC驱动程序,它使用定时器来安排访问,以开始采样或处理接收到的数据。
使用中断驱动驱动程序虽然效率更高,但会给设计增加额外的实现复杂性。首先,嵌入式开发人员需要启用适当的中断,以便在驱动程序中使用,例如接收、传输和缓冲区已满。通常发现,由于现代中断控制器的复杂性,开发人员很难让中断正常工作。它们通常需要在通用寄存器的外围级别设置中断,有时甚至需要配置优先级和其他设置。
接下来,中断的使用可以引入遵循一整套额外的最佳实践的需要。例如,最好的做法是:
—缩短中断时间
—将共享变量声明为volatile
—处理高优先级项目,然后卸载到应用程序进行处理
当事件发生时,你不希望在驱动程序中有数千行代码被执行的中断。相反,你希望处理关键任务,比如从UART缓冲区中提取一个字符,并将其放入应用程序的循环缓冲区中。
最后,我们还需要担心诸如中断被禁用、中断时间和运行速率、优先级以及中断是否可能丢失等问题。虽然其中一些项目看起来额外的复杂性可能不值得付出努力,但对执行时间的改进可能是巨大的。例如,电池供电的设备可能进入深度睡眠模式,只在醒来时将字符存储在缓冲区中,然后返回睡眠状态。这样做可以节省大量能源。
在某些情况下,在驱动程序中使用中断实际上是处理外围事件的最佳方式。例如,你可以编写轮询的I2C驱动程序,但编写一个中断ack、nack等传输序列中发生的不同事件的I2C驱动程序会产生更干净、更小和更高效的驱动程序。
技术3:DMA驱动的驱动程序
有些驱动程序在系统中移动大量数据,如I2S和SDIO。管理这些类型接口上的缓冲区可能需要CPU的持续操作。如果CPU落后或必须处理另一个系统事件,数据可能会丢失或延迟,这可能会给用户造成明显的问题,例如音频跳过。与吞吐量相关的嵌入式开发人员可以使用DMA控制器在CPU的微控制器周围移动数据。
这些驱动程序背后的想法是DMA控制器可以通过以下方式在微控制器周围移动数据:
—外围存储器
—内存对内存
—外设存储器
使用DMA的优点是,当DMA通道为驱动程序移动数据时,CPU可以停止做其他事情,基本上一次完成两件事情。
虽然在驱动程序中使用DMA控制器以减少CPU执行的需要是非常理想的,但大多数微控制器的可用DMA通道数量有限。因此,不能将每个驱动程序都写入DMA。相反,开发人员需要选择带宽受限且能从DMA中获益匪浅的外围设备,如外部存储器、ADC和通信通道的接口。
在没有I2S或SDIO的应用程序中,开发人员可以使用DMA将传入的UART字符移动到循环缓冲区中,一旦设置了某个限制,就会对该缓冲区进行处理。可以通过轮询应用程序结构或通过DMA控制器设置中断来监控此限制。可以想象,DMA驱动程序是驱动程序最有效的实现方式,但根据开发人员的技能水平以及他们以前是否使用过DMA,它们的实现也可能很复杂。这不应该阻止开发者尝试在他们的驱动程序中使用DMA。
在本文中,我们研究了嵌入式开发人员可以用来为微控制器外围设备和外部设备编写驱动程序的三种主要技术。一般来说,开发人员在默认情况下应该在轮询实现上使用中断驱动程序实现,除非使用的外围设备速度很快,即数Mbps。DMA可以用于任何驱动程序,但我通常为需要高吞吐量的接口(如外部内存或通信接口)保留DMA通道。你选择的选项将高度依赖于最终应用程序。
发表评论 取消回复