开发固件的团队和嵌入式软件经常根据目标开发软件。虽然使用开发板来了解你正在编写代码的处理器、外围设备和设备不一定有什么问题,但针对目标的开发效率低下且耗时。在运行你的代码之前,你需要交叉编译它,删除目标,编程它,验证它,然后开始你的调试会话。
在与CI/CD集成和测试代码工作时存在潜在的伸缩问题。你曾经尝试过在嵌入式目标上运行单元测试或覆盖率报告吗?这是可以做到的,但要正确设置和工作通常是相当痛苦的。相反,你可以使用几种技术来模拟你的固件和嵌入式软件,这将帮助你快速移动而没有额外的麻烦。
模拟技术1: Renode.io和QEMU
嵌入式开发人员在模拟系统时面临的最大挑战是如何模拟低级软件。最低级别与硬件交互,这意味着需要使用特殊工具来理解硬件。在使用微控制器时,有两种工具相对流行:Renode.io和QEMU。
QEMU是一个通用的开源机器仿真器和虚拟化器。QEMU可以模拟各种处理器,允许为一种CPU设计的软件在另一种CPU上运行。对于使用不同架构(如ARM、PowerPC、MIPS或x86)的嵌入式系统的固件或应用程序开发人员来说,该功能非常宝贵。QEMU的缺点是你会发现对微控制器的支持不多。例如,你可能会发现微控制器可以与USART外设一起使用,但不支持定时器和ADC。
Renode是一个开发框架,通过物理硬件模拟来加速物联网和嵌入式系统的开发。开发人员可以模拟微控制器外部的CPU、外设和设备,如传感器。支持I2C、CAN、SPI、Flash、USB、UART等外设。Renode比QEMU更注重嵌入式。到目前为止,它对嵌入式目标的支持要好得多。
模拟技术2:关注应用程序代码
嵌入式软件架构是两种架构的故事。第一个是高级业务逻辑,提供客户功能,不关心底层硬件。第二个是与硬件交互的实时代码,它并不关心那里有什么硬件。
当你想要模拟你的嵌入式应用程序时,你应该确定是否需要模拟该硬件相关的代码。大多数客户只关心他们交互的功能。如果是这样的话,模拟你的应用程序代码比低级代码更重要。如果你能在硬件准备就绪之前开发并运行你的应用程序代码,你就可以更快地将其提供给客户。如果你在客户面前获得代码,你可以获得他们的反馈并尽早进行调整。你越早做出改变,你花在这些改变上的钱就越少,这些改变花费的时间就越少。
在主机上模拟应用程序代码通常只不过是为该主机添加一个构建目标。例如,如果你用C或C++编写,你将调用为编译应用程序代码而设置的主机构建目标。然后你可以运行生成的可执行文件。你可能认为这给使用RTOS的系统带来了问题。通常不会。许多RTOS供应商提供可以在Windows、Linux和MacOS上编译的RTOS版本。这意味着你可以在你选择的RTOS上运行你的应用程序代码!你会发现你可以添加代码来可视化系统行为,将数据转储到数据库等。
你应该问自己的问题是你是否需要模拟底层代码。如果没有,请集中精力模拟你的应用程序代码。你会发现,这样做,你也可以自然地编写与硬件无关的代码。结果是更加可重用、可移植和可扩展的软件。
模拟技术3:利用指令集模拟器
另一种可以用来在主机上测试代码的模拟器是指令集模拟器。这些模拟器允许你运行应用程序代码和固件。它们通过在IDE中直接运行处理器和外设的低级指令来实现这一点。你会在Keil MDK,、IAR EWARM、MPLAB X等ide中找到这些模拟器。
这些模拟器的功能往往各不相同。例如,你可能会发现可以模拟处理器内核,但不支持外设。你可以验证指令是否正确运行、算法结果等,但无法证明与外设的交互是否有效。虽然这可能不是最佳选择,但它可以让你脱离目标运行代码,并在没有独特工具的情况下在更高级别的代码上取得快速进展。
结论
利用模拟是一项伟大的现代技术,可以帮助你更快地开发固件。偏离目标的工作越多,效率就越高,因为你可以避免那些漫长的编译、编程和调试周期。你会发现写单元测试和在模拟中运行代码会迫使你编写更具可移植性和可重用性的代码。脱离目标运行迫使你编写抽象出硬件的解耦代码。结果是一个更清晰、可扩展和可测试的软件实现,你可以在构建硬件之前对其进行验证。