C 如何为数据保留固定的闪存部分?

C 如何为数据保留固定的闪存部分?,c,avr,avr-gcc,sections,flash-memory,C,Avr,Avr Gcc,Sections,Flash Memory,我需要在闪存中存储一些大数据块,在闪存中经常读取数据,偶尔使用SPM进行重写。我已经知道了如何使用指向\uuu flash和pgm\u read\u byte的指针来访问它,如何不忽略常量(尽管我写了它),如何在循环中实际访问数组,这样它就不会得到完全优化(内联后),但我真的不知道如何声明我的数组 const uint8_t persistent_data[1024] __attribute__(( aligned(SPM_PAGESIZE),

我需要在闪存中存储一些大数据块,在闪存中经常读取数据,偶尔使用SPM进行重写。我已经知道了如何使用指向
\uuu flash
pgm\u read\u byte
的指针来访问它,如何不忽略
常量(尽管我写了它),如何在循环中实际访问数组,这样它就不会得到完全优化(内联后),但我真的不知道如何声明我的数组

const uint8_t persistent_data[1024] __attribute__(( aligned(SPM_PAGESIZE), 
                                                    section("mycustomdata") )) = {};
工作大约很好,除了我不想初始化它。在对我的设备(Arduino ATmega328P)进行编程时,我希望保留此部分,以便它保留应用程序先前写入的数据。上面的零初始化它,我的十六进制文件包含零,程序员很高兴地用它来覆盖我的数据

使用
\uuuu flash
修饰符而不是
\uuuu属性((“…”))
在此处的作用大致相同,只是它将数组放置在其他位置,我无法控制数组的放置位置。当我使用
\uuu flash
并忽略初始化时,它仍然会这样做(尽管我得到一个“未初始化变量'persistent\u data'放入程序内存区域[-Wuninitialized]”警告)

现在我试图省略初始化器:

const uint8_t persistent_data[1024] __attribute__(( aligned(SPM_PAGESIZE),
                                                    section("mycustomdata") ));
并且得到了意想不到的结果。.lss输出的部分数据显示

Idx Name          Size      VMA       LMA       File off  Algn
  …
  1 mycustomdata  00000480  00800480  000055e2  00005700  2**7
                  CONTENTS, ALLOC, LOAD, DATA
  2 .text         00005280  00000000  00000000  000000d4  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, CODE

这将所有初始化零点都放在HEX文件中的加载内存地址55 e2(而不是省略它们),而虚拟内存地址(变量<代码>持久性数据指向)指的是0480—在文本段的代码中间。p> (我还试图省略

常量
,并省略
常量
和初始化器,两者的效果与仅省略初始化器相同)

我不知所措。我可能需要使用
extern
吗?(任何这样做的尝试都会导致“未定义对持久_数据的引用”错误)。我需要使用链接器脚本吗


如何使
持久化\u数据
引用任何其他数据都不使用的程序内存位置,并使编译器不在十六进制文件中为该位置发出任何初始化数据?

您似乎没有意识到您实际上需要两个版本的十六进制文件-一个适合“新”的版本安装在一个新的(或更糟的:重复使用,因此随机闪存内容)芯片上,该芯片初始化闪存部分以确保其中没有可能被解释的任意数据,另一个用于更新错过该部分的预编程芯片,以便保留用户已经修改的数据。因此,无论如何,您都需要初始化此部分的版本

实现这一点的最简单方法与第一个示例类似,初始化数据以构建代码的“裸芯片”版本,并通过使用objcopy从对象文件中删除此初始化部分来生成“更新”版本(假设您使用GNU工具链)。请参阅此工具的
-R
选项

此外,请确保此数据节位于固定的地址—您不希望每次更改代码中的某些内容时它都会移动


如果可用,我宁愿尝试使用EEPROM,也不愿经历重新编程的麻烦。

我想,在编程时,使用引导加载程序代码不要编写整个闪存。假设您从0x0000编程到0x7fff,只编程到0x6fff(我不知道页面大小,但类似于此),并使用0x7000到0x7fff作为常量位置。如果代码已经用数据更新,您可能必须在代码内部开发某些逻辑,而不是重新初始化。我想说的是,我不认为您可以控制不从同一代码在flash中写入特定位置。相反,您需要从编写flash的应用程序中进行控制,或者由谁进行编程part@Sudhee真正地啊。我正在考虑编写一个bash脚本,从十六进制中删除相应的行,因为我想最小化传输的文件大小。我想我会像你建议的那样调整引导加载程序,作为一个额外的障碍,但是我希望尽可能长时间保留原始Arduino引导加载程序,以使我的用户更简单。我确实考虑过单独的初始化固件,然而,在我的应用程序中已经有一个init命令可以处理这个问题,所以我认为它与这个问题无关。存在防止执行任意数据的保护措施。关于eeprom:这可能更简单,但是它不够快(在阅读时),也不够大,不适合我的用例。谢谢你的回答!我来调查一下。关于在固定地址定位分区,这就是为什么我选择使用分区属性而不是
\uu flash
。我还没有尝试,但我计划使用
--节开始
选项。将
“$(ToolchainDir)\avr objcopy.exe”-O ihex-R.eeprom-R.fuse-R.lock-R.signature-R.user\u signatures-R mycustomdata”$(OutputFileName.elf”“$(OutputFileName)\u update.hex“
添加到构建后事件中就成功了。