Esp32 esp-lcd lvgl 9.3 st7789v3 troubles with drawings and colours

hello. i have a display tft 240x280 st7789v3 i used nopnop library with lvgl 8 and all was good. sinse i tried to go to lvgl 9 and esp-lcd i faced wrong colours and problems with widgets. Help me please right initialize this display.

#include "lvgl.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define LCD_HOST       SPI2_HOST
#define PIN_NUM_MOSI   23
#define PIN_NUM_CLK    18
#define PIN_NUM_CS     5
#define PIN_NUM_DC     27
#define PIN_NUM_RST    33
#define PIN_NUM_BK     32

#define LCD_H_RES      240
#define LCD_V_RES      280
#define LCD_V_OFFSET   20

static const char *TAG = "main";

static lv_display_t *disp;
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;

static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
    esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
    lv_display_flush_ready(disp);
}

void app_main(void)
{
    ESP_LOGI(TAG, "Init LVGL");
    lv_init();

    static uint8_t *buf1 = NULL;
    buf1 = heap_caps_malloc(LCD_H_RES * 40 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);

    disp = lv_display_create(LCD_H_RES, LCD_V_RES);
    lv_display_set_flush_cb(disp, flush_cb);
    lv_display_set_buffers(disp, buf1, NULL, LCD_H_RES * 40 * sizeof(lv_color_t), LV_DISPLAY_RENDER_MODE_PARTIAL);

    ESP_LOGI(TAG, "Init backlight");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_BK
    };
    gpio_config(&bk_gpio_config);
    gpio_set_level(PIN_NUM_BK, 1);

    ESP_LOGI(TAG, "Init SPI panel");
    spi_bus_config_t buscfg = {
        .sclk_io_num = PIN_NUM_CLK,
        .mosi_io_num = PIN_NUM_MOSI,
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = PIN_NUM_DC,
        .cs_gpio_num = PIN_NUM_CS,
        .pclk_hz = 20 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
        .on_color_trans_done = NULL,
        .user_ctx = NULL,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));


    // typedef struct {
    //     int reset_gpio_num;          // GPIO number for the reset pin
    //     int color_space;             // Color space (e.g., RGB, BGR)
    //     int bits_per_pixel;          // Bits per pixel (e.g., 16, 18)
// } lcd_panel_dev_config_t;
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_NUM_RST,          // GPIO номер для сброса панели
        .color_space = ESP_LCD_COLOR_SPACE_RGB, // Цветовое пространство (RGB или BGR)
        .bits_per_pixel = 16,                   // Количество бит на пиксель (например, 32 для RGB888)

    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

    esp_lcd_panel_reset(panel_handle);
    esp_lcd_panel_init(panel_handle);
    esp_lcd_panel_invert_color(panel_handle, false);
    esp_lcd_panel_mirror(panel_handle, false, false);
    esp_lcd_panel_swap_xy(panel_handle, false);
    esp_lcd_panel_set_gap(panel_handle, 0, LCD_V_OFFSET);

    // Прямое задание MADCTL = 0x00
    //esp_lcd_panel_io_tx_param(io_handle, 0x36, (uint8_t[]){0x00}, 1);

    esp_lcd_panel_disp_on_off(panel_handle, true);

    // Надпись
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello ST7789V3!");
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 10);

    // Кнопка
    lv_obj_t *btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn, 100, 40);
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 20);
    lv_obj_t *lbl2 = lv_label_create(btn);
    lv_label_set_text(lbl2, "PRESS");

    while (1) {
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}



