Loading a 320x240 bmap

Hi all,

I am trying to add a loading image to my project and wanted to add a ‘loading’ screen to it. To do that I took a 320x240 bmp file and converted it using the online converter to both a tru colour and 8bit image.

When I try to use is as true colour I immediately run into an out of memory error as I believe it is trying to load the entire 150kb image into RAM at once while I only have about 100kb total available.

If I instead try to use the 8bit colour version, it does load but seems to permenantly take up the full 77kb of memory and I cannot seem to free it even by setting variables to None an gc.collect() calls. In addition to this the colours are very wrong but that is a secondary issue.

Is there a way to load the image slowly as it is displayed and then removed from memory afterwards?

Boot file:

import machine
import ili9XXX
import lvgl as lv

disp = ili9XXX.ili9341(spihost=2, miso=19, mosi=23, clk=18, cs=2, dc=12, rst=4, rot=ili9XXX.LANDSCAPE, width=320, height=240)

with open('/images/scuba_snake_8bit.bin') as f:
  img_data = f.read()

scr = lv.obj()

img = lv.img(scr)
img_dsc = lv.img_dsc_t(
        "header": {"always_zero": 0, "w": 320, "h": 240, "cf": lv.img.CF.INDEXED_8BIT},
        "data_size": len(img_data),
        "data": img_data,


# Load the screen and display image

images.zip (65.9 KB)

LVGL tries to cache loaded images to speed up re-rendering. Try clearing this image out of the cache with lv.img.cache_invalidate_src(img_dsc).

Hi @embeddedt

I have just tried adding that in after displaying the image but have not seen any freeing of memory, I am still left with only ~20kb free

I believe the image has to stay in memory while it’s attached to an image object; I’m not sure that you can remove it after rendering until you delete that image object.

@embeddedt is there any way to just do a single push of the image to the display then so that it stays until a flush / overwritten without staying in memory? I have done it on the past with a custom driver for an ILI9341 display but don’t recall an option to do so with the lvgl driver.

Unfortunately LVGL doesn’t have a built-in facility for doing something like that, as it generally expects to have full control of what’s being displayed.

However, you could do this by manually copying the image to the display and calling lv.obj.invalidate(lv.scr_act()) when you want LVGL to take over again.

You should imho be able to dump the raw image into the ili driver by calling its flush function yourself. You’d probably have to copy your image in chunks into buf1 of the ili9xxx driver so flush can access the buffer via dma. Since you want to use small chunks, anyway, this woudn’t hurt.

1 Like

I have done some more testiung on this and have looked into using a PNG and decoding (as described here: MicroPython Images) but that also seems to cause memory issues when trying to display the image. I have also looked at flush but it doesnt apear to be able to take an image input but rather a single colour.

IMHO flush takes the native raw data your display uses. E.g. 16 bit 565 RGB in my case of a 320*240 ili9341.

I have written a super class that inherits from the ILI9341 class with an additional function to write a Bin file. I am still having prolems with colours but I think that is down to the conversion to RGB565, I used the online tool but they are still wrong

Wrong colors might be related to the fact that low and high bytes are swapped with LV_COLOR_16_SWAP enabled.

@minyiky do you think a Micropython API for lv_lib_split_jpg library could be useful for your use case?

1 Like

Ahh thank you, such a simple thing to miss, it is now working properly