ESP32 display flipped

Description

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

Seeed XIAO ESP32s3

What do you want to achieve?

Trying to flip the display to be landscape and text to be flipped the correct way

What have you tried so far?

Using different combinations of true and false in

  ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));```

Also tried swapping 240 and 320 in
```c #define LCD_H_RES 240
#define LCD_V_RES 320

to no avail. The canvas rotates to landscape but the display itself is still portrait so when the canvas renders on the screen the left and right side of it are cut off, and the space underneath is grey due to it being out of canvas.

Code to reproduce

Add the relevant code snippets here.

#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_err.h"
#include "esp_log.h"
#include <stdio.h>

#include "esp_lcd_ili9341.h"
#include "esp_lcd_panel_interface.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_vendor.h"

#include "esp_lvgl_port.h"
#include "lvgl.h"

// ----- Adjust these to your wiring -----
#define LCD_HOST SPI2_HOST

// XIAO ESP32S3 default SPI pins (per Seeed docs)
#define PIN_NUM_SCLK 7 // D8
#define PIN_NUM_MOSI 9 // D10
// MISO not used by ILI9341
// #define PIN_NUM_MISO        8   // D9 (if needed, wire it & add to bus
// config)

// Control pins you chose above
#define PIN_NUM_DC 6  // D1
#define PIN_NUM_RST 5 // D4; use -1 if your board ties reset
#define PIN_NUM_CS 4  // D0
#define PIN_NUM_BL -1 // D3; set to -1 if backlight hardwired

// Panel resolution (portrait default for most 2.8” ILI9341)
#define LCD_H_RES 240
#define LCD_V_RES 320

static const char *TAG = "APP";

static void backlight_on(void) {
#if PIN_NUM_BL >= 0
  gpio_config_t io_conf = {
      .pin_bit_mask = 1ULL << PIN_NUM_BL,
      .mode = GPIO_MODE_OUTPUT,
      .pull_down_en = 0,
      .pull_up_en = 0,
      .intr_type = GPIO_INTR_DISABLE,
  };
  gpio_config(&io_conf);
  gpio_set_level(PIN_NUM_BL, 1); // Full brightness (or drive PWM if needed)
#endif
}

static void event_handler(lv_event_t *e) {
  lv_event_code_t code = lv_event_get_code(e);
  lv_obj_t *obj = lv_event_get_target(e);

  if (code == LV_EVENT_CLICKED) {
    ESP_LOGI("LVGL", "Button clicked!");
    lv_label_set_text(obj, "Clicked!");
  }
}

void app_main(void) {
  ESP_LOGI(TAG, "Initialize SPI bus");
  spi_bus_config_t buscfg = ILI9341_PANEL_BUS_SPI_CONFIG(
      PIN_NUM_SCLK,                     // SCLK
      PIN_NUM_MOSI,                     // MOSI
      LCD_H_RES * 40 * sizeof(uint16_t) // Max transfer bytes (tune if needed)
  );
  ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

  ESP_LOGI(TAG, "Create panel IO (SPI)");
  esp_lcd_panel_io_handle_t io_handle = NULL;
  const esp_lcd_panel_io_spi_config_t io_config = ILI9341_PANEL_IO_SPI_CONFIG(
      PIN_NUM_CS, // CS
      PIN_NUM_DC, // DC
      NULL,       // no on_color_trans_done callback (LVGL port handles sync)
      NULL);
  ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST,
                                           &io_config, &io_handle));

  ESP_LOGI(TAG, "Install ILI9341 panel driver");
  esp_lcd_panel_handle_t panel_handle = NULL;
  const esp_lcd_panel_dev_config_t panel_config = {
      .reset_gpio_num = PIN_NUM_RST, // -1 if not used
      .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
      .bits_per_pixel = 16, // RGB565
  };
  ESP_ERROR_CHECK(
      esp_lcd_new_panel_ili9341(io_handle, &panel_config, &panel_handle));

  ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
  ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));

  // Rotate to landscape (ILI9341 is rotated by swapping X/Y and mirroring Y)
  ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
  ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));

  ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

  backlight_on();

  ESP_LOGI(TAG, "Init LVGL port");
  const lvgl_port_cfg_t lvgl_cfg =
      ESP_LVGL_PORT_INIT_CONFIG(); // creates LVGL task/timer for you
  ESP_ERROR_CHECK(lvgl_port_init(&lvgl_cfg));

  ESP_LOGI(TAG, "Add LVGL display");
  const lvgl_port_display_cfg_t disp_cfg = {
      .io_handle = io_handle,
      .panel_handle = panel_handle,
      .buffer_size = LCD_H_RES * 40, // tune as needed
      .double_buffer = true,
      .hres = LCD_H_RES,
      .vres = LCD_V_RES,
      .monochrome = false,
      // .color_format = LV_COLOR_FORMAT_RGB565,  // keep if available in your
      // version; otherwise comment out
      .flags = {
          .buff_dma = true,
          .swap_bytes = false,
      }};

  lv_disp_t *disp = lvgl_port_add_disp(&disp_cfg);
  (void)disp;

  ESP_LOGI(TAG, "Create Hello World label");
  // When touching LVGL from your app task, lock/unlock the port:
  lvgl_port_lock(0);
  lv_obj_t *label = lv_label_create(lv_screen_active());
  lv_label_set_text(label, "Hello world");
  lv_obj_center(label);

  lv_obj_t *btn1 = lv_button_create(lv_screen_active());
  lv_obj_add_event_cb(btn1, event_handler, LV_EVENT_ALL, NULL);
  lv_obj_align(btn1, LV_ALIGN_CENTER, 0, -40);
  lv_obj_remove_flag(btn1, LV_OBJ_FLAG_PRESS_LOCK);

  label = lv_label_create(btn1);
  lv_label_set_text(label, "Button");
  lv_obj_center(label);

  lvgl_port_unlock();

  ESP_LOGI(TAG,
           "Done. LVGL task runs in background. Nothing to do in app_main.");
}

Screenshot and/or video

your problem is not in LVGL but is instead in the driver you are using for the display. Look at mirroring and swapping xy axis. Those will correct your issue. There are usually functions in the driver that allow you to do this.

1 Like

Do you have any idea of what I need to do? I’ve tried setting flip x y to true to no avail, or instead point me towards the direction of some resources which can help. Thanks

By looking at your code you have a comment line that doesn’t agree with what the settings are…

// Rotate to landscape (ILI9341 is rotated by swapping X/Y and mirroring Y)
  ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
  ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, true, false));

it should be

// Rotate to landscape (ILI9341 is rotated by swapping X/Y and mirroring Y)
  ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
  ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, true));

another issue is you are setting the display driver to 16 bits per pixel and you are setting LVGL to 24 bits per pixel (default). If you are going to set the display driver to 16 bits per pixel you need to set the color format for LVGL as RGB565 which is 16 bits per pixel.