help me please. Thanx in advance. ChatGpt and Search are losing in this battle((



playing with settings . code attached is for photo_2025-07-28_11-30-48

#include "lvgl.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define LCD_HOST       SPI2_HOST
#define PIN_NUM_MOSI   23
#define PIN_NUM_CLK    18
#define PIN_NUM_CS     5
#define PIN_NUM_DC     27
#define PIN_NUM_RST    33
#define PIN_NUM_BK     32

#define LCD_H_RES      240
#define LCD_V_RES      280
#define LCD_V_OFFSET   20

#define rgb565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3))

#define RED    rgb565(255,   0,   0) // 0xf800
#define GREEN  rgb565(  0, 255,   0) // 0x07e0
#define BLUE   rgb565(  0,   0, 255) // 0x001f
#define BLACK  rgb565(  0,   0,   0) // 0x0000
#define WHITE  rgb565(255, 255, 255) // 0xffff
#define GRAY   rgb565(128, 128, 128) // 0x8410
#define YELLOW rgb565(255, 255,   0) // 0xFFE0
#define CYAN   rgb565(  0, 156, 209) // 0x04FA
#define PURPLE rgb565(128,   0, 128) // 0x8010

static const char *TAG = "main";

static lv_display_t *disp;
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;

static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
    esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
    lv_display_flush_ready(disp);
}

void app_main(void)
{
    ESP_LOGI(TAG, "Init LVGL");
    lv_init();

    static lv_color_t *buf1 = NULL;
    buf1 = heap_caps_malloc(LCD_H_RES * 80 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);

    disp = lv_display_create(LCD_H_RES, LCD_V_RES);
    lv_display_set_flush_cb(disp, flush_cb);
    lv_display_set_buffers(disp, buf1, NULL,
        LCD_H_RES * 80 * sizeof(lv_color_t),
        LV_DISPLAY_RENDER_MODE_PARTIAL);

    ESP_LOGI(TAG, "Init backlight");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_BK
    };
    gpio_config(&bk_gpio_config);
    gpio_set_level(PIN_NUM_BK, 1);

    ESP_LOGI(TAG, "Init SPI panel");
    spi_bus_config_t buscfg = {
        .sclk_io_num = PIN_NUM_CLK,
        .mosi_io_num = PIN_NUM_MOSI,
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = PIN_NUM_DC,
        .cs_gpio_num = PIN_NUM_CS,
        .pclk_hz = 40 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
        .on_color_trans_done = NULL,
        .user_ctx = NULL,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(
        (esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_NUM_RST,
        .color_space = ESP_LCD_COLOR_SPACE_RGB,  // ВАЖНО: BGR!
        .bits_per_pixel = 16,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

// Прямая отправка команд инициализации (по даташиту ST7789V3)
    //uint8_t madctl = 0x01; // MY=0, MX=0, MV=0, ML=0, RGB=1
    //esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1); // MADCTL = 0x00

    //uint8_t pixfmt = 0x55; // 16 бит на пиксель (RGB565)
    //esp_lcd_panel_io_tx_param(io_handle, 0x3A, &pixfmt, 1); // COLMOD

    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, false));
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, LCD_V_OFFSET));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
    lv_color_t color;
    color.blue = 0xff;
    color.red = 0xff;
    color.green = 0xff;
    lv_obj_set_style_bg_color(lv_scr_act(), color, 0);

    
    lv_obj_t *label = lv_label_create(lv_scr_act());
    // Стиль для текста
    unsigned char r,g,b;
    r=255;
    g=0;
    b=0;
    color.blue = ((b & 0xF8) << 8);
    color.red = ((r & 0xFC) << 3);
    color.green = (g >> 3);
    
    static lv_style_t label_style;
    lv_style_init(&label_style);
    lv_style_set_text_color(&label_style, color); // цвет текста
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_style_set_text_font(&label_style, &lv_font_montserrat_20); // встроенный шрифт 20px
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_label_set_text(label, "Hello ST7789V3!");
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 30);
    
    // Кнопка с закруглением
    lv_obj_t *btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn, 100, 40);
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 20);

    // Текст на кнопке
    lv_obj_t *lbl = lv_label_create(btn);
    lv_label_set_text(lbl, "PRESS");
    color.blue = 0x00;
    color.red = 0x00;
    color.green = 0x00;
    lv_obj_set_style_bg_color(lbl, color, 0); // синий цвет
    lv_obj_center(lbl); // Центрируем текст внутри кнопки
    lv_obj_set_style_radius(btn, 10, 0); // закругление

    color.blue = 0x00;
    color.red = 0x00;
    color.green = 0x00;
    lv_obj_set_style_bg_color(btn, color, 0); // синий цвет
    lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, 0);


    while (1) {
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}


continue experimenting … seems now i have only color problem. dunno what i do and why but i should kick this display ass

finally idk how i do this but with nopnop macros i did it

#include "lvgl.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define LCD_HOST       SPI2_HOST
#define PIN_NUM_MOSI   23
#define PIN_NUM_CLK    18
#define PIN_NUM_CS     5
#define PIN_NUM_DC     27
#define PIN_NUM_RST    33
#define PIN_NUM_BK     32

