STM32 LTDC + LVGL: Rectangle rendering corrupted

What do you want to achieve?

I want to display a simple UI using LVGL on an RGB LCD panel (ST7701, 480x854) with LTDC.
Specifically, I want to render a solid background and a small rectangle correctly without any distortion.


What have you tried so far?

  • Filling the framebuffer manually in lcd_init() using lcd_fill_color() works correctly (solid red screen is displayed without issues).

  • LTDC is configured and running in RGB565 mode with external SRAM (FMC, 16-bit bus).

  • LVGL is initialized and a simple test function is executed to draw:

    • A green background
    • A blue rectangle
  • The background is rendered correctly.

  • However, the rectangle appears corrupted:

    • It is diagonally shifted and looks sliced.
    • It does not form a proper rectangle.

Additional debugging:

  • I inspected the framebuffer memory directly using the debugger.
  • Some memory locations do not contain the expected values based on coordinate calculations.
  • The first pixel of the rectangle is correct (blue),
  • But inside the rectangle, pixel values become inconsistent or misaligned.
  • The corruption pattern appears diagonally across the screen.

Code to reproduce

/* You code here */

int main(void)
{

/* USER CODE BEGIN 1 /
/
USER CODE END 1 */

/* MPU Configuration--------------------------------------------------------*/
MPU_Config();

/* Enable the CPU Cache */

/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();

/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init /
/
USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals /
MX_GPIO_Init();
MX_FMC_Init();
MX_LTDC_Init();
MX_QUADSPI_Init();
MX_UART5_Init();
MX_USART1_UART_Init();
MX_TIM4_Init();
/
USER CODE BEGIN 2 */
lv_init();

lcd_init();
// lv_port_disp_init();

// ── 테스트 UI
// lv_obj_t *label = lv_label_create(lv_scr_act());
// lv_label_set_text(label, “Hello, LVGL!”);
// lv_obj_center(label);

// lv_demo_widgets();
lvgl_simple_test();
/* USER CODE END 2 */

/* Infinite loop /
/
USER CODE BEGIN WHILE */
while (1)
{
lv_task_handler();

HAL_Delay(1);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

}
/* USER CODE END 3 */
}

void lcd_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};

/* PC10(CLK), PC12(MOSI)를 SPI3 AF에서 GPIO Output으로 재설정 */
GPIO_InitStruct.Pin   = LCD_SPI_CLK_Pin | LCD_SPI_MOSI_Pin;
GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull  = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

// ✅ 두 레이어 모두 검정으로 초기화
memset((void *)0x60000000, 0x00, 480 * 854 * 2);
memset((void *)0x60100000, 0x00, 480 * 854 * 2);

// 1. 프레임버퍼에 RED 미리 채워두기 (ST7701 활성화 시 바로 표시)
lcd_fill_color(LCD_COLOR_RED);

// 2. ST7701 리셋
lcd_reset();

// 3. ST7701 초기화
lcd_config();

// 4. 백라이트 켜기
lcd_backlight_set(LCD_BL_MAX);

void * fb1 = (void *)LCD_FB_LAYER0;   // ⚠️ SRAM 주소로 수정
void * fb2 = (void *)LCD_FB_LAYER1;   // ⚠️ SRAM 주소로 수정

lv_display_t * disp = lv_st_ltdc_create_direct(fb1, fb2, 0);

}

void lvgl_simple_test(void)
{
// LVGL 객체로 그리기 (FB 직접 접근 X)
lv_obj_t *scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, lv_color_hex(0x00FF00), 0);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);

lv_obj_t *box = lv_obj_create(scr);
lv_obj_set_size(box, 100, 100);
lv_obj_set_pos(box, 10, 10);
lv_obj_set_style_bg_color(box, lv_color_hex(0x0000FF), 0);

}

Screenshot and/or video


Environment

  • MCU/MPU/Board: STM32H743ZIT6 + External SRAM (FMC, 2MB) + ST7701 RGB LCD (480x854)
  • LVGL version: 9.3

Most probably it’s no LVGL bug, just it a bit incorrect peripherial setup in STM32. Check FMC SRAM timing with chip datashet and set the correct value… OR simply for “hit or not” try the slow down bus/RAM/LTDC/FMC speed parameter values like DATA_SETUP_TIME, DATA_HOLD_TIME and so on.

@sphinx3015 , please take look at this porting:

More details, visit the official documentation