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

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


当前回答

这个答案假设你关心的是一个工作正常的系统,而不是一个成本最低或速度快的系统;大多数玩放射性物品的人都看重正确性/安全性而不是速度/成本

有几个人建议您可以进行硬件更改(很好,答案中已经有很多好东西,我不打算重复所有内容),还有一些人建议冗余(原则上很好),但我认为没有人建议冗余在实践中如何工作。你怎么会失败?你怎么知道什么时候出了问题?许多技术都是在一切都会成功的基础上工作的,因此失败是一件棘手的事情。然而,一些为规模而设计的分布式计算技术预计会出现故障(毕竟,规模足够大,多个节点中的一个节点的故障是不可避免的,单个节点的平均无故障时间为MTBF);你可以利用它来保护你的环境。

以下是一些想法:

确保整个硬件复制n次(其中n大于2,最好是奇数),并且每个硬件元素可以与其他硬件元素通信。以太网是实现这一点的一种明显方式,但还有许多其他更简单的路由可以提供更好的保护(例如CAN)。尽量减少常见组件(甚至电源)。例如,这可能意味着在多个地方对ADC输入进行采样。确保应用程序状态在一个地方,例如在有限状态机中。这可以完全基于RAM,但并不排除稳定的存储。因此,它将存储在几个地方。对状态变化采用仲裁协议。例如,请参见RAFT。当您在C++中工作时,有一些众所周知的库可以实现这一点。只有当大多数节点同意时,才能对FSM进行更改。为协议堆栈和仲裁协议使用一个已知的好库,而不是自己滚动一个,否则当仲裁协议挂断时,您在冗余方面的所有好工作都将被浪费。确保您对FSM进行校验和(例如,CRC/SHA),并将CRC/CHA存储在FSM本身中(以及在消息中传输,并对消息本身进行校验和)。让节点定期对照这些校验和、传入消息的校验和检查其FSM,并检查其校验和是否与仲裁的校验和匹配。在系统中构建尽可能多的其他内部检查,使检测到自身故障的节点重新启动(这比在有足够节点的情况下继续半工作要好)。尝试让他们在重新启动过程中彻底退出仲裁,以防他们再次出现。在重新启动时,让他们检查软件映像(以及他们加载的任何其他内容),并在重新引入仲裁之前进行完整的RAM测试。使用硬件支持您,但要小心操作。例如,您可以获取ECC RAM,并定期对其进行读/写,以纠正ECC错误(如果错误无法纠正,则会死机)。然而(从内存来看)静态RAM比DRAM更能耐受电离辐射,因此最好使用静态DRAM。请参见“我不会做的事情”下的第一点。

假设您在一天内任何给定节点都有1%的失败机会,假设您可以使失败完全独立。如果有5个节点,一天内需要3个节点失败,这是0.00001%的概率。有了更多,你就明白了。

我不会做的事情:

低估了一开始没有问题的价值。除非重量是一个问题,否则你的设备周围的一大块金属将是一个比程序员团队所能想到的更便宜、更可靠的解决方案。同样,EMI输入的光学耦合也是一个问题,等等。无论怎样,在采购部件时,都要尽量选择那些抗电离辐射性能最好的部件。使用自己的算法。人们以前也做过这种事。利用他们的工作。容错和分布式算法很难。尽可能利用他人的工作。使用复杂的编译器设置,天真地希望您检测到更多失败。如果你运气好,你可能会发现更多的失败。更有可能的是,您将在编译器中使用一个测试较少的代码路径,特别是如果您自己滚动的话。使用在您的环境中未经测试的技术。大多数编写高可用性软件的人必须模拟故障模式,以检查其HA是否正常工作,并因此错过了许多故障模式。你处于“幸运”的境地,经常按需出现故障。因此,测试每种技术,并确保其应用程序实际提高MTBF的数量超过引入它的复杂性(复杂性带来了bug)。特别是将此应用于我的建议重新仲裁算法等。

其他回答

既然您专门要求软件解决方案,而且您使用的是C++,为什么不使用运算符重载来创建自己的安全数据类型呢?例如:

不要使用uint32_t(以及double、int64_t等),而是制作自己的SAFE_uint32-t,其中包含uint32/t的倍数(最小值为3)。重载您想要执行的所有操作(*+-/<<>>==!=等),并使重载的操作对每个内部值独立执行,即不要执行一次并复制结果。在之前和之后,检查所有内部值是否匹配。如果值不匹配,可以将错误的值更新为最常见的值。如果没有最常见的值,您可以安全地通知存在错误。

这样,即使ALU、寄存器、RAM或总线上发生损坏也无所谓,您仍然可以多次尝试并很好地捕获错误。然而,请注意,这只适用于您可以替换的变量-例如,堆栈指针仍然是易受影响的。

附带故事:我遇到了一个类似的问题,也是在一个旧的ARM芯片上。结果发现,这是一个使用旧版本GCC的工具链,与我们使用的特定芯片一起,在某些边缘情况下触发了一个错误,这会(有时)破坏传递到函数中的值。在将设备归咎于无线电活动之前,确保设备没有任何问题,是的,有时是编译器错误=)

在小型卫星的软件/固件开发和环境测试方面工作了大约4-5年,我想在这里分享我的经验。

*(小型卫星比大型卫星更容易发生单次事件干扰,因为其电子部件的尺寸相对较小且有限)

非常简洁和直接:没有机制可以从可检测到的错误中恢复过来软件/固件本身的情况,至少没有用于恢复目的的软件/固件的最低工作版本副本,以及支持恢复的硬件(功能)。

现在,这种情况通常在硬件和软件两级处理。在这里,根据您的要求,我将分享我们在软件级别可以做的事情。

…恢复目的。。。。提供在真实环境中更新/重新编译/刷新软件/固件的能力。这几乎是高度电离环境中任何软件/固件的必备功能。如果没有这一点,您可以拥有任意数量的冗余软件/硬件,但在某一点上,它们都会崩溃。所以,准备好这个功能!…最低工作版本。。。在您的代码中具有响应性、多个副本、最低版本的软件/固件。这类似于Windows中的安全模式。不要只拥有一个功能完整的软件版本,而是拥有软件/固件的最低版本的多个副本。最小副本通常比完整副本小得多,并且几乎总是只有以下两个或三个功能:能够监听来自外部系统的命令,能够更新当前软件/固件,能够监控基本操作的内务数据。…复制…某处。。。在某处安装冗余软件/固件。无论有无冗余硬件,您都可以尝试在ARM uC中使用冗余软件/固件。这通常是通过在单独的地址中有两个或多个相同的软件/固件来实现的,这些软件/固件将向彼此发送心跳信号,但一次只有一个处于活动状态。如果已知一个或多个软件/固件没有响应,请切换到其他软件/固件。使用这种方法的好处是,我们可以在发生错误后立即进行功能更换,而无需与负责检测和修复错误的任何外部系统/方进行任何联系(在卫星情况下,通常是任务控制中心(MCC))。严格来说,如果没有冗余硬件,这样做的缺点是实际上无法消除所有单点故障。至少,您仍然会有一个单一的故障点,那就是交换机本身(或者通常是代码的开头)。然而,对于高度电离环境中受尺寸限制的设备(如微微/毫微微卫星),在没有额外硬件的情况下将单点故障减少到一点仍然值得考虑。更重要的是,用于切换的代码肯定会比整个程序的代码少得多,从而显著降低了在其中出现单一事件的风险。但是,如果您没有这样做,您的外部系统中应该至少有一个副本,该副本可以与设备接触并更新软件/固件(在卫星情况下,它也是任务控制中心)。您还可以在设备的永久内存存储中保存副本,该副本可以被触发以恢复正在运行的系统的软件/固件…可检测到的错误情况。。该错误必须是可检测的,通常通过硬件纠错/检测电路或通过一小段纠错/检测代码来检测。最好将这些代码放得小、多,并且独立于主软件/固件。其主要任务仅用于检查/纠正。如果硬件电路/固件是可靠的(例如,它比其余的更抗辐射-或具有多个电路/逻辑),那么您可以考虑使用它进行错误校正。但如果不是,最好将其作为错误检测。可通过外部系统/设备进行校正。对于纠错,您可以考虑使用像Hamming/Golay23这样的基本纠错算法,因为它们可以更容易地在电路/软件中实现。但这最终取决于团队的能力。对于错误检测,通常使用CRC。…支持恢复的硬件现在是这个问题上最困难的方面。最终,恢复需要负责恢复的硬件至少能够正常工作。如果硬件永久损坏(通常发生在其总电离剂量达到一定水平后),则软件无法帮助恢复。因此,对于暴露在高辐射水平下的设备(如卫星)来说,硬件无疑是最重要的关注点。

除了上述预测固件错误的建议外,我还建议您:

子系统间通信协议中的错误检测和/或错误校正算法。这是另一个几乎必须具备的功能,以避免从其他系统接收到不完整/错误的信号过滤ADC读数。请勿直接使用ADC读数。通过中值过滤器、均值过滤器或任何其他过滤器对其进行过滤-切勿相信单个读数。多采样,而不是少采样-合理。

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

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

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

如果你的硬件出现故障,你可以使用机械存储来恢复它。如果你的代码库很小,并且有一些物理空间,那么你可以使用一个机械数据存储。

材料表面不会受到辐射的影响。将有多个档位。机械读卡器将在所有齿轮上运行,并且可以灵活地上下移动。向下表示为0,向上表示为1。从0和1可以生成代码库。

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

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

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