Screen Freeze when tyring to _ui_screen_change

Description

Hi all,
I’m quite new to the LVGL world but I like it very much.
I have created simple screen made of only ONE screen for a round display 240x240 pixel.
It was time to try some feature and several screen so I have created a project with 4 screens using SquareLine Studio 1.3.1:

  • the first one is only made of 3 spinners [Screen2]
  • the second one has 2 arcs and 2 labels[Screen1]
  • the third one has a Bar, two Switch, a pinbox a spinner [screen4]
    -the last one is composed by one chart.[Screen3]

To change screen I have set up event based on screen loaded in the following way

void ui_event_Screen2(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    lv_obj_t * target = lv_event_get_target(e);
    if(event_code == LV_EVENT_SCREEN_LOADED) {
        ESP_LOGI(ui_tag, "Screen2 Load Screen1");
        _ui_screen_change(&ui_Screen1, LV_SCR_LOAD_ANIM_OVER_TOP, 500, 2000, &ui_Screen1_screen_init);
    }
}

But when I load the code on my ESP32 98% of time the screen freeze on the first LOAD and no other displays are loaded.
By pushing the reset button I’m able to let the ESP32 to load some other screen but it does not appens every time I do that.

What MCU/Processor/Board and compiler are you using?

ESP32 Wroom ew

What LVGL version are you using?

8.3.8

What do you want to achieve?

I want to understand how to manage multiple screens becaus I believe I’m doing something wrong.

What have you tried so far?

In my MAIN file I’m only calling the

  • Initalization display function (it works because I tested it with a single display application)
  • call task timer to run lv_timer_handler every 10ms ( it should work because I testd it with a single display application)

This is why Im trying to modify the STACK size of my TASK but with no changes
I tried to modify the updating timer task to speed up or down the execution of the lv_timer_handler task, but with no success.

I have attached the ESP-PROD JTAG debugger and GDB, with it I can not find the issue because the screen loading seems to work but I get stuck on the second screen or on the third.

Code to reproduce

Add a code snippet which can run in the simulator. It should contain only the relevant code that compiles without errors when separated from your main code base.
MAIN:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"

#include "display/display.h"
#include "display/gc9a01.h"
#include "display/ui_helpers.h"


/* PRIVATE STRUCTRES ---------------------------------------------------------*/

/* VARIABLES -----------------------------------------------------------------*/
static const char *TAG = "main";
/* DEFINITIONS ---------------------------------------------------------------*/

/* MACROS --------------------------------------------------------------------*/

/* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/
static void lvgl_time_task(void*param);
/* FUNCTION PROTOTYPES -------------------------------------------------------*/
#define NUM_RECORDS 100

void app_main(void)
{
	ESP_LOGI(TAG, "Start Main");
	gc9a01_displayInit();
	displayConfig();    

 xTaskCreatePinnedToCore(lvgl_time_task, "lvgl_time_task", 2048*5, NULL, 2, NULL, 1);

}


/**
 * @brief 	LVGL library timer task. Necessary to run once every 10ms
 *
 */
void lvgl_time_task(void* param)
{
	ESP_LOGI(TAG, "TIME Task");


	TickType_t xLastWakeTime = xTaskGetTickCount();

	while(1)
	{
        // The task running lv_timer_handler should have lower priority than that running `lv_tick_inc`
        lv_timer_handler();
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10) );
		
	}
}



UI.c from SquareLine Studio 1.3.1

// This file was generated by SquareLine Studio
// SquareLine Studio version: SquareLine Studio 1.3.1
// LVGL version: 8.3.6
// Project name: First_Test

#include "ui.h"
#include "ui_helpers.h"

///////////////////// VARIABLES ////////////////////
void chart_Animation(lv_obj_t * TargetObject, int delay);
static const char *ui_tag = "ui_tag";
// SCREEN: ui_Screen2
void ui_Screen2_screen_init(void);
void ui_event_Screen2(lv_event_t * e);
lv_obj_t * ui_Screen2;
lv_obj_t * ui_Panel2;
lv_obj_t * ui_Spinner1;
lv_obj_t * ui_Spinner2;
lv_obj_t * ui_Spinner3;
lv_obj_t * ui_Spinner4;

