After an experiment, it seems I can do a splash screen without using lv_task_once(3) or lv_async_call(3) @embeddedt .
The LVGL lack of task synchronisation doesn’t affect programs starting with less than three automatic (no user interaction) screen calls, so this works:
int main(void)
{
// Initialise and configure
...
lv_img_create(lv_scr_act(), NULL); // Root level object
lv_img_set_src(); // Cause a splashscreen to appear
// Begin user interaction, the real application
lv_obj_t *next_scr = create_screen_2();
lv_scr_load_anim(next_scr, LV_SCR_LOAD_ANIM_OVER, 250ms, 2000ms, true);
// The third screen (not shown) appears due to a
// event, which doesn't lead to the LVGL problem
// of several screens appearing at the same time.
}
Control flow
The advice given by @embeddedt to implement control flow in button callbacks helps avoid the problems from my declarative (see my Screen 1/2/3/4) approach.