ESP32S3 with LovyanGFX / Double buffer with direct render mode

Description

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

LVGL 9.1 + ESP32S3 with platformIO (framework : Arduino)
Library use to drive screen : LovyanGFX
Screen used : ILI9488

What LVGL version are you using?

LVGL 9.1

What do you want to achieve?

I want to use 2 full screen size buffer in direct render mode.

What have you tried so far?

Using two partial size buffer with LV_DISPLAY_RENDER_MODE_PARTIAL → Working

Code to reproduce

Partial mode version

Setup () [only revelant part] :


/*Set to your screen resolution*/
#define TFT_HOR_RES   480
#define TFT_VER_RES   320


/*LVGL draw into this buffer, 1/10 screen size usually works well. The size is in bytes*/
#define DRAW_BUF_SIZE ((TFT_HOR_RES * TFT_VER_RES) /10   * (LV_COLOR_DEPTH ) / 4)

uint8_t*  draw_buf = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM);
uint8_t*  draw_buf_2 = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM);



Setup() {
  lcd.init();
  lcd.setRotation(3);

  lv_init();

  static lv_display_t *lvDisplay = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
  lv_display_set_color_format(lvDisplay, LV_COLOR_FORMAT_RGB565);
  lv_display_set_flush_cb(lvDisplay, my_disp_flush);
  lv_display_set_buffers(lvDisplay, draw_buf, draw_buf_2, DRAW_BUF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);

}

flush callback :

void my_disp_flush(lv_display_t* display, const lv_area_t* area, unsigned char* data) {

  uint32_t w = lv_area_get_width(area);
  uint32_t h = lv_area_get_height(area);
  lv_draw_sw_rgb565_swap(data, w*h);
  if (lcd.getStartCount() == 0) {   // Processing if not yet started
    
    lcd.startWrite();
  }
  lcd.pushImageDMA( area->x1
                , area->y1
                , area->x2 - area->x1 + 1
                , area->y2 - area->y1 + 1
                ,(uint16_t*) data); 

  lv_display_flush_ready(display);
}

Direct mode version

I have only changed size of the buffer and buffer configuration :

Setup () *[only revelant part]* :
```c

/*Set to your screen resolution*/
#define TFT_HOR_RES   480
#define TFT_VER_RES   320


/*LVGL draw into this buffer, 1/10 screen size usually works well. The size is in bytes*/
#define DRAW_BUF_SIZE ((TFT_HOR_RES * TFT_VER_RES)   * (LV_COLOR_DEPTH ) / 4)

uint8_t*  draw_buf = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM);
uint8_t*  draw_buf_2 = (uint8_t *)heap_caps_malloc(DRAW_BUF_SIZE, MALLOC_CAP_SPIRAM);



Setup() {
  lcd.init();
  lcd.setRotation(3);

  lv_init();

  static lv_display_t *lvDisplay = lv_display_create(TFT_HOR_RES, TFT_VER_RES);
  lv_display_set_color_format(lvDisplay, LV_COLOR_FORMAT_RGB565);
  lv_display_set_flush_cb(lvDisplay, my_disp_flush);
  lv_display_set_buffers(lvDisplay, draw_buf, draw_buf_2, DRAW_BUF_SIZE, LV_DISPLAY_RENDER_MODE_DIRECT);

}

Screenshot and/or video

Partial mode with “screen scanning” effect : link

Direct mode (not working at all) : link

Post

Hey guys,

As you can see in the video, there is some “screen scanning” effect when loading a new screen (not sure of the translastion in english :sweat_smile:).

To get rid of that I’m trying to work with two full sized buffer. (buffers located in PSRAM)
My code is already working with partial screen buffer but it’s not working at all with two full sized buffers (see the 2nd video).

From reading other post, I understand that I need to edit my ‘flush_cb’ because in DIRECT_MODE, data returned is not the same as in PARTIAL_MODE.
I’m also aware that I need to use DMA because otherwise there is no point in having 2 full sized buffers.

The fact is, I have no idea how to edit my flush callback. I copy-pasted the example from LovyanGFX with a few modification, and it was working (shame on me :pensive:).

My first question is, am I adressing the problem in the right way?

Second question is, how to edit my flush callback ?

Many thanks in advance.
Thomas.

Hey guys,

I had set this topic aside a bit, but if anyone can help or has a lead, I’d be grateful.

Thomas.

Hi Pataone!
Can PSRAM be used with DMA directly on the SPI bus to update the display? I thought not-
I am using M5Core2 and M5CoreS3 modules.

Hi ZsoltyFM,

Apologies for the delay, and Happy New Year! :tada:

From my testing and research, it seems that SPI PSRAM cannot be accessed with DMA. Only internal RAM appears to support it.

I experienced very poor results when refreshing the screen using MALLOC_CAP_SPIRAM.

I hope this helps.

Best regards,
Thomas

I don’t know the usage case here, but it’s generally a bad idea to use a malloc for refreshing. malloc can be a very slow function, so it’s better to malloc spaces at start of the program, and only refresh it’s content at each frame. Most interactive libs would give you this advice.

Can be interesting to read on the subject:

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/memory-types.html#dma-capable-requirement

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/memory-types.html#dma-buffer-in-the-stack