// SCREEN: ui_Screen1
void ui_Screen1_screen_init(void);
void ui_event_Screen1(lv_event_t * e);
lv_obj_t * ui_Screen1;
lv_obj_t * ui_humArc;
lv_obj_t * ui_Humydity;
lv_obj_t * ui_tempArc;
lv_obj_t * ui_Temperature;
lv_obj_t * ui_Checkbox1;

// SCREEN: ui_Screen4
void ui_Screen4_screen_init(void);
void ui_event_Screen4(lv_event_t * e);
lv_obj_t * ui_Screen4;
lv_obj_t * ui_Bar1;
lv_obj_t * ui_Switch1;
lv_obj_t * ui_Switch2;
lv_obj_t * ui_Spinbox1;
lv_obj_t * ui_Spinner5;

// SCREEN: ui_Screen3
void ui_Screen3_screen_init(void);
lv_obj_t * ui_Screen3;
lv_obj_t * ui_Chart1;
lv_obj_t * ui____initial_actions0;

lv_chart_series_t * ui_Chart1_series_1;
lv_chart_series_t * ui_Chart1_series_2;

///////////////////// TEST LVGL SETTINGS ////////////////////
#if LV_COLOR_DEPTH != 16
    #error "LV_COLOR_DEPTH should be 16bit to match SquareLine Studio's settings"
#endif
#if LV_COLOR_16_SWAP !=1
    #error "LV_COLOR_16_SWAP should be 1 to match SquareLine Studio's settings"
#endif

///////////////////// ANIMATIONS ////////////////////
void chart_Animation(lv_obj_t * TargetObject, int delay)
{
    ESP_LOGI(ui_tag, "Chart Animation Task");
    ui_anim_user_data_t * PropertyAnimation_0_user_data = lv_mem_alloc(sizeof(ui_anim_user_data_t));
    PropertyAnimation_0_user_data->target = TargetObject;
    PropertyAnimation_0_user_data->val = -1;
    lv_anim_t PropertyAnimation_0;
    lv_anim_init(&PropertyAnimation_0);
    lv_anim_set_time(&PropertyAnimation_0, 1000);
    lv_anim_set_user_data(&PropertyAnimation_0, PropertyAnimation_0_user_data);
    lv_anim_set_custom_exec_cb(&PropertyAnimation_0, _ui_anim_callback_set_opacity);
    lv_anim_set_values(&PropertyAnimation_0, 0, 255);
    lv_anim_set_path_cb(&PropertyAnimation_0, lv_anim_path_linear);
    lv_anim_set_delay(&PropertyAnimation_0, delay + 0);
    lv_anim_set_deleted_cb(&PropertyAnimation_0, _ui_anim_callback_free_user_data);
    lv_anim_set_playback_time(&PropertyAnimation_0, 0);
    lv_anim_set_playback_delay(&PropertyAnimation_0, 0);
    lv_anim_set_repeat_count(&PropertyAnimation_0, 0);
    lv_anim_set_repeat_delay(&PropertyAnimation_0, 0);
    lv_anim_set_early_apply(&PropertyAnimation_0, false);
    lv_anim_set_get_value_cb(&PropertyAnimation_0, &_ui_anim_callback_get_opacity);
    lv_anim_start(&PropertyAnimation_0);

}

///////////////////// FUNCTIONS ////////////////////
void ui_event_Screen2(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    lv_obj_t * target = lv_event_get_target(e);
    if(event_code == LV_EVENT_SCREEN_LOADED) {//LV_EVENT_SCREEN_LOADED
        ESP_LOGI(ui_tag, "Screen2 Load Screen1");
        _ui_screen_change(&ui_Screen1, LV_SCR_LOAD_ANIM_OVER_TOP, 500, 2000, &ui_Screen1_screen_init);
    }
}

void ui_event_Screen1(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    lv_obj_t * target = lv_event_get_target(e);
    if(event_code == LV_EVENT_SCREEN_LOADED) {
        ESP_LOGI(ui_tag, "Screen1 Load Screen4");
        _ui_screen_change(&ui_Screen4, LV_SCR_LOAD_ANIM_OVER_TOP, 100, 2000, &ui_Screen4_screen_init);
    }
}
void ui_event_Screen4(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    lv_obj_t * target = lv_event_get_target(e);
    if(event_code == LV_EVENT_SCREEN_LOADED) {
        ESP_LOGI(ui_tag, "Screen4 Load Screen3");
        _ui_screen_change(&ui_Screen3, LV_SCR_LOAD_ANIM_FADE_ON, 100, 100, &ui_Screen3_screen_init);
    }
}

