LVGL 8.3 | Meter | Needle is flickering while updating its value

Important: unclear posts may not receive useful answers.

STM32L4P5VG.zip (151.3 KB)

Description

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

Microcontroller: STM32L4P5VGT6 with STM32CubeIDE v1.16.0
GUI development: EEZ studio v0.14.0

What LVGL version are you using?

LVGL v8.3

What do you want to achieve?

Updating the elements without flickering

What have you tried so far?

I have tried playing with the settings inside “STYLE” and “FLAGS” for the Meter widget.

Code to reproduce

I’ve attached the UI design files.

int main(void)
{
	lv_init();
	ui_init();
	for(;;)
	{
		HAL_Delay(5);
		lv_timer_handler();
		ui_tick();

		i+=adder;
		{
			set_var_command_speed(abs(i));
			char _t[10];
			sprintf(_t, "%d", abs(i));
			set_var_command_speed_text(_t);
			update_screen = true;
		}
		if(i >= 50)
		{
			adder=-1;
		}
		if(i <= -50)
		{
			adder=1;
		}
	}
}

Screenshot and/or video

If possible, add screenshots and/or videos about the current state.
Slo-Mo video of the UI

I went into the debug more of STM and tried back tracing the source of the problem.
First of all, I’m calling a function inside vars.c to update the value to be displayed on the “meter” widget. Thereafter, when the object value is updated by ui_tick(), the lv_timer_handler() seems to be clearing the concerned area by drawing a blank rectangle over it

lv_obj_draw(lv_event_t * e)
{
    else if(code == LV_EVENT_DRAW_MAIN) {
        lv_draw_rect(draw_ctx, &draw_dsc, &coords); // this function
    }
}

and later drawing the new content over it by calling the lv_meter_event()

lv_meter_event(const lv_obj_class_t * class_p, lv_event_t * e)
{
    if(code == LV_EVENT_DRAW_MAIN) {
        // drawing the needles, etc.
    }
}

I temporarily commented out the lv_draw_rect() inside lv_obj_draw(), but then the next draw just overlapped the previous one (makes sense).
This cycle of clearing first and then drawing again is giving a flickering effect.

@kisvegabor any help here?

Does this only occur with the meter or also with any object that changes visually? Try changing a label text every second or so, I suspect you will see the same effect then.

Looks like LVGL is drawing directly to your display buffer, that will always cause this effect no matter what, if you update quickly enough it may not be visible.

Yes, this effect is visible on labels as well.
For example, if a variable is updated every 5ms (ui_ticks is also running every 5ms), then the needle on the meter and the text label flicker a lot. Slowing down the update rate to every 100ms improves it a little, but the flicker is still visible.

I feel its more efficient to overwrite the existing area with the new area instead of first erasing then drawing, but I don’t know where exactly to make these changes.

I think it will be quite complicated to make the change you are suggesting, as it is at the core of LVGL. Perhaps try a different method for flushing to your display, I think partial refresh will mostly fix this if implemented correctly.

Primary your code is nonsense. Managing time ticks inside loop cant work ok.
Optimal is inc ticks irq or base it on hw timer. On STM TIM2 is 32bit optimal here.

Thats correct, but for now I just want to test the functionality of the GUI before I write a production-level code that includes timers, etc.

I enabled the second buffer and then copied them using DMA2D.
Both buffers are of full size.
This time, the flickering has reduced, but not completely eliminated.
I’m still trying to find out why, but my guess is that the framebuffer_2 is copied into framebuffer_1 and transferred to the screen, before the area in buffer2 is completely updated.

1 Like

Hello,

Yes I suspect that may be the case, when do you call the lv_display_flush_ready() function?
I call it at the end of DMA transfer and do not get any noticable flickering, some slight tearing is to be expected depending on the speed of your processor.

in real world lvconf is set to 30ms refresh by default, then screen is updated only every sixth lv_timer_handler call, but this must have info about real ms. Too your code stupid update and increment every 5ms somethink , that isnt raely visible on display or send to framebuffer…

I’ve modified the “LV_DISP_DEF_REFR_PERIOD” from 30 to 20, 10, 5, 1 (ms)
No difference.
I’ve modified the code as follows

int main(void)
{
	lv_init();
	ui_init();
	for(;;)
	{
		HAL_Delay(5);
		lv_timer_handler();
		ui_tick();
	}
}

timer_isr_callback() // a timer running at 10Hz
{
	i += adder;
	{
		set_var_command_speed(i); // update the value for the meter needle
	}
	if (i >= 100)
	{
		adder = -1;
	}
	if (i <= 0)
	{
		adder = 1;
	}
}

Moreover, the lvgl ticks are updated from systick

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  HAL_SYSTICK_IRQHandler();
  lv_tick_inc(1);
  #ifdef USE_RTOS_SYSTICK
    osSystickHandler();
  #endif

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */

  /* USER CODE END SysTick_IRQn 1 */
}

Even now, the flickering issue remains, as in the process of erasing the area, then drawing new area is visible on the screen.

show this func and read Operating system and interrupts — LVGL documentation

update from interrupt callback is unsupported…

Issue solved.

  1. Use 2 full-sized frame buffers.
  2. Use RTOS instead of baremetal.
  3. Define separate threads for lv_timer_handler() and ui_tick().
  4. Use mutex for enabling either lv_timer_handler() or the lv_…() functions, at one time.
  5. provide sufficient stack size for the tasks.

Refer the following code for ST controllers

Thanks for the helping pointers.

1 Like