Buffer size and flushing action


Through simple example for LVGL6.0, I’ve tried to create objects and control touch actions.

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

STM32F767II, IAR Workbench

What do you want to achieve?

I would like to check the primary functions provided by the library.

What have you tried so far?

Running the flush function with DMA with changing of buffer size.
Running the flush function without DMA with changing of buffer size.

If I set the one buffer size is 480x272, the flush function is OK.
But, if I set the buffer size to be less than 480x272, the flush function returns error (HAL_Error).

  • LCD resolution: 480 x 272

I’d like to know what I have missed.

Screenshot and/or video

Run the simple button example with a buffer size smaller than 272.
The error is occurred in flush function. err 2 is HAL_Error.

Code to reproduce

tft_init() -> modifying buffer size

#define LINE_NUMBER    (100)  //272
void tft_init(void)
  static lv_color_t buf1[LV_HOR_RES_MAX * LINE_NUMBER];  // 480 x 100 
  //static lv_color_t buf2[LV_HOR_RES_MAX * LINE_NUMBER ];
  static lv_disp_buf_t     disp_buf;
  lv_disp_buf_init(&disp_buf, buf1, NULL, LV_HOR_RES_MAX * LINE_NUMBER );
  //lv_disp_buf_init(&disp_buf, buf1, buf2, LV_HOR_RES_MAX * LINE_NUMBER );
  lv_disp_drv_t disp_drv;

tft_flush() with DMA

static void tft_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)

	/*Return if the area is out the screen*/
	if(area->x2 < 0) return;
	if(area->y2 < 0) return;
	if(area->x1 > TFT_HOR_RES - 1) return;
	if(area->y1 > TFT_VER_RES - 1) return;

	/*Truncate the area to the screen*/
	int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
	int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
	int32_t act_x2 = area->x2 > TFT_HOR_RES - 1 ? TFT_HOR_RES - 1 : area->x2;
	int32_t act_y2 = area->y2 > TFT_VER_RES - 1 ? TFT_VER_RES - 1 : area->y2;

	x1_flush = act_x1;
	y1_flush = act_y1;
	x2_flush = act_x2;
	y2_fill = act_y2;
	y_fill_act = act_y1;
	buf_to_flush = color_p;
	HAL_StatusTypeDef err;
	err = HAL_DMA_Start_IT(&DmaHandle,(uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush],
			  (x2_flush - x1_flush + 1));
	if(err != HAL_OK)
        printf("err occurred ---------------------------------------- \r\n");
        printf("err: %d\r\n", err);
	  while(1);	/*Halt on error*/

Screenshot and/or video

I’ve tried it with simple flush function (put all pixels to the screen one-by-one).
buffer size = 480x272 -> flush function OK, click event OK
buffer size < 480x272 -> flush function may be OK, But when clicked the button, weird display as shown below

Code to reproduce

simple flush function

