Are there any LVGL driver example for STM32H7 with DMA?

I’ve got the example working on the STM32F746 disco and get a frame rate of about 30FPS using this code:

My project need to use a STM32H743 and I’m using the dev board from waveshare:

I’ve managed to get LVGL v 7.8.1 working but the frame rate is really slow at about 15 FPS.
In ex_disp_flush() it is drawing one pixel at a time in a loop.

I’ve tried to use the DMA function from the F746 example but it is not working on the H743 as it give a hard fault. I think the settings are quite different but I can not work out what.

Are there any example driver with DMA for use with the STM32H743 ?

You could try the project; I believe the display hardware on the F769 board is closer to what you find on an H7 than the F746 board.

Other than that, I don’t think there is any H7 example project at the moment. :slightly_frowning_face:

I own a OpenH7XX board, and running lvgl on it is no problem.
I think there is no real difference between the different STM32F families in relation of using lvgl.

Maybe more a misinterpretation of FPS which is shown within the display when you set LV_USE_PERF_MONITOR to 1 witin lv_conf.h?

Setting the framerate is done with the setting of LV_DISP_DEF_REFR_PERIOD within lv_conf.h
So if you set 20 (ms) you get 50 FPS, with 30 (ms) you get 33 FPS.
The % CPU is calculated as the number of ticks (1 ms) which the function (‘task’) _lv_disp_refr_task needs for doing the drawing.

FPS is of course going down if _lv_disp_refr_task take more than 100% of CPU time. This indeed can be caused by a slow flush_cb function.

My flush_cb is also a simple (two, to be honest) loop. I do not use DMA2D because I need a rotation of the display for which I can’t use the DMA2D.

So the question is, when do you see the FPS of 15? Always? Means there is not really something to redraw (means also CPU is 0%)? Or under heavy redraw action (when CPU is getting high)?

The LV_DISP_DEF_REFR_PERIOD is set at 30. I’m using the lv_demo_music() and can see the update is sluggish. The average FPS is 14.

static void ex_disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
    int32_t x, y;
    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
         	BSP_LCD_DrawPixel(x, y, color_p->full);

void BSP_LCD_DrawPixel(uint16_t Xpos, uint16_t Ypos, uint32_t RGB_Code)
  /* Write data value to all SDRAM memory */
  if(hLtdcHandler.LayerCfg[ActiveLayer].PixelFormat == LTDC_PIXEL_FORMAT_RGB565)
  { /* RGB565 format */
	  *(__IO uint16_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (2*(Ypos*BSP_LCD_GetXSize() + Xpos))) = (uint16_t)RGB_Code;

  { /* ARGB8888 format */
    *(__IO uint32_t*) (hLtdcHandler.LayerCfg[ActiveLayer].FBStartAdress + (4*(Ypos*BSP_LCD_GetXSize() + Xpos))) = RGB_Code;

Maybe drawing the pixel can be optimised ?

Are you using a single buffer?
Maybe you can show your initialization? The part where you call lv_disp_buf_init.

Of course the ex_disp_flush can be written to use the DMA2D.
You also could try to write your own DrawPixel function. One which uses fixed framebuffer addess and fixed display sizes to avoid calling subfunctions.
But I don’t think, that’s the problem here.

I tried the lv_demo_music with my board.
Framerate is 33 FPS as expected. Of course can go down on start of animation.
I just see some strange artifacts on the screen. Seems to be that something isn’t really properly scaled up
to my 800 x 480 resolution.

This is my init:

     /* LittlevGL requires a buffer where it draws the objects. The buffer's has to be greater than 1 display row*/
     static lv_disp_buf_t disp_buf_2;
     static lv_color_t buf2_1[LV_HOR_RES_MAX * 40];                        /*A buffer for 10 rows*/
     static lv_color_t buf2_2[LV_HOR_RES_MAX * 40];                        /*An other buffer for 10 rows*/
     lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 40);   /*Initialize the display buffer*/

	* Register the display in LittlevGL

    /*Set the resolution of the display*/
     display_drv.hor_res = 800;
     display_drv.ver_res = 480;

	/*Used to copy the buffer's content to the display*/
     display_drv.flush_cb = ex_disp_flush;

    /*Set a display buffer*/
     display_drv.buffer = &disp_buf_2;

    /*Finally register the driver*/

How are you initialising LVGL ?

I am also using a 800 x 480 4.5" LCD. I don’t see any artefacts.

You just need only one buffer. So remove the bug_2_2.
Just do:

lv_disp_buf_init (&disp_buf_2, buf2_1, NULL, LV_HOR_RES_MAX * 40);

Using two buffers is meant for double buffering, and in this case you need two buffers which can hold the full frame.
I’m not sure, but I think double buffering is not really working good. Sometimes lvgl makes full copy of one frame buffer to the second, and then the real drawing takes place. The full buffer copying will take ‘a lot’ of time. Which is in addition to the normal drawing. Maybe this is the reason for lower FPS.


lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 40);   /*Initialize the display buffer*/

lv_disp_buf_init (&disp_buf_2, buf2_1, NULL, LV_HOR_RES_MAX * 40);

Didn’t make any difference to the frame rate.

That’s how I do it.

Sure your MCU clock isn’t slow?

The MCU is running at 400MHz.

Found my mistake within flush function. So, artefacts are away.

This is my flush function:

  int32_t     y;
  int32_t     x;
  int32_t     ys;
  int32_t     xs;
  uint32_t    w;
  ULONG       ulSource;
  ULONG       ulDest;

  w = lv_area_get_width (area);

  for (x = area->x1, xs = 0; x <= area->x2; x++, xs++) {
    for (y = area->y1, ys = 0; y <= area->y2; y++, ys++) {
      ulSource = (ULONG) color_p    + ((xs + (ys * w)) * sizeof (lv_color_t));
      ulDest   = (ULONG) 0xd0000000 + ((x  + (y  * disp_drv->hor_res)) * sizeof (lv_color_t));
      *((ULONG*) ulDest) = *((ULONG*) ulSource);

When playing music (ok, no sound output of course), FPS is 33 and CPU is around 50%