///////////////////// SCREENS ////////////////////

void ui_init(void)
{
    lv_disp_t * dispp = lv_disp_get_default();
    lv_theme_t * theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED),
                                               true, LV_FONT_DEFAULT);
    lv_disp_set_theme(dispp, theme);
    ui_Screen2_screen_init();
    ui_Screen1_screen_init();
    ui_Screen4_screen_init();
    ui_Screen3_screen_init();
    ui____initial_actions0 = lv_obj_create(NULL);
    lv_disp_load_scr(ui_Screen2);
}

Could you please help me to find the issue?
Thank you in advance.
Rebel88

you have 3 immediate screen changes chained up. it seems a lot and worth testing to reduce that.

The first screen you’re loading is ui_screen2.
But as soon as ui_Screen2 is loaded, LVGL loads ui_Screen1. And as soon as ui_Screen1 is loaded it loads ui_Screen4.

Hi Virtzka,
Thankyou for your answer.
So, basically, my error is in the change screen function!
If I understand correctly,when the LV_EVENT_SCREEN_LOADED is found it will call:

  1. screen 2 loads screen 1
    2)immediatly screen 1 loads screen 4
  2. immediatly screen4 loads screen 3
    The results is the fereezing of the uc.
    I will change this methodology by creating a Case statement to change the screen Nd not using the event.
    Does it sounds righrt?
    Thankyou

Hello all,
I have modified my code following your suggestions but the issue is still present.
I have tried following:

  1. removed event based change screen
  2. relpaced with a task called every second used to update the screen with the _ui_screen_change function
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"

#include "display/display.h"
#include "display/gc9a01.h"
#include "display/ui_helpers.h"


/* PRIVATE STRUCTRES ---------------------------------------------------------*/

/* VARIABLES -----------------------------------------------------------------*/
static const char *TAG = "main";
/* DEFINITIONS ---------------------------------------------------------------*/

/* MACROS --------------------------------------------------------------------*/

/* PRIVATE FUNCTIONS DECLARATION ---------------------------------------------*/
static void lvgl_time_task(void*param);
static void lvgl_change_scr_task(void* param);
/* FUNCTION PROTOTYPES -------------------------------------------------------*/
#define NUM_RECORDS 100

void app_main(void)
{
	ESP_LOGI(TAG, "Start Main");
	gc9a01_displayInit();

	displayConfig();    

 xTaskCreatePinnedToCore(lvgl_time_task, "lvgl_time_task", 2048*5, NULL, 2, NULL, 1);

 xTaskCreatePinnedToCore(lvgl_change_scr_task, "lvgl_change_screen", 2048*10, NULL, 4, NULL, 1);

}


/**
 * @brief 	LVGL library timer task. Necessary to run once every 10ms
 *
 */
void lvgl_time_task(void* param)
{
	ESP_LOGI(TAG, "TIME Task");


	TickType_t xLastWakeTime = xTaskGetTickCount();

	while(1)
	{
        // The task running lv_timer_handler should have lower priority than that running `lv_tick_inc`
        lv_timer_handler();
        vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10) );
		
	}
}