#define LCD_H_RES      240
#define LCD_V_RES      280
#define LCD_V_OFFSET   20

#define rgb565(r, g, b) (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3))

lv_color_t my_lv_color_hex3(uint32_t c)
{
    return lv_color_make((uint8_t)(((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), (uint8_t)((c & 0xF0) | ((c & 0xF0) >> 4)),
                         (uint8_t)((c & 0xF) | ((c & 0xF) << 4)));
}

#define RED    rgb565(255,   0,   0) // 0xf800
#define GREEN  rgb565(  0, 255,   0) // 0x07e0
#define BLUE   rgb565(  0,   0, 255) // 0x001f
#define BLACK  rgb565(  0,   0,   0) // 0x0000
#define WHITE  rgb565(255, 255, 255) // 0xffff
#define GRAY   rgb565(128, 128, 128) // 0x8410
#define YELLOW rgb565(255, 255,   0) // 0xFFE0
#define CYAN   rgb565(  0, 156, 209) // 0x04FA
#define PURPLE rgb565(128,   0, 128) // 0x8010

static const char *TAG = "main";

static lv_display_t *disp;
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;

static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
    esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
    lv_display_flush_ready(disp);
}

void app_main(void)
{
    ESP_LOGI(TAG, "Init LVGL");
    lv_init();

    static lv_color_t *buf1 = NULL;
    buf1 = heap_caps_malloc(LCD_H_RES * 80 * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);

    disp = lv_display_create(LCD_H_RES, LCD_V_RES);
    lv_display_set_flush_cb(disp, flush_cb);
    lv_display_set_buffers(disp, buf1, NULL,
        LCD_H_RES * 80 * sizeof(lv_color_t),
        LV_DISPLAY_RENDER_MODE_PARTIAL);

    ESP_LOGI(TAG, "Init backlight");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_BK
    };
    gpio_config(&bk_gpio_config);
    gpio_set_level(PIN_NUM_BK, 1);

    ESP_LOGI(TAG, "Init SPI panel");
    spi_bus_config_t buscfg = {
        .sclk_io_num = PIN_NUM_CLK,
        .mosi_io_num = PIN_NUM_MOSI,
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = PIN_NUM_DC,
        .cs_gpio_num = PIN_NUM_CS,
        .pclk_hz = 40 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
        .on_color_trans_done = NULL,
        .user_ctx = NULL,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(
        (esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_NUM_RST,
        .color_space = ESP_LCD_COLOR_SPACE_BGR,  // ВАЖНО: BGR!
        .bits_per_pixel = 16,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

// Прямая отправка команд инициализации (по даташиту ST7789V3)
    //uint8_t madctl = 0x01; // MY=0, MX=0, MV=0, ML=0, RGB=1
    //esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1); // MADCTL = 0x00

    //uint8_t pixfmt = 0x55; // 16 бит на пиксель (RGB565)
    //esp_lcd_panel_io_tx_param(io_handle, 0x3A, &pixfmt, 1); // COLMOD
// Установка MADCTL: MY=0, MX=0, MV=0, ML=0, RGB/BGR=1 (SWAP)
    uint8_t madctl = 0x08; // только BGR
    esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1);

    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, false));
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, LCD_V_OFFSET));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));
    
    lv_color_t color = lv_color_hex3(rgb565(0,0,255));

    lv_obj_set_style_bg_color(lv_scr_act(), color, 0);

    
    lv_obj_t *label = lv_label_create(lv_scr_act());
    // Стиль для текста
    color = lv_color_hex3(rgb565(255,255,255));
    
    static lv_style_t label_style;
    lv_style_init(&label_style);
    lv_style_set_text_color(&label_style, color); // цвет текста
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_style_set_text_font(&label_style, &lv_font_montserrat_20); // встроенный шрифт 20px
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_label_set_text(label, "Hello ST7789V3!");
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 30);
    
    // Кнопка с закруглением
    lv_obj_t *btn = lv_btn_create(lv_scr_act());
    lv_obj_set_size(btn, 100, 40);
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 20);

    // Текст на кнопке
    lv_obj_t *lbl = lv_label_create(btn);
    lv_label_set_text(lbl, "PRESS");
    color = lv_color_hex3(rgb565(0,0,0));

    lv_obj_set_style_bg_color(lbl, color, 0); // синий цвет
    lv_obj_center(lbl); // Центрируем текст внутри кнопки
    lv_obj_set_style_radius(btn, 10, 0); // закругление

    color = lv_color_hex3(rgb565(0,0,0));
    lv_obj_set_style_bg_color(btn, color, 0); // синий цвет
    lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, 0);


    while (1) {
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(5));
    }
}


