Gestures are slow perceiving, only detecting one of 5-10 tries

give this a try

#include <stdio.h>
#include <unistd.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_st7789.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lvgl.h"


static const char *TAG = "MyDisplay";

/* LCD size */
#define DISP_HOR_RES   240
#define DISP_VER_RES   320

/* LCD settings */
#define DISP_DRAW_BUFF_HEIGHT 50


/* LCD pins */
#define DISP_SPI_NUM         SPI3_HOST
#define DISP_GPIO_SCLK       GPIO_NUM_41 // GPIO_NUM_6
#define DISP_GPIO_MOSI       GPIO_NUM_40 // GPIO_NUM_7
#define DISP_GPIO_RST        GPIO_NUM_39 // GPIO_NUM_8
#define DISP_GPIO_DC         GPIO_NUM_44 // GPIO_NUM_4
#define DISP_GPIO_CS         GPIO_NUM_42 // GPIO_NUM_5
#define DISP_GPIO_BL         GPIO_NUM_1  // GPIO_NUM_15

/* Touch settings */
#define DISP_TOUCH_I2C_NUM       I2C_NUM_1
#define DISP_TOUCH_I2C_CLK_HZ    400000     // 400000

/* LCD touch pins */
#define TOUCH_I2C_SCL       GPIO_NUM_21  // GPIO_NUM_21   9
#define TOUCH_I2C_SDA       GPIO_NUM_14  // GPIO_NUM_14  10
#define TOUCH_GPIO_INT      GPIO_NUM_38  // GPIO_NUM_38
#define TOUCH_GPIO_RST      GPIO_NUM_11  // GPIO_NUM_11 // dummy


#define BUFFER_SIZE  (DISP_HOR_RES * DISP_VER_RES * sizeof(uint16_t) / 10)


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

static void* buf1 = NULL;
static void* buf2 = NULL;


// this gets called when the DMA transfer of the buffer data has completed
static bool notify_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_display_t *disp = (lv_display_t *)user_ctx;
    lv_display_flush_ready(disp);
    return false;
}

static void flush_cb(lv_display_t *disp, const lv_area_t *area, uint8_t *px_map)
{
    int x1 = area->x1;
    int x2 = area->x2;
    int y1 = area->y1;
    int y2 = area->y2;

    // uncomment the following line if the colors are wrong
    // lv_draw_sw_rgb565_swap(px_map, (x2 + 1 - x1) * (y2 + 1 - y1));

    esp_lcd_panel_draw_bitmap((esp_lcd_panel_handle_t)lv_display_get_user_data(disp), x1, y1, x2 + 1, y2 + 1, px_map);
}


static void lvgl_tick_increment(void *arg)
{
    // Tell LVGL how many milliseconds have elapsed
    lv_tick_inc(2); // tjek
}


static esp_err_t lvgl_tick_init(void)
{
    esp_timer_handle_t  tick_timer;

    // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &lvgl_tick_increment,
        .name = "LVGL tick",
    };
    ESP_RETURN_ON_ERROR(esp_timer_create(&lvgl_tick_timer_args, &tick_timer), TAG, "esp_timer_create error");
    return esp_timer_start_periodic(tick_timer, 2 * 1000); // 2 ms
}


static esp_err_t lvgl_init(void)
{
    lv_init();

    display = lv_display_create(DISP_HOR_RES, DISP_VER_RES);

    buf1 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL |  MALLOC_CAP_DMA);
    buf2 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL |  MALLOC_CAP_DMA);

    lv_display_set_buffers(display, buf1, buf2, BUFFER_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);

    lv_display_set_user_data(display, panel_handle);
    lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);

    lv_display_set_flush_cb(display, flush_cb);

     const esp_lcd_panel_io_callbacks_t cbs = {
        .on_color_trans_done = notify_flush_ready,
    };
    /* Register done callback */
    ESP_RETURN_ON_ERROR(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, display), TAG, "esp_lcd_panel_io_register_event_callbacks error");
    ESP_RETURN_ON_ERROR(esp_lcd_panel_init(panel_handle), TAG, "esp_lcd_panel_init error");
    return ESP_OK;
}


