嵌入式应用的测试代码

背景:

我正在利用Atmel AVR atmega2560开发一个大型项目。 该项目包含许多基于硬件的function(7个SPI设备,2个I2C,2个RS485 MODBUS端口,大量模拟和数字I / O)。 我为所有这些设备开发了“驱动程序”,它们为主应用程序循环提供了访问所需数据的接口。

题:

我正在开发的项目最终必须符合SIL标准。

我希望能够测试代码并提供良好的代码覆盖率。 但是,我无法找到任何信息让我开始研究如何设置这样的测试框架。

我的想法是,我可以拥有一套自动化测试,可以测试未来的错误修复和function添加,以确定它们是否会破坏代码。 问题是我不明白如何在芯片上测试代码。

我是否需要硬件来监控设备上的I / O并模拟外部连接的设备? 任何可以提供的指针都将受到高度赞赏。

–Steve

这是一个非常好的问题 – 嵌入式开发人员的共同关注点。 不幸的是,大多数嵌入式开发人员并不像您那样关注并且仅在真实硬件上测试代码。 但正如另一个答案所指出的,这基本上可以测试代码的名义function而不是角落/错误情况。

这个问题没有一个简单的解决方案。 然而,存在一些指导方针和技术来做一个相对好的工作。

首先,将代码分成几层。 一层应该是“硬件不可知的” – 即函数调用 。 不要要求用户直接写入HW寄存器。 另一个(下层)处理HW。 可以“模拟”该层以测试更高级别。 如果没有硬件,则无法真正测试较低级别,但它不会经常更改并需要深度硬件集成,所以这不是问题。

“测试工具”将是您的所有高级HW不可知代码,具有专门用于测试的“假”低级别。 这可以模拟硬件设备的正确和错误function,从而允许您在PC上运行自动化测试。

切勿在真实硬件上或对真实硬件运行unit testing。 始终模拟您的I / O接口。 否则,您无法模拟错误条件,更重要的是,您无法依靠测试成功。

因此,您需要将应用程序拆分为可以独立测试的各种部分。 模拟器(或模拟)这些测试所需的所有硬件并在开发PC上运行它们。

这应该涵盖了大部分代码,并为您提供驱动程序。 尝试在没有硬件的情况下尽可能多地使用驱动程序代码。 对于其余部分,您必须想办法让代码在硬件上运行。 这通常意味着您必须创建一个带有响应信号等的外部设备的测试台。由于这很脆弱(如“您的测试无法自动完成此工作”),您必须在准备好硬件后手动运行这些测试。

Vectorcast是一种商业工具,可以在代码覆盖的硬件上运行unit testing。

你有JTAG连接器吗? 您可以使用JTAG来模拟芯片上的错误情况。

我喜欢分开任务。 例如,当我为Atmel AVR创建循环缓冲区时,我在Code :: Blocks中编写了所有内容,并使用常规GCC编译器而不是AVR GCC编译器编译它,然后我为它创建了一个unit testing。 我使用了一个特殊的头文件来提供我想要使用的正确数据类型(例如uint8_t)。 我发现了unit testing的错误,修复了它们,然后将固定代码转移到AVR Studio并集成它。 之后,我使用写入支持函数和ISR来使缓冲区适合有用的代码(即,从缓冲区中弹出一个字节,将其推入UART数据输出寄存器,将字符串常量附加到缓冲区以获取printf函数等)。 然后我使用AVR模拟器确保我的ISR和函数被调用,并且正确的数据显示在寄存器中。 之后我将它编程到芯片上并且工作得很好。

与AVR Studio相比,我更喜欢Code :: Blocks的调试function,所以我尽可能使用上述方法。 当我不能,我通常只处理硬件。 例如,我有一个自动产生方波的计时器。 我能做的最好的事情就是看到模拟器中的针位被弄乱了。 在那之后,我只需要勾起一个范围并确保。

我喜欢在调试问题时使用多级方法。 例如,对于时钟,第一层是“将探针放在时钟引脚上,看看那里是否有信号”。 如果没有,探测uC上的引脚并寻找信号。 然后,我在我的一个UART中编写了一个调试接口,在那里我可以查看特定的寄存器值,并确保它们是它们应该是的。 因此,如果它不起作用,下一步是“调用寄存器值并确保它是正确的。”

在计划调试时,请尝试提前四步。 这里应该有+ 5V,但如果没有呢? 写入调试接口可以切换引脚并查看是否更改了引脚。 如果那不起作用怎么办? 做其他事情等等等。你遇到了一个问题,你会遇到’我没有想法为什么这个不行的!!!!’ 但希望你事先能弄清楚原因。