void lvgl_change_scr_task(void* param)
{
	
	TickType_t xLastWakeTime = xTaskGetTickCount();
	static uint16_t counter=0;
	while(1)
	{
		
		vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(1000) );
		ESP_LOGI(TAG, "Chart Task %d ", counter);

//--- check screen on display

		if(lv_scr_act() == ui_Screen2)
			ESP_LOGI(TAG, "Chart Task Screen 2 on display");
		if(lv_scr_act() == ui_Screen1)
			ESP_LOGI(TAG, "Chart Task Screen 1 on display");
		if(lv_scr_act() == ui_Screen3)
			ESP_LOGI(TAG, "Chart Task Screen 3 on display");
		if(lv_scr_act() == ui_Screen4)
			ESP_LOGI(TAG, "Chart Task Screen 4 on display");

//execute action when counter is equal to a specific number
		if(counter == 3)
		{
			_ui_screen_change(&ui_Screen1, LV_SCR_LOAD_ANIM_NONE, 500, 0, &ui_Screen1_screen_init);
			ESP_LOGI(TAG, "Chart Task Called screen_change function to SCREEN 1");
			
		}
		
		if(counter == 6)
		{
			_ui_screen_change(&ui_Screen4, LV_SCR_LOAD_ANIM_NONE, 500, 0, &ui_Screen4_screen_init);
			ESP_LOGI(TAG, "Chart Task Called screen_change function to SCREEN 4");
			//_ui_screen_delete(&ui_Screen2);
			//ui_Screen3_screen_init();
		}
	 
	
/*
		if(counter == 9)
			{
				_ui_screen_change(&ui_Screen3, LV_SCR_LOAD_ANIM_NONE, 500, 0, &ui_Screen3_screen_init);
				ESP_LOGI(TAG, "Chart Task Called screen_change function to SCREEN 3");
			}
*/		
		counter++;

		
	}
}

and this is the ui.c file screated by SquareLine Studio

// This file was generated by SquareLine Studio
// SquareLine Studio version: SquareLine Studio 1.3.1
// LVGL version: 8.3.6
// Project name: First_Test

#include "ui.h"
#include "ui_helpers.h"

///////////////////// VARIABLES ////////////////////
static const char *ui_tag = "ui_tag";
// SCREEN: ui_Screen2
void ui_Screen2_screen_init(void);
void ui_event_Screen2(lv_event_t * e);
lv_obj_t * ui_Screen2;
lv_obj_t * ui_Panel2;
lv_obj_t * ui_Spinner1;
lv_obj_t * ui_Spinner2;
lv_obj_t * ui_Spinner3;
lv_obj_t * ui_Spinner4;

// SCREEN: ui_Screen1
void ui_Screen1_screen_init(void);
void ui_event_Screen1(lv_event_t * e);
lv_obj_t * ui_Screen1;
lv_obj_t * ui_humArc;
lv_obj_t * ui_Humydity;
lv_obj_t * ui_tempArc;
lv_obj_t * ui_Temperature;
lv_obj_t * ui_Checkbox1;

// SCREEN: ui_Screen4
void ui_Screen4_screen_init(void);
void ui_event_Screen4(lv_event_t * e);
lv_obj_t * ui_Screen4;
lv_obj_t * ui_Bar1;
lv_obj_t * ui_Switch1;
lv_obj_t * ui_Switch2;
lv_obj_t * ui_Spinbox1;
lv_obj_t * ui_Spinner5;

// SCREEN: ui_Screen3
void ui_Screen3_screen_init(void);
lv_obj_t * ui_Screen3;
lv_obj_t * ui_Chart1;
lv_obj_t * ui____initial_actions0;

lv_chart_series_t * ui_Chart1_series_1;
lv_chart_series_t * ui_Chart1_series_2;

///////////////////// TEST LVGL SETTINGS ////////////////////
#if LV_COLOR_DEPTH != 16
    #error "LV_COLOR_DEPTH should be 16bit to match SquareLine Studio's settings"
#endif
#if LV_COLOR_16_SWAP !=1
    #error "LV_COLOR_16_SWAP should be 1 to match SquareLine Studio's settings"
#endif

///////////////////// ANIMATIONS ////////////////////


///////////////////// FUNCTIONS ////////////////////
void ui_event_Screen2(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    lv_obj_t * target = lv_event_get_target(e);
    if(event_code == LV_EVENT_SCREEN_LOADED) {//LV_EVENT_SCREEN_LOADED
        ESP_LOGI(ui_tag, "Screen2 Load Screen1");
        _ui_screen_change(&ui_Screen1, LV_SCR_LOAD_ANIM_OVER_TOP, 500, 2000, &ui_Screen1_screen_init);
    }
}

void ui_event_Screen1(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    lv_obj_t * target = lv_event_get_target(e);
    if(event_code == LV_EVENT_SCREEN_LOADED) {
        ESP_LOGI(ui_tag, "Screen1 Load Screen4");
        _ui_screen_change(&ui_Screen4, LV_SCR_LOAD_ANIM_OVER_TOP, 100, 2000, &ui_Screen4_screen_init);
    }
}
void ui_event_Screen4(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);
    lv_obj_t * target = lv_event_get_target(e);
    if(event_code == LV_EVENT_SCREEN_LOADED) {
        ESP_LOGI(ui_tag, "Screen4 Load Screen3");
        _ui_screen_change(&ui_Screen3, LV_SCR_LOAD_ANIM_FADE_ON, 100, 100, &ui_Screen3_screen_init);
    }
}