static esp_err_t display_init(void)
{
    /* LCD backlight and DC */
    gpio_config_t gpio_cfg = {
        .pin_bit_mask = (1ULL << DISP_GPIO_BL),
        .mode = GPIO_MODE_OUTPUT,
    };
    ESP_RETURN_ON_ERROR(gpio_config(&gpio_cfg), TAG, "gpio_config error");

    /* LCD initialization */
    ESP_LOGD(TAG, "Initialize SPI bus");
    spi_bus_config_t buscfg = {
        .sclk_io_num = DISP_GPIO_SCLK,
        .mosi_io_num = DISP_GPIO_MOSI,
        .miso_io_num = GPIO_NUM_NC,
        .quadwp_io_num = GPIO_NUM_NC,
        .quadhd_io_num = GPIO_NUM_NC,
        .max_transfer_sz = BUFFER_SIZE
    };
    ESP_RETURN_ON_ERROR(spi_bus_initialize(DISP_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "spi_bus_initialize error");

    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = DISP_GPIO_DC,
        .cs_gpio_num = DISP_GPIO_CS,
        .pclk_hz = 80 * 1000 * 1000,
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10
    };

    ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)DISP_SPI_NUM, &io_config, &io_handle), "esp_lcd_new_panel_io_spi error");

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = DISP_GPIO_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
        .flags.reset_active_high = 1
    };

    ESP_RETURN_ON_ERROR(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle), "esp_lcd_new_panel_st7789 error");

    return ESP_OK;
}


void app_main() {

    vTaskDelay(5000/portTICK_PERIOD_MS);

    esp_err_t ret = display_init(void);

    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "ST7796 failed to initilize");
        while (1);
    }
    ret = lvgl_init(void);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "LVGL Display failed to initialize");
        while (1);
    }

    ret = lvgl_tick_init();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Timer failed to initialize");
        while (1);
    }


    // Create a simple label
    lv_obj_t *label = lv_label_create(lv_screen_active());
    lv_label_set_text(label, "Hello, LVGL!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

    gpio_set_level(DISP_GPIO_BL, 1); // Turn on backlight

    long curtime = esp_timer_get_time()/1000;
    int counter = 0;

    // Handle LVGL tasks
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10));
        lv_task_handler();

        if (esp_timer_get_time() / 1000 - curtime > 1000) {
            curtime = esp_timer_get_time() / 1000;

            char textlabel[20];
            sprintf(textlabel, "Running: %u\n", counter);
            printf(textlabel);
            lv_label_set_text(label, textlabel);
            counter++;
        }
    }
}

I have added

.flags.reset_active_high = 1

that made no difference. I also tried to set it to 0, just to try something.

I have added

ESP_RETURN_ON_ERROR(esp_lcd_panel_init(panel_handle), TAG, "esp_lcd_panel_init error");

also made no difference. lvgl_tick_increment, flush_cb and notify_flush_ready is called, and data looks legit… No log errors. The only thing happening, is that I can see, when the backlight is turned on. Hardware for sure work, since the picture I posted, is from very same hardware, and my initial hello-world also worked…

Its really strange.

One question. I have all the options in menuconfig, basically same settings as in the lV_conf_template.h (not used). Do I need to set something here? I have tried to toggle “use ST7789”, but it also makes no difference.

Full code, including my comments:

#include "esp_log.h"

#include <stdio.h>
#include <unistd.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "esp_lcd_panel_st7789.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lvgl.h"

static const char *TAG = "MyDisplay";

/* LCD size */
#define DISP_HOR_RES   240 // 320
#define DISP_VER_RES   320 // 240

/* LCD settings */
#define DISP_DRAW_BUFF_HEIGHT 50

/* LCD pins */
#define DISP_SPI_NUM         SPI3_HOST
#define DISP_GPIO_SCLK       GPIO_NUM_41 // GPIO_NUM_6
#define DISP_GPIO_MOSI       GPIO_NUM_40 // GPIO_NUM_7
#define DISP_GPIO_RST        GPIO_NUM_39 // GPIO_NUM_8
#define DISP_GPIO_DC         GPIO_NUM_44 // GPIO_NUM_4
#define DISP_GPIO_CS         GPIO_NUM_42 // GPIO_NUM_5
#define DISP_GPIO_BL         GPIO_NUM_1  // GPIO_NUM_15

/* Touch settings */
#define DISP_TOUCH_I2C_NUM       I2C_NUM_1
#define DISP_TOUCH_I2C_CLK_HZ    400000     // 400000

