Performance ideas

I have an application with 12 screens, and I’m working at improving performance.

The screens are240x240 16bit 565RGB and the bus is 25mhz SPI, with 4 screens sharing a bus, so 3 buses total.

My driver is written using a queue system and DMA, so my_disp_flush writes a selected area and the flush_complete_cb is fired to call lv_disp_flush_ready.

My SDRAM buffers are set to slightly oversize so I don’t have true double buffering, which would case unnecessary bus traffic.

The bottlenecks are as follows:
When a screen has more than two areas to refresh, it spends a lot of time in one of the while(vdb->flushing); instead of proceeding on to try the next screen.

At this point, I think the library should at least have some RTOS macro options to task yield at these points, and perhaps the task scheduler or lv_refr_areas could be tweaked to yield a more round robin approach between screens?

1 Like

12 screens… I certainly wasn’t thinking of that when multi-display support was implemented back in 6.0. :slightly_smiling_face:

Here’s our discussion about that:

7.0 will have a wait_cb function which can be used for this purpose, but you need to make sure that your RTOS can switch tasks frequently enough so that this doesn’t add a delay.

In the past @kisvegabor had floated the idea of changing the display refresh logic to use something along the lines of a state machine instead of a while(vdb->flushing) loop. If that were done, it would potentially allow for multiple displays being refreshed at the same time. I’d be willing to experiment with that, but it would have to wait until 7.1, as 7.0 is essentially feature-frozen at this point.

1 Like

Another related question, is there any way to tweak the task order?

For example, I’d really like to refresh screens in a particular order, in my case I’d like to use bus 1,2,3, and so on, rather than screen order. Is this random or does it depend on the order lv_disp_drv_register gets called?

I’ve never tested it, but if I’ve read the task handling code correctly, they will refresh in the reverse order of calls to lv_disp_drv_register. So if you register bus 1, 2, and 3 (in that order), 3 will be refreshed first.

@friesendrywall We can really improve the refreshing logic as @embeddedt mentioned.
I’ve added this to my todo list for the upcoming releases.

@ embeddedt

7.0 will have a wait_cb function which can be used for this purpose

Trying to put a wait callback wait_cb function for frame synchronization. I am using version 7.2.0. My OLED has a FR signal output on every frame to solve tearing effect.
The wait_cb function is shown below:

void my_wait_cb(lv_disp_drv_t * disp_drv)
//enable gpio irq on 0->1 transition
//wait_until_FR pin triggered
//reset FR pin state
//disable gpio irq 

The function is registered with disp_drv.wait_cb = my_wait_cb

Trying to trace the while(vdb->flushing) loop from lv_refr.c at:

if(lv_disp_is_double_buf(disp_refr) == false) {
        while(vdb->flushing) {
            if(disp_refr->driver.wait_cb)  disp_refr->driver.wait_cb(&disp_refr->driver);

The line after while(vdb->flushing) is not exceuted, that means vdb->flushing is always 0.

I am setting a single full frame buffer to cover the entire display by
lv_disp_buf_init(&lv_disp_buf, lv_buf_array, NULL, LV_HOR_RES_MAX*LV_VER_RES_MAX);

Not sure if that is the reason. Any idea?


wait_cb can be used to perform some simple and short task while LVGL waits for something.

Exactly what does synchronizing frames mean in your case. You want to wait for FR signal to start rendering?

Please, create a new topic for it to keep forum clean.