我想在stm32中保存一个闪存区域来存储我自己的配置信息。
为此,我想将闪存的第二个扇区保存在STM32F2/STM32F4 (存储在0x08004000-0x08007FFF的16 at )上。
检查internet和堆栈溢出您有4种方法来执行这个
1)
#pragma location=0x08004000 __no_init const char ReservedArea[16*1024];
2)
__no_init const char ReservedArea[16*1024] @0x08004000;
3)创建一个节+# location=
icf项目:
place at address mem: 0x08004000 { readonly section ConfigSection };
C档案:
#pragma location="ConfigSection" __no_init const char ReservedArea[16*1024];
4)
在项目.icf文件IAR为自定义数据定义内存区域中定义一个节
Bug或问题发现
方法1到3工作正常。链接器包括我的变量的空间区域。您可以检查使用十六进制编辑器生成的.bin文件,也可以只进行调试,并看到该变量为@ 0x08004000。
这些方法发现的问题是,iar链接器在0x08000800-0x08003FFF之间留下了超过12千字节的闪存。验证这一点的最佳方法是移除var,编译,在注释中写入bin文件的大小,然后添加变量。如果这样做,您将注意到,当新bin文件大小必须精确到16 is时,它的大小大于16 is。
如果您将地址从0x08004000移动到0x0800C000,而不作任何其他更改,则文件大小将以另一个32千字节的速度增加,并且前面的所有区域都设置为0x00,未在bin文件中使用。这对于我们的项目来说是一个大问题,因为我使用bin文件之外的其余未使用区域来允许固件更新。
通过检查地图文件,您将看到保留区域之前的区域也未使用。
我尝试了几种方法来解决这个问题,比如用address定义两个变量、播放几个小时、检查链接器选项、优化、使用其他#杂注选项等等。
关于4方法,它将变量存储在系统中,但它没有得到我想要的地址。问题可能是这两个区域共享地址空间。
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];这是我的问题吗?它是一个bug吗?任何提示都是受欢迎的。
提前谢谢。
发布于 2016-05-12 07:53:05
好的,我终于明白了它是如何工作的。链接器搜索包含代码的最长未使用空间。
就我个人而言,我认为这不是最好的方法,如果函数或const变量有足够的空间容纳,我更希望链接器使用第一个未使用的区域。
为了限制这一点,我刚刚添加了下一个代码(stm32F4示例)。
const char unusedarea[128*3*1024] @0x08020000 ;
#pragma required=unusedarea这将使用介于0x08020000和0x0807FFFF之间的空间,并强制链接器使用其他区域。有效地发挥了作用。
这允许我保留空间,但留下所需的空间免费和未使用。我甚至可以从bin文件中删除最后的384 kb,并且只上传前128 kb。
编辑。将这些var设置为__no_init bin文件仍然很小,并且在使用jtag时不会覆盖备用记录。
发布于 2016-05-11 14:53:27
对我来说,这听起来不像是一个bug,而是一个你需要处理的问题。.bin文件是一个原始内存文件,其中文件的每个字节映射到内存中的一个字节。您如何期望.bin文件表示位于偏移量0x4000或0xC0000的字节,而不表示之前的所有字节?.bin文件必须包含两个内存段之间所有未使用的字节,以便维护后续部分的相对偏移量。
您是否担心未使用的字节是0x00,因此它们无法编程而不首先被擦除?如果是这样,那么您可能可以配置链接器(或任何用于创建.bin文件的程序),以便对所有未使用的字节使用0xFF而不是0x00。检查链接器(或命令行)选项。
还是您担心.bin文件包含大量未使用的内存,需要更长的时间才能下载和重新编程?还是.bin文件现在太大,不适合您为固件更新保留的内存区域?在这两种情况下,解决方案都是将固件更新分为两个单独的部分。例如,第一部分只包含从0x08000000开始并在代码结束处结束的代码。第二部分包含从0x08004000开始的数据。两个分段的.bin文件的大小将比合并的.bin文件小得多,因为它们之间不需要包含所有未使用的内存。您的固件更新例程将需要足够聪明,以识别每一部分,并编程到适当的内存地址。
如果您不想处理单独的.bin文件,那么可以考虑下载.hex文件,而不是.bin文件。.hex文件不是内存字节的一对一映射,而是包含允许跳过未使用内存区域的编码信息。但是,您的嵌入式固件更新例程必须足够聪明,在编写闪存程序之前解码十六进制文件。
发布于 2016-07-20 07:12:48
我试图在一个已知的闪存地址中放置一些常量,但是使用上面处理的那些方法,我无法得到结果。我试着用语用定位,但我没有得到所有的结果,也与@但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文档,如:技术说明27498
如果有帮助的话,我正在使用IAR6.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};诚挚的问候,
伊万
https://stackoverflow.com/questions/37164033
复制相似问题