/* LCD touch pins */
#define TOUCH_I2C_SCL       GPIO_NUM_21  // GPIO_NUM_21   9
#define TOUCH_I2C_SDA       GPIO_NUM_14  // GPIO_NUM_14  10
#define TOUCH_GPIO_INT      GPIO_NUM_38  // GPIO_NUM_38
#define TOUCH_GPIO_RST      GPIO_NUM_11  // GPIO_NUM_11 // dummy

// SPI device handle
// spi_device_handle_t spi;

#define BUFFER_SIZE         (DISP_HOR_RES * DISP_VER_RES * sizeof(uint16_t) / 10)

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

static void* buf1 = NULL;
static void* buf2 = NULL;

// this gets called when the DMA transfer of the buffer data has completed
//////// I have checked this function is called debugging. Putting a printf here crashes
static bool notify_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    lv_display_t *disp = (lv_display_t *)user_ctx;
    lv_display_flush_ready(disp);  // I have tried to change this to the global display variable, no change
    return false;
}

static void flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map)
{
    int x1 = area->x1;
    int x2 = area->x2;
    int y1 = area->y1;
    int y2 = area->y2;
    
    // uncomment the following line if the colors are wrong
//    lv_draw_sw_rgb565_swap(px_map, (x2 + 1 - x1) * (y2 + 1 - y1)); // I have tried with and without this

printf("Flushing: %d %d %d %d\n", x1, x2, y1, y2);

//    for (int i=0; i<(x2-x1)*(y2-y1); i++) {
//       printf("%02X ", px_map[i]);  // Print each byte as a two-digit hex value 

//       px_map[i] = 0x55; // just trying something
//    }
//    printf("\n");  // Newline at the end for better readability
    
    // I have tried to use the global esp_lcd_panel_handle_t in stead of (esp_lcd_panel_handle_t)lv_display_get_user_data(disp), made no difference
    esp_lcd_panel_draw_bitmap((esp_lcd_panel_handle_t)lv_display_get_user_data(disp), x1, y1, x2 + 1, y2 + 1, px_map);
}

static esp_err_t lvgl_init(void)
{
    lv_init();

    display = lv_display_create(DISP_HOR_RES, DISP_VER_RES);

//    buf1 = (void *)spi_bus_dma_memory_alloc(DISP_SPI_NUM, BUFFER_SIZE, 0);
//    buf2 = (void *)spi_bus_dma_memory_alloc(DISP_SPI_NUM, BUFFER_SIZE, 0);

    buf1 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL |  MALLOC_CAP_DMA);
    buf2 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL |  MALLOC_CAP_DMA);

    lv_display_set_buffers(display, buf1, buf2, BUFFER_SIZE, LV_DISPLAY_RENDER_MODE_PARTIAL);

    lv_display_set_user_data(display, panel_handle);
    lv_display_set_color_format(display, LV_COLOR_FORMAT_RGB565);

    lv_display_set_flush_cb(display, flush_cb);

     const esp_lcd_panel_io_callbacks_t cbs = {
        .on_color_trans_done = notify_flush_ready,
    };
    /* Register done callback */
    ESP_RETURN_ON_ERROR(esp_lcd_panel_io_register_event_callbacks(io_handle, &cbs, display), TAG, "esp_lcd_panel_io_register_event_callbacks error"); // I have tried to use 
    ESP_RETURN_ON_ERROR(esp_lcd_panel_init(panel_handle), TAG, "esp_lcd_panel_init error");
    return ESP_OK;
}

