Nothing shows up

Description

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

STM32F103RCT6, CubeIDE

display: 128*160, RGB565(16 bit), ST7735/ST7789 lcd driver.

What do you want to achieve?

I want to make any object on display.
When I run the only initialization & configuration code (written on lvgl documentation), there is no error.
Actually I’m not sure initialization&configuration is properly done because I can only see the white screen after running the code.

After that, I added the example code on lvgl lib(-lvgl/examples/get_started/lv_example_get_started_1.c/lv_example_get_started_1()), and hard fault occurred.
I guess it is because of memory or lcd driver-lvgl connection.
Is there any other possibility on code? Please help :sob:

When I defined lv_disp_buf_t valuable and lv_disp_buf_init func, it was impossible because they aren’t contained in lv_hal_disp.h. Instead of it, lv_disp_draw_buf_t and lv_disp_draw_buf_init are in it. I’ve used them.

What have you tried so far?

initialization and import lv_example_get_started_1() func.

Code to reproduce

Add the relevant code snippets here.

// lv_conf.h file
// attached that I added or revised 
/* Maximal horizontal and vertical resolution to support by the library.*/
#define LV_HOR_RES_MAX 128
#define LV_VER_RES_MAX 160

/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH     16

/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
#  define LV_MEM_SIZE    (10U * 1024U)          /*[bytes]*/

int main(void)
{
// there are initialization functions above (deleted for posting)
  App_Start();
  while(1)
  {
	        lv_tick_inc(10);
	        lv_task_handler();
	        HAL_Delay(10);
  }
}
/*initialization and configuration*/
int lv_config_main(void)
{
	lv_init();
    static lv_disp_draw_buf_t disp_buf;									
    static lv_color_t buf_1[LV_HOR_RES_MAX * 10];											
    lv_disp_draw_buf_init(&disp_buf, buf_1, NULL, LV_HOR_RES_MAX * 10);

    lv_disp_drv_t disp_drv;												
    lv_disp_drv_init(&disp_drv);										
    disp_drv.draw_buf = &disp_buf;										
    disp_drv.flush_cb = LCD_flush;										
    lv_disp_t * disp_ex;
    disp_ex = lv_disp_drv_register(&disp_drv);									
}
void LCD_flush(lv_disp_drv_t * drv, const lv_area_t * area,  lv_color_t * color_map)
{
	uint16_t x, y;
	uint32_t size = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1);
    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
        	LCD_DrawPaint((uint16_t ) area->x1, (uint16_t ) area->y1, (uint16_t *)color_map);
        	color_map++;
        }
    }
	lv_disp_flush_ready(drv);
	DEV_Digital_Write(DEV_CS_PIN, 1);
}

void LCD_DrawPaint(uint16_t x, uint16_t y, uint16_t Color)
{
	LCD_SetCursor(x, y);
	LCD_WriteData_Word(Color);
}
#define DEV_Digital_Write(_pin, _value) 	HAL_GPIO_WritePin(_pin, _value == 0? GPIO_PIN_RESET:GPIO_PIN_SET)

void DEV_SPI_WRite(uint8_t _dat)
{
	HAL_SPI_Transmit(&hspi1, (uint8_t *)&_dat, 1, 500);
}

void LCD_SetCursor(uint16_t X, uint16_t Y)
{
	LCD_Write_Command(0x2a);
	LCD_WriteData_Byte(X >> 8);
	LCD_WriteData_Byte(X);
	LCD_WriteData_Byte(X >> 8);
	LCD_WriteData_Byte(X);

	LCD_Write_Command(0x2b);
	LCD_WriteData_Byte(Y >> 8);
	LCD_WriteData_Byte(Y);
	LCD_WriteData_Byte(Y >> 8);
	LCD_WriteData_Byte(Y);

	LCD_Write_Command(0x2C);
}

void LCD_WriteData_Word(uint16_t data)
{
	DEV_Digital_Write(DEV_CS_PIN, 0);
	DEV_Digital_Write(DEV_DC_PIN, 1);
	DEV_SPI_WRITE((data>>8) & 0xff);
	DEV_SPI_WRITE(data);
	DEV_Digital_Write(DEV_CS_PIN, 1);
}

