This however goes away once the benchmark is finished and the results are shown so it appears to either be some kind of strange buffer situation or a some kind of flushing before ready condition?
As far as I can tell, I’m doing everything correctly in terms of setup and usage of the underlying esp lcd functionality, but still the problem persists.
Weirdly, if I use the Arduino IDE, and an example I found online here:
I get it to run well (ensuring I choose the options spoken about in the video below) so I picked through the library he’s using (Arduino GFX) so I could copy the esp init details and ensure I’m doing it the same way with the same timings etc, but I still get the same thing.
The details of the screen:
Name of the module: ZX2D10GE01R (Panlee)
480x480 resolution
ST7701S driver
ESP32-S3 N16R8 built in
Software dev environment:
I’m using PlatformIO with ESP-IDF 5.1.1 (as far as I can make out from platformio feedback during upload.
I’m limited by the number of links I can put here as a new user so I’ll upload the code below
I’m attaching here the code for main.c, screen.c, board.h, lv_conf.h, platformio.ini, and sdkconfig. The platform.ini and sdkconfig files have had .txt added to the end to allow for uploading
Ok, after trying LOTS of different things, I have been able to ‘solve’ it by forcing LVGL to redraw the entire framebuffer every time (instead of just the area that has changed). This affects the performance quite a lot so I will continue to investigate to see exactly where the problem occurs. I have a feeling it is not in LVGL but in the code supplied by the manufacturer of the hardware.
To force the redraw of the entire buffer, edit screen.c and find the function called qmsd_rgb_init. Add the following:
lv_disp_drv_init(&disp_drv);
disp_drv.full_refresh = 1; // Add this line just after the line above
The problem is in the manufacturers supplied code. I am not sure how it ever would have worked without forcing the entire framebuffer to be rendered.
Every render cycle, a callback is called (lv_disp_drv_t.flush_cb) which passed in the area to draw and a pointer to the pixel data. The manufacturer;s callback looks like this:
static void __qsmd_rgb_disp_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
int offsetx1 = area->x1;
int offsetx2 = area->x2;
int offsety1 = area->y1;
int offsety2 = area->y2;
esp_lcd_panel_draw_bitmap(g_panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_p);
lv_disp_flush_ready(disp_drv);
}
From what I can tell, the pointer to the pixel data (color_p) is always the top of the framebuffer (it alternates between buf0 and buf1) even when a partial area is being drawn. The callback code is using a function called esp_lcd_panel_draw_bitmap (link) to dump a bitmap from the framebuffer to the screen. It expects the pixel data to be contiguous - which it is when drawing the whole framebuffer, but which it never is when drawing a partial area of the buffer
I’m not familiar with ESP32 yet, but I’m assuming there will be a function like esp_lcd_panel_draw_bitmap which allows drawing partial bitmaps (specify src and dest offsets and sizes separately). I’ll keep looking.
This display is an RGB display The color deoth is 16 bit so it only uses RGB565. There is an SPI attachment as well that is used to set up the bridge driver that is used between the display and the driver IC. You must set the render mode in LVGL to full in order for it to work properly partial mode is not going to work right. You need to use the esp-lcd component soecifically the rgb panel portion of the code. set the driver to use 2 frame buffers in spiram. collect the pointers for the frame buffers from the driver and pass them to the lvgl display driver. This is the important thing, you need to register a vsync callback. in that callback function is when you call the flush ready function in LVGL. This is what will switch the pointers. The rgb driver in the esp-lcd component has DMA memory support for SPIRAM. this allows the double buffering feature in lvgl to work and that is gong to get you the best possible performance. There is a cost of the additional memory use but on the S3 you want to get the model that has 8 mb of SPIRAM which would allow you to do that. YOu can also do it with smaller SPIRAM amounts it all depends on your application code.