static esp_err_t display_init(void)
{
    // LCD backlight and DC
    gpio_config_t gpio_cfg = {
        .pin_bit_mask = (1ULL << DISP_GPIO_BL) | (1ULL << DISP_GPIO_DC),
        .mode = GPIO_MODE_OUTPUT,
    };
    ESP_ERROR_CHECK(gpio_config(&gpio_cfg));

    gpio_set_level(DISP_GPIO_BL, 1); // Turn on backlight
    gpio_set_level(DISP_GPIO_DC, 1); // Default to data mode

    // LCD initialization
    ESP_LOGD(TAG, "Initialize SPI bus");
    spi_bus_config_t buscfg = { };
        buscfg.sclk_io_num = DISP_GPIO_SCLK;
        buscfg.mosi_io_num = DISP_GPIO_MOSI;
        buscfg.miso_io_num = GPIO_NUM_NC;
        buscfg.quadwp_io_num = GPIO_NUM_NC;
        buscfg.quadhd_io_num = GPIO_NUM_NC;
        buscfg.max_transfer_sz = BUFFER_SIZE; // DISP_HOR_RES * DISP_DRAW_BUFF_HEIGHT * sizeof(uint16_t);
    ESP_RETURN_ON_ERROR(spi_bus_initialize(DISP_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");

    esp_lcd_panel_io_spi_config_t io_config = {
        .dc_gpio_num = DISP_GPIO_DC,
        .cs_gpio_num = DISP_GPIO_CS,
        .pclk_hz = 10 * 1000 * 1000, // 80
        .lcd_cmd_bits = 8,
        .lcd_param_bits = 8,
        .spi_mode = 0,
        .trans_queue_depth = 10,
    };
    ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)DISP_SPI_NUM, &io_config, &io_handle), TAG, "SPI init failed");

    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = DISP_GPIO_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
        .flags.reset_active_high = 1
    };

    ESP_RETURN_ON_ERROR(esp_lcd_new_panel_st7789(io_handle, &panel_config, &panel_handle), TAG, "Display init failed");

//    uint8_t madreg = 0x36;  // Rotate reg 0x00 0x60 0xC0 0xA0
//    uint8_t madctl = 0x60;  // Rotate reg 0x00 0x60 0xC0 0xA0
//    esp_lcd_panel_io_tx_param(io_handle, &madreg, &madctl, 1); // 0x36 er rotate reg (ST7789_MADCTL)

    return ESP_OK;
}

static void lvgl_tick_increment(void *arg)
{
    // Tell LVGL how many milliseconds have elapsed
    lv_tick_inc(2); // tjek 

//    printf("#");
}

static esp_err_t lvgl_tick_init(void)
{
    esp_timer_handle_t  tick_timer;

    // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &lvgl_tick_increment,
        .name = "LVGL tick",
    };
    ESP_RETURN_ON_ERROR(esp_timer_create(&lvgl_tick_timer_args, &tick_timer), TAG, "Creating LVGL timer filed!");
    return esp_timer_start_periodic(tick_timer, 2 * 1000); // 2 ms
}

static void lvgl_task(void *arg) {

    vTaskDelay(5000/portTICK_PERIOD_MS);

    esp_log_level_set("lcd_panel.st7789", ESP_LOG_VERBOSE);
    esp_log_level_set(TAG, ESP_LOG_VERBOSE);

    esp_err_t ret = display_init();

    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "ST7789 failed to initilize");
        while (1);
    }
    ret = lvgl_init();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "LVGL Display failed to initialize");
        while (1);
    }

    ret = lvgl_tick_init();
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Timer failed to initialize");
        while (1);
    }

    gpio_set_level(DISP_GPIO_BL, 1); // Turn on backlight again

    // Create a simple label
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello, LVGL!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

    long curtime = esp_timer_get_time()/1000;
    int counter = 0;

    // Handle LVGL tasks
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10));
        lv_task_handler();

        if (esp_timer_get_time()/1000 - curtime > 1000) {
            curtime = esp_timer_get_time()/1000;

            char textlabel[20];
            sprintf(textlabel, "Running: %u\n", counter);
            printf(textlabel);
            lv_label_set_text(label, textlabel);
            counter++;
        }
    }
}

void app_main() {

    vTaskDelay(5000/portTICK_PERIOD_MS);

    TaskHandle_t taskHandle = NULL;
    BaseType_t res = xTaskCreatePinnedToCore(lvgl_task, "LVGL task", 8192, NULL, 4, &taskHandle, 0); // stack, params, prio, handle, core

    while(true) {

        vTaskDelay(100/portTICK_PERIOD_MS);
    }

}

If I port your suggestions to my original code, using the LVGL implementation, this is actually working. Your solution, using the esp driver, is it faster, or what is the advantage? Or is the LVGL one depreciated?

https://docs.lvgl.io/master/details/integration/driver/display/st7789.html

This seems to be running:

#include "esp_log.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/lock.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#include "esp_lcd_panel_io.h"
#include "esp_lcd_panel_vendor.h"
#include "esp_lcd_panel_ops.h"
#include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_check.h"
#include "esp_err.h"
#include "esp_log.h"
#include "lvgl.h"

static const char *TAG = "MyDisplay";

/* LCD size */
#define DISP_HOR_RES   320
#define DISP_VER_RES   240

