【问题标题】:Most memory-efficient way to define hundreds of double constants定义数百个双常量的最节省内存的方法
【发布时间】:2014-02-17 10:53:15
【问题描述】:

定义数百个用于嵌入式 C 程序的双精度(64 位浮点)常量的最节省内存的方法是什么?请注意,此应用程序受内存限制,我需要尽可能多地节省 RAM。

这是一款 Atmel AVR,带有 2048B RAM,时钟频率为 8MHz。 32K 闪存。

【问题讨论】:

  • 在什么方面有效率?内存、速度、编译简单性?
  • 在源代码方面还是什么?如果您有完整的常量列表,则可以构建压缩方案。
  • 我澄清了最初的问题 - 我正在尝试最大限度地减少内存使用量。压缩不是一个可行的选择。
  • 如果压缩不是一个选项,你应该如何消耗总共少于 64*N 位?
  • :) “在需要时加载到内存中” 您只是在放置它们的位置之间进行选择——在代码或数据部分。您的程序将自然地至少使用每个常量一次,因此它们都将在代码部分中,这不少于,但可能超过数据部分中每个常量的单个记录。但是随后代码将引用它们,这将为每个常量添加一个指针。不确定什么更“有效”,但这需要经过大量测试,可能不是为了问 SO。

标签: c embedded


【解决方案1】:

在很大程度上,让常量不使用内存的方法是将它们存储在一个文件中并根据需要读取它们。

如果您不能这样做,那么常量必须构成程序的一部分,并且它们将以一种或另一种方式占用内存,无论是在数据段中还是作为指令中的立即数。

如果不需要全精度,您可以将数据减少到 float 而不是 double

一些处理器架构可以在指令中编码简单的浮点常量。如果您的目标是这样的处理器,您应该研究它的文档以了解支持哪些常量。这不太可能对一般数据有用。

如果数据具有某种模式,您可以根据需要使用它来生成运行时所需的部分。 (这包括各种形式的压缩和解压缩,这取决于数据中的模式。)显然,这取决于数据的性质,您的问题中没有包含这些性质。

应该考虑的另一种可能性是您的程序是否需要它使用的所有原始数据,或者是否可以提前执行某些工作以减少所需的数据。

否则,总的来说,数据就是数据,它会占用它所占用的空间。

【讨论】:

  • 当内存真的很低时,可以设计和模拟一个专用处理器的指令集,它可以有效地加载浮点常量,例如来自 PATRICIA 树 -- 并希望实施得到回报。
  • @AkiSuihkonen:(a) 树只是一种组织数据的方式,而不是压缩它的方式。没有理由期望它会节省空间。 (b) 模拟某些处理器来加载数据是没有意义的,除非您打算使用它来生成数据,以某种方式利用其中的模式。那么这就是简单的压缩-解压,我的回答中已经提到了。
  • 鉴于问题的嵌入式性质,这可能是一个系统,其中“文件”解决方案可能看起来更像是使用适当的编译器和链接器标志来保持闪存中的常量,特别是避免 RAM副本从闪存初始化,然后从不更改。默认情况下,许多工具链会将常量变量放置在 RAM 中,因为对 MCU 上的程序(闪存)空间的数据访问往往会挑战流水线,因此速度很慢,但是在优先考虑紧凑的内存占用而不是速度的情况下,专门指示可能很有用工具链将其留在闪存中。
  • @ChrisStratton:这是有道理的。 OP 必须提供有关其系统的更多详细信息。静态或自动对象都可以将其初始值存储在闪存中,并且只有在表达式中使用它们时才会开始占用 RAM 中的空间。所以真正的问题可能是最小化程序的工作内存。
【解决方案2】:

期待您使用 AVRStudio:
当您只想将变量放置到闪存时,您可以使用

#include <avr/pgmspace.h>
const char myString[] PROGMEM = "AT\r";
const float myFloat PROGMEM = 3.1415926535f;

有关放置和阅读(AVR)的更多信息,请访问 Data in Program Space

不存在通用解决方案,它取决于平台(冯诺依曼或哈佛)和工具链。

一些编译器使用
__attribute__(section(".myFlashSection"))
其他一些使用编译指示如
#pragma SET_CONST_PAGE(ConstArea)

还有一些奇怪的,比如

#pragma define_section flash_table ".myFlashTable.text" RW
#pragma section flash_table begin

而其他人总是将 const 数据移动到闪存部分。

【讨论】:

  • 我知道 PROGMEM 宏并且之前已经将它与字符串一起使用,因此在需要之前不会在内存中分配它们。这个宏包含在 avrlibc 中,据我所知,它只适用于 AVR 芯片。假设我正在使用 ARM 芯片并想做同样的事情 - 你知道完成这个的方法/这甚至是正确的方法吗?我知道从闪存访问 PROGMEM 数据会导致性能下降,因为访问时间比 RAM 长得多。关于延迟是什么的任何想法?这是使用所有这些双精度的性能关键代码。
【解决方案3】:

将其声明为const double array_name[] = { ... }; 并期望链接器仅将其存储在闪存中。

请注意,您必须检查映射文件以确保没有复制到内存中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-12
    • 1970-01-01
    • 2010-10-22
    • 2013-10-30
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    相关资源
    最近更新 更多