单片机开发人员需要掌握的一项基本技能是,了解如何编写驱动程序。在嵌入式系统中,通常有两种类型的驱动程序:单片机外围设备驱动程序和通过I2C,SPI或UART等接口连接的外部设备驱动程序。
如今,在许多情况下,单片机供应商都提供了其芯片的示例驱动程序,这些驱动程序可以按原样使用,或者可能需要进行生产修改。外部驱动程序可能包含伪代码,但是单片机开发人员几乎总是自己编写驱动程序。
针对这个问题,重要的是要意识到,我们有多种方法可以编写驱动程序,并且编写驱动程序的方式会极大地影响系统性能,能耗以及我们在开发产品时希望跟踪的许多其他因素。在本文中,英锐恩单片机开发工程师将探讨几种常见的单片机驱动程序设计模式,以及它们如何影响应用程序代码。
一、轮询驱动程序
首先是开发驱动程序,用于对外围设备进行轮询以查看其是否准备发送或接收信息。轮询驱动程序非常易于实现,因为它们通常只轮询标志而已。例如,模数转换器(ADC)驱动程序可能会启动转换序列,然后简单地阻止处理器执行并不断检查ADC完成标志。这段代码如下所示:
Adc_Start(); while(ADC_COMPLETE_FLAG == FALSE); AdcResults = Adc_ReadAll(); return AdcResults;
如上面的案例,代码不断轮询ADC_COMPLETE_FLAG,大概将其映射到硬件位,以查看何时有数据可用。在将这样的硬件测试称为轮询时,它会产生一些值得讨论的特性。
首先,当我们有一个使用轮询的驱动程序时,在大多数实现中,该驱动程序将成为阻塞驱动程序。这意味着一旦调用驱动程序,它将不会从驱动程序返回,直到获得所需的结果为止。在其他实现中,我们只需让驱动程序检查一次结果然后返回即可。在这种情况下,应用程序负责轮询驱动程序,我们将认为驱动程序是非阻塞的。从设计的角度来看,由开发人员决定应在何处进行轮询。在驱动程序中可以减轻应用程序的负担,但是如果应用程序这样做,则可以灵活地执行其他活动并以较低的速率轮询驱动程序。
接下来,一般来说,轮询非常容易实现。通常,开发人员所需要做的就是观察寄存器中的几位并监视它们,以决定何时与设备进行交互。最后,虽然易于实现,但通常认为轮询效率低下。其他技术(例如使用中断)仅在需要执行某些操作时才通知CPU,这会使轮询效率非常低下。我经常将民意调查与一个长途旅行中坐车的孩子不断询问“我们到了吗?”联系起来。轮询不断问:“你准备好了吗?现在怎么样?现在?”。
这使我们可以使用中断来实现更高效但稍微复杂的驱动程序。
二、中断驱动程序
在驱动程序中使用中断非常有用,因为它可以大大提高代码执行效率。中断告诉处理器现在已经准备好驱动程序,而我们跳转以处理该中断,而不是不断检查是否该做某事。通常,我们可以使用两种类型的中断驱动程序机制:事件驱动程序和调度程序。当外围设备中发生需要处理的事件时,事件驱动的驱动程序将触发中断。例如,我们可能有一个UART驱动程序,当在缓冲区中接收到新字符时,该驱动程序将触发中断。另一方面,我们可能有一个ADC驱动器,该驱动器使用计时器来安排访问以开始采样或处理接收到的数据。
使用中断驱动的驱动程序虽然效率更高,但可能会增加设计的实现复杂性。首先,单片机开发人员需要启用适当的中断以在驱动程序中使用,例如接收,发送和缓冲区已满。我通常发现,由于现代中断控制器的复杂性,单片机开发人员很难使中断起作用。它们通常需要在外围设备级别的通用寄存器中设置中断,然后有时甚至需要配置优先级和其他设置。几年前,我整理了有关配置中断的分步指南,可以在此处下载。
接下来,使用中断可能会导致需要遵循一些额外的因素。例如:
1.中断时间短;
2.将共享变量声明为volatile;
3.处理高优先级项目,然后卸载到应用程序进行处理。
谁都不想在驱动程序中发生事件时,执行数千行代码的中断。相反,应该处理的是关键任务,例如从UART缓冲区中提取字符并将其放入应用程序的循环缓冲区中。
最后,我们还需要担心诸如中断被禁用,中断时序和运行速率,优先级以及是否有可能错过中断之类的问题。尽管其中一些项目似乎不值得付出额外的复杂性,但执行时间的改善却是巨大的。例如,电池供电的设备可以进入深度睡眠模式,仅唤醒后将字符存储在缓冲区中,然后返回睡眠状态。这样做可以节省大量的电量。
在某些情况下,在驱动程序中使用中断确实是处理外围事件的最佳方法。例如,您可以编写一个轮询的I2C驱动程序,但编写一个在传输序列中发生的不同事件(如ack,nack等)时中断的驱动程序,则驱动程序将更干净,更小,更高效。
三、DMA驱动的驱动程序
有些驱动程序会通过I2S和SDIO等系统移动大量数据。在这些类型的接口上管理缓冲区可能需要CPU不断采取措施。如果CPU落后或必须处理其他系统事件,则数据可能会丢失或延迟,这可能会给用户带来明显的问题,例如音频跳跃。与吞吐量相关的开发人员可以改用DMA控制器在单片机中为CPU移动数据。
这些驱动程序背后的想法是,DMA控制器可以通过以下方式在单片机周围移动数据:
(1)外围到内存;
(2)内存到内存;
(3)内存到外围。
使用DMA的好处是,当DMA通道为驱动程序移动数据时,CPU可以关闭其他操作,本质上可以同时完成两件事。
迫切需要在驱动程序中使用DMA控制器以减少执行CPU的需要,但大多数单片机具有有限数量的可用DMA通道。因此,不能将每个驱动程序都编写为使用DMA。取而代之的是,开发人员需要选择带宽受限的外围设备,这些外围设备将受益于DMA,例如外部存储器,ADC和通信通道的接口。
在没有I2S或SDIO的应用程序中,开发人员可以使用DMA将传入的UART字符移动到循环缓冲区中,一旦设置了特定限制,该缓冲区将被处理。可以通过轮询应用程序结构或通过DMA控制器设置中断来监视此限制。您可以想象,DMA驱动程序是驱动程序最有效的实现,但是根据开发人员的技术水平以及他们以前是否使用过DMA,实现起来也可能很复杂。但是,单片机开发人员可以尝试在其驱动程序中使用DMA。
结论
在本文中,我们研究了嵌入式开发人员可以用来为单片机外围设备和外部设备编写驱动程序的三种主要技术。为了比较地总结这些技术,下表为我们讨论的每种技术以及实现的相对复杂性和执行效率。
通常,除非使用的外设速度很快(即几Mbps),否则开发人员默认情况下应在轮询实现上使用中断驱动程序实现。DMA可以用于任何驱动程序,但是我通常为需要高吞吐量的接口(例如外部存储器或通信接口)保留DMA通道。但是,怎么选择在很大程度上取决于最终应用程序。
以上就是英锐恩单片机开发工程师分享的3种驱动器设计技术。英锐恩专注单片机应用方案设计与开发,提供8位单片机、16位单片机、32位单片机、运放芯片和模拟开关。