/* LCD settings */
#define DISP_DRAW_BUFF_HEIGHT 50

/* LCD pins */
#define DISP_SPI_NUM         SPI3_HOST
#define DISP_GPIO_SCLK       GPIO_NUM_41 // GPIO_NUM_6
#define DISP_GPIO_MOSI       GPIO_NUM_40 // GPIO_NUM_7
#define DISP_GPIO_RST        GPIO_NUM_39 // GPIO_NUM_8
#define DISP_GPIO_DC         GPIO_NUM_44 // GPIO_NUM_4
#define DISP_GPIO_CS         GPIO_NUM_42 // GPIO_NUM_5
#define DISP_GPIO_BL         GPIO_NUM_1  // GPIO_NUM_15

/* Touch settings */
#define DISP_TOUCH_I2C_NUM       I2C_NUM_1
#define DISP_TOUCH_I2C_CLK_HZ    400000     // 400000

/* LCD touch pins */
#define TOUCH_I2C_SCL       GPIO_NUM_21  // GPIO_NUM_21   9
#define TOUCH_I2C_SDA       GPIO_NUM_14  // GPIO_NUM_14  10
#define TOUCH_GPIO_INT      GPIO_NUM_38  // GPIO_NUM_38
#define TOUCH_GPIO_RST      GPIO_NUM_11  // GPIO_NUM_11 // dummy

// SPI device handle
spi_device_handle_t spi;

#define BUFFER_SIZE         (DISP_HOR_RES * DISP_VER_RES * sizeof(lv_color_t) / 10)

static lv_disp_t *disp = NULL;
static lv_color_t* buf1 = NULL;
static lv_color_t* buf2 = NULL;

static bool notify_flush_ready(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx)
{
    if (disp != NULL) lv_display_flush_ready(disp);
    return false;
}

static esp_err_t display_init(void)
{
    // LCD backlight and DC
    gpio_config_t gpio_cfg = {
        .pin_bit_mask = (1ULL << DISP_GPIO_BL) | (1ULL << DISP_GPIO_DC),
        .mode = GPIO_MODE_OUTPUT,
    };
    ESP_ERROR_CHECK(gpio_config(&gpio_cfg));

    gpio_set_level(DISP_GPIO_BL, 1); // Turn on backlight
    gpio_set_level(DISP_GPIO_DC, 1); // Default to data mode

    // LCD initialization
    ESP_LOGD(TAG, "Initialize SPI bus");
    spi_bus_config_t buscfg = { };
        buscfg.sclk_io_num = DISP_GPIO_SCLK;
        buscfg.mosi_io_num = DISP_GPIO_MOSI;
        buscfg.miso_io_num = GPIO_NUM_NC;
        buscfg.quadwp_io_num = GPIO_NUM_NC;
        buscfg.quadhd_io_num = GPIO_NUM_NC;
        buscfg.max_transfer_sz = BUFFER_SIZE; // DISP_HOR_RES * DISP_DRAW_BUFF_HEIGHT * sizeof(uint16_t);
    ESP_RETURN_ON_ERROR(spi_bus_initialize(DISP_SPI_NUM, &buscfg, SPI_DMA_CH_AUTO), TAG, "SPI init failed");

    // SPI device configuration not using the above
    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = 80 * 1000 * 1000, // Clock out at 10 MHz
        .mode = 0,                          // SPI mode 0
        .spics_io_num = DISP_GPIO_CS,       // CS pin
        .queue_size = 7,
        .flags = SPI_DEVICE_HALFDUPLEX,
        .post_cb = notify_flush_ready, // Called when DMA transfer is complete
    };
    ESP_ERROR_CHECK(spi_bus_add_device(DISP_SPI_NUM, &devcfg, &spi));

    lv_display_t * lv_st7789_create(uint32_t hor_res, uint32_t ver_res, lv_lcd_flag_t flags, lv_st7789_send_cmd_cb_t send_cmd_cb, lv_st7789_send_color_cb_t send_color_cb);

    return ESP_OK;
}

static void lvgl_tick_increment(void *arg)
{
    // Tell LVGL how many milliseconds have elapsed
    lv_tick_inc(2); // tjek 
}

