ARM MCU, how to determine free RAM? - Page 1
Forum section: electronics / general

author: zapta
author_rank: Super Contributor
timestamp: April 29, 2015, 11:33:44 pm
content: I have a C++ program that runs on a NXP ARM M0 (LPC11U35). How do I determine the amount of free RAM? That is, the space between the bottom of the stack and the top of the heap?If it matters, this is a LPCXpresso project exported from mbed.org.

author: ttt
author_rank: Regular Contributor
timestamp: April 30, 2015, 01:17:42 am
content: Quote from: zapta on April 29, 2015, 11:33:44 pmDisassemble your binary. I believe the built-in disassemble function in LPCXpresso/Eclipse does not include the data/bss sections unfortunately. LPCexpresso uses gcc which means the command line tool to disassemble is 'arm-none-eabi-objdump'(.exe on windows). Something like this should work:"arm-none-eabi-objdump -D firmware.elf > firmware.s"You can only dump elf binaries, not raw bin files. -D will make sure that all sections are dumped. After that inspect firmware.s and look for "section .data" and "section .bss".Example (from my project here:https://github.com/tinic/rgb-led-panel-sign-v2):Code:Disassembly of section .data:10000000 <SystemCoreClock>:10000000:03938700orrseqr8, r3, #0, 14Disassembly of section .bss:10000004 <_bss>:10000004:00000000andeqr0, r0, r010000008 <_ZZL13gradient_testvE1s>:10000008:00000000andeqr0, r0, r01000000c <_ZL10data_pages>:...10001b6c <_ZZL13gradient_testvE1p>:10001b6c:00000000andeqr0, r0, r010001b70 <_ZZ18PININT0_IRQHandlervE15led_blink_count>:10001b70:00000000andeqr0, r0, r010001b74 <_ZZ14DMA_IRQHandlervE15led_blink_count>:10001b74:00000000andeqr0, r0, r010001b78 <_ZZ4mainE15led_blink_count>:10001b78:00000000andeqr0, r0, r010001b7c <_ZZL12output_framevE15led_blink_count>:10001b7c:00000000andeqr0, r0, r0Look for the highest address listed here, in this example 10001b7c. SRAM on most LPC devices starts at 0x10000000 and ends at 0x10002000 (8KB) which means in this case I have 0x480 (1152) bytes left in SRAM.Keep in mind that the stack starts at 0x10001FFF going down which will reduce the total amount of SRAM you will have. Common source of unexplained bugs when the two collide...

author: ttt
author_rank: Regular Contributor
timestamp: April 30, 2015, 01:22:34 am
content: Quote from: ttt on April 30, 2015, 01:17:42 amMy assumption is that you don't use new/delete of course. I am not aware of a good method to determine how much stack space you use unless you instrument your code and spit your stack pointer in strategic locations through UART.

author: zapta
author_rank: Super Contributor
timestamp: April 30, 2015, 02:25:19 am
content: Quote from: ttt on April 30, 2015, 01:22:34 amI am currently not using malloc/new (though I consider to use it during initialization) but the libraries I use may do, not sure. I Will try ttt's method (thanks!) of static analysis and will see what it gives me.I can get the bottom of the stack from my code (e.g the address of a local variable) but how do I get the top of the heap? There must be some pointer somewhere that gold the current boundary of the heap's reservation.

author: ttt
author_rank: Regular Contributor
timestamp: April 30, 2015, 02:48:52 am
content: Quote from: zapta on April 30, 2015, 02:25:19 amIf malloc/new are used somewhere in your project you should be able to get stats on the memory allocator you will suck in (taking up valuable Flash space). See :http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0171b/Cihhgjad.htmlIf you just want to get the raw stack pointer I usually use this:Code:static volatile uint32_t __attribute__((noinline)) get_sp(void) {volatile register uint32_t sp asm("sp");return sp;}A local variable address will also work in most cases. I prefer this method through a function call as it pins the stack pointer even if you have optimizations turned to O3 or something which can cause the stack pointer not to be what you expect sometimes.

author: andyturk
author_rank: Frequent Contributor
timestamp: April 30, 2015, 03:21:13 am
content: Quote from: ttt on April 30, 2015, 01:17:42 amEh?Easier to use the 'size' program (or whatever it's called for your toolchain):Code:$ ls -l build/tiva.elf-rwxr-xr-x 1 andy staff 1257825 Apr 29 20:07 build/tiva.elf$ arm-none-eabi-size build/tiva.elftextdatabssdechexfilename2021941004244482276463793ebuild/tiva.elfIn this example, 'text' is the size of the read only code that goes in flash. 'data' is the size of static variables that are initialized to something other than zero. 'bss' is the size of static variables that are initialized to zero. So, the static RAM usage of this program is 24448+1004 bytes.Subtract that number from the amount of RAM you have to work with and you'll get a decent idea of "free RAM". Of course, you'll have to take into account your linker map, thread stacks, etc.If you want to calculate how much stack space you're using, a good way is to initialize the entire block of RAM that your stack can use to some obvious sentinel value (e.g., 0xAAAA5555). Then scan the block starting from the lowest address until you find a value other than the sentinel. If you're running an RTOS, you may need to hack the kernel. It's best to do the scan after you've exercised the program in ways that will consume the most stack.

author: ttt
author_rank: Regular Contributor
timestamp: April 30, 2015, 05:42:52 am
content: Quote from: andyturk on April 30, 2015, 03:21:13 amLPCexpresso actually prints this out in the build log every time you build. I've never found it reliable enough to figure out the actual high address though, especially if you end up using large aligned structures (like those needed for DMA).

author: Jeroen3
author_rank: Super Contributor
timestamp: April 30, 2015, 06:59:40 am
content: You should export stack and heap base/limit symbols from the startup file. If you want to now it runtime.Otherwise you just read the linker map file.

author: zapta
author_rank: Super Contributor
timestamp: April 30, 2015, 07:54:31 am
content: Quote from: Jeroen3 on April 30, 2015, 06:59:40 amThis one seems to contain the top of the heap and grows when I allocate using 'new'.extern uint32_t __end_of_heap;Can you confirm that this is indeed the top of the heap?

author: Jeroen3
author_rank: Super Contributor
timestamp: April 30, 2015, 09:10:26 am
content: Heap is managed in the C(++) runtime environment. I was unable to find a actual pointer of some kind to use to determine heap usage (with rcvt C). But you do know the heap base and heap limit, because you've defined those.You can get the actual stack usage(s) from the stack pointer(s). And you also know the base and limits of the stack(s).But there is no reason to know free memory imho, especially for an M0. If the program links without failure, it fits. Simply because the stack and heap and statically allocated, as are the globals/statics. All locals exist on stack, or whatever strategy the compile uses. You, the programmer, should only check for stack overflows. The linker can only predict the worst-case stack usage for each routine in the map file (callgraph). This is a nice guideline for the stack size.I do not know how to generate that callgraphs for gcc. Google surely does.

author: nctnico
author_rank: Super Contributor
timestamp: April 30, 2015, 09:47:23 am
content: Quote from: ttt on April 30, 2015, 01:17:42 amActually letting the linker create a map file makes an easier read. One of the tricks I used in the past is to sample the stack pointer in the timer interrupt and record the lowest value. Compare that with the highest RAM address and you know how much stack space is left. I don't know how that would work for C++ if you have objects which are created during runtime.

author: Jeroen3
author_rank: Super Contributor
timestamp: April 30, 2015, 09:52:18 am
content: I actually made a little tool the ease the reading of linker map file.https://github.com/Jeroen6/MapViewerIt only works for the ARM Compiler 5.

author: zapta
author_rank: Super Contributor
timestamp: May 01, 2015, 02:03:44 am
content: Quote from: ttt on April 30, 2015, 02:48:52 amThe above code gave me a warning about suppressed register variable read/writes.I ended up using this and I think the result is correct. Also single stepped it with a hardware debugger.Code:extern uint32_t __end_of_heap;uint32_t estimateStackFreeSize() {uint32_t dummy;return reinterpret_cast<uint32_t>(&dummy) - __end_of_heap;}

author: nctnico
author_rank: Super Contributor
timestamp: May 01, 2015, 11:06:28 am
content: That is also a method. But you are pushing the limits even further by adding something to the stackOff topic: how is C++ working on the LPC11U35? Using C++ on a microcontroller has been on my todo list for a long time.

author: zapta
author_rank: Super Contributor
timestamp: May 02, 2015, 12:19:35 am
content: Quote from: nctnico on May 01, 2015, 11:06:28 amIt's an estimation only, I will make sure to leave a few hundred bytes margin anyway.C++ works great, I use compile time features such as name spaces and run time feature such as virtual method and no complain whatsoever.