Description
I have the need to set up double buffering in external SRAM. At this stage, I am using a draw_pixel function in my flush cb, this is low, so I want a way to draw a buffer, and then switch between the two buffers (one being displayed, one being drawn)
What MCU/Processor/Board and compiler are you using?
I am using an STM32 F769 on a custom board. I have external SRAM connected to it (IS61WV102416BLL). I then have a DSI to LVDS bridge as a display controller (SN65DSI83-Q1).
What would be the best way to get the most out of LVGL?
I assume that I should set up two buffers in the external SRAM (this memory can be directly accessed by the STM32 by using the appropriate address), so how would I go about creating these buffers in the SRAM and giving them to LVGL?
Then, I also assume there has to be some way of switching between buffers in my SRAM. It is my understanding that LVGL handles this internally (one buffer is drawn at a time while the other is being displayed) but how would I go about telling my display which buffer to read? I am assuming it needs to know:
LVGL is drawing buffer 1, so I should display buffer 2.
LVGL is drawing buffer 2, so I should display buffer 1.
I have limited understanding of how the display controller works, I have been developing for only a year now, and haven’t got the grasp of how these components work together on a low level.
What LVGL version are you using?
8+ (master, latest)
What do you want to achieve?
I want to get the most out of LVGL, possibly by implementing double buffering in external SRAM.
What have you tried so far?
At this stage, I have enabled double buffering, but my flush cb is very primitive:
In my init:
/*A static or global variable to store the buffers*/
static lv_disp_draw_buf_t My_Display_buf;
/*Static or global buffer(s). The second buffer is optional*/
static lv_color_t buf_1[LCDSize_Horizontal * 10];
static lv_color_t buf_2[LCDSize_Horizontal * 10];
/*Initialize `disp_buf` with the buffer(s). With only one buffer use NULL instead buf_2 */
lv_disp_draw_buf_init(&My_Display_buf, buf_1, buf_2, LCDSize_Horizontal*10);
/*Once the buffer initialization is ready a lv_disp_drv_t display driver needs to be initialized with lv_disp_drv_init(&disp_drv)*/
static lv_disp_drv_t LCD_Driver;
MyLCDDisplay = LVGLDisplayDriverInit(&LCD_Driver, &My_Display_buf);
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one
*`put_px` is just an example, it needs to implemented by you.*/
int32_t x, y;
for(y = area->y1; y <= area->y2; y++)
{
for(x = area->x1; x <= area->x2; x++) {
LVGL_DrawPixel(x, y, *color_p);
color_p++;
}
}
/* IMPORTANT!!!
* Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
lv_disp_t* LVGLDisplayDriverInit(lv_disp_drv_t* disp_drv, lv_disp_draw_buf_t* disp_buf)
{
//Initialise the driver
lv_disp_drv_init(disp_drv);
/*Set the resolution of the display*/
disp_drv->hor_res = LCDSize_Horizontal;
disp_drv->ver_res = LCDSize_Vertical;
/*Used to copy the buffer's content to the display*/
disp_drv->flush_cb = My_Flush_Callback;
/*Set a display buffer*/
disp_drv->draw_buf = disp_buf;
/*Finally register the driver*/
return lv_disp_drv_register(disp_drv);
}
This is my draw pixel fn
/**
* @brief Draws a pixel on LCD.
*/
void LVGL_DrawPixel(uint16_t Xpos, uint16_t Ypos, lv_color_t _color)
{
if(LCD_Settings.BPP*(Ypos*LCDControl_GetXSize() + Xpos) < LCD_Settings.Screensize_X*LCD_Settings.Screensize_Y*LCD_Settings.BPP)
{
uint8_t B = _color.ch.blue;
uint8_t G = _color.ch.green;
uint8_t R = _color.ch.red;
/* Write data value to all SDRAM memory */
*(__IO uint16_t*) (hltdc.LayerCfg[ActiveLayer].FBStartAdress + (LCD_Settings.BPP*(Ypos*LCDControl_GetXSize() + Xpos))) = RGBConvert(R,G,B);
}
}
I read the fn brief for lv_disp_draw_buf_init, where the following is stated
* @param buf2 Optionally specify a second buffer to make image rendering and image flushing
* (sending to the display) parallel.
* In the `disp_drv->flush` you should use DMA or similar hardware to send
* the image to the display in the background.
* It lets LVGL to render next frame into the other buffer while previous is being
* sent. Set to `NULL` if unused.
But I am still unsure of how to tell my display which buffer to display. I am also unsure of how to create the buffers at a specific address in the SRAM.
Any advice on where to look would be greatly appreciated.