【问题标题】:Embedded systems worst practices?嵌入式系统最糟糕的做法?
【发布时间】:2010-09-20 01:36:54
【问题描述】:

在开发嵌入式系统时,您认为“最差的做法”是什么?

我不应该做的一些想法是:

  • 避免抽象硬件层,而是在整个代码中分散硬件访问。
  • 没有任何类型的仿真环境,只有实际的硬件可以运行/可爱。
  • 避免单元测试,可能是由于以上两点
  • 不以分层结构开发系统,因此较高层可能依赖于已调试和工作的较低层功能
  • 选择硬件而不考虑将使用它的软件和工具
  • 使用为便于调试而设计的硬件,例如没有测试点、没有调试 LED、没有 JTAG 等。

    我敢肯定有很多关于不该做什么的好主意,让我们听听!

  • 【问题讨论】:

      标签: embedded anti-patterns


      【解决方案1】:

      初始化后的动态内存分配。系统启动并运行后,内存池应保持静态。

      【讨论】:

      • 很好的答案,如果系统必须处理可变长度的使用输入,例如我有一个接受 XML 配置的系统。在浏览器中,生成的数据结构可能很小也可能很大。如何最好地处理这类案件?
      • 取决于系统的大小和时间限制。在嵌入式世界的高端,动态分配是合理的。
      • 如果它是一次性事件,那么我不会反对动态分配一块足够大的内存来保存文件。如果是重复出现,但只是初始化后的动态分配,那我觉得这也是可以接受的。
      • 一个好的方法是编写一个后进先出或双后进先出分配器(一个后进先出自下而上分配,而独立的后进先出自上而下分配)。如果正在分配的对象的生命周期符合双 LIFO 模式,那么它可以比使用 malloc/free 更干净。
      【解决方案2】:

      尝试在不访问您正在开发的实际硬件的情况下进行开发。

      【讨论】:

      • 嘿,比尔·盖茨建立了他的帝国,他为一台他从未接触过的机器开发了一个基本的解释器(根据传说,它第一次被实际加载到目标中,Altair 8800) .这就是模拟器的用途!
      • @Tim:我个人最喜欢的是一位正在为客户的系统进行开发的朋友,除了通过电子邮件发送客户代码并获取结果之外,无法访问该系统。他说他学到了很多,但不会再这样做了。
      • 我大多不同意。独立于平台的编码原则意味着您应该能够在没有硬件的情况下获得很长的路要走。当然,您最终还是会需要它,而且风险管理越早越好。
      • @Craig McQueen:独立于平台的仿真可以让人们在没有硬件的情况下获得很长的路要走。不幸的是,随后可能会发现真实硬件的时序行为与仿真器有很大不同,以至于需要进行重大修改。
      【解决方案3】:

      嵌入式系统中的一件重要事情是独立于您的应用程序评估技术,包括软件(编译器、库、操作系统)和硬件(芯片组)。避免使用这些测试台是危险的。应该购买评估套件或建立自己的测试台。

      【讨论】:

        【解决方案4】:

        假设字节顺序永远相同。

        (将其扩展到寄存器的大小以及有关硬件规格的任何内容)

        (cmets 中的案例说明)。

        【讨论】:

        • 我曾经不得不将应用程序从使用大端序的 Verifone POS 迁移到使用小端序的较新版本。这不是前面代码中唯一的错误,但也是最不明显的。
        【解决方案5】:
        • 略过日志记录设施。嵌入式系统很难调试,您需要大量日志记录。
        • 无法允许记录级别。许多系统中的一个系统会表现出奇怪的行为,您需要将该系统的日志记录的调试级别设置为更详细的级别。
        • 不允许某种输出端口允许登录到例如控制台。
        • 无法“单步执行”代码。
        • 无法分析代码,因此您可以查看哪些位需要优化,例如在汇编程序中。
        • 未开发某种“健全性测试”,以便您可以在装载后和发货前快速检查设备是否正常工作。
        • 设计基于一些“本土”操作系统

        【讨论】:

          【解决方案6】:

          如果不进一步定义“嵌入式编程”,就不可能说出什么是好的或坏的做法。

          例如,在 CE 或 XPe 平台上,您可能使用的许多技术在 CE 或 XPe 平台上完全不适合使用狡猾的非标准方言“C”对 8 位微控制器进行编程。

          在许多情况下,抽象是一种(过度)昂贵的奢侈品,因此“避免它”可能是好事而不是坏事。

          【讨论】:

          • 好点,但有时我想知道与我使用的某些设备相比,CE 是否真的是“嵌入式”的?它真的是嵌入式系统的“劳斯莱斯”。
          【解决方案7】:

          这里有几个:

          • 不要设计易于解释的架构,让您的开发人员、经理和客户都能理解。

          • 嵌入式系统几乎总是对成本敏感的平台。不要计划硬件变得更慢(更便宜),也不要计划关键数据路径中的新功能。

          • 大多数嵌入式系统都是“无头”的(没有键盘或鼠标或任何其他 HID)。不要在你的日程安排中计划编写调试工具。并且不要资源至少一名开发人员来维护它们。

          • 请务必低估获得提示所需的时间。这就是让核心 CPU 达到可以与您和您与它对话的程度所需的时间。

          • 始终假设硬件子系统可以开箱即用,例如内存、时钟和电源。

          【讨论】:

          • “并且不要资源至少一名开发人员来维护它们。”太真实了。我看到一个开发团队在三年的时间里变得越来越慢,没有任何时间分配给工具开发。
          【解决方案8】:
          • 未初始化的异常向量(你知道,对于那些“永远不会到达”的异常向量)
          • 跟我说:全局变量。尤其是在 ISR 和没有保护的任务(或前台循环)之间共享的那些。
          • 未能在必要时使用“volatile”。
          • 具有 DisableInterrupts() 和 EnableInterrupts() 配对的例程。知道了?不是RestoreInterrupts(),而是ENABLE。是的,嵌套。
          • 测试时没有可切换的 GPIO。
          • 板上没有测试点。
          • 没有用于查看运行时系统状态的 LED 或串行端口。
          • 无法测量 CPU 的繁忙/空闲程度。
          • 除了最可怕的情况外,所有情况都使用内联汇编。编写快速标注。
          • 使用 for (i = 0; i
          • 尽可能不使用 const 来保留 RAM 并减少启动时间(不复制/初始化变量)

          我还有很多,但这应该让我们开始......

          【讨论】:

          • 不错的清单。如果可以的话,我会给你一个 +2。
          • 如果可以的话,我会给这个+100。将此转发给其他同事。
          【解决方案9】:

          好的,第 2 轮....还有一些:

          • 不要使用看门狗定时器(尤其是内置的!)

          • 当缩放整数数学足够时使用浮点类型和例程

          • 在没有保证时使用 RTOS

          • 当 RTOS 真的有意义时不要使用它

          • 切勿查看生成的汇编代码以了解幕后情况

          • 编写固件,使其无法在现场更新

          • 不要记录您所做的任何假设

          • 如果您在测试/调试时看到奇怪的东西,请忽略它,直到它再次发生;这可能不是什么重要的事情,比如掉电、错过的中断、堆栈损坏的迹象或其他一些转瞬即逝的间歇性问题

          • 在调整堆栈大小时,最好的理念是“从小处着手并不断增加,直到程序停止崩溃,然后我们可能就可以了”

          • 不要利用 Micrium 的 uC/Probe 等运行时分析工具(我相信还有其他工具)

          • 在运行主应用程序之前不要包括硬件的开机自检 - 嘿,启动代码正在运行,有什么可能不工作?

          • 绝对不要在您不会实施的 POST(上图)中包含 RAM 测试

          • 如果目标处理器有一个 MMU,尽管如此,不要使用那个可怕的 MMU!尤其是不要让它保护您免受对代码空间的写入、从数据空间的执行等......

          • 如果您一直在测试、调试和集成一组特定的编译器选项(例如无/低优化),请务必在最终版本构建之前打开全面优化!!!!但只有在您不打算测试时才打开优化。我的意思是,您已经测试了几个月 - 会出什么问题?!??!

          【讨论】:

            【解决方案10】:

            在我伤害自己之前有人阻止我。

            顺便说一句,我意识到并非所有这些都严格特定于嵌入式开发,但我相信它们中的每一个在嵌入式世界中至少与现实世界一样重要。

            • 在制定时间表时,请继续前进,并假设一切都会在第一时间进行。

            • 在没有示波器和/或逻辑分析仪的情况下启动电路板。特别是。范围,那永远没用。

            • 在设计时不要考虑电源。热量、效率、纹波对 ADC 读数和系统行为的影响、EMF 辐射、启动时间等问题并不重要。

            • 无论你做什么,都不要使用复位控制器(5 美分 IC 类型),只需使用 RC 电路(希望其中耦合有大量高频 AC 噪声)

              李>
            • 拥抱大爆炸!!!不要逐步开发小块并经常集成,傻瓜!!!只需与同事一起编写几个月的代码,然后在大型贸易展演示的前一天晚上将它们全部拼凑起来!

            • 不要使用调试/跟踪语句检测代码。能见度很差。

            • 在您的 ISR 中做很多事情。冒泡排序、数据库查询等...嘿,可能没有人会打扰您,请您发言,朋友,尽情享受吧!!!

            • 在设计中忽略电路板布局。让自动布线器在那些匹配的阻抗走线和大电流、高频电源上发挥作用。嘿,伙计,你还有更重要的事情要操心!!!

            • 使用全新的、beta 版、未发布的早期采用者芯片,尤其是在安全至关重要(航空、医疗)或大批量(召回 100 万个单位很有趣)的情况下。既然 4 核 300 MHz 7 级流水线芯片上有新的硅采样,为什么还要去拉斯维加斯?

            【讨论】:

            • 我敢肯定,一旦我一直压抑的记忆消退并且我停止抽搐,我会发现这很有趣。 +1 表示我需要度过的“心理健康”日...... :-)
            【解决方案11】:
            • 将您的固件模块编写为完全通用的,接受所有可能的参数作为变量,即使您上面的层总是使用相同的参数调用。

            • 在代码的任何地方都使用 memcpy,即使系统中有 DMA 引擎(何必麻烦硬件)。

            • 设计一个复杂的分层固件架构,然后让模块直接访问更高级别模块拥有的全局变量。

            • 选择一个 RTOS,但不要费心测试它的实际性能(我们不能相信供应商给出的数字吗?)

            【讨论】:

              【解决方案12】:

              在您的解决方案中使用多个处理器并确保它们具有相反的字节序。然后确保它们之间的接口是其中一个可以直接访问另一个内存。

              是的,我之前已经对这种架构进行了编程。

              【讨论】:

              • 如果我没记错的话,TI 的 OMAP5912 将小端 ARM 处理器与大端 c55 DSP 结合在一个设备中,通过共享内存进行通信。与所有工程一样,这种引入的复杂性是权衡使用这些经过验证的技术所带来的好处的一部分。
              【解决方案13】:

              打印。

              如果您的跟踪工具需要上下文切换和/或中断,您将永远无法调试任何与时间相关的内容。

              写入内存缓冲区(memcpy'ing enums 而不是 s(n)printf 的奖励积分),并在其他时间读取。

              【讨论】:

                【解决方案14】:

                这可能更像是一个硬件解决方案——但对于从头开始的新项目,低估资源需求是一个大问题,尤其是在使用没有简单方法扩展代码/存储大小的小型独立微控制器时。

                【讨论】:

                  【解决方案15】:

                  不要:

                  • 留下无用的中断向量(毕竟,它们永远不会被触发,那有什么坏处...),而不是让它们跳转到默认的未使用的中断处理程序有用的东西。

                  • 不熟悉您正在使用的处理器的细节,尤其是在您编写任何低级驱动程序时。

                  • 选择闪存数量最少的处理器系列版本,因为您始终可以“稍后升级”,除非成本无法避免。

                  【讨论】:

                    【解决方案16】:

                    这不仅适用于嵌入式系统,而且将所有这些时间都花在寻找错误(调试)上,而不是用很酷的东西来避免错误,例如代码审查绝对是一种常用的最坏做法。

                    另一个是让一个巨大的处理器完成所有工作,而不是将问题分解为小问题,例如有更多的小处理器。还记得可可吗?

                    【讨论】:

                      【解决方案17】:

                      这在很大程度上取决于您正在编程的控制器类型。有时成本是最重要的事情,你试图用尽可能少的钱过日子。这就是我通常坐的船。以下是我使用过的一些最糟糕的做法:

                      • 不要专注于改进您的流程。下次再努力一点。稍后当我们不忙于仓促发布新产品同时支持所有这些领域的错误时,我们可以担心这些东西。
                      • 避免设计一种让您的生活更轻松的工程工具,如果您确实构建了一个,请不要让它向设备发送无效输入
                      • 不要质疑优化。这是魔法。编译器知道它在做什么。永远不会有编译器错误,尤其是对于您的客户 7 位 PIC 子微控制器。太多人会注意到吧?
                      • 像运行物理引擎一样进行除法和乘法运算,无需担心溢出、精度损失、舍入为零。
                      • 如果您的计时似乎有效,请不要检查您是否偏离了 1 分或是否随时间漂移。您在高中时演奏打击乐,您会注意到 7200000 个时钟周期和 7200001 个时钟周期之间的差异。
                      • 依靠对您的固件一无所知的小组进行的系统级测试
                      • 在尽可能多的不同设备上工作。有几个调试器会话与不同的开发环境一起使用。开发一种产品,同时对另一种产品进行基准测试,并尝试在第三个产品上重现现场问题。
                      • 匆忙发布新版本的代码,因为您只更改了一件事,而且您可能没有破坏它。生产线停了,我们不能浪费时间!
                      • 如果优化已关闭,请不要进行任何类型的测试来警告您。应该不会对吧?您刚刚安装的新 IDE 版本不可能破坏该设置。
                      • 将代码编写得足够好才能工作。花 75% 的时间把它弄到一半。
                      • 不要对功能设计有任何意见。允许任何功能收集几天的状态信息。无法为测试注入此状态信息。当您尝试重现人们在现场看到的错误时,这将为您提供空闲时间,并且生产人员也会感谢他们的休息时间

                      【讨论】:

                        【解决方案18】:

                        从软件的角度来看,不要花时间学习硬件。

                        【讨论】:

                          【解决方案19】:

                          一些额外的注意事项:

                          • 将硬件相关部件的开发和测试留到最后才发现硬件无法正常工作、无法按预期工作或存在一些无法在软件中修复的缺陷(例如,不需要的非破坏所有进一步信号处理的线性失真)。
                          • 简单地设计模拟-数字电路,而不考虑数字部分中发生的事情如何影响模拟部分(例如,串扰,导致从 ADC 读取错误数据)。

                          【讨论】:

                            【解决方案20】:
                            • 假设微机按照数据手册的规定做了/没有按照数据手册的承诺去做。
                            • 将看门狗服务例程置于高优先级定时中断中,这样无论发生什么其他情况,看门狗都不会失败。
                            • 使用互联网上的任何代码,尤其是来自 Arduino/Pic 网站的代码。
                            • 假设从一个组件到下一个组件都有任何标准定义,例如 Tx/Rx(我们这里有一个带有 2 个通信端口的 Sony 设备,其中一个的 Tx/Rx 相对于另一个相反)。
                            • 认为客户在售出至少 100 台之前会费心检查/测试任何东西
                            • 假设该领域的任何其他参与者实际上都知道他们在做什么(我们有一份标准文档,上面写着“我们认为这是我们的旧协议所做的,但没有人真正记得”)

                            【讨论】:

                              【解决方案21】:

                              我在嵌入式系统工作超过 8 年和教授嵌入式系统的经验中的一些最糟糕的做法:

                              1. 数据类型的选择 - 嵌入式系统资源稀缺。如果数据的范围是 5-200,则没有必要将其声明为 int。所需的只有 8 位,而使用的是 32 位。浪费 24 位。

                              错误的数据类型也可能是灾难性的。

                              1. 在 ISR 中做大量工作 - ISR 应尽可能短。我见过一些人在 ISR 中实现了整个逻辑,这非常非常糟糕。太糟糕了,它应该被列为犯罪。改用标志

                              2. 使用整数作为标志 - 这更像是第 1 点的扩展。您只需要一位。不要为此使用 16 或 32 位。

                              3. 但我所见过的最糟糕的情况是一遍又一遍地考虑算法以获得最佳和最完美的方法。停止!!牢记最佳实践,让系统首先运行。

                              还有很多。你可以read some of them here

                              【讨论】:

                                猜你喜欢
                                • 2010-12-05
                                • 2010-09-16
                                • 1970-01-01
                                • 2015-11-09
                                • 2014-09-07
                                • 1970-01-01
                                • 2020-10-05
                                • 2017-01-07
                                • 1970-01-01
                                相关资源
                                最近更新 更多