esp-idf-st7789-master.rar — Яндекс Диск iattached project coz of it may depends on some sdkkonfig params

OK I am going to do a little buff shine on the code for ya to eliminate some things that do not need to be there and to speed things up also…

#include "lvgl.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define LCD_HOST       SPI2_HOST
#define PIN_NUM_MOSI   23
#define PIN_NUM_CLK    18
#define PIN_NUM_CS     5
#define PIN_NUM_DC     27
#define PIN_NUM_RST    33
#define PIN_NUM_BK     32

#define LCD_H_RES      240
#define LCD_V_RES      280
#define LCD_V_OFFSET   20


#define BUFF_SIZE   (LCD_H_RES * LCD_V_RES * 2 / 10)


#define RED    0xFF0000 // 0xf800
#define GREEN  0x00FF00 // 0x07e0
#define BLUE   0x0000FF // 0x001f
#define BLACK  0x000000 // 0x0000
#define WHITE  0xFFFFFF // 0xffff
#define GRAY   0x808080 // 0x8410
#define YELLOW 0xFFFF00 // 0xFFE0
#define CYAN   0x009CD1 // 0x04FA
#define PURPLE 0x800080 // 0x8010

static const char *TAG = "main";

static lv_display_t *disp;
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;


static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
    // uncomment the line below if the colors are still messed up. 
    // lv_draw_sw_rgb565_swap(px_map, lv_area_get_size(area));
    esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
}


static bool on_color_trans_done(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_display_flush_ready((lv_display_t *)user_ctx);
}


static void increase_lvgl_tick(void *arg)
{
    lv_tick_inc(2);
}


