9 years, 2 months ago.

NRF51822 Heap can not be fully used

Hi There,

I have a really weird prolem and i hope someone can help. mbed uses the shared memory model:

quote from mbed Handbook

     +--------+   Last Address of RAM
      | Stack  |
      |   |    |
      |   v    |
      +--------+
RAM   |        |
      |        |
      +--------+
      |   ^    |
      |   |    |
      | Heap   |
      +--------+
      |   ZI   |
      +--------+
      |   RW   |  
      +========+  First Address of RAM
      |        |
Flash |        |

In case of the NRF51822 we have 16kB of ram, where the first 8kB are reserved for the soft device (can be seen in the linker file, where the ram region 0x20002000 to 0x20004000 is available for the application). what I would expect is, when my application uses nkB for Stack, ZI, RW I have (8-n)kB available for the heap. Unfortunaterly this seems not to be the case. I have written a small program:

Import programHeap_Test

Test program to fill up the heap

with this simple code:

main.cpp

#include "mbed.h"

volatile uint8_t* heap_tester;

int main(void)
{
 while(true)
 {
   heap_tester = new uint8_t;
 }
}

where you can see that the stack is used down to the address 0x20003FA8 and you can watch the heap increase (=> heap_tester gets the pointer to the allocated memory within the heap) but only until 0x20003200! after that the program hangs somewhere in _ttywrch and if you step in the debugger disassembler you can see that the new fails to allocate new memory (_heap_full is called after).

I have also tried to init the ram with a magic pattern, to see if something uses the area between 0x20003200 and 0x20003FA8, but it always remains as initialised.

Does someone has an explanation to this, or is there a bug somewhere?

Thanks, Jonas

1 Answer

9 years, 2 months ago.

First of all, I think this is related: http://developer.mbed.org/forum/bugs-suggestions/topic/4809/

That is only relevant for targets compiled using ARM instead of micro-ARM. Which looking at targets.py seems to include the NRF51822, while with its size it would make alot more sense to me to use the smaller micro-ARM. Someone should look at that tbh.

Now regular ARM compiler seems to have a rather large safety margin between heap and stack (possibly because while heap checks for collision, stack does not. So it is nice if your heap refuses an allocation to prevent memory corruption, but not if your next stack increase happily overwrites heap space, but the margin is really large).

Now my personal opinion is that for the average MCU program it should either fit, or not fit. And if it doesn't fit it is going to crash horribly, regardless if the heap allocation nicely returns NULL or not. So returning NULL if it doesn't (malloc does that btw, new just crashes as you see) is nice for debugging, but not really required. (This because you cannot check every variable you allocate if there is still memory, but considering in your current situation it crashes anyway I don't think it matters if it crashes due to memory corruption or because it thinks there is no memory).

Now if you agree on that, what I assume will work (this is if I am correct that it is the same issue as in that topic):

#pragma import __use_two_region_memory

This makes the compiler think heap and stack are on independent memories, so heap/stack colission detection is completely removed! Now it is not hard to check yourself if heap and stack collided, but anyway, something to try out :).

@Jonas, can you run, t here are some programs, like in the post Erik shared, to print the output of when exactly heap gets full and share the output with us

posted by Martin Kojtal 13 Jan 2015

Hi Martin, i used the program and get the following output:

Start
i is at 536887272
Mallocced 1024 bytes at 536882800, diff = 4468
Mallocced 1024 bytes at 536883832, diff = 3436
Mallocced 1024 bytes at 536884864, diff = 2404
Mallocced 1024 bytes at 0, diff = 536887268
SP = 536887264

after adding the

#pragma import __use_two_region_memory 

i get:

Start
i is at 536887272
Mallocced 1024 bytes at 536882792, diff = 4476
Mallocced 1024 bytes at 536883824, diff = 3444
Mallocced 1024 bytes at 536884856, diff = 2412
Mallocced 1024 bytes at 536885888, diff = 1380

it seems to crash (obviously by corrupting the stack), but I can allocate more Memory than before :)

posted by Jonas Gartmann 26 Jan 2015