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

时间:2016-05-11 13:22:45

标签: linker embedded stm32 iar stm32f4

我想在stm32中保存一个闪存区域来存储我自己的配置信息。

为了做到这一点,我想在STM32F2 / STM32F4上保存闪存的第二个扇区(16kb存储在0x08004000-0x08007FFF)

检查互联网和stackoverflow,您有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 file:

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

4)

在项目.icf文件IAR define memory region for custom data

中定义一个部分

发现错误或问题

方法1到3 正常工作。链接器包含我的变量的空间区域。您可以检查使用十六进制编辑器生成的.bin文件,或只调试该变量是@ 0x08004000。

这些方法发现的问题是iar链接器在0x08000800 - 0x08003FFF之间留下超过12k字节的闪存。验证这一点的最佳方法是删除var,编译,写入bin文件大小的注释,然后添加变量。如果你这样做,你会注意到新的bin文件大小必须精确到16kb时大于16kb。

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

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

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

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

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 code

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

const char ReservedArea[16*1024];

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

提前致谢。

3 个答案:

答案 0 :(得分:3)

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

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

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

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

答案 1 :(得分:0)

好的,最后我明白了它的运作方式。链接器搜索最长的未使用空间以包含那里的代码。

我个人认为这不是最好的方法,如果函数或const变量有足够的空间可供使用,我宁愿链接器使用第一个未使用的区域。

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

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

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

这允许我保留空间,但留下所需空间免费和未使用。我甚至可以从bin文件中删除最后384 kb,并仅上传前128个字节。

编辑。将这些变量设置为__no_init bin文件仍然很小,并且使用jtag时不会覆盖保留áreas

答案 2 :(得分:0)

我试图将一些常量放入知道的FLASH地址,但是使用上面提到的那些方法我得不到结果。我尝试了pragma位置,我没有得到所有的结果,也与@但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};

致以最诚挚的问候,

伊万

相关问题