void app_main(void)
{
    ESP_LOGI(TAG, "Init LVGL");
    lv_init();

    static lv_color_t *buf1 = NULL;
    buf1 = heap_caps_malloc(BUFF_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
    buf2 = heap_caps_malloc(BUFF_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);

    assert(buf1);
    assert(buf2);

    disp = lv_display_create(LCD_H_RES, LCD_V_RES);
    lv_display_set_flush_cb(disp, flush_cb);
    lv_display_set_buffers(disp, buf1, buf2, BUFF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);
    lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);


    ESP_LOGI(TAG, "Init backlight");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_BK
    };
    gpio_config(&bk_gpio_config);
    gpio_set_level(PIN_NUM_BK, 1);

    ESP_LOGI(TAG, "Init SPI panel");
    spi_bus_config_t buscfg = {
        .sclk_io_num = PIN_NUM_CLK,
        .mosi_io_num = PIN_NUM_MOSI,
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = BUFF_SIZE,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = PIN_NUM_DC,
        .cs_gpio_num = PIN_NUM_CS,
        .pclk_hz = 80 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
        .on_color_trans_done = &on_color_trans_done,
        .user_ctx = disp,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(
        (esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_NUM_RST,
        // .color_space = ESP_LCD_COLOR_SPACE_BGR,  // ВАЖНО: BGR!
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
        .bits_per_pixel = 16,
    };

    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

// Прямая отправка команд инициализации (по даташиту ST7789V3)
    //uint8_t madctl = 0x01; // MY=0, MX=0, MV=0, ML=0, RGB=1
    //esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1); // MADCTL = 0x00

    //uint8_t pixfmt = 0x55; // 16 бит на пиксель (RGB565)
    //esp_lcd_panel_io_tx_param(io_handle, 0x3A, &pixfmt, 1); // COLMOD
// Установка MADCTL: MY=0, MX=0, MV=0, ML=0, RGB/BGR=1 (SWAP)
    // uint8_t madctl = 0x08; // только BGR
    // esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1);

    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, false));
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, LCD_V_OFFSET));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

    ESP_LOGI(TAG, "Install tick timer");
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &increase_lvgl_tick,
        .name = "lvgl_tick"
    };
    esp_timer_handle_t lvgl_tick_timer = NULL;
    ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, 2000));

    lv_color_t color = lv_color_hex(0x0000FF);
    lv_obj_set_style_bg_color(lv_screen_active(), color, 0);

    lv_obj_t *label = lv_label_create(lv_screen_active());
    // Стиль для текста
    color = lv_color_hex(0xFFFFFF);

    static lv_style_t label_style;
    lv_style_init(&label_style);
    lv_style_set_text_color(&label_style, color); // цвет текста
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_style_set_text_font(&label_style, &lv_font_montserrat_20); // встроенный шрифт 20px
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_label_set_text(label, "Hello ST7789V3!");
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 30);

    // Кнопка с закруглением
    lv_obj_t *btn = lv_button_create(lv_screen_active());
    lv_obj_set_size(btn, 100, 40);
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 20);

    // Текст на кнопке
    lv_obj_t *lbl = lv_label_create(btn);
    lv_label_set_text(lbl, "PRESS");
    color = lv_color_hex(0x000000);

    lv_obj_set_style_bg_color(lbl, color, 0); // синий цвет
    lv_obj_center(lbl); // Центрируем текст внутри кнопки
    lv_obj_set_style_radius(btn, 10, 0); // закругление

    lv_obj_set_style_bg_color(btn, color, 0); // синий цвет
    lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, 0);

    while (1) {
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

Hello thanx. Can you explain what you did and why?

#include "lvgl.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/spi_master.h"
#include "esp_timer.h"
#include "esp_log.h"
#include "driver/gpio.h"

#define LCD_HOST       SPI2_HOST
#define PIN_NUM_MOSI   23
#define PIN_NUM_CLK    18
#define PIN_NUM_CS     5
#define PIN_NUM_DC     27
#define PIN_NUM_RST    33
#define PIN_NUM_BK     32

#define LCD_H_RES      240
#define LCD_V_RES      280
#define LCD_V_OFFSET   20


#define BUFF_SIZE   (LCD_H_RES * LCD_V_RES * 2 / 10)


#define RED    0xFF0000 // 0xf800
#define GREEN  0x00FF00 // 0x07e0
#define BLUE   0x0000FF // 0x001f
#define BLACK  0x000000 // 0x0000
#define WHITE  0xFFFFFF // 0xffff
#define GRAY   0x808080 // 0x8410
#define YELLOW 0xFFFF00 // 0xFFE0
#define CYAN   0x009CD1 // 0x04FA
#define PURPLE 0x800080 // 0x8010

static const char *TAG = "main";

static lv_display_t *disp;
static esp_lcd_panel_io_handle_t io_handle = NULL;
static esp_lcd_panel_handle_t panel_handle = NULL;


static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
    // uncomment the line below if the colors are still messed up. 
    // lv_draw_sw_rgb565_swap(px_map, lv_area_get_size(area));
    esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
}


static bool on_color_trans_done(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_display_flush_ready((lv_display_t *)user_ctx);
    return ESP_OK;
}


static void increase_lvgl_tick(void *arg)
{
    lv_tick_inc(2);
}


void app_main(void)
{
    ESP_LOGI(TAG, "Init LVGL");
    lv_init();

    static lv_color_t *buf1 = NULL;
    static lv_color_t *buf2 = NULL;
    buf1 = heap_caps_malloc(BUFF_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
    buf2 = heap_caps_malloc(BUFF_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);

    assert(buf1);
    assert(buf2);

    disp = lv_display_create(LCD_H_RES, LCD_V_RES);
    lv_display_set_flush_cb(disp, flush_cb);
    lv_display_set_buffers(disp, buf1, buf2, BUFF_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);
    lv_display_set_color_format(disp, LV_COLOR_FORMAT_RGB565);


    ESP_LOGI(TAG, "Init backlight");
    gpio_config_t bk_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_BK
    };
    gpio_config(&bk_gpio_config);
    gpio_set_level(PIN_NUM_BK, 1);

    ESP_LOGI(TAG, "Init SPI panel");
    spi_bus_config_t buscfg = {
        .sclk_io_num = PIN_NUM_CLK,
        .mosi_io_num = PIN_NUM_MOSI,
        .miso_io_num = -1,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = BUFF_SIZE,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));

    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = PIN_NUM_DC,
        .cs_gpio_num = PIN_NUM_CS,
        .pclk_hz = 80 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
        .on_color_trans_done = &on_color_trans_done,
        .user_ctx = disp,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(
        (esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &io_handle));

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = PIN_NUM_RST,
        // .color_space = ESP_LCD_COLOR_SPACE_BGR,  // ВАЖНО: BGR!
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
        .bits_per_pixel = 16,
    };

    ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle));

