longer string makes code goes into HardFault.

Hi everyone!

I start working in a company that has a equipment with a code that already works fine. I was asked to include a string in one splash screen and then I did. No problem! Then I was pointed again to change the text of this string. The old one had 9 bytes long and when I changed the string to some 18 bytes long, the code started crashinng when a call to lv_disp_load_scr(ui_splash) occurs. ui_splash is a poiter to an object of lv_obj_t type and is created with ui_splash = lv_obj_create(NULL);.

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

  • The code runs on a device with one STM32FH573 with 640K of RAM and 2M of flash with one ST7735S display using SPI with DMA and everything configured correctly.
  • Compiler is arm-none-eabi-gcc 12.2 that comes with the CubeIDE.

What LVGL version are you using?

  • This project uses the version 8.3
/***************************
 * CURRENT VERSION OF LVGL
 ***************************/
#define LVGL_VERSION_MAJOR 8
#define LVGL_VERSION_MINOR 3
#define LVGL_VERSION_PATCH 6
#define LVGL_VERSION_INFO ""

What do you want to achieve?

Make the code run with the correct string into the splash screen.

What have you tried so far?

  • I explained in the text body below.
  • As well as I turned the LV_LOGS on and all the lv_conf helpers to analyse memory and so one… Nothing seems to explain the root cause of this problem

Code to reproduce

  • Sorry guys I have a contract with the company in which I can’t expose the source code…

The code starts, everything goes well, then I call lv_obj_del(ui_splash); and after initialize the next screen that creates all the lv_obj_t objects with success, the code lv_disp_load_scr(ui_next_screen); is called to load that screen. But inside this functionn the crash happens. More specifically in:

Thread #1 (Suspended : Signal : SIGINT:Interrupt)	
HardFault_Handler() at stm32h5xx_it.c:107 0x8002ef4	
<signal handler called>() at 0xffffffa8	
lv_obj_get_parent() at lv_obj_tree.c:296 0x803167c	
lv_obj_get_screen() at lv_obj_tree.c:264 0x80315c6	
lv_obj_get_disp() at lv_obj_tree.c:277 0x80315f4	
scr_load_internal() at lv_disp.c:471 0x80261d2	
lv_scr_load_anim() at lv_disp.c:230 0x8025caa	
lv_disp_load_scr() at lv_disp.c:84 0x8025b18	
AnotherScreenInit() at AnotherScreen.c:13 0x8023e7c	
SMGoToScreen() at ScreenManager.c:222 0x8023d96	
SMOverwriteScreen() at ScreenManager.c:89 0x8023b5e	
SplashScreenTick() at SplashScreen.c:28 0x8025772	
SMTickHandler() at ScreenManager.c:142 0x8023bb8	
UiRun() at UiController.c:290 0x8018aea	
SystemControllerRun() at SystemController.c:116 0x8018484	
device_main() at device_main.c:84 0x8022182	
main() at main.c:128 0x800207e	

The central question here is → if I stop call lv_obj_del commenting the code, everythign works fine! But, if I keep the code, even deleting the lv objects, the code works until I start printing a string with more than 11 characters.

  • this is the function where the splash screen is initialized…
