OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9329|回复: 19

MDK const U16__attribute__((at(0x0800E400)))RO-data统计特别大

[复制链接]

4

主题

19

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
211
金钱
211
注册时间
2014-2-20
在线时间
56 小时
发表于 2016-1-6 19:41:25 | 显示全部楼层 |阅读模式
1金钱
在没有添加前的编译结果如下

Build target 'Target 1'
linking...
Program Size: Code=36454 RO-data=3802 RW-data=176 ZI-data=1880  
FromELF: creating hex file...
"..\OBJ\NRF24L01.axf" - 0 Error(s), 0 Warning(s).
Build Time Elapsed:  00:00:01


增加如下代码,
const u16 gFlashDefValue1[512] __attribute__((at(0x0800E400)));
const u16 gFlashDefValue2[512] __attribute__((at(0x0800E800)));
const u16 gFlashDefValue3[512] __attribute__((at(0x0800EC00)));
const u16 gFlashDefValue4[512] __attribute__((at(0x0800F000)));

编译结果如下

linking...
Program Size: Code=36454 RO-data=26010 RW-data=176 ZI-data=1880  
FromELF: creating hex file...
"..\OBJ\NRF24L01.axf" - 0 Error(s), 14 Warning(s).
Build Time Elapsed:  00:00:07


查看增加后的map文件发现如下
      Code (inc. data)   RO Data    RW Data    ZI Data      Debug   Object Name
    ----------------------------------------------------------------------
     33184       3054      24024       2564       3332     327979   Object Totals
         0          0         32              0            0          0   (incl. Generated)
         2          0         19934          7          2           0   (incl. Padding)


请问incl.Padding是在哪里有定义一个19934这么大的RO空间呢,
a.PNG

最佳答案

