Esp32 Using two buttons to display image issues

I am a novice in microPython and My English is so-so.
My code has 5 images that can be switched between two buttons for display.
Sometimes the code can run normally, sometimes an error is reported.
I tried img2.delete(),or img2.del_async(),or img2.del_delayed(1000),or lv.img.cache_invalidate_src(None)
In order to describe my problem more clearly, I have created a video on Bilibili at 帮忙看看怎么有时候程序运行不了?lvgl+micropython 实体按键_哔哩哔哩_bilibili

In order to describe my problem more clearl
Here is my code

Blockquote import lvgl as lv
import fs_driver
from ili9XXX import *
from encoder_driver import ButtonsInputEncoder, EncoderInputDriver
import network
import gc,micropython
import sys
#micropython.alloc_emergency_exception_buf(100)
lv.init()
#lv.img.cache_set_size(4)
‘’‘mosi–>sda,clk–>scl’‘’
disp = st7735(
clk=18,mosi=23,rst=22,dc=21, cs=4, backlight=15, backlight_on=1,
width=128, height=160,colormode=COLOR_MODE_RGB, invert=False , rot=PORTRAIT
,start_x=2, start_y=1, double_buffer=False)#dc=12, rst=13,MADCTL_MX|MADCTL_MY False True
button_encoder = ButtonsInputEncoder(left=27, right=25, press=26)
button_driver = EncoderInputDriver(button_encoder)
scr = lv.scr_act()
scr.set_style_bg_color(lv.color_hex(0x000000), lv.PART.MAIN)
Blockquote
a=1
def btn_event_cb(e):
global a,img2
code = e.get_code()
btn = e.get_target_obj()
a+=1
if code == lv.EVENT.CLICKED:
img2.delete()
img2 = lv.img(lv.scr_act())
img2.set_src(fun(a))
img2.align(lv.ALIGN.CENTER,0,0)
lv.img.cache_invalidate_src(None)
gc.collect()
#print(gc.mem_free())
label = btn.get_child(0)
label.set_text(str(a))
def btn_event_cb1(e):
global a,img2
code = e.get_code()
btn = e.get_target_obj()
a-=1
if a<1:
a=1
if code == lv.EVENT.CLICKED:
img2.delete()
img2 = lv.img(lv.scr_act())
img2.set_src(fun(a))
img2.align(lv.ALIGN.CENTER,0,0)
lv.img.cache_invalidate_src(None)
gc.collect()
#print(gc.mem_free())
label = btn.get_child(0)
label.set_text(str(a))
def fun(x):
gc.collect()
try:
with open(‘{}.png’.format(x),‘rb’) as f:
png_data = f.read()
except:
print(“Could not find wink.png”)
sys.exit()
#“header”: {“always_zero”: 0, “w”: 128, “h”: 72, “cf”: lv.COLOR_FORMAT.RAW_ALPHA},
wink_argb = lv.img_dsc_t({
‘data_size’: len(png_data),
‘data’: png_data
})
return wink_argb

Blockquote
‘’‘def fun(x):
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, ‘S’)
#img2 = lv.img(lv.scr_act())
# The File system is attached to letter ‘S’
img2.set_src(“S:{}.png”.format(x) )#“S:bulb.gif” “S:222222.gif”
img2.align(lv.ALIGN.CENTER,0,0)’‘’