void ui_splash_screen_init(void)
{
    char str_firm[20];
    ui_splash = lv_obj_create(NULL);
    lv_obj_clear_flag(ui_splash, LV_OBJ_FLAG_SCROLLABLE);  
    lv_obj_set_style_bg_color(ui_splash, lv_color_hex(0xFBDD56), LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_bg_opa(ui_splash, 255, LV_PART_MAIN | LV_STATE_DEFAULT);

    ui_logo = lv_img_create(ui_splash);
    lv_img_set_src(ui_logo, &ui_img_logo_png);
    lv_obj_set_width(ui_logo, LV_SIZE_CONTENT); 
    lv_obj_set_height(ui_logo, LV_SIZE_CONTENT);    
    lv_obj_set_align(ui_logo, LV_ALIGN_CENTER);
    lv_obj_clear_flag(ui_logo, LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_CLICK_FOCUSABLE | LV_OBJ_FLAG_GESTURE_BUBBLE |
                      LV_OBJ_FLAG_SNAPPABLE | LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_SCROLL_ELASTIC | LV_OBJ_FLAG_SCROLL_MOMENTUM |
                      LV_OBJ_FLAG_SCROLL_CHAIN); 

    // ### THIS IS THE CODE I ADDED AND WORKS UNTIL THE STRING NEEDED TO BE CHANGED TO ANOTHER WITH JUST FEW BYTES MORE

    sprintf(str_firm, "HERE GOES W");       //Here everything goes perfectly!
    //sprintf(str_firm, "HERE GOES WRONG"); //Here if uncomment thi line, the crash occurs
    ui_versionMsg = lv_label_create(ui_splash);

	lv_obj_set_width(ui_versionMsg, LV_SIZE_CONTENT);
	lv_obj_set_height(ui_versionMsg, LV_SIZE_CONTENT);
	lv_obj_set_align(ui_versionMsg, LV_ALIGN_TOP_MID);
	lv_label_set_text(ui_versionMsg, str_firm);
	lv_obj_set_y(ui_versionMsg, 110);
	lv_obj_clear_flag(ui_versionMsg, LV_OBJ_FLAG_PRESS_LOCK | LV_OBJ_FLAG_CLICK_FOCUSABLE | LV_OBJ_FLAG_GESTURE_BUBBLE |
					  LV_OBJ_FLAG_SNAPPABLE | LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_SCROLL_ELASTIC | LV_OBJ_FLAG_SCROLL_MOMENTUM |
					  LV_OBJ_FLAG_SCROLL_CHAIN);
    lv_obj_set_style_text_color(ui_versionMsg, lv_color_hex(0x4D4B5C), (lv_style_selector_t)LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_opa(ui_versionMsg, 255, (lv_style_selector_t)LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_set_style_text_font(ui_versionMsg, &lv_font_montserrat_10, (lv_style_selector_t)LV_PART_MAIN | LV_STATE_DEFAULT);
    //### 
}

Then the sequence is:

void SplashScreenInit() {
    if (!m_instance->m_isInitialized)
    {
        ui_splash_screen_init(); //the code execute this successfully!
        m_instance->m_isInitialized = true;
    }

    lv_disp_load_scr(ui_splash); //here as well... successfully!
    .
    .
    .
}

Now the logic is that the screen manager is called asking to change the screen. I dont know why but the screen manager uses a stack to keep control of the screens:

void SMOverwriteScreen(ScreenType newScreen)
{
	Screen *currentScreen;
	if((currentScreen = SMGetCurrentScreen()) != NULL)
	{
		if (currentScreen->m_type == newScreen)
		{
			return;
		}
		if (currentScreen->DeInit != NULL)
		{
            // One curious fact is that if I uncomment the code `sprintf(str_firm, "HERE GOES WRONG");` that makes everything crash and stop calling Deinit() commenting the line below
            // everything get working back.
			currentScreen->DeInit(); //current screen is ui_splash that only sets the m_isInitialized to false and deletes the ui_splash object.
		}
	}
	if (StackPop(&stack.m_stack) != NULL)
	{
		if (StackPush(&stack.m_stack,newScreen))
		{
			SMGoToScreen(newScreen); //here is the new screen that will load...
		}
	}
}

And you see here:

void SMGoToScreen(ScreenType screenType)
{
	if (screenType == ScreenTypeNone)
    {
		return;
	}
	screenTable[screenType].Init(); //And the code executes this function that is the initialization of the new screen to be showed
}

That .Init() is a pointer to a function to initialise the next screen as you see below:

void AnotherScreenInit()
{
    if (!m_instance->m_isInitialized)
    {
        ui_another_screen_init();
        m_instance->m_isInitialized = true;
    }

    lv_disp_load_scr(ui_next_screen); //The code crashes here
}

and

void ui_another_screen_init(void)
{
    ui_next_screen = lv_obj_create(NULL);
    lv_obj_clear_flag(ui_next_screen,
                      LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_PRESS_LOCK |
                          LV_OBJ_FLAG_SCROLLABLE | LV_OBJ_FLAG_SCROLL_ELASTIC |
                          LV_OBJ_FLAG_SCROLL_MOMENTUM); 

    ui_next_stuff = lv_obj_create(ui_next_screen);
    lv_obj_set_width(ui_next_stuff, 68);
    lv_obj_set_height(ui_next_stuff, 34);
    lv_obj_set_x(ui_next_stuff, 26);
    lv_obj_set_y(ui_next_stuff, 69);
    .
    .
    .
    //This is only for demonstration purposes
}

Thanks in advance…