static esp_err_t lvgl_tick_init(void)
{
    esp_timer_handle_t  tick_timer;

    // Tick interface for LVGL (using esp_timer to generate 2ms periodic event)
    const esp_timer_create_args_t lvgl_tick_timer_args = {
        .callback = &lvgl_tick_increment,
        .name = "LVGL tick",
    };
    ESP_RETURN_ON_ERROR(esp_timer_create(&lvgl_tick_timer_args, &tick_timer), TAG, "Creating LVGL timer filed!");
    return esp_timer_start_periodic(tick_timer, 2 * 1000); // 2 ms
}

// Send short command to the LCD. This function shall wait until the transaction finishes. 
int32_t my_lcd_send_cmd(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, const uint8_t *param, size_t param_size)
{
    // Send the command
    if (cmd && cmd_size > 0) {
        spi_transaction_t trans = {
            .length = cmd_size * 8, // Command size in bits
            .tx_buffer = cmd,
        };
        gpio_set_level(DISP_GPIO_DC, 0); // DC low for command
        spi_device_transmit(spi, &trans); // Transmit command
    }

    // Send parameters (if any)
    if (param && param_size > 0) {

        spi_transaction_t trans = {
            .length = param_size * 8, // Parameters size in bits
            .tx_buffer = param,
        };

        gpio_set_level(DISP_GPIO_DC, 1); // DC high for data
        spi_device_transmit(spi, &trans); // Transmit parameters
    }

    return 0;
}

int32_t my_lcd_send_color(lv_display_t *disp, const uint8_t *cmd, size_t cmd_size, uint8_t *param, size_t param_size)
{
    // Send the command (if required for color data)
    if (cmd && cmd_size > 0) {
        spi_transaction_t trans = {
            .length = cmd_size * 8, // Command size in bits
            .tx_buffer = cmd,
        };
        gpio_set_level(DISP_GPIO_DC, 0); // DC low for command
        spi_device_transmit(spi, &trans); // Transmit command
    }

    // Send color data
    if (param && param_size > 0) {

        uint16_t *pixel_data = (uint16_t *)param;
        size_t pixel_count = param_size / 2; // Each pixel is 2 bytes (RGB565)

        // Perform byte-swapping
        for (size_t i = 0; i < pixel_count; i++) {
            pixel_data[i] = (pixel_data[i] >> 8) | (pixel_data[i] << 8);
        }

        spi_transaction_t trans = {
            .length = param_size * 8, // Color data size in bits
            .tx_buffer = param,
        };
        gpio_set_level(DISP_GPIO_DC, 1); // DC high for data
        spi_device_transmit(spi, &trans); // Transmit color data
    }

    return 0;
}

static void lvgl_task(void *arg) {

    // LVGL init
    lv_init();

    // LVGL driver init
    display_init();

    // Tick init
    if (ESP_OK == lvgl_tick_init()) printf("Timer tick init OK");

    buf1 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL |  MALLOC_CAP_DMA);
    buf2 = heap_caps_calloc(1, BUFFER_SIZE, MALLOC_CAP_INTERNAL |  MALLOC_CAP_DMA);

    disp = lv_st7789_create(DISP_HOR_RES, DISP_VER_RES, 0, my_lcd_send_cmd, my_lcd_send_color);
    if (!disp) {
        ESP_LOGE(TAG, "Failed to initialize lv_st7789");
    }
    lv_display_set_buffers(disp, buf1, buf2, BUFFER_SIZE/sizeof(lv_color_t), LV_DISP_RENDER_MODE_PARTIAL);

    uint8_t cmd = 0x36;       // Command to set MADCTL
    uint8_t madctl = 0x60;    // Value for rotation (Landscape mode)
    my_lcd_send_cmd(disp, &cmd, 1, &madctl, 1); // Hardware rotate display

    // Create a simple label
    lv_obj_t *label = lv_label_create(lv_scr_act());
    lv_label_set_text(label, "Hello, LVGL!");
    lv_obj_align(label, LV_ALIGN_CENTER, 0, 0);

    long curtime = esp_timer_get_time()/1000;
    int counter = 0;

    // Handle LVGL tasks
    while (1) {
        vTaskDelay(pdMS_TO_TICKS(10));
        lv_task_handler();

        if (esp_timer_get_time()/1000 - curtime > 1000) {
            curtime = esp_timer_get_time()/1000;

            char textlabel[20];
            sprintf(textlabel, "Running: %u\n", counter);
            printf(textlabel);
            lv_label_set_text(label, textlabel);
            counter++;
        }
    }
}

