Description
Hi everyone,
I am experiencing tearing artifacts on my SPI TFT display (ILI9341) when using LVGL. Even after trying multiple SPI speeds from 21 MHz down to 5.25 MHz, the screen still shows tearing when updating UI elements.
What MCU/Processor/Board and compiler are you using?
- MCU: STM32F407
- Display: ILI9341 240×320 SPI
- Compiler/IDE: STM32CubeIDE with HAL
- **LVGL version:
branch (8.3.x)
What do you want to achieve?
Any suggestion to do expirement and to find down the root cause and fix it.
What have you tried so far?
- Adjusted SPI clock speed:
- 21 MHz (SPI prescaler = 2) → tearing occurs
- 10.5 MHz (SPI prescaler = 4) → still tearing
- 5.25 MHz (SPI prescaler = 8) → tearing reduced but still visible
- Used double buffering in LVGL with
lv_disp_draw_buf_init. - Called
lv_disp_flush_ready()only after the SPI transfer completes.
Code to reproduce
static void tft_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
{
if(area->x2 < 0 || area->y2 < 0 || area->x1 > (TFT_HOR_RES - 1) || area->y1 > (TFT_VER_RES - 1)) {
lv_disp_flush_ready(drv);
return;
}
/*Return if the area is out the screen*/
if(area->x2 < 0) return;
if(area->y2 < 0) return;
if(area->x1 > TFT_HOR_RES - 1) return;
if(area->y1 > TFT_VER_RES - 1) return;
/*Truncate the area to the screen*/
int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
int32_t act_x2 = area->x2 > TFT_HOR_RES - 1 ? TFT_HOR_RES - 1 : area->x2;
int32_t act_y2 = area->y2 > TFT_VER_RES - 1 ? TFT_VER_RES - 1 : area->y2;
lv_coord_t w = (area->x2 - area->x1) + 1;
lcd_set_display_area(act_x1,act_x2,act_y1,act_y2);
uint32_t len = (act_x2 - act_x1 + 1) * 2ul;
lcd_send_cmd_mem_write();
for(uint32_t y = act_y1; y <= act_y2; y++) {
lcd_write((uint8_t*)color_p, len);
color_p += w;
}
lv_disp_flush_ready(&disp_drv);
}
void lcd_write(uint8_t *buffer, uint32_t length)
{
// Modify SPI data size to 16 bits
__HAL_SPI_DISABLE(&lcd_spi_handle);
SET_SPI_16BIT_MODE(&lcd_spi_handle);
__HAL_SPI_ENABLE(&lcd_spi_handle);
// Transmit 16-bit data
LCD_CS_LOW();
uint16_t *data_ptr = (uint16_t *)buffer;
while (length) {
// Wait until TX buffer is empty
while (!(lcd_spi_handle.Instance->SR & SPI_SR_TXE));
// Send 16-bit data
lcd_spi_handle.Instance->DR = *data_ptr++;
length -= sizeof(uint16_t);
// Wait until transmission is complete
while (lcd_spi_handle.Instance->SR & SPI_SR_BSY);
}
LCD_CS_HIGH();
// Restore back to 8-bit mode
__HAL_SPI_DISABLE(&lcd_spi_handle);
SET_SPI_8BIT_MODE(&lcd_spi_handle);
__HAL_SPI_ENABLE(&lcd_spi_handle);
}
Screenshot and/or video
Thank you and appreciate your time
Thinh
