I looked into this a bit further and it looks like LVGL requires a lot of RAM in order to render text with the subpix option enabled. See the code in question here.
LVGL allocates two buffers of size glyph_width * glyph_height
. If the font is big enough, this may be a significantly large buffer. There seems to be a cap of _LV_MASK_BUF_MAX_SIZE
which is defined by default to 2048 bytes (see here).
That in theory should result into a max of 4 kB per glyph. However, the two buffers are not freed after rendering a letter, they are “released” in what seems to be another layer of abstraction on top of the heap.
For the next letter, LVGL tries to reallocate those two buffers but fails for some reason, must be fragmentation or something. See the following logs.
I’m tempted to open an issue on Github about this, because I think this should work having 8 kB of free RAM. If it’s not supposed to work, then at least there should be a note about this in the documentation.
// ---------------------------------------------------------------------------------------------------
// Label updated here
// ---------------------------------------------------------------------------------------------------
[Trace] (8.992, +9) lv_timer_handler: begin (in lv_timer.c line #69)
[Trace] (8.992, +0) lv_timer_handler: finished (1 ms until the next timer call) (in lv_timer.c line #144)
[Trace] (9.002, +10) lv_timer_handler: begin (in lv_timer.c line #69)
[Trace] (9.002, +0) lv_timer_exec: calling timer callback: 0x6001687d (in lv_timer.c line #312)
[Trace] (9.002, +0) _lv_disp_refr_timer: begin (in lv_refr.c line #184)
[Info] (9.002, +0) lv_obj_update_layout: Layout update begin (in lv_obj_pos.c line #311)
[Trace] (9.003, +1) event_send_core: Sending event 44 to 0x202089d4 with 0x202018a4 param (in lv_event.c line #405)
[Trace] (9.003, +0) event_send_core: Sending event 44 to 0x202089d4 with 0x202018ac param (in lv_event.c line #405)
[Trace] (9.003, +0) event_send_core: Sending event 41 to 0x202089d4 with 0x202018f8 param (in lv_event.c line #405)
[Trace] (9.004, +1) event_send_core: Sending event 34 to 0x20208878 with 0x202089d4 param (in lv_event.c line #405)
[Trace] (9.004, +0) event_send_core: Sending event 44 to 0x202089d4 with 0x20201894 param (in lv_event.c line #405)
[Trace] (9.004, +0) event_send_core: Sending event 44 to 0x202089d4 with 0x20201894 param (in lv_event.c line #405)
[Trace] (9.004, +0) event_send_core: Sending event 44 to 0x20208878 with 0x2020182c param (in lv_event.c line #405)
[Trace] (9.005, +1) event_send_core: Sending event 44 to 0x20208878 with 0x2020182c param (in lv_event.c line #405)
[Trace] (9.005, +0) lv_obj_update_layout: Layout update end (in lv_obj_pos.c line #314)
[Info] (9.005, +0) lv_obj_update_layout: Layout update begin (in lv_obj_pos.c line #311)
[Trace] (9.005, +0) event_send_core: Sending event 44 to 0x202089d4 with 0x202018a4 param (in lv_event.c line #405)
[Trace] (9.005, +0) event_send_core: Sending event 44 to 0x202089d4 with 0x202018ac param (in lv_event.c line #405)
[Trace] (9.005, +0) lv_obj_update_layout: Layout update end (in lv_obj_pos.c line #314)
[Trace] (9.006, +1) event_send_core: Sending event 18 to 0x20208878 with 0x202018a8 param (in lv_event.c line #405)
[Trace] (9.006, +0) event_send_core: Sending event 20 to 0x20208878 with 0x20201878 param (in lv_event.c line #405)
[Trace] (9.006, +0) event_send_core: Sending event 21 to 0x20208878 with 0x20201878 param (in lv_event.c line #405)
[Trace] (9.006, +0) event_send_core: Sending event 26 to 0x20208878 with 0x202016c8 param (in lv_event.c line #405)
[Trace] (9.008, +2) event_send_core: Sending event 27 to 0x20208878 with 0x202016c8 param (in lv_event.c line #405)
[Trace] (9.008, +0) event_send_core: Sending event 22 to 0x20208878 with 0x20201878 param (in lv_event.c line #405)
[Trace] (9.008, +0) event_send_core: Sending event 20 to 0x202089d4 with 0x20201830 param (in lv_event.c line #405)
[Trace] (9.008, +0) event_send_core: Sending event 21 to 0x202089d4 with 0x20201830 param (in lv_event.c line #405)
[Trace] (9.008, +0) event_send_core: Sending event 26 to 0x202089d4 with 0x20201620 param (in lv_event.c line #405)
[Trace] (9.008, +0) event_send_core: Sending event 27 to 0x202089d4 with 0x20201620 param (in lv_event.c line #405)
[Warn] (9.008, +0) lv_draw_label: lv_draw_label: start
(in lv_draw_label.c line #250)
[Trace] (9.009, +1) lv_mem_monitor: begin (in lv_mem.c line #239)
[Trace] (9.009, +0) lv_mem_monitor: finished (in lv_mem.c line #253)
[Warn] (9.009, +0) draw_letter_subpx: lv_draw_letter: start (in lv_draw_label.c line #644)
[Warn] (9.009, +0) draw_letter_subpx: used: 4256 ( 35 %), frag: 0 %, biggest free: 8032 (in lv_draw_label.c line #645)
[Trace] (9.009, +0) lv_mem_buf_get: begin, getting 2001 bytes (in lv_mem.c line #266)
[Trace] (9.009, +0) lv_mem_realloc: reallocating 0 with 2001 size (in lv_mem.c line #184)
[Trace] (9.009, +0) lv_mem_realloc: allocated at 0x20208b18 (in lv_mem.c line #203)
[Trace] (9.009, +0) lv_mem_buf_get: allocated (buffer id: 0, address: 0x20208b18) (in lv_mem.c line #304)
[Trace] (9.009, +0) lv_mem_buf_get: begin, getting 2001 bytes (in lv_mem.c line #266)
[Trace] (9.009, +0) lv_mem_realloc: reallocating 0 with 2001 size (in lv_mem.c line #184)
[Trace] (9.009, +0) lv_mem_realloc: allocated at 0x202092f0 (in lv_mem.c line #203)
[Trace] (9.009, +0) lv_mem_buf_get: allocated (buffer id: 1, address: 0x202092f0) (in lv_mem.c line #304)
[Trace] (9.010, +1) lv_mem_buf_release: begin (address: 0x20208b18) (in lv_mem.c line #320)
[Trace] (9.010, +0) lv_mem_buf_release: begin (address: 0x202092f0) (in lv_mem.c line #320)
[Trace] (9.010, +0) lv_mem_monitor: begin (in lv_mem.c line #239)
[Trace] (9.010, +0) lv_mem_monitor: finished (in lv_mem.c line #253)
[Warn] (9.010, +0) draw_letter_subpx: lv_draw_letter: finish (in lv_draw_label.c line #845)
[Warn] (9.010, +0) draw_letter_subpx: used: 8272 ( 68 %), frag: 0 %, biggest free: 4016 (in lv_draw_label.c line #846)
[Trace] (9.010, +0) lv_mem_monitor: begin (in lv_mem.c line #239)
[Trace] (9.010, +0) lv_mem_monitor: finished (in lv_mem.c line #253)
[Warn] (9.010, +0) draw_letter_subpx: lv_draw_letter: start (in lv_draw_label.c line #644)
[Warn] (9.010, +0) draw_letter_subpx: used: 8272 ( 68 %), frag: 0 %, biggest free: 4016 (in lv_draw_label.c line #645)
[Trace] (9.010, +0) lv_mem_buf_get: begin, getting 1914 bytes (in lv_mem.c line #266)
[Trace] (9.010, +0) lv_mem_buf_get: returning already allocated buffer (buffer id: 0, address: 0x20208b18) (in lv_mem.c line #288)
[Trace] (9.010, +0) lv_mem_buf_get: begin, getting 1914 bytes (in lv_mem.c line #266)
[Trace] (9.010, +0) lv_mem_buf_get: returning already allocated buffer (buffer id: 1, address: 0x202092f0) (in lv_mem.c line #288)
[Trace] (9.011, +1) lv_mem_buf_release: begin (address: 0x20208b18) (in lv_mem.c line #320)
[Trace] (9.011, +0) lv_mem_buf_release: begin (address: 0x202092f0) (in lv_mem.c line #320)
[Trace] (9.011, +0) lv_mem_monitor: begin (in lv_mem.c line #239)
[Trace] (9.018, +0) lv_mem_buf_release: begin (address: 0x20209b04) (in lv_mem.c line #320)
[Trace] (9.018, +0) lv_mem_buf_get: begin, getting 128 bytes (in lv_mem.c line #266)
[Trace] (9.019, +1) lv_mem_buf_get: returning already allocated buffer (buffer id: 2, address: 0x20209b04) (in lv_mem.c line #288)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x20209b04) (in lv_mem.c line #320)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 256 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 256 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: returning already allocated buffer (buffer id: 1, address: 0x202092f0) (in lv_mem.c line #288)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x202092f0) (in lv_mem.c line #320)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x20209b04) (in lv_mem.c line #320)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 128 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: returning already allocated buffer (buffer id: 2, address: 0x20209b04) (in lv_mem.c line #288)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x20209b04) (in lv_mem.c line #320)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 256 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 256 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: returning already allocated buffer (buffer id: 1, address: 0x202092f0) (in lv_mem.c line #288)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x202092f0) (in lv_mem.c line #320)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x20209b04) (in lv_mem.c line #320)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 128 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: returning already allocated buffer (buffer id: 2, address: 0x20209b04) (in lv_mem.c line #288)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x20209b04) (in lv_mem.c line #320)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 256 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: begin, getting 256 bytes (in lv_mem.c line #266)
[Trace] (9.019, +0) lv_mem_buf_get: returning already allocated buffer (buffer id: 1, address: 0x202092f0) (in lv_mem.c line #288)
[Trace] (9.019, +0) lv_mem_buf_release: begin (address: 0x202092f0) (in lv_mem.c line #320)
// ---------------------------------------------------------------------------------------------------
// Label updated here
// ---------------------------------------------------------------------------------------------------
[Trace] (9.054, +9) lv_timer_handler: begin (in lv_timer.c line #69)
[Trace] (9.054, +0) lv_timer_exec: calling timer callback: 0x6001687d (in lv_timer.c line #312)
[Trace] (9.054, +0) _lv_disp_refr_timer: begin (in lv_refr.c line #184)
[Info] (9.055, +1) lv_obj_update_layout: Layout update begin (in lv_obj_pos.c line #311)
[Trace] (9.055, +0) event_send_core: Sending event 44 to 0x202089d4 with 0x202018a4 param (in lv_event.c line #405)
[Trace] (9.055, +0) event_send_core: Sending event 44 to 0x202089d4 with 0x202018ac param (in lv_event.c line #405)
[Trace] (9.055, +0) lv_obj_update_layout: Layout update end (in lv_obj_pos.c line #314)
[Trace] (9.055, +0) event_send_core: Sending event 18 to 0x20208878 with 0x202018a8 param (in lv_event.c line #405)
[Trace] (9.056, +1) event_send_core: Sending event 20 to 0x20208878 with 0x20201878 param (in lv_event.c line #405)
[Trace] (9.056, +0) event_send_core: Sending event 21 to 0x20208878 with 0x20201878 param (in lv_event.c line #405)
[Trace] (9.056, +0) event_send_core: Sending event 26 to 0x20208878 with 0x202016c8 param (in lv_event.c line #405)
[Trace] (9.058, +2) event_send_core: Sending event 27 to 0x20208878 with 0x202016c8 param (in lv_event.c line #405)
[Trace] (9.058, +0) event_send_core: Sending event 22 to 0x20208878 with 0x20201878 param (in lv_event.c line #405)
[Trace] (9.058, +0) event_send_core: Sending event 20 to 0x202089d4 with 0x20201830 param (in lv_event.c line #405)
[Trace] (9.058, +0) event_send_core: Sending event 21 to 0x202089d4 with 0x20201830 param (in lv_event.c line #405)
[Trace] (9.058, +0) event_send_core: Sending event 26 to 0x202089d4 with 0x20201620 param (in lv_event.c line #405)
[Trace] (9.058, +0) event_send_core: Sending event 27 to 0x202089d4 with 0x20201620 param (in lv_event.c line #405)
[Warn] (9.058, +0) lv_draw_label: lv_draw_label: start
(in lv_draw_label.c line #250)
[Trace] (9.059, +1) lv_mem_monitor: begin (in lv_mem.c line #239)
[Trace] (9.059, +0) lv_mem_monitor: finished (in lv_mem.c line #253)
[Warn] (9.059, +0) draw_letter_subpx: lv_draw_letter: start (in lv_draw_label.c line #644)
[Warn] (9.059, +0) draw_letter_subpx: used: 4256 ( 35 %), frag: 0 %, biggest free: 8032 (in lv_draw_label.c line #645)
[Trace] (9.059, +0) lv_mem_buf_get: begin, getting 2001 bytes (in lv_mem.c line #266)
[Trace] (9.059, +0) lv_mem_realloc: reallocating 0 with 2001 size (in lv_mem.c line #184)
[Trace] (9.059, +0) lv_mem_realloc: allocated at 0x20208b18 (in lv_mem.c line #203)
[Trace] (9.059, +0) lv_mem_buf_get: allocated (buffer id: 0, address: 0x20208b18) (in lv_mem.c line #304)
[Trace] (9.059, +0) lv_mem_buf_get: begin, getting 2001 bytes (in lv_mem.c line #266)
[Trace] (9.059, +0) lv_mem_realloc: reallocating 0 with 2001 size (in lv_mem.c line #184)
[Trace] (9.059, +0) lv_mem_realloc: allocated at 0x202092f0 (in lv_mem.c line #203)
[Trace] (9.059, +0) lv_mem_buf_get: allocated (buffer id: 1, address: 0x202092f0) (in lv_mem.c line #304)
[Trace] (9.060, +1) lv_mem_buf_release: begin (address: 0x20208b18) (in lv_mem.c line #320)
[Trace] (9.060, +0) lv_mem_buf_release: begin (address: 0x202092f0) (in lv_mem.c line #320)
[Trace] (9.060, +0) lv_mem_monitor: begin (in lv_mem.c line #239)
[Trace] (9.060, +0) lv_mem_monitor: finished (in lv_mem.c line #253)
[Warn] (9.060, +0) draw_letter_subpx: lv_draw_letter: finish (in lv_draw_label.c line #845)
[Warn] (9.060, +0) draw_letter_subpx: used: 8272 ( 68 %), frag: 0 %, biggest free: 4016 (in lv_draw_label.c line #846)
[Trace] (9.060, +0) lv_mem_monitor: begin (in lv_mem.c line #239)
[Trace] (9.060, +0) lv_mem_monitor: finished (in lv_mem.c line #253)
[Warn] (9.060, +0) draw_letter_subpx: lv_draw_letter: start (in lv_draw_label.c line #644)
[Warn] (9.060, +0) draw_letter_subpx: used: 8272 ( 68 %), frag: 0 %, biggest free: 4016 (in lv_draw_label.c line #645)
[Trace] (9.060, +0) lv_mem_buf_get: begin, getting 2048 bytes (in lv_mem.c line #266)
[Trace] (9.060, +0) lv_mem_realloc: reallocating 0x20208b18 with 2048 size (in lv_mem.c line #184)
[Trace] (9.060, +0) lv_mem_realloc: allocated at 0x20209ac8 (in lv_mem.c line #203)
[Trace] (9.060, +0) lv_mem_buf_get: allocated (buffer id: 0, address: 0x20209ac8) (in lv_mem.c line #304)
[Trace] (9.060, +0) lv_mem_buf_get: begin, getting 2048 bytes (in lv_mem.c line #266)
[Trace] (9.060, +0) lv_mem_realloc: reallocating 0x202092f0 with 2048 size (in lv_mem.c line #184)
[Error] (9.060, +0) lv_mem_realloc: couldn't allocate memory (in lv_mem.c line #199)
[Error] (9.060, +0) lv_mem_buf_get: Asserted at expression: buf != NULL (Out of memory, can't allocate a new buffer (increase your LV_MEM_SIZE/heap size)) (in lv_mem.c line #298)