我们正在编译一个嵌入式C++应用程序,它部署在电离辐射轰击的环境中的屏蔽设备中。我们正在为ARM使用GCC和交叉编译。在部署时,我们的应用程序会生成一些错误的数据,并且比我们希望的更频繁地崩溃。硬件是为这个环境而设计的,我们的应用程序已经在这个平台上运行了几年。
我们是否可以对代码进行更改,或对编译时进行改进,以识别/纠正由单个事件扰乱导致的软错误和内存损坏?是否有其他开发人员成功地减少了软错误对长时间运行的应用程序的有害影响?
我们正在编译一个嵌入式C++应用程序,它部署在电离辐射轰击的环境中的屏蔽设备中。我们正在为ARM使用GCC和交叉编译。在部署时,我们的应用程序会生成一些错误的数据,并且比我们希望的更频繁地崩溃。硬件是为这个环境而设计的,我们的应用程序已经在这个平台上运行了几年。
我们是否可以对代码进行更改,或对编译时进行改进,以识别/纠正由单个事件扰乱导致的软错误和内存损坏?是否有其他开发人员成功地减少了软错误对长时间运行的应用程序的有害影响?
当前回答
你问的是一个非常复杂的话题——不容易回答。其他答案是可以的,但它们只涵盖了你需要做的所有事情的一小部分。
正如在评论中看到的,不可能100%解决硬件问题,但是使用各种技术很可能减少或解决这些问题。
如果我是你,我会创建最高安全完整性级别(SIL-4)的软件。获取IEC 61513文件(适用于核工业)并遵循该文件。
其他回答
以下是一些想法和想法:
更创造性地使用ROM。
在ROM中存储任何可以存储的东西。不要计算东西,而是将查找表存储在ROM中。(确保编译器将查找表输出到只读部分!在运行时打印内存地址以进行检查!)将中断向量表存储在RAM中。当然,运行一些测试以查看ROM与RAM相比的可靠性。
为堆栈使用最好的RAM。
堆栈中的SEU可能是最可能的崩溃源,因为它是索引变量、状态变量、返回地址和各种类型的指针通常存在的地方。
执行计时器滴答声和看门狗计时器例程。
您可以在每一次计时器计时时运行一个“健全性检查”例程,以及一个看门狗例程来处理系统锁定。您的主代码还可以周期性地增加一个计数器以指示进度,而健全性检查例程可以确保发生了这种情况。
在软件中执行纠错代码。
您可以为数据添加冗余,以便能够检测和/或纠正错误。这将增加处理时间,可能会使处理器长时间暴露在辐射中,从而增加出错的机会,因此您必须考虑权衡。
记住缓存。
检查CPU缓存的大小。您最近访问或修改的数据可能位于缓存中。我相信您可以禁用至少一些缓存(以较大的性能代价);你应该试试看缓存对SEU的敏感性。如果缓存比RAM更硬,那么您可以定期读取和重新写入关键数据,以确保它保留在缓存中并使RAM恢复正常。
巧妙地使用页面错误处理程序。
如果将内存页标记为不存在,CPU将在您尝试访问它时发出页面错误。您可以创建一个页面错误处理程序,在处理读取请求之前进行一些检查。(PC操作系统使用此功能透明地加载已交换到磁盘的页面。)
对关键的事情使用汇编语言(可能是所有事情)。
使用汇编语言,您知道寄存器中的内容和RAM中的内容;你知道CPU使用的是什么特殊的RAM表,你可以用迂回的方式来设计,以降低风险。
使用objdump实际查看生成的汇编语言,并计算每个例程占用的代码量。
如果你使用的是像Linux这样的大型操作系统,那么你就是在自找麻烦;有太多的复杂性和太多的事情要出错。
记住这是一场概率游戏。
一位评论者说
你为捕捉错误而编写的每一个例程都会因同样的原因而失败。
虽然这是真的,但检查例程正确运行所需的(例如)100字节代码和数据中发生错误的机会要比其他地方发生错误的几率小得多。如果你的ROM非常可靠,并且几乎所有的代码/数据都在ROM中,那么你的可能性就更大了。
使用冗余硬件。
使用具有相同代码的两个或更多相同硬件设置。如果结果不同,应触发重置。对于3个或更多设备,您可以使用“投票”系统来尝试确定哪一个已被破坏。
这是一个非常广泛的主题。基本上,您无法真正从内存损坏中恢复,但至少可以尝试立即失败。以下是您可以使用的一些技巧:
校验和常量数据。如果有任何配置数据长期保持不变(包括已配置的硬件寄存器),请在初始化时计算其校验和并定期验证。当您看到不匹配时,应该重新初始化或重置。冗余存储变量。如果你有一个重要的变量x,把它的值写在x1、x2和x3中,然后读为(x1==x2)?x2:x3。实施程序流程监控。将全局标志与从主循环调用的重要函数/分支中的唯一值进行异或。在接近100%测试覆盖率的无辐射环境中运行程序,应为您提供循环结束时标志的可接受值列表。如果看到偏差,则重置。监视堆栈指针。在主循环的开头,将堆栈指针与其预期值进行比较。偏差复位。
您可能还对有关算法容错的丰富文献感兴趣。这包括旧的赋值:编写一个排序,当恒定数量的比较将失败时(或者,更糟糕的版本,当失败的比较的渐近数量为n次比较的log(n)时),正确地对其输入进行排序。
开始阅读黄和亚伯拉罕1984年的论文《矩阵运算的基于算法的容错》。他们的想法隐约类似于同态加密计算(但实际上并不相同,因为他们正在尝试在操作级别进行错误检测/纠正)。
该论文的一个较新的后代是Bosilca、Delmas、Dongarra和Langou的“基于算法的容错应用于高性能计算”。
考虑到超级跑车的评论、现代编译器的趋势以及其他因素,我很想回到古代,用汇编和静态内存分配的方式到处编写整个代码。对于这种完全的可靠性,我认为组装不再会带来很大的成本差异。
你需要3台以上的从机,在辐射环境外有一台主机。所有I/O都通过包含表决和/或重试机制的主机。每个从设备必须有一个硬件监视器,并且撞击它们的调用应该被CRC等包围,以降低非自愿撞击的概率。转发应该由主机控制,因此与主机的连接丢失等于几秒钟内重新启动。
此解决方案的一个优点是,您可以对主机和从机使用相同的API,因此冗余成为一种透明的特性。
编辑:从评论中,我觉得有必要澄清“CRC的想法”。如果你用CRC来围绕碰撞,或者对来自主设备的随机数据进行摘要检查,那么从设备碰撞它自己的看门狗的可能性接近于零。只有当受监视的从设备与其他设备对齐时,才从主设备发送随机数据。随机数据和CRC/摘要在每次碰撞后立即清除。主从缓冲频率应超过看门狗超时的两倍。每次从主机发送的数据都是唯一生成的。