IAR EWARM 6.5 将const 变量存储在某个地址BUG?

IAR EWARM 6.5 Storing a const variable in a certain address BUG?

我想在stm32中预留一块flash memory来存放自己的config信息

为此,我想将闪存的第二个扇区保存在 STM32F2/STM32F4(16kb 存储在 0x08004000-0x08007FFF)

检查 internet 和 Whosebug 你有 4 种方法可以做到这一点

1)

#pragma location=0x08004000 __no_init const char ReservedArea[16*1024];

2)

__no_init const char ReservedArea[16*1024] @0x08004000;

3) 创建一个部分 + #pragma location=

项目 icf:

place at address mem: 0x08004000 { readonly section ConfigSection };

c 文件:

#pragma location="ConfigSection" __no_init const char ReservedArea[16*1024];

4)

正在项目 .icf 文件中定义一个部分

发现错误或问题

方法 1 到 3 没问题。链接器为我的变量包含一个 space 区域。您可以检查使用十六进制编辑器生成的 .bin 文件,或者只是调试并查看变量是 @0x08004000.

使用这些方法发现的问题是 iar 链接器在 0x08000800 - 0x08003FFF 之间未使用超过 12kb 的闪存。验证这一点的最好方法是删除 var,编译,在注释中写下 bin 文件的大小,然后添加变量。如果执行此操作,您会注意到新的 bin 文件大小大于 16kb,而它必须精确为 16kb。

如果您将地址从 0x08004000 移动到 0x0800C000 而没有任何其他更改,文件大小将再增加 32kbytes,并且之前的所有区域都设置为 0x00,并且在 bin 文件中未使用。这对我们的项目来说是个大问题,因为我使用了 bin 文件中其余未使用的区域来允许固件更新。

查看地图文件,保留区之前的区域也未使用。

我尝试了几种方法来解决这个问题,但没有成功,例如用地址定义 2 个变量,玩了几个小时,检查链接器选项,优化,使用其他 #pragma 选项等。

关于第四种方法,它将变量存储在系统中,但没有获得我想要的地址。问题可能在于两个区域共享地址 space.

icf文件

   define region LANGUAGE_region   = mem:[from 0x08004000 to 0x08007FFF];
   define region ROM_region      = mem:[from __ICFEDIT_region_ROM_start__   to __ICFEDIT_region_ROM_end__];
   define region RAM_region      = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];

   "LANGUAGE_PLACE":place at start of LANGUAGE_region  { section .LANGUAGE_PLACE.noinit };

c代码

extern const char ReservedArea[16*1024] @".LANGUAGE_PLACE.noinit";

const char ReservedArea[16*1024];

是我的问题吗?这是一个错误吗?欢迎任何提示。

提前致谢。

这对我来说不像是错误,而是您需要处理的问题。 .bin 文件是原始内存文件,其中文件的每个字节都映射到内存中的一个字节。您如何期望 .bin 文件表示位于偏移量 0x4000 或 0xC0000 处的字节而不表示之前的所有字节? .bin 文件必须包含两个内存部分之间所有未使用的字节,以保持后续部分的相对偏移量。

您是否担心未使用的字节为 0x00,因此如果不先擦除它们就无法对其进行编程?如果是这样,那么您可以将链接器(或您用来创建 .bin 文件的任何程序)配置为对所有未使用的字节使用 0xFF 而不是 0x00。检查链接器(或命令行)选项。

或者您是否担心 .bin 文件包含大量未使用的内存,这将需要更长的时间来下载和重新编程?或者 .bin 文件现在是否太大而无法放入您为固件更新保留的内存区域?无论哪种情况,解决方案都是将固件更新分为两个独立的部分。例如,第一部分仅包含从 0x08000000 开始到代码结束位置结束的代码。第二部分包含从 0x08004000 开始的数据。两个分区的 .bin 文件的大小将比组合的 .bin 文件小得多,因为它们不需要包括其间所有未使用的内存。您的固件更新例程需要足够智能以识别每个部分并将它们编程到正确的内存地址。

如果您不想处理单独的 .bin 文件,那么您可以考虑下载 .hex 文件而不是 .bin 文件。 .hex 文件不是内存字节的一对一映射,它包含允许跳过未使用内存区域的编码信息。但是,您的嵌入式固件更新例程必须足够智能,以便在对闪存编程之前解码 hex 文件。

好吧,我终于明白了它是如何工作的。链接器搜索最长未使用的 space 以在其中包含代码。

我个人认为这不是最好的方法,如果函数或 const 变量有足够的 space 来容纳,我更希望链接器使用第一个未使用的区域。

为了限制这一点,我刚刚添加了下一个代码(stm32F4 示例)

const char unusedarea[128*3*1024] @0x08020000 ;
#pragma required=unusedarea

这使用 0x08020000 和 0x0807FFFF 之间的 space 并强制链接器使用其他区域。并且有效地发挥了作用。

这让我可以保留 space,但留下所需的 space 免费且未使用。我什至可以从 bin 文件中删除最后的 384 kb,只上传前 128 kb。

已编辑。将这些变量设置为 __no_init bin 文件仍然很小,并且在使用 jtag

时不会覆盖保留区域

我试图将一些常量放入已知的 FLASH 地址中,但是使用上面处理的那些方法我没有得到结果。我尝试了 pragma location,但我没有得到任何结果,也尝试了 @ 但 IAR 抱怨这个。我要存储的变量是 FW 的版本,所以它有一个 12 字节的值,我这样声明它作为一个全局值(在我想要的函数之外,所以它可以从 .c 的所有函数访问):

#pragma location=0x00001FF0
__no_init const uint8_t version[12] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B};

我还检查了 IAR 文档,例如: Technical Note 27498

如果有帮助,我正在使用 IAR 6.5(因为我注意到某些方法需要更新的 6.70!

已编辑:

好吧,现在可以执行以下操作了:

.icf 文件中:

/* Now I have a read only section in the ROM address 0x00001FF4 */
"ROM":
place at address mem:0x00001FF4 { readonly section .version };

.c源文件中:

#pragma location=".version"
__root const uint8_t version[12] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B};

此致,

伊万