How to implement / link Lvgl custom external malloc in ESP-IDF

What do you want to achieve?

I want to create custom functions for Lvgl memory allocator and that compilation and linking work.

What have you tried so far?

I downloaded Lvgl from “ESP Component Registry”.

In esp-idf menuconfig, inside Lvgl component config , i select the option “implement the function externally” in “Malloc functions source”.

I created the malloc families functions inside my components folder in my project folder.
C:\esp32-Proj\proj\components\lv_mem_custom_alloc\src\include\lv_mem_custom_alloc.h
C:\esp32-Proj\proj\components\lv_mem_custom_alloc\src\lv_mem_custom_alloc.c
C:\esp32-Proj\proj\components\lv_mem_custom_alloc\CMakeLists.txt

Lvgl folder stay located in managed_components folder inside my project folder.
C:\esp32-Proj\proj\managed_components\lvgl__lvgl

I tried using inline functions too in a .h file, but no luck.

When compiling project, at linker stage, the linker show undefined reference to.

Doubts

How do I get lvgl to recognize(link) my components folder (subfolder inside components folder) ?
C:\esp32-Proj\proj\components\lv_mem_custom_alloc

What are all the functions that need to be defined, which ones are mandatory, and how do I define / write mem_init() if needed ?
There’s a memory_init() function that I’m not sure it is necessary. I think only malloc(), realloc() and free() would be needed, but it seems I need to define other functions as well.

Is there any documentation on how to do this ?

Code to reproduce

lv_mem_custom_alloc.h file:

void* lv_malloc_core(size_t size);
void* lv_realloc_core(void* ptr, size_t size);
void lv_free_core(void* ptr);

lv_mem_custom_alloc.c file:

void* lv_malloc_core(size_t size)
{
    return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT, MALLOC_CAP_SPIRAM);
}

void* lv_realloc_core(void* ptr, size_t size)
{
    return heap_caps_realloc_prefer(ptr, size, 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT, MALLOC_CAP_SPIRAM);
}

void lv_free_core(void* ptr)
{
    heap_caps_free(ptr);
}

Notes:

  • The project is running (without custom memory allocator), but sometimes, i think, that “normal” allocator cannot allocate memory, and the system crash or the task running lvgl crash.
  • Bot Challenge

Environment

ESP32-S3
ESP-IDF 5.5.3 with visual studio code
LVGL 9.4.0
Custom board.

It seems that this solved it (It compiled and linked, but I haven’t tested it on the hardware yet).

Necessary functions (only .c file, the function interface(.h file), the lvgl library already provides):
lv_malloc_core()
lv_realloc_core()
lv_free_core()
lv_mem_init()

Optional functions (only .c file, the function interface(.h file), the lvgl library already provides):
lv_mem_monitor_core() // I left a comment in my source code.
lv_mem_test_core() // I left a comment in my source code.

Note:
lv_mem_init() only needs to be declared empty for compilation, since heap initialization is provided by esp-idf.

I don’t know if all the steps below are necessary, but this is how it worked.

  1. In your component’s CMakeLists.txt file (the one containing the memory functions), add:
  2. Define Visibility as INTERFACE
    If your component provides the functions that LVGL uses, it needs to export those definitions. In your component’s CMakeLists.txt file under components:

idf_component_register(
SRCS “your_memory.c”
INCLUDE_DIRS “include”
// Forces the linker to include all the functions of this component.
// even if no one explicitly calls them in the main
WHOLE_ARCHIVE // I only added this to my idf_component_register because the rest I already had.
)

// This tells CMake: "Whoever uses me (or whoever the system links to)
// It needs to be linked to my memory functions.
target_link_libraries(${COMPONENT_LIB} INTERFACE “-u lv_malloc_core”)
target_link_libraries(${COMPONENT_LIB} INTERFACE “-u lv_realloc_core”)
target_link_libraries(${COMPONENT_LIB} INTERFACE “-u lv_free_core”)

#target_link_libraries(${COMPONENT_LIB} INTERFACE “-u lv_mem_monitor_core”) // comment out
#target_link_libraries(${COMPONENT_LIB} INTERFACE “-u lv_mem_test_core”) // comment out

  1. Linking Order
    ESP-IDF links components in the order they appear. If LVGL requests malloc_custom and your component hasn’t yet been “seen” by the linker, it will throw an error.
    Add the following to the CMakeLists.txt file at the project root.

// It forces the linker to process its memory component before LVGL.
idf_build_set_property(LINK_COMPONENTS “lv_mem_custom_alloc” APPEND)

@Baldhead , Thank you for sharing your result. Is it possible to create a user guide for ESP-IDF?

I tested it on the hardware and it actually worked.

The Lvgl developers may utilize the text for documentation purposes if they so choose.