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