This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSP430F5438a Malloc() Error



Hi,

I have firmware that cycles through a linked list of events. Each event has an unsigned int capture/compare value and a pointer to a function. Using Timer_A0 interrupt, the linked list executes the function, cycles to the next node in the list, updates Timer_A0 to the next capture/compare value, and then deletes the node.

I have a loop that constantly adds events to the linked list and it allocates memory for the events using malloc. 

I noticed that only 1 out of 3 of the calls to malloc actually succeeds. It follows a pattern of Success, Fail, Fail, Success, Fail, Fail, etc...

Each Node has 3 pointers, an unsigned int, and an unsigned char (so a total of 9 bytes right?)

Can anyone explain why these calls to malloc are failing?

Thanks,

Seth Berggren

  • OK,

    With a little bit more debugging I found out that the first 17 malloc calls succeed. Then it fails until an event occurs and a node is freed. Then it will succeed once and then fail several times again.

    I reduced the size of the struct to 3 pointers and 1 unsigned int (8 bytes). Is there really only enough memory available for 17*8 = 136 bytes? (There is 6 bytes of data upon compilation, so maybe 142 bytes)

    I thought there was more space on the heap than this. Can anyone explain this?

    Thanks,

    Seth Berggren

  • Seth Berggren said:
    Can anyone explain why these calls to malloc are failing?

    Because you malloc- memory from main loop but free it in the ISR. Imagine what happens when ISR fires while malloc call in progress? - Yes, anything can happen. So you have to make malloc wrapper function (safemalloc?) which disables global interrupts before malloc call and enables after.

     Actually using dynamic memory in small embedded systems is... how to say... not recommended.

  • I dont free it in ISR. All the ISR does is set a flag. That flag gets periodically serviced by the main loop.

    The ISR is not the problem, it is one line.

  • Seth Berggren said:
    All the ISR does is set a flag.

    I have no idea then. But I can suggest to read this:

    http://www.design-reuse.com/articles/25090/dynamic-memory-allocation-fragmentation-c.html

  • Seth Berggren said:
    Using Timer_A0 interrupt, the linked list executes the function, cycles to the next node in the list, updates Timer_A0 to the next capture/compare value, and then deletes the node.

    You hopefully do not execute the funciton from inside the ISR, do you?

    Well, about malloc, malloc allocaes memory from the heap. Normally, the heap is the free, unused area from above the global variables to the bottom of the stack. Or, on bigger systems, the heap is dynamically expanded into virtual memory.
    However, on the MSP, the resources like ram are limited. Between the global vars (and local static vars) and the stack, there is not that much ram left, and it is a varying amount.

    So you defien the amount of heap (and stack) you need in the poroject settings and the linker (which cannot know anything about stack growth or synamic memory allocation) can give you a linker error if there isn't that much left.

    The default for the reserved stack size (which will be totally ignored by the CPU, of course, as the stack will grow as the stack needs) is somewhere around 80 bytes, and the default heap size si also specified in the projec tsettings. But other than the stack, the heap really won't grow beyond this. Now the 5438 has whopping 16k of ram, ye tthe default stack size is still only a few hundred bytes. You can raise the maximum (and minimum, as this value is reserved as a monolithic block) of the heap in the project settings. The reserved space then is of course lost in a whole for other purposes. Just like assigning a large global array.
    Well, dynamic memory allocation doesn't make too much sense. You cannot allocate more than what is there, so you can already go for the worst case and statically allocate the memory, e.g. an arra yof your event structs. And fill it like a cyclic buffer. Not to mention the spee dgain if you don't have to look for free memory blocks on teh heap on each malloc.

    Seth Berggren said:
    Each Node has 3 pointers, an unsigned int, and an unsigned char (so a total of 9 bytes right?)
    No. Structures that contain int or long int members (or pointers) are always padded to an even size. This is because you couldn't put them into an array with an odd length - access to their int members would be impossible (or at least very inefficient) when they are not aligned to an even memory address. Which would happen for every second struct in the array if it had an odd size.
    So structs that contain other (larger) members tan char are always padded with an (invisible) char to an even length.
    Also, malloc and (specially free) have organizational overhead. Then for every allocated memory block, information about its size needs to be stored somewhere (usually right before the allocated memory). So the allcoaitons blocks form sort of a linked list themselves. So each struct with 9 bytes of allocates ram uses 12 bytes of ram. (on a PC, the organizational data is a whole segment of 16 bytes, not only two for the block length as on the MSP. And aligned to 16 byte borders.)

  • Wow, very helpful. Thanks. (I don't execute any code in the ISR, my ISR is one line of code)

    I will go with the method of defining a static array of structs. This makes a lot more sense and is faster than malloc.

    I am a little bit confused about the padding of the struct. Pointer and int types are 2 bytes, which is an even size right?

    Thanks,

    Seth Berggren

  • Seth Berggren said:
    I am a little bit confused about the padding of the struct. Pointer and int types are 2 bytes, which is an even size right?

    Yes, but the final char is not. If the struct size were 9, then an array of these structs would have the first array element beginning on an even address, the next on an odd (and therefore the pointers and ints in the struct beginning on an odd address).
    Now the MSP can do 16 bit operations only on even addresses. When you use a 16 bit operation, the LSB of the source or target address is silently ignored. If an int woul dbe on, say, 0x1001, the processor would read 0x1000/0x1001 instead of 0x1001/0x1002.
    This is important to know if you receive structs in a ring buffer where they do not necessarily begin at an even address. AN older version of MSPGCC did access hte members wrong in this case, whiel a newer one notices that the alignment is not ensured and composes all 16 bit struc tmembers by two 8 bit reads and a swap and OR operation. Which is by a factor of 4 (a tleast) slower.
    To avoid this overhead, the compiler will automatically add invisible padding member bytes to a struct so that its total size as well as the offset of every 16/32 bit member of the struct is an even value. If the struct has only byte-sized members, then this won't happen. Structs with byte-sized members only can have an odd size.

**Attention** This is a public forum