static void LCD_Write_Command(uint16_t data)
{
	DEV_Digital_Write(DEV_CS_PIN, 0);
	DEV_Digital_Write(DEV_DC_PIN, 0);
	DEV_SPI_WRITE(data);
}

void LCD_WriteData_Word(uint16_t data)
{
	DEV_Digital_Write(DEV_CS_PIN, 0);
	DEV_Digital_Write(DEV_DC_PIN, 1);
	DEV_SPI_WRITE((data>>8) & 0xff);
	DEV_SPI_WRITE(data);
	DEV_Digital_Write(DEV_CS_PIN, 1);
}

One problem I see:

    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
        	LCD_DrawPaint((uint16_t ) area->x1, (uint16_t ) area->y1, (uint16_t *)color_map);
        	color_map++;
        }
    }

You always call LCD_DrawPaint with area->x1 and area->y1.
So you are writing always to the same pixel!

:rofl:
I changed x1 and y1 to x and y. Thanks lol.
There is no change, though.

You can try to write a fixed color value to all pixels, to see whether there is a change in display.
If nothing changes, there could be something wrong on data transmission to the display,
or something wrong in setting up the display controller.

I saw this thread which is similar with my case.
I changed heap and stack size 0x200,0x400 to 0x4000, but nothing changed at all :cry:

When I used only LCD driver without lvgl, there was no problem.
changing color, making shape and other things were enabled.
After importing lvgl and applying lcd_flush function, I cannot see anything changed.

The function I used is below.
When I used this function on main.c, it worked. The screen color was changed with 0x34AF.
However, I put it in Flushing function, anything happened.
It means the flushing process doesn’t work?

// coloring the screen
void LCD_ClearWindow(uint16_t Xstart, uint16_t Ystart, uint16_t Xend, uint16_t Yend,uint16_t color)
{
	uint16_ti,j;
	LCD_SetWindow(Xstart, Ystart, Xend-1,Yend-1);
	for(i = Ystart; i <= Yend-1; i++){
		for(j = Xstart; j <= Xend-1; j++){
			LCD_WriteData_Word(color);
		}
	}
}
void LCD_flush(lv_disp_drv_t * drv, const lv_area_t * area,  lv_color_t * color_map)
{
	LCD_ClearWindow(area-> x1, area-> y1, area-> x2, area-> y2, 0x34AF);
    }

I don’t know what kind of IDE you use, whether you have some Debugger or not.
If you can do debugging, you can set a breakpoint to LCD_flush.

Or you can call LCD_flush manually (with dummy values) after App_Start to see whether you can see something on display.

I’m using STM32CubeIDE and there is debugger.
I set the breakpoint at

    disp_drv.flush_cb = LCD_flush;

However, when I clicked ‘step into’ button in debug mode, it just passed away it and ran to next line. It didn’t stepped into the function.
When I saw the variables in debug window, flush_cb value was changed to LCD_flush.

1223

disp_drv.flush_cb = LCD_flush;

This line is telling lvgl that LCD_flush is the function which lvgl has to call if drawing is finished.
It’s just an assignment of LCD_flush function address to the call back function variable.

You have to set the breakpoint to LCD_flush itself.
If the break occurs you know that your flush function is called from lvgl.
If no break occurs then something is wrong.

When I set breakpoint in LCD_flush, nothing happened, It just passed that line, not stepped into there. It means something is wrong… :disappointed_relieved:

Then, I should re-check lcd driver and SPI comm, I guess.

That means that LVGL has probably crashed for some reason. Try enabling logging.

When tracing it, I found something.
After initialization, a lot of memory allocation&reallocation occurred.
I just run the configuration code without example lines.
LVGL tried to create object, especially screen at first, but there is 0 parent. Doesn’t it mean the screen isn’t created?