///////////////////// SCREENS ////////////////////

void ui_init(void)
{
    lv_disp_t * dispp = lv_disp_get_default();
    lv_theme_t * theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED),
                                               true, LV_FONT_DEFAULT);
    lv_disp_set_theme(dispp, theme);
    ui_Screen2_screen_init();
    ui_Screen1_screen_init();
    ui_Screen4_screen_init();
   // ui_Screen3_screen_init();
    ui____initial_actions0 = lv_obj_create(NULL);
    lv_disp_load_scr(ui_Screen2);
}

as you can easly see I had to comment the ui_screen3 initialization to let the code working.
Indeed, if I enable the ui_Screen3_screen_init() funcion I have the Scen Freeze as in the initial code.

This is why I’m thinking on a memory issue rather than a procedure issue

Further more, if I use only 2 screen

ui_Screen2_screen_init();
    ui_Screen3_screen_init();

and I start with the screen 2 and after call the

_ui_screen_change(&ui_Screen3, LV_SCR_LOAD_ANIM_NONE, 500, 0, &ui_Screen3_screen_init);

I still have the freeze issue.

Instead if i start with the screen 3 and after call the screen 2 everything works smooth untill I try to load again the Screen 3, then I have the freeze.

This is the cose of the Sreen 3 ( it contains a chart)

// This file was generated by SquareLine Studio
// SquareLine Studio version: SquareLine Studio 1.3.1
// LVGL version: 8.3.6
// Project name: First_Test

#include "../ui.h"

void ui_Screen3_screen_init(void)
{
    ui_Screen3 = lv_obj_create(NULL);
    lv_obj_clear_flag(ui_Screen3, LV_OBJ_FLAG_SCROLLABLE);      /// Flags

    ui_Chart1 = lv_chart_create(ui_Screen3);
    lv_obj_set_width(ui_Chart1, 153);
    lv_obj_set_height(ui_Chart1, 116);
    lv_obj_set_x(ui_Chart1, 11);
    lv_obj_set_y(ui_Chart1, -2);
    lv_obj_set_align(ui_Chart1, LV_ALIGN_CENTER);
    lv_chart_set_type(ui_Chart1, LV_CHART_TYPE_LINE);
    lv_chart_set_axis_tick(ui_Chart1, LV_CHART_AXIS_PRIMARY_X, 10, 5, 5, 2, true, 50);
    lv_chart_set_axis_tick(ui_Chart1, LV_CHART_AXIS_PRIMARY_Y, 10, 5, 5, 2, true, 50);
    lv_chart_set_axis_tick(ui_Chart1, LV_CHART_AXIS_SECONDARY_Y, 10, 5, 5, 2, false, 25);
    ui_Chart1_series_1 = lv_chart_add_series(ui_Chart1, lv_color_hex(0x808080),
                                                                 LV_CHART_AXIS_PRIMARY_Y);
    static lv_coord_t ui_Chart1_series_1_array[] = { 0, 10, 20, 40, 80, 80, 40, 20, 10, 0 };
    lv_chart_set_ext_y_array(ui_Chart1, ui_Chart1_series_1, ui_Chart1_series_1_array);
    
    ui_Chart1_series_2 = lv_chart_add_series(ui_Chart1, lv_color_hex(0xFF0000),
                                                                 LV_CHART_AXIS_SECONDARY_Y);
    static lv_coord_t ui_Chart1_series_2_array[] = { 5, 10, 20, 25, 46, 5, 8, 7 };
    lv_chart_set_ext_y_array(ui_Chart1, ui_Chart1_series_2, ui_Chart1_series_2_array);
    lv_obj_set_style_bg_color(ui_Chart1, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_Chart1, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_color(ui_Chart1, lv_color_hex(0x000000), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_border_opa(ui_Chart1, 0, LV_PART_MAIN | LV_STATE_DEFAULT);

    

}

do you have any help?