Difference between linker script's "HEAP SIZE" and BSP's "TOTAL_HEAP_SIZE"

almomo1 wrote on Wednesday, September 26, 2018:

Hi,

I’m new in the forum because I’m currently developing my fist FreeRTOS application; it runs on a Xilinx’s Microblaze over a Kintex FPGA and a custom board. SDK (eclipse environment for Xilinx) allows to change some kernel parameters in the BSP, such as TOTAL_HEAP_SIZE.

My application running over FreeRTOS needs a relative big heap which is allocated in 512Mbyte DDR3 RAM. I want to allocate 1Mbyte for heap, and the rest (511 MByte) for data buffers (mainly for DMAs).

Where should I set the 1MByte value, in the linker script “HEAP SIZE” field or in the BSP property “Total_Heap_Size”?

According to FreeRTOS documentation, “Total_Heap_Size” is the amount of memory FreeRTOS will use when allocating memory dinamically (malloc). So then, what’s “HEAP_SIZE” in linker script useful for?

What’s the difference between both parameters?

Thanks!

almomo1 wrote on Wednesday, September 26, 2018:

Ok, I checked where variables are allocated in memory and figured out the answer:

  • TOTAL_HEAP_SIZE is memory allocated to the FreeRTOS kernel, which is used internally to create semaphores, tasks, queues, etc. and can’t be user by the application. As it is statically created, it is allocated in bss section.

  • Linker script’s “Heap Size” is memory allocated to the application through malloc calls. In my application, that is DD3 RAM.

I got confused by figure 7 in book “Mastering the FreeRTOS RealTime Kernel - A Hands-On Tutorial Guide”, where you can see how user data is allocated into kernel’s heap, which still doesn’t make sense to me.

richarddamon wrote on Wednesday, September 26, 2018:

With FreeRTOS, unless you are using heap3.c for FreeRTOS heap management, there are possibly two heaps in the system. One is the standard C heap, which is what the linker script setting controls, this will control the memory available by malloc() and famiy. The second is the heap managed by thr FreeRTOS heap function for the use of FreeRTOS, and any application the uses the calls to the FreeRTOS heap. That size is controlled by TOTAL_HEAP_SIZE.

If you application make use of malloc(), then I would suggest, using heap3 or a variant of it. One issue is that normally out of the box, malloc() isn’t thread safe, so either you need to in code guards around malloc() (in which case it might be easier just to call the FreeRTOS heap functions) or find the hooks within the implementation of malloc() and family (if available) that can make them thread safe. If you do the latter, then it make sense to use a variant of heap3 that just directly calls malloc and lets them do all the work and avoid the split heap.

almomo1 wrote on Monday, October 01, 2018:

Xilinx’s SDK sets heap_4.c as default heap manager, and don’t think if I can change that: when BSP is reloaded, default configuration is applied, so heap_4.c is included again.
If I call FreeRTOS mallocs, where is the memory allocated, standard C heap or FreeRTOS heap? I think it will be allocated in FreeRTOS heap, but just to be sure.

Thanks for your answer.

richarddamon wrote on Monday, October 01, 2018:

First, you most certainly can change it, if the SDK doesn’t provide an option for this, you can just manually delete heap_4.c from the project and add in heap_3.c, perhaps from a clean copy of FreeRTOS copied into your project. You may need to redo this every time you regenerate the project via the tool.

If you call pvPortMalloc() you will get memory from the FreeRTOS heap, the amount of which is controlled by configAPPLICATION_ALLOCATED_HEAP in FreeRTOSConfig.h, if you call malloc(), you will use the system provided malloc() function (which might not be thread safe) whose size is generally controlled by linker parameters. Only if pvPortMalloc() calls malloc() itself will these be the same heap.

If the application has code that MUST call malloc (typically because some third party or using parts of the system library use it), it makes sense to try and make malloc thread safe and make everything use it. This requires some knowledge of the library structure. Some standard libraries provide a call back that can be used to make the heap functions thread safe, in other cases you may be able to replace malloc/free with thread safe version (perhaps calling pvPortMalloc, provided you don’t need realloc support), but for this you need to know if malloc defers to something deeper that perhaps parts of the library uses.

rtel wrote on Monday, October 01, 2018:

Richard D - there are two ways of using FreeRTOS with the Xilinx SDK - the first is to use a FreeRTOS BSP and the second is to use a ‘standalone’ BSP. The latter case is what you are used to - you manually add the FreeRTOS files into the project as any other source file and the BSP only includes drivers. In the former case the FreeRTOS source files are added to the project automatically as part of the BSP along with the dirvers - in which case the files that are included are actually defined by a TCL script inside the Xilinx tools installation directory. Both FreeRTOS and the drivers are configured using a graphical wizard - as I recall the size of the malloc() (as opposed to the FreeRTOS pvPortMalloc()) heap is set in the tools options somewhere.

almomo1 wrote on Tuesday, October 02, 2018:

Yes, you’re right. I use the former case, I use the tool-asisted FreeRTOS BSP, and I’m sure Xilinx’s SDK restores BSP files each time you re-generate the project (it does with driver files too). Unfortunately, re-generation must be done each time bitstream changes, and that happens often during developing phase.
Furthermore, some defines such as configAPPLICATION_ALLOCATED_HEAP can’t be changed in FreeRTOSConfig.h because it is back to its default value after regenerating.
Thank you both for your help; I solved the initial problem by separating kernel’s heap into fast BRAM memory (allocated in BSS) and program heap into slower DDR3. I use malloc before creating any thread to allocate a big memory pool in DDR3, so I don’t have to pay attention to thread-safe implementation of malloc, as no reallocs have to be done on runtime.