查看完整内容[请看2#楼]

这个问题其实很好理解,主要就是理解下面这个问题: MDK如何实现将数据存储到FLASH指定地址? 我们在烧录数据的时候,一般是从0x08000000开始按照顺序烧录到flash里面的,如何让数据能够定义到绝对地址如0800F000, 就必须保证文件内数据也是存储在该地址,为了实现这个目的,MDK在生成文件时会填充0x00字段,从而确保能够将数据定义到该字段,形成如下结构: 从实际情况也能验证这个原理,我以我的测试代码为例: const u1 ...
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1770
金钱
1770
注册时间
2015-6-11
在线时间
313 小时
发表于 2016-1-6 19:41:26 | 显示全部楼层
本帖最后由 zc123 于 2016-1-7 10:19 编辑

这个问题其实很好理解,主要就是理解下面这个问题:
MDK如何实现将数据存储到FLASH指定地址?
我们在烧录数据的时候,一般是从0x08000000开始按照顺序烧录到flash里面的,如何让数据能够定义到绝对地址如0800F000, 就必须保证文件内数据也是存储在该地址,为了实现这个目的,MDK在生成文件时会填充0x00字段,从而确保能够将数据定义到该字段,形成如下结构:
11.png
从实际情况也能验证这个原理,我以我的测试代码为例:

const u16 gFlashDefValue4[512] __attribute__((at(0x0800F000))) = {0x1111, 0x1111, 0x1111, 0x0111, 0x0111, 0x0111};
QQ图片20160107095133.png
可以看到Code+ReadOnly = 15236+47228 = 62464
而gFlashDefValue4占绝对地址F000+512*2 = 62464。
至于ZI-Data为什么在末尾。这是MDK编译时决定的,从生成的BIN文件也可以证实该观点:
8.png
9.png
如果你自己查看生成文件也可以发现中间填充了大量的0x00.
知道原因了,那么也可以明白,占有ROM大小是由数据存储FLASH地址和ZI-Data共同决定的,那么现在就有两种解决方式:
1. 不用管ReadOnly的大小,因为中间填充0字段本就是无用flash,Code增加会自动减少填充字节,而不会增加总容量(除非Code本身超过了flash定义的地址,这个是另外一种情况。)
    但有一点要注意, FLASH定义绝对地址时要考虑ZI-Data的长度,否则可能会导致FLASH溢出
2. 如果了解IAP,就知道可以使用两次烧写,程序烧写在起始部分,数据烧写在0x0800F000, 这样程序中只要存储个地址,到时就可以直接读取了。

QQ图片20160107095133.png
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2016-1-7 23:21:53 | 显示全部楼层
zc123 发表于 2016-1-6 19:41
这个问题其实很好理解,主要就是理解下面这个问题:
MDK如何实现将数据存储到FLASH指定地址?
我们在烧录 ...

高手.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

4

主题

19

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
211
金钱
211
注册时间
2014-2-20
在线时间
56 小时
 楼主| 发表于 2016-1-9 16:23:28 | 显示全部楼层
多谢,受教了。
回复

使用道具 举报

24

主题

208

帖子

0

精华

高级会员

Rank: 4

积分
715
金钱
715
注册时间
2014-4-8
在线时间
160 小时
发表于 2016-5-18 14:12:30 | 显示全部楼层
zc123 发表于 2016-1-6 19:41
这个问题其实很好理解,主要就是理解下面这个问题:
MDK如何实现将数据存储到FLASH指定地址?
我们在烧录 ...

有一个问题想请教你,我下面写四行代码
1、const u8 a[1] __attribute__((at(0x0800F000))) = {0x01};
2、const u8 a[1] __attribute__((at(0x0800F000))) ;
3、u8 a[1] __attribute__((at(0x0800F000))) = {0x01};
4、u8 a[1] __attribute__((at(0x0800F000)));

现在说一下1,3两行代码,并进行对比。是在0x0800F000的地址填充一个“0x01”这样

的一个数据,但是,实际上后面还是有很多东西的,我看了map文件,发现编译器,根本

没有在这个flash空间上写任何东西,那这些东西是什么?如果我用写flash的程序,只

写0x0800F000这个地址上的信息的时候,后面的数据会被擦除,系统下电之后,程序不

能运行,通过仿真看是进入了HardFault异常错误

下面说一下2,4两行代码,并进行对比,其实就差了一个const,第二行语句,在

0x0800F000地址的后面,还是有一堆不知道干啥的数据,map文件中还是没有写,若是使

用flash写函数,写了,后面的数据会别擦除,然后重启之后,就又进入了HardFault异

常错误。第四行代码,在内存中看的话,这个是完全正常的,后面没有任何的数据,若

是通过flash函数写进去,没有问题。

关于HardFault异常错误
1、进入仿真环境,使用usmart调用写flash函数
2、写完flash之后,使用mdk进行复位操作
3、根本不知道是在哪里进入的错误,因为只要是单步运行,程序一直不会死机,全速运

行或者是执行一个程序段,程序就会死机,所以,暂且以我的水平,查不出来是为什么

进去的,看过反汇编,没有发现大问题。

其实const就是给编译器看的,但是不知道为什么2,4这两个语句会存在差异

请高手指教
在此谢过
回复

使用道具 举报

24

主题

208

帖子

0

精华

高级会员

Rank: 4

积分
715
金钱
715
注册时间
2014-4-8
在线时间
160 小时
发表于 2016-5-18 14:13:30 | 显示全部楼层
xinxian 发表于 2016-5-18 14:12
有一个问题想请教你,我下面写四行代码
1、const u8 a[1] __attribute__((at(0x0800F000))) = {0x01};
...

不知道我说明白了吗……
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2016-7-12
在线时间
0 小时
发表于 2016-7-12 15:14:09 | 显示全部楼层
xinxian 发表于 2016-5-18 14:12
有一个问题想请教你,我下面写四行代码
1、const u8 a[1] __attribute__((at(0x0800F000))) = {0x01};
...

楼主 你说的在后面跟的不知道干啥的数据 ,我理解应该就是二楼说的ZI-DATA数据。 我也想请教一下,不知道有没有办法,把这个ZI-DATA仍然放在代码段的后边(紧接着code),然后flash这边通过attribute分配地址的数据,后面能不能不跟其他信息(也就是把ZI-DATA提到前面)。
回复

使用道具 举报

1

主题

20

帖子

0

精华

高级会员

Rank: 4

积分
532
金钱
532
注册时间
2015-10-16
在线时间
65 小时
发表于 2016-8-5 16:54:26 | 显示全部楼层
Mark
回复

使用道具 举报

3

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
167
金钱
167
注册时间
2016-1-16
在线时间
15 小时
发表于 2016-11-27 20:00:42 | 显示全部楼层
必须留个名,请教的问题和五楼七楼一样,知道有一种在Link文件的时候修改flash的存储结构可以达到7楼的要求,还没有试过,5楼这样的问题 期待2楼这样的高手来回答,实际上对于MDK的使用规则知道的太少了
回复

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1770
金钱
1770
注册时间
2015-6-11
在线时间
313 小时
发表于 2016-12-13 13:17:31 | 显示全部楼层
本帖最后由 zc123 于 2016-12-13 13:23 编辑

       好久没看,帖子又被顶上来了,一年前因为积累知识的不足,虽然解释还算详细,但支撑点不足,且因为粗心对最末尾字段的解读有错,所以这里在详细说明下:
这是keil显示的代码统计
(图片详见附件一)

简单解释下, code:代码, RO-data:只读数据,  RW-data: 初始化了的可读写数据  ZI-data:定义了但未初始化的可读写数据
理解的这点,在详细的看下方生成的.map文件, 就会发现KEIL中显示的是下图的Grand Totals/ELF Image Totals, 而实际存储在ROM中的数据并不包含ZI-Data(这也好理解,ZI-Data未初始化,对于MDK并不需要单独提供地址保存其初始化数据)
(图片详见附件二)

那么我之前的回答就有问题,.map文件中提供的信息才是正确的, ROM Totals不仅告诉了地址大小,还提供了数据在生成bin中的存储顺序。真实的结构是应该与上述保存一致code、RO-Data,(填充字节+attribute字段), RW-Data。
(图片详见附件三)

说了这么多,就是为了解释5楼的问题(为了方便查看改为16字节)_:
1. const u8 a[16] __attribute__((at(0x0800F000))) = {0x01, 0x10, 0x10, 0x01};
2. const u8 a[16] __attribute__((at(0x0800F000))) ;
语句1、2被定义为const类型的数据,即为RO-data,那么即便代码里没有初始化,也会被默认初始化为0, 所以一定会放在flash的指定字段(也就是attribute定义的地址中)。
这也是附件4在地址0x0800F000~0x0800F010处显示为0x01, 0x10, 0x10, 0x01, 0x00... 0x00附件五0x00......0x00原因
3. u8 a[16] __attribute__((at(0x0800F000))) = {0x01, 0x20, 0x10, 0x02};
4. u8 a[16] __attribute__((at(0x0800F000)));
       语句3可以看出变量a是RW-data, RW-data需要的初始化数据也是要写入flash的,因此也会在0x0800F000写下数据。至于清除flash地址及后续数据,相当于给所有RW-data都初始化为0xFF,出现hardfault也就正常了
      语句4则是ZI-data, 而对于ROM中,ZI-data是没有初始化信息需要写入flash的,也就是 __attribute__((at(0x0800F000)))在这里没有意义,是无效语句,所以你清除并不影响。
这也是附件6在地址0x0800F000~0x0800F010处显示为0x01, 0x20, 0x10, 0x02, 0x00... 0x00, 附件7中该语句并没有生效的原因。
附件1.png
附件2.png
附件3.png
附件4.png
附件5.png
附件6.png
附件7.png
回复

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1770
金钱
1770
注册时间
2015-6-11
在线时间
313 小时
发表于 2016-12-13 13:28:03 | 显示全部楼层
另外去对比下
const u8 a[16] __attribute__((at(0x0800F000))) = {0x01, 0x10, 0x10, 0x01};
u8 a[16] __attribute__((at(0x0800F000))) = {0x01, 0x20, 0x10, 0x02};
的map文件,就会发现(填充字节+attribute)分别被定义到RO-data和RW-data字段,也间接证明了上述结构。
回复

使用道具 举报

0

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
157
金钱
157
注册时间
2016-7-1
在线时间
66 小时
发表于 2016-12-14 14:14:49 | 显示全部楼层
本帖最后由 lovekoufu 于 2016-12-14 14:18 编辑
zc123 发表于 2016-12-13 13:28
另外去对比下
const u8 a[16] __attribute__((at(0x0800F000))) = {0x01, 0x10, 0x10, 0x01};
u8 a[16] _ ...

加const表示在存储flash区,起始地址是0x0800 0000,不加const表示在RAM区,起始地址是0x2000 000,
绝对定位的地址也得跟着修改
回复

使用道具 举报

3

主题

401

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1770
金钱
1770
注册时间
2015-6-11
在线时间
313 小时
发表于 2016-12-14 15:04:34 | 显示全部楼层
lovekoufu 发表于 2016-12-14 14:14
加const表示在存储flash区,起始地址是0x0800 0000,不加const表示在RAM区,起始地址是0x2000 000,
绝对 ...

attribute定位的是初始化信息存放的地址,定位于flash中是没错的,你可以看我上面附件6的截图。
回复

使用道具 举报

2

主题

14

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
298
金钱
298
注册时间
2014-8-22
在线时间
91 小时
发表于 2017-1-13 19:29:54 | 显示全部楼层
我这样写到了FLASH没问题,但使用写FLASH修改数据后,单片机复位重启没反应了,不知道什么原因
回复

使用道具 举报

4

主题

40

帖子

0

精华

高级会员

Rank: 4

积分
924
金钱
924
注册时间
2014-1-9
在线时间
115 小时
发表于 2017-1-30 21:03:19 | 显示全部楼层
我貌似懂了~~~~  
积极思考造成积极人生,消极思考造成消极人生。
回复

使用道具 举报

9

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
162
金钱
162
注册时间
2017-3-7
在线时间
25 小时
发表于 2017-3-7 09:27:55 | 显示全部楼层
xinxian 发表于 2016-5-18 14:12
有一个问题想请教你,我下面写四行代码
1、const u8 a[1] __attribute__((at(0x0800F000))) = {0x01};
...

我跟你遇到了同样的问题,一断电就好像没有程序样,不知道你是怎么解决的,求教
回复

使用道具 举报

9

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
162
金钱
162
注册时间
2017-3-7
在线时间
25 小时
发表于 2017-3-7 11:21:34 | 显示全部楼层
zc123 发表于 2016-12-13 13:17
好久没看,帖子又被顶上来了,一年前因为积累知识的不足,虽然解释还算详细,但支撑点不足,且因为 ...

请问下,在用到attribute这个语法的时候怎么去避免hardfault这种错误呢
回复

使用道具 举报

24

主题

208

帖子

0

精华

高级会员

Rank: 4

积分
715
金钱
715
注册时间
2014-4-8
在线时间
160 小时
发表于 2017-3-10 17:43:58 | 显示全部楼层
809659312 发表于 2017-3-7 11:21
请问下,在用到attribute这个语法的时候怎么去避免hardfault这种错误呢

1、你使用attribute at定义了一个空间对吧    其实这个空间之后是有数据的   你可以用软件仿真去看
2、你一定是擦数据了!!因为你每次擦除的时候  ,就擦了这个页的数据  也就是相当于你擦了跟着attribute at后面的数据   这个就不行了

解决办法  1、 在你擦之前 把后面的数据读出来  然后原封不动的写回去   2、使用attribute at将整个页都占了  也就是很暴力的将后面的数据压到flash的下一页
回复

使用道具 举报

9

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
162
金钱
162
注册时间
2017-3-7
在线时间
25 小时
发表于 2017-3-11 21:24:42 | 显示全部楼层
xinxian 发表于 2017-3-10 17:43
1、你使用attribute at定义了一个空间对吧    其实这个空间之后是有数据的   你可以用软件仿真去看
2、 ...

恩,是你说的那样,确实有数据,一开始看着那些数据还有点熟悉,不过分得太散就没怎么注意,不过我现在能理解了,因为attribute是跟那些已赋值的常量存到一起的,重写的时候都擦出了,所以会出错。谢谢指点........
回复

使用道具 举报

16

主题

54

帖子

0

精华

初级会员

Rank: 2

积分
190
金钱
190
注册时间
2015-4-7
在线时间
22 小时
发表于 2017-12-11 14:30:10 | 显示全部楼层
zc123 发表于 2016-12-13 13:17
好久没看,帖子又被顶上来了,一年前因为积累知识的不足,虽然解释还算详细,但支撑点不足,且因为 ...

对于语句3和4,通过变量赋值的形式肯定是没有效果的,不会改变flash中变量的值,不会引起hardfault。对于这两种情况,擦除肯定是一页的内容,后面的数据擦除后就会导致hardfault
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-24 05:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表