【问题标题】:Embedded systems : last gasp before reboot嵌入式系统:重启前的最后喘息
【发布时间】:2011-01-14 15:19:45
【问题描述】:

当嵌入式系统出现严重问题时,我倾向于将错误写入闪存中的特殊日志文件,然后重新启动(如果内存不足,则没有太多选择)。

我意识到即使这样也可能出错,因此我尝试将其最小化(通过在最终写入期间不分配任何内存,并提高写入进程的优先级)。

但这依赖于检索日志文件的人。现在我正在考虑在重新启动之前通过 intertubes 发送消息以报告错误。

再想一想,当然,最好在重启后发送该消息,但这确实让我开始思考......

如果发现不可恢复的错误,我应该怎么做?如何在处于不稳定状态的系统中尽可能安全地执行这些操作?

【问题讨论】:

  • 我认为您的意思是“没有太多选择”

标签: embedded


【解决方案1】:

一种策略是使用在开机/重启期间初始化的 RAM 部分。这可以用来存储重启后的数据,然后当你的应用重启时,在代码的早期它可以检查内存并查看它是否包含任何有用的数据。如果是,则将其写入日志,或通过通讯频道发送。

如何保留未初始化的 RAM 部分取决于平台,并且取决于您是否运行管理 RAM 初始化的成熟操作系统 (Linux)。如果您在一个由 C 启动代码完成 RAM 初始化的小型系统上,那么您的编译器可能有办法将数据(文件范围变量)放在不同的部分(除了通常的例如 .bss ) 不是由 C 启动代码初始化的。

如果数据没有被初始化,那么它可能会在上电时包含随机数据。要确定它是否包含随机数据或有效数据,请使用哈希,例如CRC-32,以确定其有效性。如果您的处理器有办法告诉您是在重新启动还是在上电复位,那么您还应该使用它来确定上电后数据无效。

【讨论】:

  • 非常像 Amiga Guru 冥想和 Kickstart。这意味着我喜欢它。 :-)
  • 这可能是一种非常好的方法,因为可以确保闪存文件系统(或等效文件系统)在写入闪存之前正常运行;如果不是这样,您可以使用“严重的闪存问题”消息锁定系统,而不会干扰任何比现在更糟糕的事情。
【解决方案2】:

对此没有单一的答案。我将从看门狗定时器开始。如果出现严重错误,这会重新启动系统。

需要考虑的其他事项 - 日志文件中不是的内容也很重要。如果您记录了各种任务/操作的例行更新,那么您可以从缺失的内容中学习。

最后,如果出现问题而您仍在运行:进入临界区,关闭尽可能多的操作系统,关闭外围设备,尽可能多地记录状态信息,然后重新启动!

