曾经在2年多前遇到以下的情况。产品使用了stm32的flash存储用户关键数据。产品试产,给用户使用以后,反应有程序跑飞的情况。分析退货,发现编译器编译了程序后,把一部分代码指定到了最后一个page存储。而最后一个flash page恰好就是存储用户关键数据的。
于是出现以下循环:编译器把部分程序编译保存到了最后一个page-》产品生产出厂-》用户使用,保存关键数据到最后一个page-》关键数据把程序段复写-》程序跑飞。
为了解决以下的问题,只要在程序中加入一个const变量,预留1个page的空间,不允许编译器把代码写到指定的位置。
在map里面随便找个数据,可以看到uart_dma_fxntable的位置位于 0X800 3e94,
假如想让uart_dma_fxntable代码不保存在 0X800 3e94所在的page,可以在代码中加入以下内容
__root __no_init uint8_t flash_default[1024] @ (0x08003C00);
__no_init uint8_t flash_default[1024] @ (0x08003C00);
这段的内容可以在《EWARM_DevelopmentGuide.ENU.pdf》中找到原型,可以搜索 __no_init的用法
如果不加 __root是起不到效果的,因为程序中没有使用到flash_default这个数组,所以这个数组是会被编译器优化掉的。
加上 __root表示编译器需要把程序中没有使用到的变量也保存到flash中,比如生产时间等。
__root 关键字保证没有使用的函数或者变量也能够包含在目标代码中.
定义存放在__flash 空间的数据在程序编译时会自动生成代码嵌入到flash代码中,
对于程序没有使用也要求编译的数据(比如可以在代码中嵌入你的版本号,时间等)必须加关键字__root 限制
加上上面的代码以后,重新编译,可以看到uart_dma_fxntable的代码位置有了变化,
0x08003C00所在的page被const 变量flash_default占用。(不再会被别的代码段占用)
readonly data部分出现框起来的1024字节的增加
那么是否可以用const代替这里的__no_init呢?
答案是不可以,如果使用const,因为初始化没有赋值,所以变量的值都是默认的0,最后一页的内容都会变成0
使用__no_init,变量的值是没有init的0XFF,最后一页的内容是0XFF。0XFF才是我们需要的状态