[Trace]  (0.000)  lv_obj_create_from_class: Creating object with 0x8028c74 class on 0 parent     (in lv_obj_class.c line #44)
[Trace]     (0.000)  lv_mem_alloc: allocating 40 bytes      (in lv_mem.c line #118)
[Trace]  (0.000)  lv_mem_alloc: allocated at 0x200012e4  (in lv_mem.c line #143)
[Trace]  (0.000)  lv_obj_constructor: begin      (in lv_obj.c line #612)
[Trace]  (0.000)  lv_obj_constructor: creating a screen  (in lv_obj.c line #617)
[Trace]  (0.000)  lv_mem_alloc: allocating 4 bytes       (in lv_mem.c line #118)
[Trace]  (0.000)  lv_mem_alloc: allocated at 0x20001310  (in lv_mem.c line #143)
[Trace]  (0.000)  lv_obj_constructor: finished   (in lv_obj.c line #710)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0 with 8 size     (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x20001320        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x20001320 with 16 size   (in lv_mem.c line #176)
[Trace] (0.000)   lv_mem_realloc: allocated at 0x20001320        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x20001320 with 24 size   (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x20001320       (in lv_mem.c line #195)
[Trace]   (0.000)  lv_event_send: Sending event 35 to 0x200012e4 with 0 param     (in lv_obj.c line #196)
[Trace]  (0.000)  lv_event_send: Sending event 18 to 0x200012e4 with 0x2000bdde param    (in lv_obj.c line #196)
[Trace]  (0.000)  lv_obj_create_from_class: Object created at 0x200012e4 address with 0x8028c74 class on 0 parent        (in lv_obj_class.c line #68)
[Trace]    (0.000)   lv_obj_create_from_class: Creating object with 0x8028c74 class on 0 parent     (in lv_obj_class.c line #44)
[Trace]     (0.000)  lv_mem_alloc: allocating 40 bytes      (in lv_mem.c line #118)
[Trace]  (0.000)  lv_mem_alloc: allocated at 0x2000133c  (in lv_mem.c line #143)
[Trace]  (0.000)  lv_obj_constructor: begin      (in lv_obj.c line #612)
[Trace]  (0.000)  lv_obj_constructor: creating a screen  (in lv_obj.c line #617)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x20001310 with 8 size    (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x20001310        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_obj_constructor: finished   (in lv_obj.c line #710)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0 with 8 size     (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x20001368        (in lv_mem.c line #195)
[Trace]  (0.000) lv_mem_realloc: reallocating 0x20001368 with 16 size    (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x20001368        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x20001368 with 24 size  (in lv_mem.c line #176)
[Trace]   (0.000)  lv_mem_realloc: allocated at 0x20001368        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_event_send: Sending event 35 to 0x2000133c with 0 param     (in lv_obj.c line #196)
[Trace]  (0.000)  lv_event_send: Sending event 18 to 0x2000133c with 0x2000bdde param    (in lv_obj.c line #196)
[Trace]  (0.000)  lv_obj_create_from_class: Object created at 0x2000133c address with 0x8028c74 class on 0 parent        (in lv_obj_class.c line #68)
[Trace]     (0.000)  lv_obj_create_from_class: Creating object with 0x8028c74 class on 0 parent     (in lv_obj_class.c line #44)
[Trace]     (0.000)  lv_mem_alloc: allocating 40 bytes      (in lv_mem.c line #118)
[Trace]  (0.000)  lv_mem_alloc: allocated at 0x20001384  (in lv_mem.c line #143)
[Trace]  (0.000)  lv_obj_constructor: begin      (in lv_obj.c line #612)
[Trace]  (0.000)  lv_obj_constructor: creating a screen  (in lv_obj.c line #617)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x20001310 with 12 size   (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x20001310        (in lv_mem.c line #195)
[Trace]  (0.000) lv_obj_constructor: finished    (in lv_obj.c line #710)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0 with 8 size     (in lv_mem.c line #176)
[Trace]  (0.000) lv_mem_realloc: allocated at 0x200013b0         (in lv_mem.c line #195)
[Trace] (0.000)   lv_mem_realloc: reallocating 0x200013b0 with 16 size   (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x200013b0        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x200013b0 with 24 size   (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x200013b0        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_event_send: Sending event 35 to 0x20001384 with 0 param     (in lv_obj.c line #196)
[Trace]  (0.000) lv_event_send: Sending event 18 to 0x20001384 with 0x2000bdde param     (in lv_obj.c line #196)
[Trace]  (0.000)  lv_obj_create_from_class: Object created at 0x20001384 address with 0x8028c74 class on 0 parent        (in lv_obj_class.c line #68)
[Trace]     (0.000)  lv_mem_realloc: reallocating 0x20001368 with 16 size  (in lv_mem.c line #176)
[Trace]   (0.000)  lv_mem_realloc: allocated at 0x20001368        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x20001368 with 8 size    (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x20001368        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x20001368 with 0 size    (in lv_mem.c line #176)
[Trace] (0.000)   lv_mem_realloc: using zero_mem         (in lv_mem.c line #178)
[Trace] (0.000)   lv_mem_free: freeing 0x20001368        (in lv_mem.c line #153)
 [Trace] (0.000)   lv_event_send: Sending event 35 to 0x2000133c with 0 param     (in lv_obj.c line #196)
[Trace]  (0.000)  lv_event_send: Sending event 18 to 0x2000133c with 0x2000be06 param    (in lv_obj.c line #196)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x200013b0 with 16 size   (in lv_mem.c line #176)
[Trace]  (0.000) lv_mem_realloc: allocated at 0x200013b0         (in lv_mem.c line #195)
[Trace] (0.000)   lv_mem_realloc: reallocating 0x200013b0 with 8 size    (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: allocated at 0x200013b0        (in lv_mem.c line #195)
[Trace]  (0.000)  lv_mem_realloc: reallocating 0x200013b0 with 0 size    (in lv_mem.c line #176)
[Trace]  (0.000)  lv_mem_realloc: using zero_mem (in lv_mem.c line #178)
[Trace]  (0.000)  lv_mem_free: freeing 0x200013b0       (in lv_mem.c line #153)
[Trace]   (0.000)  lv_event_send: Sending event 35 to 0x20001384 with 0 param     (in lv_obj.c line #196)
[Trace]  (0.000)  lv_event_send: Sending event 18 to 0x20001384 with 0x2000be06 param    (in lv_obj.c line #196)
[Trace]  (0.000)  lv_mem_alloc: allocating 32 bytes      (in lv_mem.c line #118)
[Trace]  (0.000)  lv_mem_alloc: allocated at 0x200013b0  (in lv_mem.c line #143)
[Trace]  (0.000)  lv_mem_alloc: allocating 32 bytes      (in lv_mem.c line #118)
[Trace]  (0.000)  lv_mem_alloc: allocated at 0x200013d4  (in lv_mem.c line #143)

when I watched lv_hal_disp.c, parent = null is default setting. I think It means that’s not error.

lv_disp_t * lv_disp_drv_register(lv_disp_drv_t * driver)
{
     ...

    disp->act_scr   = lv_obj_create(NULL, NULL); /*Create a default screen on the display*/
    disp->top_layer = lv_obj_create(NULL, NULL); /*Create top layer on the display*/
    disp->sys_layer = lv_obj_create(NULL, NULL); /*Create sys layer on the display*/
    lv_obj_remove_style(disp->top_layer, LV_PART_ANY, LV_STATE_ANY, NULL);
    lv_obj_remove_style(disp->sys_layer, LV_PART_ANY, LV_STATE_ANY, NULL);
    lv_obj_clear_flag(disp->top_layer, LV_OBJ_FLAG_CLICKABLE);
    lv_obj_clear_flag(disp->sys_layer, LV_OBJ_FLAG_CLICKABLE);

    ...
    return disp;
}

I’m trying to fix the problem night and day, now I’ve found something.
When I tried to run lv_example_get_started_1(), hard fault occurred. On the other hands, there is no error when I run lv_example_get_started_2(), 3().

I don’t know the reason, but I’m debugging with example 2, 3 :cry:
Anyway, I’m checking all lines to solve the problem.
Please let me know if anyone find weird things :slightly_smiling_face:

Set a break point in main (within your while(1) loop) e.g. when calling lv_task_handler().
Does it break on run?
Let it run again (resume) . Does it break again? You can do that multiple times!?

If it is not breaking again, stop the running, and look where the program currently is.
Any exception? looping forever?

When I set breakpoint at lv_task_handler() in main.c, program is still running in one loop forever.
It is HAL_Delay func, and the messasge “handle_vCont_t, Thread already stopped” popped up in console window.


//---------------------------------------------------------------//
  * @brief This function provides minimum delay (in milliseconds) based
  *        on variable incremented.
  * @note In the default implementation , SysTick timer is the source of time base.
  *       It is used to generate interrupts at regular time intervals where uwTick
  *       is incremented.
  * @note This function is declared as __weak to be overwritten in case of other
  *       implementations in user file.
  * @param Delay specifies the delay time length, in milliseconds.
  * @retval None
//---------------------------------------------------------------//

__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while ((HAL_GetTick() - tickstart) < wait)
  {
  }
}

reference function is below:

//defgroup HAL_Private_Variables HAL Private Variables

__IO uint32_t uwTick;
uint32_t uwTickPrio   = (1UL << __NVIC_PRIO_BITS); /* Invalid PRIO */
HAL_TickFreqTypeDef uwTickFreq = HAL_TICK_FREQ_DEFAULT;  /* 1KHz */

__weak void HAL_IncTick(void)
{
  uwTick += uwTickFreq;
}
__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}

Just to be sure:
It is breaking, you do a resume, it’s breaking again, you do a resume and it’s breaking again and so forth…

If you stop it manually it is reasonable that the program is running in the while loop in HAL_Delay, as this is a busy waiting loop.

the latter is my status.
I’m truly exhausted by endless work but I’m debugging anyway.

How does your App_Start look like?

I cannot write all of them, but it is easy to understand.

void App_Start(void)
{
	// deleted variables defined 

		HAL_UART_Receive_IT(&huart1, _rxBuffer1, RX_BUF_SIZE);

		#ifdef AL_LCD                     // preprocessor 
		     lv_init();
		     LCD_Init();                     // lcd initialization function
		     lv_config_main();
		#endif

		RED_LED_OFF;
		BLU_LED_ON;


		while(1)
		{

			#ifdef AL_RTC                     // preprocessor 
				now_sec = Rtc_Display();        // function to get current time 

				if ( now_sec != prev_sec )
				{
					BLU_LED_TGL;
					prev_sec = now_sec;
				}
			#endif

			Key_Check();        // key pad input function

			if ( uart_chk > 100 )
			{
				Uart1_rx_check();
				uart_chk = 0;
			}

			HAL_Delay(1);
			uart_chk++;
		}


}

When I call LCD_flush() in my_app.c, randomly declaring variables, the break point works!
I can step into the function.
Is it meaningful?

int lv_config_main(void)
{
	lv_init();

    static lv_disp_draw_buf_t disp_buf;								
    static lv_color_t buf_1[LV_HOR_RES_MAX*10];
    lv_disp_draw_buf_init(&disp_buf, buf_1, NULL, LV_HOR_RES_MAX * 10);

    lv_disp_drv_t disp_drv;	
    lv_disp_drv_init(&disp_drv);
    disp_drv.draw_buf = &disp_buf;

	lv_area_t area;
	lv_color_t * color_map;
	uint16_t *color;

	area.x1 = 0;
	area.y1 = 0;
	area.x2 = 52;
	area.y2 = 43;
	color = 0xb3fd;
	color_map = (lv_color_t*) color;

	LCD_flush(&disp_drv, &area, &color_map);

    lv_disp_t * disp_ex;
    disp_ex = lv_disp_drv_register(&disp_drv);									// Register the driver and save the created display objects

}