【讨论】:

    【解决方案3】:

    您要确保做的一件事是不损坏可能合法存在于闪存中的数据,因此,如果您尝试在崩溃情况下写入信息,则需要谨慎操作,并了解系统可能是一个非常糟糕的状态,所以你所做的任何事情都需要以一种不会让事情变得更糟的方式来完成。

    通常,当我检测到崩溃状态时,我会尝试将信息吐出串行端口。可从崩溃状态访问的 UART 驱动程序通常非常简单 - 它只需要一个简单的轮询驱动程序,当忙位清除时将字符写入发送数据寄存器 - 崩溃处理程序通常不需要很好地配合多任务处理,所以轮询很好。而且一般不需要担心传入的数据;或者至少不需要担心以无法通过轮询处理的方式传入的数据。事实上,崩溃处理程序通常不能期望多任务处理和中断处理能够正常工作,因为系统已经搞砸了。

    我尝试让它写入寄存器文件、堆栈的一部分和任何可能可用且有趣的重要 OS 数据结构(当前任务控制块或其他东西)。看门狗定时器通常负责在此状态下重置系统,因此崩溃处理程序可能没有机会写入所有内容,因此首先转储最重要的内容(不要让崩溃处理程序启动看门狗 - 你不想让一些错误错误地阻止看门狗重置系统)。

    当然,这在开发设置中最有用,因为当设备发布时,它可能没有任何东西连接到串行端口。如果您希望能够在发布后捕获这些类型的故障转储,则需要将它们写入适当的位置(例如可能是闪存的保留部分 - 只需确保它不是正常数据/文件系统区域的一部分,除非您确保它不会损坏该数据)。当然,您需要在启动时检查该区域,以便可以检测到它并将其发送到有用的地方,否则没有意义,除非您可能会在事后取回单元并将它们连接到可以查看的调试设置数据。

    【讨论】:

      【解决方案4】:

      我认为正确的异常处理最著名的例子是导弹自毁。该异常是由软件中的算术溢出引起的。显然有很多跟踪/记录媒体涉及,因为根本原因是已知的。发现被调试了。

      因此,每个嵌入式设计都必须包含 2 个功能:记录媒体(如日志文件)和优雅停止,如禁用所有计时器/中断、关闭所有端口并处于无限循环或在导弹发生时 - 自毁。

      【讨论】:

        【解决方案5】:

        在嵌入式系统中重新启动之前将消息写入闪存通常是一个坏主意。正如您所指出的,没有人会阅读该消息,如果问题不是暂时性的,您会磨损闪光灯。

        当系统处于不一致状态时,您几乎无法可靠地做任何事情,最好的办法是尽快重新启动系统,以便您可以从暂时性故障(时序、特殊外部事件、等等。)。在某些系统中,我编写了一个陷阱处理程序,它使用一些保留的内存,以便它可以设置串行端口,然后发出堆栈转储和注册内容,而无需额外的堆栈空间或破坏寄存器。

        这样的转储简单重启是合理的,因为如果问题是暂时的,重启将解决问题,您希望保持简单并让设备继续运行。如果问题不是暂时的,那么您无论如何都不会取得进展,有人可以过来连接诊断设备。

        关于故障和恢复的非常有趣的论文:WHY DO COMPUTERS STOP AND WHAT CAN BE DONE ABOUT IT?

        【讨论】:

          【解决方案6】:

          对于一个非常简单的系统,您有可以摆动的别针吗?例如,当您启动时将其配置为具有高输出,如果事情向南(即看门狗重置挂起)则将其设置为低。

          【讨论】:

            【解决方案7】:

            你有没有考虑过使用垃圾收集器?

            我不是在开玩笑。

            如果你在嵌入式系统中动态分配, 为什么不预留一个标记缓冲区,当粪便碰到旋转的鼓风机时进行标记和清扫。

            您可能已经获得了 malloc(或其他)实现的源代码,对吧?

            如果您的嵌入式系统没有库资源,请忘记我曾经建议过它,但请告诉我们其他人它在什么设备中,这样我们就可以避免使用它。哎呀(你如何在没有库源的情况下进行调试?)。

            如果你的系统已经死了......谁在乎它需要多长时间。很明显,它立即运行并不重要。 如果是这样,您无论如何都不能冒险“死”?

            【讨论】:

            • 这是可能的,但我更喜欢让它更简单。一块静态分配的内存,用作缓冲池。在嵌入式电信中,分配消息缓冲区等的时间超过一分钟(ymmv)是不寻常的,因此在测试期间,我扫描池以寻找分配“太长时间”的缓冲区并对其进行跟踪。但是,虽然垃圾收集器可能会使系统运行时间更长一点,但它只会推迟不可避免的事情。如果垃圾收集可以重新获得资源,那么我在某处编码草率。
            • 你所描述的无论如何都是一种GC。如果您的系统崩溃,那么您确实在某处编码草率或保持 100% 的时间运行不是必需的。在这种情况下,“足够好”就可以了。如果您的嵌入式系统被外部事件所淹没,同样,如果它在规范范围内失败,那么继续并失败。但如果你这样做,增加你的“不堪重负的错误”计数器。也许在那个备用闪存扇区中保留一个“在这个时间戳上不堪重负”的队列。如果您连接到真实网络,请发送 SNMP 陷阱。
            猜你喜欢
            • 2012-07-30
            • 2014-09-17
            • 2010-09-20
            • 2016-03-28
            • 2015-12-27
            • 2020-10-05
            • 2017-01-07
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多