Blockquote
img2 = lv.img(lv.scr_act())
img2.set_src(fun(a))
img2.align(lv.ALIGN.CENTER,0,0)
#lv.img.cache_set_size(2)#lv.img.cache_invalidate_src()
print(gc.mem_free()
btn = lv.btn(lv.scr_act()) # Add a button the current screen
btn.set_pos(10, 10) # Set its position
btn.set_size(100, 40) # Set its size
btn.align(lv.ALIGN.CENTER,0,-50)
btn.add_event(btn_event_cb, lv.EVENT.CLICKED, None)
label = lv.label(btn) # Add a label to the button
label.set_text(“Button”) # Set the labels text
label.center()
btn1 = lv.btn(lv.scr_act()) # Add a button the current screen
btn1.set_pos(10, 10) # Set its position
btn1.set_size(100, 40) # Set its size
btn1.align(lv.ALIGN.CENTER,0,50)
btn1.add_event(btn_event_cb1, lv.EVENT.CLICKED, None)
label = lv.label(btn1) # Add a label to the button
label.set_text(“Button”) # Set the labels text
label.center()
group = lv.group_create() # Create a group
group.add_obj(btn)
group.add_obj(btn1)
button_driver.group = group

Here is the error message
Traceback (most recent call last):
File “lv_utils.py”, line 124, in task_handler
MemoryError: memory allocation failed, allocating 20000 bytes

Please give me some help and tell me what to do.
thanks

You are running into a memory fragmentation problem because of the constant deletion and creation of an lv.img object.

This is what you need to do. use array.array and create a buffer the size of the largest image that is going to be loaded. This can be done dynamically using the following code

import os 

def get_largest_file_size(path):
    max_size = 0
    for f in os.listdir(path):
        f = path + '/' + f
        max_size = max(os.stat(f)[6], max_size)
    return max_size

once you have the size then you can allocate a buffer. This code needs to run at the module level just after you get the display driver initialized.

import array

buf = array.array('B', [0] * get_largest_file_size('path_to_images'))

You reuse the lv.img object over and over again. No need to delete it. You also reuse the buffer that holds the img data.

What I have not done is tried using a memoryview object when creating the lv.img_dsc_t object. It might work passing a memoryview object


import array
import os 

def get_largest_file_size(path):
    max_size = 0
    for f in os.listdir(path):
        f = path + '/' + f
        max_size = max(os.stat(f)[6], max_size)
    return max_size


buf = array.array('B', [0] * get_largest_file_size('path_to_images'))
mv_buf = memoryview(buf)


def get_image(path):
    size = os.stat(path)[6]
    with open(path, 'rb') as f:
        buf[:size] = f.read()

    return lv.img_dsc_t({
        'data_size': size,
        'data': mv_buf[:size]
    })

img.set_src(get_image('path_to_images/image.png'))
img.invalidate()
lv.refr_now()

the above is pseudo code and has not been tested. there are probably some errors in it so it should be used as a reference and not something that would actually run.

刀友 你好!

thanks for you help.
I will use your opinions to change my code for testing later

你好.‘与其感慨路难行 不如马上出发’ 。 :grin:

snap!!! forgot to grab my secret decoder ring from the lucky charms box…

I am guessing the big smiley face means it is fixed?? maybe?

Confucius saying??

1 Like

Maybe my English expression is not good
those Chinese language Just a line from the Dota2 game.
the big smiley face just an expression

Maybe my English expression is not good
those Chinese language Just a line from the Dota2 game.
the big smiley face just an expression

I ran it through google translate. I probably didn’t get a correct translation but I am sure it was close.

I followed your suggestion and set the buf. The problem still exists.
Perhaps I don’t have the skills to do that you said. ‘‘This code needs to run at the module level just after you get the display driver initialized’’
I have also read the official website document porting/draw.html and bindings/micropython.html Memory Management.
Finally I observed the image display and found that most of the problems were caused by an error in the largest image displayed.
If I load the images size in descending order. Sometimes there is no error reported.
So, I used Pillow to reduce the size of all images, and my code can now run.

If the images don’t have any alpha to them where the background in LVGL comes through the image then lower the bit depth to 24 You can do this using a program like “paint dot net” for Windows or any other kind of an image editor. I am sure there are also image converters you can find online that would also allow you to change the bit depth. If you have an image of 300 x 300 the actual amount of ram it ends up taking is 300 x 300 x 4 = 360000 bytes. by changing the bit depth to 24 the same image will only take up 300 * 300 * 3 = 270000 bytes. it’s 25% smaller which is a sizeable amount of memory.

image
你是使用的哪种图片类型?如果用CF_TRUE_COLOR确实会占用很大的内存。