// Прямая отправка команд инициализации (по даташиту ST7789V3)
    //uint8_t madctl = 0x01; // MY=0, MX=0, MV=0, ML=0, RGB=1
    //esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1); // MADCTL = 0x00

    //uint8_t pixfmt = 0x55; // 16 бит на пиксель (RGB565)
    //esp_lcd_panel_io_tx_param(io_handle, 0x3A, &pixfmt, 1); // COLMOD
// Установка MADCTL: MY=0, MX=0, MV=0, ML=0, RGB/BGR=1 (SWAP)
    // uint8_t madctl = 0x08; // только BGR
    // esp_lcd_panel_io_tx_param(io_handle, 0x36, &madctl, 1);

    ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
    ESP_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, false));
    ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, false));
    ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, LCD_V_OFFSET));
    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

    ESP_LOGI(TAG, "Install tick timer");
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &increase_lvgl_tick,
        .name = "lvgl_tick"
    };
    esp_timer_handle_t lvgl_tick_timer = NULL;
    ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer));
    ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, 2000));

    lv_color_t color = lv_color_hex(0x0000FF); which color it should be ?
    lv_obj_set_style_bg_color(lv_screen_active(), color, 0);

    lv_obj_t *label = lv_label_create(lv_screen_active());
    // Стиль для текста
    color = lv_color_hex(0xFFFFFF); which color it should be ?

    static lv_style_t label_style;
    lv_style_init(&label_style);
    lv_style_set_text_color(&label_style, color); // цвет текста
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_style_set_text_font(&label_style, &lv_font_montserrat_14); // compile error with 20px its checked in menuconfig 
    lv_obj_add_style(label, &label_style, LV_PART_MAIN);
    lv_label_set_text(label, "Hello ST7789V3!");
    lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 30);

    // Кнопка с закруглением
    lv_obj_t *btn = lv_button_create(lv_screen_active());
    lv_obj_set_size(btn, 100, 40);
    lv_obj_align(btn, LV_ALIGN_CENTER, 0, 20);

    // Текст на кнопке
    lv_obj_t *lbl = lv_label_create(btn);
    lv_label_set_text(lbl, "PRESS");
    color = lv_color_hex(0x000000);which color it should be ?

    lv_obj_set_style_bg_color(lbl, color, 0); // синий цвет
    lv_obj_center(lbl); // Центрируем текст внутри кнопки
    lv_obj_set_style_radius(btn, 10, 0); // закругление

    lv_obj_set_style_bg_color(btn, color, 0); // синий цвет
    lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, 0);

    while (1) {
        lv_timer_handler();
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

picture from u code runned


is it colors that you mean? also can u help how can i do lv_conf.h works. no its ignored. when i tried add SquareLine Studio code it says me that i need #define LV_COLOR_16_SWAP 1 but its in lv_conf.h

yours code:

// lv_draw_sw_rgb565_swap(px_map, lv_area_get_size(area));
static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
    // uncomment the line below if the colors are still messed up. 
    // lv_draw_sw_rgb565_swap(px_map, lv_area_get_size(area));
    esp_lcd_panel_draw_bitmap(panel_handle, area->x1, area->y1, area->x2 + 1, area->y2 + 1, px_map);
}

