使用微控制器的电子产品如今变得如此复杂,以至于它们通常使用实时操作系统(RTOS)。RTOS可以管理低级资源和时间,从而提高系统的实时性能并简化应用程序。
嵌入式开发团队可能会遇到的一个问题是有100多种不同的RTOS可供选择!对于一个团队来说,开始使用一个产品,但6个月后决定使用另一个产品的情况并不罕见。当这种情况发生时,如果开发人员在他们的应用程序中直接使用了RTOS,他们必须返回并更改大量代码。
另一种方法是使用操作系统抽象层(OSAL)。OSAL创建一组对应于每个RTOS中的公共特征的API。OSAL允许应用程序通过将依赖关系转移到抽象层来打破对RTOS的依赖。应用程序不再关心你使用的RTOS,只关心抽象层。
在今天的帖子中,我们将探讨为嵌入式应用创建RTOS抽象层的五个技巧。
技巧1:跨操作系统标准化操作系统抽象层(OSAL)API
OSAL的目标不是将RTOS缩小到最小公分母。相反,我们的目标是通过一个单一的标准API提供通用部分,以消除对RTOS的依赖,并改善测试和可移植性。你将需要研究流行的RTOS并确定共同的特性。
例如,如果你查看像FreeRTOS、Azure RTOS和Zephyr这样的流行RTOS,你可能会发现它们具有以下标准功能:
线程创建
信号量的创建、获取和放置
互斥体的创建、锁定和解锁
等等。
你希望识别这些标准特性,然后创建一个接口来封装你可能使用的任何RTOS的创建细节,同时将应用程序与RTOS分离。
技巧2:选择正确的抽象层次
当你开始为你的应用程序开发OSAL时,创建最终的抽象是很有诱惑力的。不要陷入这个陷阱!每个RTOS都有你想要利用的独特功能,如果你把它们隔离开来,你会带来更多的问题而不是好处。你必须选择正确的抽象层次。
正确的抽象水平将是一个基本的标准特性。一个很好的例子是检查CMSIS RTOSv2 OSAL。你会注意到他们抽象出的唯一特性是标准特性。你看不到他们实现定制的低功耗设置或类似的东西。相反,他们正在寻找每个RTOS提供的抽象标准功能。
技巧3:对特定于操作系统的特性使用包装器
一旦你有了通用的API,你可能会认为你已经将RTOS简化为通用的特性,并且你将只使用这些特性。这不是准确的想法,会有一些不常见的特性可能对你的应用程序有用。问题是,如果你直接调用这些特性,你将把你的应用程序紧密耦合到RTOS,这正是我们需要避免的!
使用RTOS特有特性的解决方案是包装这些特性。你可能有一个覆盖通用特性的OSAL,但是你最终会得到覆盖RTOS特有特性的包装器。包装器将为应用程序提供对定制特性的访问,同时维护允许脱离目标测试和模拟的依赖树。
你不能忽略RTOS的竞争优势,但你也不能抽象它们。这就是为什么使用包装器是一个很好的选择。如果你更改了RTOS,如果新的RTOS没有这个特性,你可以移除包装器并编写任何需要的gap代码来覆盖缺失的功能。
技巧4:优雅地处理特定于操作系统的限制
当你开发一个OSAL时,你需要意识到你必须管理的局限性。例如,一个RTOS的最大线程数可能与另一个不同。不同RTOS的优先级排序可能会有所不同。(随着数值越来越远离0,FreeRTOS任务具有更高的优先级。ThreadX设置0优先级最高,数字越高优先级越低!)
你需要确保你的抽象层能够成功地管理这些差异,而不会影响应用程序的性能。你还需要确保不会因为RTOS实现中的这些微小差异而导致系统崩溃或错误。
技巧5:利用单元测试工具来验证实现
编写自己的OSAL时,你可以采用的最佳实践之一是使用测试驱动开发(TDD)。TDD的一部分将是你写你的测试用例,让它失败,然后让它通过。这和OSAL有什么关系?如果你编写测试用例来验证你的OSAL,那么当你将一个RTOS连接到你的OSAL时,你可以验证它是否正确和成功地完成了!
如果你犯了一个实现错误,单元测试应该会发现它!你会立刻知道你有问题,并在它变成bug之前着手解决它。这样做当然需要更多的工作,但是最终你会发现你会得到一个更加健壮的OSAL。
结论
并非所有应用程序的RTOS都需要OSAL。但是,如果你正在开发一个将使用五年或更长时间的应用程序框架或平台,那么拥有一个OSAL是个好主意。嵌入式技术变化很快,你希望确保你不是在围绕五年后可能会改变或不存在的软件设计框架。返工软件可能很耗时,而且会引入错误。使用OSAL可以确保打破这种依赖性,并且可以在抽象之后加入任何RTOS。