static void tft_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
  int16_t y=0;
  uint16_t i, j;
  uint32_t w = lv_area_get_width(area);
  for(y = area->y1; y <= area->y2 && y < disp_drv->ver_res; y++) {
    memcpy((uint16_t *)&my_fb[y * TFT_HOR_RES + area->x1], color_p, TFT_HOR_RES* LINE_NUMBER * 2); //sizeof(lv_color_t));
    color_p += w;

Please fill the template to provide enough information to investigate your issue.

> ## Important: posts that do not use this template will be ignored or closed.
> ## Before posting
> - Get familiar with [Markdown](https://forum.lvgl.io/t/get-familiar-with-markdown/403) to format and structure your post
> - Be sure to update [lvgl](https://github.com/littlevgl/lvgl) from the latest version from the `master` branch.
> - Be sure you have checked the relevant part of the [documentation](https://docs.littlevgl.com/en/html/index.html). **We will not respond in detail to posts where you haven't read the relevant documentation.**
> - If applicable use the [Simulator](https://docs.littlevgl.com/en/html/get-started/pc-simulator.html) to eliminate hardware related issues.
>  *Delete this section if you read and applied the mentioned points.*
## Description

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

###  What do you want to achieve?

### What have you tried so far?

## 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.

The code block(s) should be formatted like:
/*You code here*/

Could you give me some hint or solution to solve this problem?

If you use memcpy you should copy 1 line at a time. See this as a reference:

Thanks for reply. I’m out of office now, so I will try it tomorrow and then tell you its result.

Thanks. the simple tft_flush() dose work perfectly.:smile:

By the way, I would like to use tft_flush() with DMA (https://github.com/littlevgl/stm32f429_disco_no_os_sw4stm32/blob/master/hal_stm_lvgl/tft/tft.c). it still dose not work.
What I have missed?

What’s not working with the DMA version?

  • Normal case
    Buffer size = 480 x 1


  • Normal case
    Buffer size = 480 x 272


  • Abnormal case: occurs when y_fill_act > y2_fill
    Buffer size = 480 x 2 ~ 480 x 271
    ex: Buffer size = 480 x 10

You should should stop flushing when you reach y2_fill. Only the area shown by the area parameter needs to be updated. See the DMA_TransferComplete function.

The DMA_TransferComplete function has been used before.
I tried to run the dma in tft_flush function when only y_fill_act is smaller than y2_fill. But it dose not work properly.
How can I stop the flush function properly.

        HAL_StatusTypeDef err = HAL_OK;
        if(y_fill_act <= y2_fill)
           err = HAL_DMA_Start_IT(&DmaHandle,(uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush],
                               (x2_flush - x1_flush + 1));

See the link in my previous comment.

I have been using the DMA_TransferComplete function same as the link.

The y_fill_act value is monitored as shown below, when the DMA_TransferComplete event is occurred.

static void DMA_TransferComplete(DMA_HandleTypeDef *han)
  y_fill_act ++;
  printf("----->DMA_TransferComplete: y_fill_act=%d\r\n", y_fill_act);
  if(y_fill_act > y2_fill) {
  } else {
    buf_to_flush += x2_flush - x1_flush + 1;
    /*##-7- Start the DMA transfer using the interrupt mode ####################*/
    /* Configure the source, destination and buffer size DMA fields and Start DMA Stream transfer */
    /* Enable All the DMA interrupts */
    if(HAL_DMA_Start_IT(han,(uint32_t)buf_to_flush, (uint32_t)&my_fb[y_fill_act * TFT_HOR_RES + x1_flush],
                        (x2_flush - x1_flush + 1)) != HAL_OK)
      while(1);	/*Halt on error*/

It’s strange that destination is the same value in the last two “blocks”.

yeah, it’s strange that y_fill_act value is not equal y1_flush too.

  • buffer size = 480 x 10
  • y_fill_act, buf_to_flush value monitoring when DMA_TransferComplete is occurred
  • y_fill_act, buf_to_flush value monitoring when tft_flush with dma function is called
    I don’t know why the ftf_flush function is called before DMA_TransferComplete is completed.

tft_flush with dma in double buffer dose work properly.
but single buffer still dose not work.
why is this?

#define LINE_NUMBER    (10)
void tft_init(void)
  static lv_color_t buf1[LV_HOR_RES_MAX * LINE_NUMBER];
  static lv_color_t buf2[LV_HOR_RES_MAX * LINE_NUMBER];
  static lv_disp_buf_t     disp_buf;
  //lv_disp_buf_init(&disp_buf, buf1, NULL, LV_HOR_RES_MAX * LINE_NUMBER );
  lv_disp_buf_init(&disp_buf, buf1, buf2, LV_HOR_RES_MAX * LINE_NUMBER );


Do you call lv_disp_flush_ready(disp_drv); only DMA_TransferComplete and not in tft_flush, right?

I added the lv_disp_flush_ready(disp_drv); in the tft_flush with DMA function to fix the event action through my previous post “Button event dose not work”.

Anyway now it works perfectly after removing the lv_disp_flush_ready in the tft_flush function.


Awesome! :slight_smile: