Don
November 10, 2020, 10:58pm
1
Description
LV_ASSERT_OBJ fires when performing a screen transition with delay.
What MCU/Processor/Board and compiler are you using?
Occurs on two platforms: STM32 and Qt on a Mac
What do you experience?
When a delay is used for the transition, we take the assert.
Changing the delay from 100 to 0 prevents the assert. I have not tried further variants of time or transition style.
It appears to be timing related, sometimes the example code gets through 20 cycles and sometimes just one or two.
What do you expect?
No assert.
Code to reproduce
// If 'delay' in the lv_scr_load_anim() call is 100, after some
// number of cycles (1-20 typically) this happens:
//
// Error: lv_obj_get_local_style (lv_obj.c #2927 lv_obj_get_local_style())
// Error: Invalid object (0x00000001001ECE50) (lv_debug.c #127 lv_debug_log_error())
//
// The check that fails is:
// lv_debug_check_obj_valid()
//
// And the object that is invalid is the screen being transitioned to.
//
// Setting the delay to 0 appears to fix it. (can run for thousands of cycles)
//
// Occurs on 7.7.1, although seen on earlier releases as well.
#include <stdio.h>
#include "lvgl/lvgl.h"
static void next_screen( lv_task_t *task );
lv_obj_t *make_screen( const char *name );
void ui_init(void)
{
// Make sure any printf() output gets flushed.
setvbuf( stdout, NULL, _IOLBF, 0 );
lv_task_create( next_screen, 500, LV_TASK_PRIO_MID, NULL );
}
static void next_screen( lv_task_t *task )
{
static int count;
static bool f = true;
const char *name;
if( f )
{
name = "Screen A";
f = false;
}
else
{
name = "Screen B";
f = true;
}
lv_obj_t *next = make_screen( name );
printf( "Begin %s load (%d) %p -> %p\n", name, ++count, lv_scr_act(), next );
// If 'delay' is 0 the problem goes away.
lv_scr_load_anim( next, LV_SCR_LOAD_ANIM_MOVE_TOP, 200, 100, true );
}
lv_obj_t *make_screen( const char *name )
{
lv_obj_t *screen = lv_obj_create( NULL, NULL );
lv_obj_t * btn = lv_btn_create( screen, NULL );
lv_obj_set_pos( btn, 10, 10 );
lv_obj_set_size( btn, 120, 50 );
lv_obj_t * label = lv_label_create( btn, NULL );
lv_label_set_text( label, name );
return screen;
}
Screenshot and/or video
If possible, add screenshots and/or videos about the current issue.
It works well for me in the simulator.
In which file and line does the assert fire? Please copy the log.
Don
November 18, 2020, 2:44pm
3
Sorry, I meant to add that in my original post!
LVGL 7.6.0
Begin Screen A load (21) 0x2400766c -> 0x240077d4
Error: lv_obj_get_local_style (lv_obj.c #2904 lv_obj_get_local_style())
Error: Invalid object (0x240077D4) (lv_debug.c #127 lv_debug_log_error())
It is quite variable. It typically crashes after 10 or 20 iterations, but I have seen it be successful for hundreds before the assert occurs.
That suggests memory corruption. You could try enabling LV_ASSERT_MEM_INTEGRITY
if it’s not already enabled.
Don
November 18, 2020, 4:19pm
6
I do have the memory integrity check enabled.
I should re-iterate that changing the delay to zero lets it run for thousands of cycles. (I wind up stopping the test, it doesn’t fail.)
That and the variability as to when it occurs makes me think timing, some race-condition?
I can reproduce it on both my target STM32 hardware and a simulator I implemented using Qt and running on my Mac, so very different environments and the same assert.
Are you deleting created screens somehow? Also did you test pointers values?
Don
November 19, 2020, 2:06pm
8
The screens are deleted automatically by LVGL after they transition.
Screen pointers aren’t tested but they are printed for diagnostics purposes.
Please try these:
In lv_disp.c
modify scr_anim_ready
like this
static void scr_anim_ready(lv_anim_t * a)
{
LV_ASSERT_MEM_INTEGRITY();
lv_disp_t * d = lv_obj_get_disp(a->var);
LV_ASSERT_MEM_INTEGRITY();
if(d->prev_scr && d->del_prev) lv_obj_del(d->prev_scr);
LV_ASSERT_MEM_INTEGRITY();
d->prev_scr = NULL;
lv_style_remove_prop(lv_obj_get_local_style(a->var, LV_OBJ_PART_MAIN), LV_STYLE_OPA_SCALE);
LV_ASSERT_MEM_INTEGRITY();
}
Enable LV_USE_DEBUG
and LV_USE_ASSERT_MEM_INTEGRITY
in lv_conf.h
Enable LV_MEM_ADD_JUNK
in lv_mem.c
Don
November 25, 2020, 2:51pm
10
Made those changes, and get the same results.
Begin Screen A load (13) 0x10a634b78 -> 0x10a634e60
Error: lv_obj_get_local_style (lv_obj.c #2927 lv_obj_get_local_style())
Error: Invalid object (0x000000010A634E60) (lv_debug.c #127 lv_debug_log_error())
(LVGL version 7.7.2)
Finally I could reproduce it and now I see the issue.
This simple code can reproduce it.
scr1 = lv_obj_create(NULL, NULL);
scr2 = lv_obj_create(NULL, NULL);
lv_scr_load_anim(scr1, LV_SCR_LOAD_ANIM_OVER_LEFT, 1000, 500, 1);
lv_scr_load_anim(scr2, LV_SCR_LOAD_ANIM_OVER_LEFT, 1000, 0, 1);
So:
scr1
will start to load with 500 ms delay.
scr2
will start to load immediately.
The problem is the screen “on-delay” is no managed properly. However I don’t know what would be the expected behaviour in this case.
Start to load scr2
and in half-time start to load scr1
too? This way scr1
will be visible in the end.
As the command to load scr2
was sent later, scr2
should be visible in the end. So delete all pending load anim when a new starts?
Please open a new issue for it on GitHub. I’m checking it more frequently.
Meanwhile, I’ve applied a fix that immediately finishes the pending screen animations when starting a new one.