I spent another day looking at this issue. The issue is caused by a collision of heap and stack. TrueSTUDIO comes with two options: Dynamic heap size (default) and Fixed heap size. In projects where no RTOS is used Atollic recommends to use the dynamic option. This worked fine and I was able to solve above issue by this change for projects where FreeRTOS is not used.
However, for projects with FreeRTOS a dynamic heap size doesn’t seem to be an option. Out of the user guide:
If using an RTOS, it is recommended to generate a system calls file, and select
the Fixed Heap size option. This option requires that the MinHeapSize
symbol is defined in the linker script .ld file. The .ld file is stored in the root
directory of the currently selected project. The heap size defined by
_MinHeap_Size must meet the heap size required by the application.
The IDE automatically created a linker and a syscalls file. For the linker file it makes no difference whether dynamic or fix heap size has been selected – it looks the same in both cases. Here the interessting lines of the linker script:
~~~
/* Highest address of the user mode stack
/
_estack = 0x2001c000; / end of 112K RAM */
/* Generate a link error if heap and stack don’t fit into RAM
/
_Min_Heap_Size = 0; / required amount of heap
/
_Min_Stack_Size = 0x400; / required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 768K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 112K
MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
}
~~~
Heap size is 0 and stack size is 1K.
Is it somehow possible to calculate those values before building the application? Shall the minimal heap size be equal to the FreeRTOS config value configTOTAL_HEAP_SIZE?
The second auto generated file is the syscalls file. This file changes completely when you compare projects with dynamic heap size and fix heap size. I think the central part of this file is the implementation of the function
sbrk(int32t incr):
~~~
caddr
t _sbrk(int32t incr)
{
extern uint32
t _MinHeap
Size; /* _MinHeap
Size symbol defined in the linker script. */
extern uint8t end asm(“end”);
const uint8
t *maxheap = (uint8
t*)((uint32t)&end + (uint32
t)&Min
HeapSize);
static uint8
t *heapend;
uint8
t *prevheap_end;
if (heap
end == 0)
heapend = &end;
prev
heapend = heap
end;
if (heapend + incr > max
heap)
{
// write(1, “Heap and stack collisionn”, 25);
// abort();
errno = ENOMEM;
return (caddrt) -1;
}
heap_end += incr;
return (caddr
t) prevheap
end;
}
~~~
The collision detection fails obviously as _MinHeap_Size is 0. Unfortunately the application does not abort at this point but continues to run. The consequence was in my case that the pointer of a queue was overridden and invalid. I would prefer to enter an endless loop if application runs out of heap.
What do you think – does this make sense? Does the function itself make sense when used with FreeRTOS??
Thanks in advance for any help.