void app_main() {

    vTaskDelay(5000/portTICK_PERIOD_MS);

    TaskHandle_t taskHandle = NULL;
    BaseType_t res = xTaskCreatePinnedToCore(lvgl_task, "LVGL task", 8192, NULL, 4, &taskHandle, 0); // stack, params, prio, handle, core

    while(true) {

        vTaskDelay(100/portTICK_PERIOD_MS);
    }

}

The advantage is it is going to be almost 2 times faster. Does your display have a power pin?

You need to change…

esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = DISP_GPIO_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
        .flags.reset_active_high = 1
    };

to

esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = DISP_GPIO_RST,
        .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
        .bits_per_pixel = 16,
        .flags = { .reset_active_high = 1 }
    };

OK, thats a lot.

Its a 1.69" touch display. Yes, there is a powerpin, layout of the connector is like this

image

The TP pins, is the the touch.

SDA is actually MISO
SCK is clock
RS is DC
CS is CS

did not make any difference

reset_active_high flag should be 0
ST7789 is active low reset.

I have added, setting DISP_GPIO_RST to output, and initial high.
Also makes no difference

I have noted one thing…

lv_color_t that I use in the working example, is 8 bit pr. color = 24 bit pr. pixel

Your code is 16 bit pr pixel.

Ah, that what the LV_COLOR_FORMAT_RGB565 is for… :slight_smile:
makes sense

What I have tried this time:

  • Created a clean project from scratch (just in case…)
    Mainly to make sure, that I have not changed anything via menuconfig
    totally clean, only the components copies in, and
    -I /components/lvgl
    added in the platformio.ini

  • Changing the text color, to make sure if did not write black text

I have noted, if I have used the working code, and left some writing on the display, it is visible for a very short time, first time this code runs. But only the first time. So the display is for sure cleared.

do you have a link to the website for the display?

Its this one:

https://www.aliexpress.com/item/1005005238299349.html?src=google

Got much of my info here, its the same display. There are various other projects, using same display.

https://www.adafruit.com/product/5206

It must be the SPI bus. Somehow its not initialized correctly… No matter what I try, there is nothing on the display. No glitch, no corrupted data, just absolutely nothing, except the lit backlight. Since I see data in flush_cb every second that is for sure not black, and the area matches something middle display, and also notify_flush_ready is called, it must be a communication issue.

The panel just referes to the SPI settings via the HOST number? Like this (esp_lcd_spi_bus_handle_t)DISP_SPI_NUM ? in the esp_lcd_new_panel_io_spi function.

Any ideas? I am running out of them… If you have something like this up running, why cant I ? …

GOT IT :slight_smile:

ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

And then there are light :slight_smile:

You asked if it was octal ram - is that actually used anywhere?

HA! I forgot to turn the thing on. LMAO.

That needs to be set for the compiling. It’s a series of CONFIG_* settings that is done in the idf. You should have an sdkconfig file that gets made that will have all of those kinds of options in it. That file gets made when you run the config for you board using idf.py.

Yes, I have the sdkconfig file, and all the options in menuconfig. I was just not aware of this option :slight_smile:

Now I just need to figure out rotate 90°. Hardware rotation seems not to be usable with the esp_lcd implementation - it just messes things up. Is there a “best way” of rotating?

I knew it was going to be something silly that I forgot to do or a setting I didn’t set.

Because you are using such a small display you want to allocate the frame buffers in internal memory using DMA memory. Make the frame buffers 1/10th the size of a foll display frame buffer.

the buffer allocation lines should look like this…

    buf1 = heap_caps_malloc(BUFFER_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
    buf2 = heap_caps_malloc(BUFFER_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);

and BUFFER_SIZE should read

#define BUFFER_SIZE  (DISP_HOR_RES * DISP_VER_RES * sizeof(uint16_t) / 10)

It is usable but you need to set LVGL’s rotation and the display rotation at the same time.

You always start off in the native display rotation. So if the native rotation is landscape then you should have the width and height in LVGL set accordingly.

The display rotation works as follows.

90°

lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90);
esp_lcd_panel_mirror(panel, true, false);
esp_lcd_panel_swap_xy(panel, true);

180°

lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_180);
esp_lcd_panel_mirror(panel, true, true);
esp_lcd_panel_swap_xy(panel, false);

270°

lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
esp_lcd_panel_mirror(panel, false, true);
esp_lcd_panel_swap_xy(panel, true);