编译用于高放射性环境的应用程序
我们正在编译一个嵌入式C / C ++应用程序,该应用程序部署在屏蔽设备中的电离辐射轰炸环境中。 我们正在使用GCC并针对ARM进行交叉编译。 部署时,我们的应用程序会产生一些错误的数据,并且会比我们想要的更频繁地崩溃。 硬件是为这种环境设计的,我们的应用程序已经在这个平台上运行了好几年。
我们可以对我们的代码进行更改,还是可以通过编译时改进来识别/纠正由单个事件冲突引起的软错误和内存损坏? 是否有其他开发人员成功地减少了长时间运行的应用程序中软错误的有害影响?
在微型卫星的软件/固件开发和环境测试*方面工作了大约4-5年,我想在此分享我的经验。
*(小型化卫星比大型卫星更容易发生单一事件干扰,因为它的电子组件尺寸相对较小,尺寸有限)
要非常简洁明了:没有任何机制可以从软件/固件本身恢复可检测到的错误情况,而不需要至少一个用于恢复目的的软件/固件的最低工作版本的一个副本 - 以及硬件支持恢复(功能)。
现在,这种情况通常在硬件和软件两个层面上处理。 在这里,如您所请求的,我将分享我们在软件级别可以做的事情。
......恢复目的......。 提供在真实环境中更新/重新编译/刷新软件/固件的功能。 对于高离子化环境中的任何软件/固件而言,这是几乎必备的功能。 没有这个,你可能会有多余的软件/硬件,只要你愿意,但是在某一点上,它们都会爆炸。 所以,准备这个功能!
...最低工作版本...在您的代码中有软件/固件的响应式,多个副本,最低版本。 这就像Windows中的安全模式。 您的软件只有一个功能完整的版本,而不是只有最低版本的软件/固件的多个副本。 最小拷贝通常比完整拷贝要小得多,几乎总是只有以下两个或三个特征:
...复制...某处...在某处有冗余的软件/固件。
无论是否使用冗余硬件,都可以尝试在ARM uC中使用冗余软件/固件。 这通常是通过在分开的地址中有两个或多个相同的软件/固件来完成的,这些软件/固件彼此之间发送心跳 - 但一次只能激活一个。 如果已知一个或多个软件/固件无响应,请切换到其他软件/固件。 使用这种方法的好处是,我们可以在发生错误后立即进行功能更换 - 与任何负责检测和修复错误的外部系统/方无任何联系(在卫星情况下,通常是任务控制中心( MCC))。
严格地说,没有多余的硬件,这样做的缺点是你实际上无法消除所有的单点故障。 至少,您仍然会遇到单点故障,这是交换机本身(或者通常是代码的开始)。 尽管如此,对于高度离子化环境下尺寸受限的设备(如微微/毫微微卫星)而言,将单点故障减少到一点而无需额外的硬件仍将值得考虑。 更重要的是,切换代码肯定比整个程序的代码少得多 - 显着降低了获取单一事件的风险。
但是如果你不这样做,你的外部系统至少应该有一个副本,可以与设备接触并更新软件/固件(在卫星情况下,它又是任务控制中心)。
...可检测到的错误情况。错误必须是可检测的,通常由硬件错误校正/检测电路或用于纠错/检测的一小段代码来检测。 最好将这些代码放在小的,多个的,独立于主软件/固件的位置。 它的主要任务只是检查/纠正。 如果硬件电路/固件是可靠的(例如它比其他部件更耐辐射 - 或者有多个电路/逻辑),那么您可以考虑对其进行纠错。 但如果不是这样,最好将其作为错误检测。 更正可以通过外部系统/设备进行。 对于纠错,您可以考虑使用像Hamming / Golay23这样的基本纠错算法,因为它们可以更容易地在电路/软件中实现。 但它最终取决于你的团队的能力。 对于错误检测,通常使用CRC。
......支持恢复的硬件现在,谈到这个问题最困难的方面。 最终,恢复需要负责恢复的硬件至少起作用。 如果硬件永久断开(通常在其总电离剂量达到一定水平后发生),那么(可惜)没有办法让软件帮助恢复。 因此,对于暴露于高辐射水平的设备(如卫星)而言,硬件正是最重要的关注点。
除了上面提到的由单一事件引起的固件错误的建议外,我还想建议你:
子系统间通信协议中的错误检测和/或错误校正算法。 为了避免从其他系统收到不完整/错误的信号,这是另一个必须具备的功能
过滤ADC读数。 不要直接使用ADC读数。 通过中值过滤器,均值过滤器或任何其他过滤器对其进行过滤 - 不要信任单个读数值。 多采样,不能少采样 - 合理。
美国国家航空和航天局有关辐射强化软件的论文。 它描述了三项主要任务:
请注意,内存扫描速率应该足够频繁,以致很少出现多位错误,因为大多数ECC内存可以从单位错误恢复,而不是多位错误。
强大的错误恢复功能包括控制流量传输(通常在错误发生前的某个时刻重新启动进程),资源释放和数据恢复。
他们对数据恢复的主要建议是通过将中间数据视为临时数据来避免它的需要,以便在错误还将数据回滚到可靠状态之前重新启动。 这听起来与数据库中“交易”的概念类似。
他们讨论了特别适用于面向对象语言(如C ++)的技术。 例如
以下是一些想法和想法:
更有创意地使用ROM。
存储任何你可以在ROM中。 而不是计算事物,在ROM中存储查找表。 (确保您的编译器正在将您的查找表输出到只读部分!在运行时打印出内存地址以进行检查!)将您的中断向量表存储在ROM中。 当然,运行一些测试来看看你的ROM相比你的RAM有多可靠。
使用你最好的RAM作为堆栈。
堆栈中的SEU可能是崩溃的最可能来源,因为它是索引变量,状态变量,返回地址和各种类型的指针通常存在的地方。
实现定时器滴答和看门狗定时器例程。
您可以在每个计时器标记中运行“健全性检查”程序,以及处理系统锁定的监视程序例程。 您的主代码也可以定期增加一个计数器来指示进度,并且完整性检查例程可以确保这一点已经发生。
用软件实现纠错码。
您可以为数据添加冗余,以便能够检测和/或纠正错误。 这会增加处理时间,可能会使处理器长时间暴露在辐射中,从而增加出现错误的可能性,因此您必须考虑权衡。
记住缓存。
检查CPU高速缓存的大小。 您最近访问或修改的数据可能会在缓存中。 我相信你可以禁用至少一些缓存(性能价格很高); 你应该试试看看这些缓存对SEU的敏感程度。 如果缓存比RAM更加坚固,那么您可以定期读取并重新编写关键数据,以确保其保持在缓存中并使RAM恢复正常。
巧妙地使用页面错误处理程序。
如果将内存页面标记为不存在,则当您尝试访问它时,CPU将发出页面错误。 您可以创建一个页面错误处理程序,在处理读取请求之前执行一些检查。 (PC操作系统使用它来透明地加载已交换到磁盘的页面。)
使用汇编语言进行关键性的事情(这可能是一切)。
使用汇编语言,您知道寄存器中的内容和RAM中的内容; 你知道CPU正在使用什么特殊的RAM表格,并且你可以用一种迂回的方式来设计事物以降低风险。
使用objdump
实际查看生成的汇编语言,并计算出每个例程所占用的代码量。
如果你正在使用像Linux这样的大型操作系统,那么你需要麻烦; 有太多的复杂性和许多事情会出错。
记住它是一种概率游戏。
一位评论者说
你为避免错误而编写的每一个程序都会因为同样的原因而失败。
虽然这是事实,但检查例程正常工作所需的100字节代码和数据出错的机会远远小于其他地方出现错误的机会。 如果你的ROM非常可靠,而且几乎所有的代码/数据都在ROM中,那么你的优势就会更好。
使用冗余硬件。
使用两个或更多相同的代码完全相同的硬件设置。 如果结果不同,应该触发重置。 使用3个或更多设备,您可以使用“投票”系统来尝试识别哪个设备受到了损害。
链接地址: http://www.djcxy.com/p/2493.html上一篇: Compiling an application for use in highly radioactive environments