[英]avr-gcc Arduino atmega2560 using far too much RAM
我目前正在尝试编译一些代码以在AVR(ATMEGA2560)上运行,看起来我的内存不足。
我查看了清单(使用avr-objdump -x -S project.elf
),发现.data
太大,无法放入8kb RAM(大约12k)中-实际上是“真正的” RAM内容从0x802FEE开始,该地址位于“外部RAM”的地址空间中。
我懂了:
Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00003088 00800200 0002297a 00022a0e 2**0
CONTENTS, ALLOC, LOAD, DATA
1 .text 0002297a 00000000 00000000 00000094 2**1
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .bss 00000755 00803288 00803288 00025a98 2**2
ALLOC
3 .stab 00001a7c 00000000 00000000 00025a98 2**2
CONTENTS, READONLY, DEBUGGING
4 .stabstr 00000d4d 00000000 00000000 00027514 2**0
CONTENTS, READONLY, DEBUGGING
然后,我对.data
符号进行了.data
并根据地址进行了排序:
grep "\.data" project.lst | sort
00800200 g .data 00000000 __data_start
00800200 l d .data 00000000 .data
00802fee g O .data 00000008 __thenan_sf
00802ff6 g O .data 00000100 __clz_tab
008030f6 l O .data 00000004 next
... lots of stuff in here ....
00803267 l O .data 00000010 CSWTCH.18
00803277 w O .data 00000010 _ZTV14HardwareSerial
00803288 g .data 00000000 __data_end
00803288 g .data 00000000 _edata
因此, .data
应该以0x800200开始,但是由于某些原因,第一个符号位于00802fee
超出了地址范围。
我想-Wl,--section-start,.data=0x800000,--defsym=__heap_end=0x8021FF
但这只能通过移回事情0x200
如预期-还是有一些的开始.data
是推动一切了。
有谁知道这是什么,或为什么会发生? 这很烦人,因为如果不是那样的话,所有内容都应该适合。
好吧,OP已经发现了(在Olaf关于从何处开始寻找位置的评论的帮助下)实际占用了空间,但是确实应该有一个答案,因此尝试在此处进行总结:
数据段中的空间也被匿名数据(代码中的文字 )尤其是字符串文字占用。
这里的棘手问题是: avr
是哈佛体系结构 ,这意味着代码和数据有不同/独立的地址空间,这与普遍的只有一个统一地址空间的冯·诺依曼体系结构相反。 c是为后者设计的,因此只能处理一个地址空间。 在avr
芯片上,数据地址空间由RAM支持,代码地址空间由闪存支持 。
现在,如果RAM不足,那么将只读数据也放入闪存中将是明智的,但是有一个陷阱:给定一个带有char *
的函数,编译器将转换该函数,并假设指针旨在指向数据寻址空间并发出从那里获取的程序集。 因此,需要另一个类似的功能来代替代码地址空间。
使用avr-gcc
和avr-libc
解决此问题的方法是提供PROGMEM
限定符,因此编译器知道以这种方式限定的数据应存在于程序存储器(代码地址空间)中。 还有一个方便的宏PSTR()
使字符串文字直接存在于程序存储器中,而无需引入另一个PROGMEM
限定的标识符。 为了使用这些功能, avr-libc
具有一些标准函数,后缀_P
(例如puts_P()
),它们的功能完全相同,但期望它们的参数位于程序存储器中。 这是一个有点麻烦使用它的方式,但在没有透明地处理这一点,只是无法Ç知道关于不同的地址空间。
由于avr
芯片上的RAM通常很小,因此您可以做一些其他事情来保存它,例如根本不使用堆(在许多嵌入式程序中,您实际上并不需要动态分配,只需考虑一下) ),在适当的地方使用位域,让编译器“打包”所有结构( -fpack-struct
选项),始终对枚举使用尽可能小的大小( -fshort-enums
选项),对于小整数始终使用uint8_t
,使用位域(或在适当的地方使用位屏蔽/移位对状态进行编码等)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.