Problem managing images

Hello,
I am developing a graphic interface with lvgl and micropython on a board based on rp2 pico using a ILI9341 monitor.
My graphic interface requires several images, I tried to use png files stored on filesystem with the decoder included in imagetools and it works fine up to 5 images, but when I try to add a 6th image I get a memory issue.
I tried then a different approach storing the image as binary codes in a frozen module, in this way all the images are loaded fine on the screen, but I got a different problem. Now when I unplug and replug the usb cable the device in not recognized: it is impossible to interact with it with Thonny or mpremote… The COM7 is not even visible anymore in Windows device manager.
Can anyone suggest a solution or at least point me in the right direction for further investigation?

Hello!
These are 2 different problems:

  1. PNG files on filesystem: these are decoded into RAM, so if you run out of RAM, then it will not load the rest. But theoretically these are decoded on-demand (and using caching), so I’m not sure about it. In some cases memory fragmentation could cause also memory issues, when there is not enough big space for the new image. Try to change image cache size, and manually delete the image object in Python code after the image is not used any more (img.delete()). Try to avoid memory fragmentation by manually deleting not used Python image object, clean image cache and do manual garbage collection before loading new image and after deleting image.
  2. Unplug USB: this is a “known” issue, I have the same problem, and I think it’s somehow Micropython framework related, as the processing of Micropython code stops, but some LVGL UI elements still response (for example button pressed state change).

Thanks @PGNet
About the 2nd answer, this problem only started to verify after I added the module with the image arrays and it also happens if I just load the graphic interface without touching anything

The problem is you are using a pico. They only have 264k of memory. MicroPython is going to take a sizeable chunk of that and then LVGL is also going to take a sizeable chunk. You really only end up with maybe 2/3rds to 1/2 of that amount for your use. Use this math to calculate the ram use for loading an image.

(image width * image height * 4) + image file size.

so for an image that is 100 x 100 in PNG file format where the majority of the pixels are random colors you end up with (100 * 100 * 4) + 25000 = 40000 + 25000 = 65000 bytes of memory used. id you only have 125K of memory available then you just used up 1/2 of that space. you will need 2 contiguous blocks of memory as well. One that is 25000 in size and the other needs to be 40000.

What size display are you using? and what is the color depth of the display? How large of a frame buffer are you using?

The display resolution is 320x240 with color depth 16 bit swap. I didn’t change any settings for frame buffer so I guess I am using default value

I need to see all of the code you are using in order to determine what you are trying to do. Also what is the width and height of the image and what file format is the image being stored in?

with a 320 x 240 display if ytou are using a frame buffer that is 1/10th the size of the display you are talking about a frame buffer that is 15360 bytes.

so from what I have found is after micropython loads you will have 192k of memory. I am not sure how much LVGL is going to consume once you import it. All of LVGL is stuffed into a single module so it would be advantageous for you to disable every single piece of LVGL you are not using. You can do that by editing the lv_conf.h file and setting the USE_* macros to a zero if it is not being used.

if you run the following code what is the output?

import gc

gc.collect()

print('free:', gc.mem_free())
print('alloc:', gc.mem_alloc())
print()

gc.collect()

print('free:', gc.mem_free())
print('alloc:', gc.mem_alloc())
print()
gc.collect()

import lvgl

print('free:', gc.mem_free())
print('alloc:', gc.mem_alloc())
print()

gc.collect()

print('free:', gc.mem_free())
print('alloc:', gc.mem_alloc())

free: 186096
alloc: 5968

free: 186096
alloc: 5968

free: 186080
alloc: 5984

free: 186080
alloc: 5984

I was using png format with the decoder from imagetools, now I am trying to convert to binary images, but it seems the binary files I get from the online converter Online image converter - BMP, JPG or PNG to C array or binary | LVGL are not displayed (no error on loading screen anyway)

You are going to be better off keeping them as PNG files due to the storage size. If you get the RAW data for them it is going to take up heap size that doesn’t get released when you import the module. While you can delete it after you have loaded it there is still going to be a large chunk of ram used simply because of the compiling of the py file that you have the data put into.

If you store the png as a file and then you close the file and delete the data buffer you should still be OK going that route.

paste the code you are using so I can see what we can tweak with it. There are some things I can more than likely improve to squeeze every drop of memory that can be gotten. The RP2 platform is hard for LVGL and using anything above a 1" display. This is because of how tight the memory is. Once you get into loading images it gets very hard and with a display resolution of 320x240 it is going to really make it hard. One of the things you can do is use smaller images and zoom in. The quality may not be as good but it would be hard to notice on a small display.

If you can get away with not using an alpha channel in your images you can save some space there as well.

The other animal to deal with is memory fragmentation and this I will discuss with you and how to work with it once I have a look at the code to see what is going on.

It actually seems the problem is solved now that I have sucesfully converted png files to binary RBG565 swap files with the online converter.

The files are still stored in the filesystem (I didn’t conver in a C array), but I don’t need the decoder for these files, I think this is the reason it doesn’t crash anymore.

The tricky part is that just using the files as they are give a distorced image, this is because the first 4 bytes are for the header, as it is explained in this discussion: Possible issues when using indexed binary images - General discussion - LVGL Forum

@kdschlosser Thank you very much for your support, maybe I will still need help to squeeze more memory later, but for now it seems to be ok :slight_smile:

thanks is really usefull