我们正在编译一个嵌入式C++应用程序,它部署在电离辐射轰击的环境中的屏蔽设备中。我们正在为ARM使用GCC和交叉编译。在部署时,我们的应用程序会生成一些错误的数据,并且比我们希望的更频繁地崩溃。硬件是为这个环境而设计的,我们的应用程序已经在这个平台上运行了几年。

我们是否可以对代码进行更改,或对编译时进行改进,以识别/纠正由单个事件扰乱导致的软错误和内存损坏?是否有其他开发人员成功地减少了软错误对长时间运行的应用程序的有害影响?


当前回答

这里有大量的回复,但我将尝试总结我对此的想法。

某些东西崩溃或不正常工作可能是您自己的错误造成的,那么当您找到问题时,应该很容易解决。但也有可能出现硬件故障,如果不是不可能,整体上很难解决。

我建议首先尝试通过日志记录(堆栈、寄存器、函数调用)来捕捉问题情况——要么将它们记录到文件中的某个位置,要么以某种方式直接发送(“哦,不,我崩溃了”)。

从这种错误情况中恢复可以是重新启动(如果软件仍然处于活动状态)或硬件重置(例如硬件看门狗)。从第一个开始更容易。

若问题是硬件相关的,那个么日志记录应该可以帮助您确定在哪个函数调用中发生了问题,这可以让您了解什么是不工作的以及在哪里。

此外,如果代码相对复杂-“分割并征服”它是有意义的-这意味着你在怀疑问题所在的地方删除/禁用一些函数调用-通常禁用一半代码并启用另一半代码-你可以得到“确实有效”/“不有效”的决定,然后你可以专注于另一半代码。(问题所在)

若问题在一段时间后发生,那个么可以怀疑堆栈溢出,那个么最好监视堆栈点寄存器,若它们不断增长。

如果你设法完全最小化代码,直到“hello world”类型的应用程序出现故障,那么硬件问题是意料之中的,需要进行“硬件升级”,这意味着发明这样的cpu/ram/-能够更好地耐受辐射的硬件组合。

最重要的事情可能是,如果机器完全停止/重新设置/不工作,您如何取回日志-这可能是bootstap应该做的第一件事-如果有问题的情况被解决,您应该回家。

如果在您的环境中也可以发送信号和接收响应,那么您可以尝试构建某种在线远程调试环境,但您必须至少有通信媒体工作,并且某些处理器/某些ram处于工作状态。通过远程调试,我的意思是GDB/GDB存根类型的方法,或者您自己实现从应用程序中获取所需的内容(例如,下载日志文件、下载调用堆栈、下载ram、重新启动)

其他回答

你需要3台以上的从机,在辐射环境外有一台主机。所有I/O都通过包含表决和/或重试机制的主机。每个从设备必须有一个硬件监视器,并且撞击它们的调用应该被CRC等包围,以降低非自愿撞击的概率。转发应该由主机控制,因此与主机的连接丢失等于几秒钟内重新启动。

此解决方案的一个优点是,您可以对主机和从机使用相同的API,因此冗余成为一种透明的特性。

编辑:从评论中,我觉得有必要澄清“CRC的想法”。如果你用CRC来围绕碰撞,或者对来自主设备的随机数据进行摘要检查,那么从设备碰撞它自己的看门狗的可能性接近于零。只有当受监视的从设备与其他设备对齐时,才从主设备发送随机数据。随机数据和CRC/摘要在每次碰撞后立即清除。主从缓冲频率应超过看门狗超时的两倍。每次从主机发送的数据都是唯一生成的。

能帮助你的是看门狗。20世纪80年代,看门狗被广泛用于工业计算。当时,硬件故障更为常见——另一个答案也提到了那个时期。

看门狗是一种组合的硬件/软件功能。硬件是一个简单的计数器,从一个数字(比如1023)向下计数到零。可以使用TTL或其他逻辑。

软件的设计使得一个例程可以监控所有基本系统的正确运行。如果此例程正确完成=发现计算机运行正常,则将计数器设置回1023。

总体设计使得在正常情况下,软件可以防止硬件计数器达到零。如果计数器达到零,计数器的硬件将执行其唯一的任务并重置整个系统。从计数器的角度来看,零等于1024,计数器继续向下计数。

该看门狗可确保所连接的计算机在多次故障情况下重新启动。我必须承认,我不熟悉能够在当今计算机上执行这种功能的硬件。与外部硬件的接口现在比过去复杂得多。

看门狗的一个固有缺点是,从出现故障到看门狗计数器达到零+重新启动时间,系统就不可用。虽然该时间通常比任何外部或人为干预短得多,但在该时间段内,受支持的设备需要能够在没有计算机控制的情况下继续工作。

我真的读了很多很棒的答案!

这是我的2美分:通过编写软件检查内存或执行频繁的寄存器比较,建立内存/寄存器异常的统计模型。此外,以虚拟机的形式创建一个仿真器,您可以在其中试验该问题。我想,如果你改变结尺寸、时钟频率、供应商、外壳等,你会观察到不同的行为。

即使我们的台式电脑内存也有一定的故障率,但这不会影响日常工作。

你问的是一个非常复杂的话题——不容易回答。其他答案是可以的,但它们只涵盖了你需要做的所有事情的一小部分。

正如在评论中看到的,不可能100%解决硬件问题,但是使用各种技术很可能减少或解决这些问题。

如果我是你,我会创建最高安全完整性级别(SIL-4)的软件。获取IEC 61513文件(适用于核工业)并遵循该文件。

有一点似乎没有人提到。你说你在GCC中开发,并在ARM上交叉编译。你怎么知道你的代码中没有关于空闲RAM、整数大小、指针大小、执行某个操作需要多长时间、系统将持续运行多长时间等的假设?这是一个非常普遍的问题。

答案通常是自动单元测试。编写在开发系统上执行代码的测试线束,然后在目标系统上运行相同的测试线束。寻找差异!

还要检查嵌入式设备上的勘误表。您可能会发现“不要这样做,因为它会崩溃,所以启用编译器选项,编译器会解决它”。

简而言之,崩溃的最可能来源是代码中的错误。在你确定这不是事实之前,不要担心更深奥的故障模式。