nex12345 wrote on Thursday, December 29, 2016:
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 _Min_Heap_Size
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
_Min_Heap_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(int32_t incr)
{
extern uint32_t _Min_Heap_Size; /* _Min_Heap_Size symbol defined in the linker script. */
extern uint8_t end asm("end");
const uint8_t *max_heap = (uint8_t*)((uint32_t)&end + (uint32_t)&_Min_Heap_Size);
static uint8_t *heap_end;
uint8_t *prev_heap_end;
if (heap_end == 0)
heap_end = &end;
prev_heap_end = heap_end;
if (heap_end + incr > max_heap)
{
// write(1, "Heap and stack collision\n", 25);
// abort();
errno = ENOMEM;
return (caddr_t) -1;
}
heap_end += incr;
return (caddr_t) prev_heap_end;
}
The collision detection fails obviously as _Min_Heap_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.