i got yellow. with uncommented swap i got blue - lv_color_t color = lv_color_hex(0xFF0000); looks right lv_color_t color = lv_color_hex(0x0000FF); - should be red yup? tadaam its purtple
comment color swap - its blue. so i got right colors only with my tricks(( i got this macroses from https://github.com/nopnop2002/espidfst7789/tree/master/components/st7789/st7789.h thats working good with colors

change this line

.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,

to

.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,

and check the colors again. If they are still out of sorts then uncomment that line in the flush function.

You should not need to do what you have done to get the colors to be proper we just need to get the settings right for the display driver.

There are 2 things that effect the color. The pixel byte order which is the RGB and BGR and the second one only applies to RGB565 which is the byte order of each pixel. So what happens is RGB565 which is expressed as rrrrr ggg | ggg bbbbb with the | being the separator for each byte. when you swap the byte order the data then becomes ggg bbbbb | rrrrr ggg. That is what the commented function call does is it swaps the bytes around for each pixel.

I suspect that your display needs to be set to RGB color order and you need to have the bytes swapped using that function in the flush function.

Now what I did in the code is I added a second buffer. I also set the size of of the buffers to be 1/10th the size of a full frame buffer. we have found this to be the optimal size. YOu were already using DMA memory for the one buffer and I directed that buffer to be created in internal RAM because it’s faster than if the buffer is located in PSRAM. I was able to do this because the size of 2 buffers is small enough to fit into the DMA space that is available in the internal memory.

Using DMA memory when not using double buffering is pointless and using double buffering without using DMA memory is pointless. But since we are using both it allows for a non blocking call to be made when sending the data from a buffer to the display. Because it’s a non blocking call that means that LVGL is now able to render at the same time a buffer is sending. BUT… we do not want ity rendering to the buffer that is being sent because that will cause data corruption. that’s where the second buffer comes into play. Calling the flush ready function is what tells LVGL that there is a free buffer to render to. we don’t want to call that in the flush function when using DMA memory because the buffer has not actually been transmitted yet. That is where that second callback function comes into play. That function gets called by the display driver only after the buffer has finished being sent. that is why the call to flush ready has been moved to there.

Now the key to making this all work properly is setting the maximum transfer size so it matches the same size as the buffers. which you can see done when initializing the driver.

Thank you for help I’ll play with this display a bit later I understand that u are telling right things but as I remember it not work for me . Will try again . I bet I made mistake somewhere.

sometimes all you need is another set of eyes to locate where the issue is. I do know that the esp-lcd component API in the ESP-IDF has been undergoing a lot of changes between the minor version updates. An example of this is the color_space field in the esp_lcd_panel_dev_config_t structure. That structure looks like this…

typedef struct {
    int reset_gpio_num; /*!< GPIO used to reset the LCD panel, set to -1 if it's not used */
    union {
        esp_lcd_color_space_t color_space;   /*!< @deprecated Set RGB color space, please use rgb_ele_order instead */
        lcd_color_rgb_endian_t rgb_endian;   /*!< @deprecated Set RGB data endian, please use rgb_ele_order instead */
        lcd_rgb_element_order_t rgb_ele_order; /*!< Set RGB element order, RGB or BGR */
    };
    lcd_rgb_data_endian_t data_endian;         /*!< Set the data endian for color data larger than 1 byte */
    uint32_t bits_per_pixel;                   /*!< Color depth, in bpp */
    struct {
        uint32_t reset_active_high: 1; /*!< Setting this if the panel reset is high level active */
    } flags;                           /*!< LCD panel config flags */
    void *vendor_config; /*!< vendor specific configuration, optional, left as NULL if not used */
} esp_lcd_panel_dev_config_t;

while the old API has been left there and is a union with the new API and it will still works the old field names have been deprecated and will eventually be removed. which is the reason why I changed the field name being used and also the enumeration name as well.

little things like that can cause some grief in the future for ya. I also changed some of the names for the LVGL function in your code as well. while the old ones may still work at some point they are going to be removed and will end up causing problems for ya. so I changed the names to the new names so that will not cause an issue in the future if you upgrade the version of LVGL that is being used.

That being said. the byte swappin for RGB565 that I mentioned above may also be able to be done using the display driver. There is this field…

lcd_rgb_data_endian_t data_endian;

in the esp_lcd_panel_dev_config_t structure that can be set as well. I have to go and look at the source code in the driver to see if that field is used and what gets done when it is used. It could reverse the byte order of the entire buffer or it could reverse the byte order on each pixel. The description they gave for it doesn’t give enough information to be able to determine which one it does.

I just looked into that field. and low and behold there is an error in the driver. The purpose of that field is to do exactly what I thought it would do EXCEPT… the st7789 display only supports doing it when using and 8 lane or 9 lane I8080 connection. So setting that when using an SPI connection is not going to work. The driver doesn’t check at all to see what type of connection is being used. There is no way for the driver to check and see what kind of a connection is being used. There is no documentation written for the driver to let the user know that the field is only supported when using an MCU connection. Had to go and look at the source code in the IDF and then look at the datasheet for the display IC to find out if it would work or not.