Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CST816 Touch driver support (IDFGH-10255) (BSP-328) #178

Closed
krupis opened this issue May 26, 2023 · 48 comments · Fixed by #181
Closed

CST816 Touch driver support (IDFGH-10255) (BSP-328) #178

krupis opened this issue May 26, 2023 · 48 comments · Fixed by #181
Assignees

Comments

@krupis
Copy link

krupis commented May 26, 2023

Is your feature request related to a problem?

I have been using ST7789 display from the lilygo and it works flawlesly.

The only issue is that I believe the esp-idf does not currently support the touch driver (CST816) for this display.

image

https://www.lilygo.cc/products/t-display-s3

I think adding support for this touch driver would be very useful for developers such as myself.

Describe the solution you'd like.

Working touch display driver for CST816 and example project on how to get it going.

Describe alternatives you've considered.

Using different displays.

Additional context.

No response

@github-actions github-actions bot changed the title CST816 Touch driver support CST816 Touch driver support (IDFGH-10255) May 26, 2023
@espzav
Copy link
Collaborator

espzav commented May 29, 2023

Hello,
the touch driver for CST816 is here: https://components.espressif.com/components/espressif/esp_lcd_touch_cst816s

@krupis
Copy link
Author

krupis commented May 29, 2023

Hello, the touch driver for CST816 is here: https://components.espressif.com/components/espressif/esp_lcd_touch_cst816s

Thanks for quick reply. Is CST816 the same as CST816S? Because the driver that you linked is for CST816S.

Regardless, I have tried to use this touch driver. My full function that initializes the LVGL Display:

void lvgl_setup()
{

    gpio_config_t pwr_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_POWER};
    ESP_ERROR_CHECK(gpio_config(&pwr_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_POWER, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    gpio_config_t input_conf =
        {
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pin_bit_mask = 1ULL << PIN_LCD_RD};
    ESP_ERROR_CHECK(gpio_config(&input_conf));

    gpio_config_t bk_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
    static lv_disp_drv_t disp_drv;      // contains callback functions

    ESP_LOGI(TAG, "Initialize Intel 8080 bus");
    esp_lcd_i80_bus_handle_t i80_bus = NULL;
    esp_lcd_i80_bus_config_t bus_config = {
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .dc_gpio_num = EXAMPLE_PIN_NUM_DC,
        .wr_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            EXAMPLE_PIN_NUM_DATA3,
            EXAMPLE_PIN_NUM_DATA4,
            EXAMPLE_PIN_NUM_DATA5,
            EXAMPLE_PIN_NUM_DATA6,
            EXAMPLE_PIN_NUM_DATA7,
        },
        .bus_width = 8,
        .max_transfer_bytes = LVGL_LCD_BUF_SIZE * sizeof(uint16_t)
        //.psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
        //.sram_trans_align = 4,
    };
    ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_i80_config_t io_config = {
        .cs_gpio_num = EXAMPLE_PIN_NUM_CS,
        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
        .trans_queue_depth = 20,
        .dc_levels = {
            .dc_idle_level = 0,
            .dc_cmd_level = 0,
            .dc_dummy_level = 0,
            .dc_data_level = 1,
        },

        .on_color_trans_done = example_notify_lvgl_flush_ready,
        .user_ctx = &disp_drv,
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));

    esp_lcd_panel_handle_t panel_handle = NULL;

    ESP_LOGI(TAG, "Install LCD driver of st7789");
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
        .rgb_endian = ESP_LCD_COLOR_SPACE_RGB,
        .bits_per_pixel = 16,
    };
    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_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, 35));

    esp_lcd_panel_invert_color(panel_handle, true);
    esp_lcd_panel_swap_xy(panel_handle, true);
    esp_lcd_panel_mirror(panel_handle, false, true);
    // the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
    esp_lcd_panel_set_gap(panel_handle, 0, 35);

    esp_lcd_panel_io_tx_param(io_handle, 0xF2, (uint8_t[]){0}, 1); // 3Gamma function disable
    esp_lcd_panel_io_tx_param(io_handle, 0x26, (uint8_t[]){1}, 1); // Gamma curve 1 selected
    esp_lcd_panel_io_tx_param(io_handle, 0xE0, (uint8_t[]){        // Set positive gamma
                                                           0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00},
                              15);
    esp_lcd_panel_io_tx_param(io_handle, 0xE1, (uint8_t[]){// Set negative gamma
                                                           0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F},
                              15);

    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));




    //TOUCH FUNCTIONS
    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;

    const i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_I2C_SDA,
        .scl_io_num = EXAMPLE_I2C_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    ESP_LOGI(TAG,"Initializing I2C for display touch");
    /* Initialize I2C */
    ESP_ERROR_CHECK(i2c_param_config(EXAMPLE_I2C_NUM, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(EXAMPLE_I2C_NUM, i2c_conf.mode, 0, 0, 0));

    
    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();




    ESP_LOGI(TAG,"esp_lcd_new_panel_io_i2c");
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_I2C_NUM, &tp_io_config, &tp_io_handle));

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 0,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

    ESP_LOGI(TAG,"esp_lcd_touch_new_i2c_cst816s");
    esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &tp);


    // static lv_indev_drv_t indev_drv;    // Input device driver (Touch)
    // lv_indev_drv_init(&indev_drv);
    // indev_drv.type = LV_INDEV_TYPE_POINTER;
    // indev_drv.disp = disp;
    // indev_drv.read_cb = example_lvgl_touch_cb;
    // indev_drv.user_data = tp;

    // lv_indev_drv_register(&indev_drv);
    //END TOUCH FUNCTIONS








    lv_init();

    // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
    lv_color_t *buf1 = heap_caps_malloc(LVGL_LCD_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_disp_draw_buf_init(&disp_buf, buf1, NULL, LVGL_LCD_BUF_SIZE);

    ESP_LOGI(TAG, "Register display driver to LVGL");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb = example_lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.user_data = panel_handle;
    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);






    ESP_LOGI(TAG, "Install LVGL 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 = &example_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, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

    xTaskCreatePinnedToCore(lvgl_timer_task, "lvgl Timer", 10000, NULL, 4, NULL, 1);
}

The display itself works without any issues. I can display images and etc using LVGL. Lets have a look at functions I use to initialize touch display:


#define EXAMPLE_I2C_NUM                 0   // I2C number
#define EXAMPLE_I2C_SCL                 18
#define EXAMPLE_I2C_SDA                 17
    //TOUCH FUNCTIONS
    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;

    const i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_I2C_SDA,
        .scl_io_num = EXAMPLE_I2C_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    ESP_LOGI(TAG,"Initializing I2C for display touch");
    /* Initialize I2C */
    ESP_ERROR_CHECK(i2c_param_config(EXAMPLE_I2C_NUM, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(EXAMPLE_I2C_NUM, i2c_conf.mode, 0, 0, 0));

    
    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();




    ESP_LOGI(TAG,"esp_lcd_new_panel_io_i2c");
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_I2C_NUM, &tp_io_config, &tp_io_handle));

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 0,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

    ESP_LOGI(TAG,"esp_lcd_touch_new_i2c_cst816s");
    esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &tp);

I get the following errors printed in the console:

[1B][0;32mI (505) LVGL_SETUP: esp_lcd_new_panel_io_i2c[1B][0m
[1B][0;32mI (505) LVGL_SETUP: esp_lcd_touch_new_i2c_cst816s[1B][0m
[1B][0;32mI (505) gpio: GPIO[16]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (515) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2 [1B][0m
[1B][0;31mE (545) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (545) CST816S: read_id(174): I2C read failed[1B][0m
[1B][0;31mE (545) CST816S: esp_lcd_touch_new_i2c_cst816s(84): Read version failed[1B][0m
[1B][0;32mI (545) gpio: GPIO[16]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (555) gpio: GPIO[21]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;31mE (565) CST816S: Initialization failed![1B][0m

It does not seem to be able to read the i2c device id:

[1B][0;31mE (545) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (545) CST816S: read_id(174): I2C read failed[1B][0m
[1B][0;31mE (545) CST816S: esp_lcd_touch_new_i2c_cst816s(84): Read version failed[1B][0m

@espzav
Copy link
Collaborator

espzav commented May 31, 2023

Hello,
it seems, that CST816 and CST816S are same. Same address and same registers. I haven't got same board and I cannot test it now. It seems, you have mistake in GPIOS on I2C. It should be like here:

#define EXAMPLE_I2C_SCL                 17
#define EXAMPLE_I2C_SDA                18

@krupis
Copy link
Author

krupis commented May 31, 2023

Hello, it seems, that CST816 and CST816S are same. Same address and same registers. I haven't got same board and I cannot test it now. It seems, you have mistake in GPIOS on I2C. It should be like here:

#define EXAMPLE_I2C_SCL                 17
#define EXAMPLE_I2C_SDA                18

Thanks for your response. I still havent been able to get it running. Can you confirm where did you get these I2C GPIO declaration. I have declared:

#define EXAMPLE_I2C_SCL                 18
#define EXAMPLE_I2C_SDA                 17

And that is correct according to the
image

Anyways, I have tried to reconfigure but getting the identical error in the terminal.

@espzav
Copy link
Collaborator

espzav commented May 31, 2023

@krupis
Copy link
Author

krupis commented May 31, 2023

I found it on the schematics: https://github.com/Xinyuan-LilyGO/T-Display-S3/blob/main/schematic/T_Display_S3.pdf

Yeah you are right. In the schematic it shows the following:
image

but in the Readme.md it shows the following:
image

Lets hope to hear from someone who managed to get it to work on the esp-idf.

@espzav
Copy link
Collaborator

espzav commented Jun 6, 2023

@Lzw655 please, could you help with this? I haven't got HW for CST816 touch.

@Alvin1Zhang Alvin1Zhang transferred this issue from espressif/esp-idf Jun 7, 2023
@github-actions github-actions bot changed the title CST816 Touch driver support (IDFGH-10255) CST816 Touch driver support (IDFGH-10255) (BSP-328) Jun 7, 2023
@krupis
Copy link
Author

krupis commented Jun 13, 2023

How is it going regarding the CST816 touch driver? Has there been any updates ?

Highly appreciate!

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 13, 2023

@krupis Sorry for being late. I have an LCD with CST816 touch in the home and I'll use it to test the driver tomorrow. Please wait another day.

But we can do some tests first. You can run the below codes and check the I2C address of the touch.

    i2c_cmd_handle_t cmd;
    for (int i = 0; i < 0x7f; i++) {
        cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        if (i2c_master_cmd_begin(BSP_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK) {
            ESP_LOGW(TAG, "%02X", i);
        }
        i2c_cmd_link_delete(cmd);
    }

@krupis
Copy link
Author

krupis commented Jun 13, 2023

i2c_cmd_handle_t cmd;
for (int i = 0; i < 0x7f; i++) {
cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
i2c_master_stop(cmd);
if (i2c_master_cmd_begin(BSP_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK) {
ESP_LOGW(TAG, "%02X", i);
}
i2c_cmd_link_delete(cmd);
}

Not a problem at all.

Do you have a T-Display-S3 from Lilygo or some custom board?

I have tried to run the command that you have suggested. I have a public repository for testing CST816 that here:
https://github.com/krupis/T-Display-S3-esp-idf

I have a lvgl_setup function that is being called in main.c to initialise the whole display:

void lvgl_setup()
{

    gpio_config_t pwr_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_POWER};
    ESP_ERROR_CHECK(gpio_config(&pwr_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_POWER, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    gpio_config_t input_conf =
        {
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pin_bit_mask = 1ULL << PIN_LCD_RD};
    ESP_ERROR_CHECK(gpio_config(&input_conf));

    gpio_config_t bk_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
    static lv_disp_drv_t disp_drv;      // contains callback functions

    ESP_LOGI(TAG, "Initialize Intel 8080 bus");
    esp_lcd_i80_bus_handle_t i80_bus = NULL;
    esp_lcd_i80_bus_config_t bus_config = {
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .dc_gpio_num = EXAMPLE_PIN_NUM_DC,
        .wr_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            EXAMPLE_PIN_NUM_DATA3,
            EXAMPLE_PIN_NUM_DATA4,
            EXAMPLE_PIN_NUM_DATA5,
            EXAMPLE_PIN_NUM_DATA6,
            EXAMPLE_PIN_NUM_DATA7,
        },
        .bus_width = 8,
        .max_transfer_bytes = LVGL_LCD_BUF_SIZE * sizeof(uint16_t)
        //.psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
        //.sram_trans_align = 4,
    };
    ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_i80_config_t io_config = {
        .cs_gpio_num = EXAMPLE_PIN_NUM_CS,
        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
        .trans_queue_depth = 20,
        .dc_levels = {
            .dc_idle_level = 0,
            .dc_cmd_level = 0,
            .dc_dummy_level = 0,
            .dc_data_level = 1,
        },

        .on_color_trans_done = example_notify_lvgl_flush_ready,
        .user_ctx = &disp_drv,
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));

    esp_lcd_panel_handle_t panel_handle = NULL;

    ESP_LOGI(TAG, "Install LCD driver of st7789");
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
        .rgb_endian = ESP_LCD_COLOR_SPACE_RGB,
        .bits_per_pixel = 16,
    };
    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_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, 35));

    esp_lcd_panel_invert_color(panel_handle, true);
    esp_lcd_panel_swap_xy(panel_handle, true);
    esp_lcd_panel_mirror(panel_handle, false, true);
    // the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
    esp_lcd_panel_set_gap(panel_handle, 0, 35);

    esp_lcd_panel_io_tx_param(io_handle, 0xF2, (uint8_t[]){0}, 1); // 3Gamma function disable
    esp_lcd_panel_io_tx_param(io_handle, 0x26, (uint8_t[]){1}, 1); // Gamma curve 1 selected
    esp_lcd_panel_io_tx_param(io_handle, 0xE0, (uint8_t[]){        // Set positive gamma
                                                           0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00},
                              15);
    esp_lcd_panel_io_tx_param(io_handle, 0xE1, (uint8_t[]){// Set negative gamma
                                                           0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F},
                              15);

    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

    lv_init();

    // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
    lv_color_t *buf1 = heap_caps_malloc(LVGL_LCD_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_disp_draw_buf_init(&disp_buf, buf1, NULL, LVGL_LCD_BUF_SIZE);

    ESP_LOGI(TAG, "Register display driver to LVGL");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb = example_lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.user_data = panel_handle;
    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);

    ESP_LOGI(TAG, "Install LVGL 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 = &example_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, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

    xTaskCreatePinnedToCore(lvgl_timer_task, "lvgl Timer", 10000, NULL, 4, NULL, 1);




    //CST816 TOUCH TESTING
    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;

    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_I2C_SDA,
        .scl_io_num = EXAMPLE_I2C_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    ESP_LOGI(TAG,"Initializing I2C for display touch");
    /* Initialize I2C */
    ESP_ERROR_CHECK(i2c_param_config(EXAMPLE_I2C_NUM, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(EXAMPLE_I2C_NUM, i2c_conf.mode, 0, 0, 0));


    i2c_cmd_handle_t cmd;
    for (int i = 0; i < 0x7f; i++) {
        cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        if (i2c_master_cmd_begin(EXAMPLE_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK) {
            ESP_LOGW(TAG, "%02X", i);
        }
        i2c_cmd_link_delete(cmd);
    }

}

As you can see at the end of my lvgl_setup, I have added the following functions:


    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_I2C_SDA,
        .scl_io_num = EXAMPLE_I2C_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    ESP_LOGI(TAG,"Initializing I2C for display touch");
    /* Initialize I2C */
    ESP_ERROR_CHECK(i2c_param_config(EXAMPLE_I2C_NUM, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(EXAMPLE_I2C_NUM, i2c_conf.mode, 0, 0, 0));


    i2c_cmd_handle_t cmd;
    for (int i = 0; i < 0x7f; i++) {
        cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        if (i2c_master_cmd_begin(EXAMPLE_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK) {
            ESP_LOGW(TAG, "%02X", i);
        }
        i2c_cmd_link_delete(cmd);
    }

And when I flash my device, it does not seem to return any errors:

[1B][0;32mI (122) esp_image: segment 3: paddr=00030020 vaddr=420000
[1B][0;32mI (221) cpu_start: Project name:     i80_controller[1B][0m
[1B][0;32mI (227) cpu_start: App version:      5552b0b-dirty[1B][0m
[1B][0;32mI (232) cpu_start: Compile time:     Jun 13 2023 10:05:43[1B][0m
[1B][0;32mI (239) cpu_start: ELF file SHA256:  a573f2e0a487791a...[1B][0m
[1B][0;32mI (245) cpu_start: ESP-IDF:          v5.0.1-dirty[1B][0m
[1B][0;32mI (250) cpu_start: Min chip rev:     v0.0[1B][0m
[1B][0;32mI (255) cpu_start: Max chip rev:     v0.99 [1B][0m
[1B][0;32mI (259) cpu_start: Chip rev:         v0.1[1B][0m
[1B][0;32mI (264) heap_init: Initializing. RAM available for dynamic allocation:[1B][0m
[1B][0;32mI (271) heap_init: At 3FC96598 len 00053178 (332 KiB): D/IRAM[1B][0m
[1B][0;32mI (278) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM[1B][0m
[1B][0;32mI (284) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM[1B][0m
[1B][0;32mI (291) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM[1B][0m
[1B][0;32mI (298) spi_flash: detected chip: winbond[1B][0m
[1B][0;32mI (302) spi_flash: flash io: dio[1B][0m
[1B][0;33mW (306) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.[1B][0m
[1B][0;32mI (319) cpu_start: Starting scheduler on PRO CPU.[1B][0m
[1B][0;32mI (0) cpu_start: Starting scheduler on APP CPU.[1B][0m
This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision v0.1, 2MB external flash
Minimum free heap size: 379836 bytes
[1B][0;32mI (381) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (391) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (391) gpio: GPIO[38]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (401) LVGL_SETUP: Initialize Intel 8080 bus[1B][0m
[1B][0;32mI (411) LVGL_SETUP: Install LCD driver of st7789[1B][0m
[1B][0;32mI (411) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (541) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (541) LVGL_SETUP: Install LVGL tick timer[1B][0m
[1B][0;32mI (541) LVGL_SETUP: Initializing I2C for display touch[1B][0m

I am guessing that's a good sign.

But when I try to call the functions to initialize CST816 driver:

    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();


    ESP_LOGI(TAG,"esp_lcd_new_panel_io_i2c");
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_I2C_NUM, &tp_io_config, &tp_io_handle));

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 0,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

    ESP_LOGI(TAG,"esp_lcd_touch_new_i2c_cst816s");
    esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &tp);

I am getting errors:

[1B][0;32mI (539) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (539) LVGL_SETUP: Install LVGL tick timer[1B][0m
[1B][0;32mI (539) LVGL_SETUP: Initializing I2C for display touch[1B][0m
[1B][0;32mI (539) LVGL_SETUP: esp_lcd_new_panel_io_i2c[1B][0m
[1B][0;32mI (549) LVGL_SETUP: esp_lcd_touch_new_i2c_cst816s[1B][0m
[1B][0;32mI (549) gpio: GPIO[16]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (559) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2 [1B][0m
[1B][0;31mE (589) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (589) CST816S: read_id(174): I2C read failed[1B][0m
[1B][0;31mE (589) CST816S: esp_lcd_touch_new_i2c_cst816s(84): Read version failed[1B][0m
[1B][0;32mI (589) gpio: GPIO[16]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (599) gpio: GPIO[21]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;31mE (609) CST816S: Initialization failed![1B][0m

If you want, you can try use my example project to get going from your side. The display seems to work fine (I can display images and other things on the display with that example project). It is just the Display that I am struggling with.

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 13, 2023

Well, I only have a custom board.

The given code is used to probe and print the I2C address of touch IC. But according to your results as below, there is no address (like 0x15) that can be found.

[1B][0;32mI (122) esp_image: segment 3: paddr=00030020 vaddr=420000
[1B][0;32mI (221) cpu_start: Project name:     i80_controller[1B][0m
[1B][0;32mI (227) cpu_start: App version:      5552b0b-dirty[1B][0m
[1B][0;32mI (232) cpu_start: Compile time:     Jun 13 2023 10:05:43[1B][0m
[1B][0;32mI (239) cpu_start: ELF file SHA256:  a573f2e0a487791a...[1B][0m
[1B][0;32mI (245) cpu_start: ESP-IDF:          v5.0.1-dirty[1B][0m
[1B][0;32mI (250) cpu_start: Min chip rev:     v0.0[1B][0m
[1B][0;32mI (255) cpu_start: Max chip rev:     v0.99 [1B][0m
[1B][0;32mI (259) cpu_start: Chip rev:         v0.1[1B][0m
[1B][0;32mI (264) heap_init: Initializing. RAM available for dynamic allocation:[1B][0m
[1B][0;32mI (271) heap_init: At 3FC96598 len 00053178 (332 KiB): D/IRAM[1B][0m
[1B][0;32mI (278) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM[1B][0m
[1B][0;32mI (284) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM[1B][0m
[1B][0;32mI (291) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM[1B][0m
[1B][0;32mI (298) spi_flash: detected chip: winbond[1B][0m
[1B][0;32mI (302) spi_flash: flash io: dio[1B][0m
[1B][0;33mW (306) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.[1B][0m
[1B][0;32mI (319) cpu_start: Starting scheduler on PRO CPU.[1B][0m
[1B][0;32mI (0) cpu_start: Starting scheduler on APP CPU.[1B][0m
This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision v0.1, 2MB external flash
Minimum free heap size: 379836 bytes
[1B][0;32mI (381) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (391) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (391) gpio: GPIO[38]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (401) LVGL_SETUP: Initialize Intel 8080 bus[1B][0m
[1B][0;32mI (411) LVGL_SETUP: Install LCD driver of st7789[1B][0m
[1B][0;32mI (411) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (541) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (541) LVGL_SETUP: Install LVGL tick timer[1B][0m
[1B][0;32mI (541) LVGL_SETUP: Initializing I2C for display touch[1B][0m

So I suspect that there is a problem with your I2C pins. You can try to swap the gpio of SDA and SCL, then run the given code again. If there is no address to be printed, maybe the hardware has some problems. Do you have another board to test?

@krupis
Copy link
Author

krupis commented Jun 13, 2023

@Lzw655

I have tried to swap the SDA and SCL pins around but the results are the same.

It is most definately not the HW related issue since I can run the LilyGO provided example code based on Arduino IDE and the Touch works fine. Unfortunately, I do not prefer the Arduino IDE and I am hoping to get it working on the esp-idf.

@C-basstien
Copy link

Hello,
I have the exact same issue with also the T-Display-S3, I have tested your code suggestion for swapping pin and it does not work. It also work fine with Arduino IDE on my side
Seb

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 13, 2023

@krupis @C-basstien Get it. Let me take a look at the code in Arduino.

@krupis
Copy link
Author

krupis commented Jun 13, 2023

@Lzw655

UPDATE
As I was testing out the I2C, I have found out a few things:
There is a RES (IO 21) pin on the T-Display-S3 display.
image

I have toggled it HIGH before scanning the i2c devices and it detected 0x15 I2C device.

My lvgl_setup looks like:
(Notice I added setting IO 21 high and also reorganized where I call the I2C functions)

void lvgl_setup()
{
    gpio_config_t pwr_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_POWER};
    ESP_ERROR_CHECK(gpio_config(&pwr_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_POWER, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    gpio_config_t input_conf =
        {
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pin_bit_mask = 1ULL << PIN_LCD_RD};
    ESP_ERROR_CHECK(gpio_config(&input_conf));

    gpio_config_t bk_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    //CST816 TOUCH TESTING FUNCTION
    gpio_config_t touch_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << PIN_TOUCH_RES};
    ESP_ERROR_CHECK(gpio_config(&touch_gpio_config));
    gpio_set_level(PIN_TOUCH_RES, 1);
    //END OF CST816 TOUCH TESTING FUNCTION



    static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
    static lv_disp_drv_t disp_drv;      // contains callback functions

    ESP_LOGI(TAG, "Initialize Intel 8080 bus");
    esp_lcd_i80_bus_handle_t i80_bus = NULL;
    esp_lcd_i80_bus_config_t bus_config = {
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .dc_gpio_num = EXAMPLE_PIN_NUM_DC,
        .wr_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            EXAMPLE_PIN_NUM_DATA3,
            EXAMPLE_PIN_NUM_DATA4,
            EXAMPLE_PIN_NUM_DATA5,
            EXAMPLE_PIN_NUM_DATA6,
            EXAMPLE_PIN_NUM_DATA7,
        },
        .bus_width = 8,
        .max_transfer_bytes = LVGL_LCD_BUF_SIZE * sizeof(uint16_t)
        //.psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
        //.sram_trans_align = 4,
    };
    ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_i80_config_t io_config = {
        .cs_gpio_num = EXAMPLE_PIN_NUM_CS,
        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
        .trans_queue_depth = 20,
        .dc_levels = {
            .dc_idle_level = 0,
            .dc_cmd_level = 0,
            .dc_dummy_level = 0,
            .dc_data_level = 1,
        },

        .on_color_trans_done = example_notify_lvgl_flush_ready,
        .user_ctx = &disp_drv,
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));

    esp_lcd_panel_handle_t panel_handle = NULL;

    ESP_LOGI(TAG, "Install LCD driver of st7789");
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
        .rgb_endian = ESP_LCD_COLOR_SPACE_RGB,
        .bits_per_pixel = 16,
    };
    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_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, 35));

    esp_lcd_panel_invert_color(panel_handle, true);
    esp_lcd_panel_swap_xy(panel_handle, true);
    esp_lcd_panel_mirror(panel_handle, false, true);
    // the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
    esp_lcd_panel_set_gap(panel_handle, 0, 35);

    esp_lcd_panel_io_tx_param(io_handle, 0xF2, (uint8_t[]){0}, 1); // 3Gamma function disable
    esp_lcd_panel_io_tx_param(io_handle, 0x26, (uint8_t[]){1}, 1); // Gamma curve 1 selected
    esp_lcd_panel_io_tx_param(io_handle, 0xE0, (uint8_t[]){        // Set positive gamma
                                                           0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00},
                              15);
    esp_lcd_panel_io_tx_param(io_handle, 0xE1, (uint8_t[]){// Set negative gamma
                                                           0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F},
                              15);

    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

    //CST816 TOUCH TESTING FUNCTION
    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;

    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_I2C_SDA,
        .scl_io_num = EXAMPLE_I2C_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    ESP_LOGI(TAG,"Initializing I2C for display touch");
    /* Initialize I2C */
    ESP_ERROR_CHECK(i2c_param_config(EXAMPLE_I2C_NUM, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(EXAMPLE_I2C_NUM, i2c_conf.mode, 0, 0, 0));

    i2c_cmd_handle_t cmd;
    for (int i = 0; i < 0x7f; i++) {
        cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        if (i2c_master_cmd_begin(EXAMPLE_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK) {
            ESP_LOGW("I2C_TEST", "%02X", i);
        }
        i2c_cmd_link_delete(cmd);
    }
    //END OF CST816 TOUCH TESTING FUNCTION


    lv_init();

    // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
    lv_color_t *buf1 = heap_caps_malloc(LVGL_LCD_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_disp_draw_buf_init(&disp_buf, buf1, NULL, LVGL_LCD_BUF_SIZE);

    ESP_LOGI(TAG, "Register display driver to LVGL");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb = example_lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.user_data = panel_handle;
    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);

    ESP_LOGI(TAG, "Install LVGL 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 = &example_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, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

    xTaskCreatePinnedToCore(lvgl_timer_task, "lvgl Timer", 10000, NULL, 4, NULL, 1);

}

The serial console output:

[1B][0;32mI (122) esp_image: segment 3: paddr=00030020 vaddr=420000ation:[1B][0m
[1B][0;32mI (221) cpu_start: Project name:     i80_controller[1B][0m
[1B][0;32mI (227) cpu_start: App version:      4803def-dirty[1B][0m
[1B][0;32mI (232) cpu_start: Compile time:     Jun 13 2023 10:23:08[1B][0m
[1B][0;32mI (239) cpu_start: ELF file SHA256:  4653f03e400515cd...[1B][0m
[1B][0;32mI (245) cpu_start: ESP-IDF:          v5.0.1-dirty[1B][0m
[1B][0;32mI (250) cpu_start: Min chip rev:     v0.0[1B][0m
[1B][0;32mI (255) cpu_start: Max chip rev:     v0.99 [1B][0m
[1B][0;32mI (259) cpu_start: Chip rev:         v0.1[1B][0m
[1B][0;32mI (264) heap_init: Initializing. RAM available for dynamic allocation:[1B][0m
[1B][0;32mI (272) heap_init: At 3FC96598 len 00053178 (332 KiB): D/IRAM[1B][0m
[1B][0;32mI (278) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM[1B][0m
[1B][0;32mI (284) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM[1B][0m
[1B][0;32mI (291) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM[1B][0m
[1B][0;32mI (298) spi_flash: detected chip: winbond[1B][0m
[1B][0;32mI (302) spi_flash: flash io: dio[1B][0m
[1B][0;33mW (306) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.[1B][0m
[1B][0;32mI (320) cpu_start: Starting scheduler on PRO CPU.[1B][0m
[1B][0;32mI (0) cpu_start: Starting scheduler on APP CPU.[1B][0m
This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision v0.1, 2MB external flash
Minimum free heap size: 379836 bytes
[1B][0;32mI (381) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (391) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (391) gpio: GPIO[38]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (401) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (411) LVGL_SETUP: Initialize Intel 8080 bus[1B][0m
[1B][0;32mI (421) LVGL_SETUP: Install LCD driver of st7789[1B][0m
[1B][0;32mI (421) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (551) LVGL_SETUP: Initializing I2C for display touch[1B][0m
[1B][0;33mW (551) I2C_TEST: 15[1B][0m
[1B][0;32mI (561) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (561) LVGL_SETUP: Install LVGL tick timer[1B][0m

That is a good sign, device with 0x15 address was found.

Now I replace

    i2c_cmd_handle_t cmd;
    for (int i = 0; i < 0x7f; i++) {
        cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        if (i2c_master_cmd_begin(EXAMPLE_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK) {
            ESP_LOGW("I2C_TEST", "%02X", i);
        }
        i2c_cmd_link_delete(cmd);
    }

with :

    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();


    ESP_LOGI(TAG,"esp_lcd_new_panel_io_i2c");
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_I2C_NUM, &tp_io_config, &tp_io_handle));
    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 1,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

    ESP_LOGI(TAG,"esp_lcd_touch_new_i2c_cst816s");
    esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &tp);

The result:

[1B][0;32mI (549) LVGL_SETUP: Initializing I2C for display touch[1B][0m
[1B][0;32mI (549) LVGL_SETUP: esp_lcd_new_panel_io_i2c[1B][0m
[1B][0;32mI (549) LVGL_SETUP: esp_lcd_touch_new_i2c_cst816s[1B][0m
[1B][0;32mI (549) gpio: GPIO[16]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (559) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2 [1B][0m
[1B][0;31mE (589) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (589) CST816S: read_id(174): I2C read failed[1B][0m
[1B][0;31mE (589) CST816S: esp_lcd_touch_new_i2c_cst816s(84): Read version failed[1B][0m

I try to play with esp_lcd_touch_config_t

Replace:

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 1,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

With

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = -1,
        .int_gpio_num = -1,
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

The serial console output:

[1B][0;32mI (382) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (392) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (392) gpio: GPIO[38]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (402) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (412) LVGL_SETUP: Initialize Intel 8080 bus[1B][0m
[1B][0;32mI (422) LVGL_SETUP: Install LCD driver of st7789[1B][0m
[1B][0;32mI (422) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (552) LVGL_SETUP: Initializing I2C for display touch[1B][0m
[1B][0;32mI (552) LVGL_SETUP: esp_lcd_new_panel_io_i2c[1B][0m
[1B][0;32mI (552) LVGL_SETUP: esp_lcd_touch_new_i2c_cst816s[1B][0m
[1B][0;32mI (552) CST816S: IC id: 181[1B][0m
[1B][0;32mI (552) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (562) LVGL_SETUP: Install LVGL tick timer[1B][0m

There are no more error messages. I am very confused. What was the issue with my initial esp_lcd_touch_config_t declaration.

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 13, 2023

@krupis Thanks for your patient test. I just notice that the RST should be set to high first.

And according to your results, I find an error in the source code. Line 71 should be placed to line 64. It may cause the level of RST not right.

if (cst816s->config.int_gpio_num != GPIO_NUM_NC) {
const gpio_config_t int_gpio_config = {
.mode = GPIO_MODE_INPUT,
.pin_bit_mask = BIT64(cst816s->config.int_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&int_gpio_config), err, TAG, "GPIO intr config failed");
}
/* Prepare pin for touch controller reset */
if (cst816s->config.rst_gpio_num != GPIO_NUM_NC) {
const gpio_config_t rst_gpio_config = {
.mode = GPIO_MODE_OUTPUT,
.intr_type = GPIO_INTR_NEGEDGE,
.pin_bit_mask = BIT64(cst816s->config.rst_gpio_num)
};
ESP_GOTO_ON_ERROR(gpio_config(&rst_gpio_config), err, TAG, "GPIO reset config failed");
/* Register interrupt callback */
if (cst816s->config.interrupt_callback) {
esp_lcd_touch_register_interrupt_callback(cst816s, cst816s->config.interrupt_callback);
}
}

Can you help me to verify it? If success, I'll fix it now.

@krupis
Copy link
Author

krupis commented Jun 13, 2023

For this test, do you want me to remove the below from my code?

     gpio_config_t touch_gpio_config =
        {
             .mode = GPIO_MODE_OUTPUT,
             .pin_bit_mask = 1ULL << PIN_TOUCH_RES};
     ESP_ERROR_CHECK(gpio_config(&touch_gpio_config));
     gpio_set_level(PIN_TOUCH_RES, 1);

For the time being, i didint remove the above.

Since I made changes in the managed component, I can no longer build the project

ERROR: Some components (espressif/esp_lcd_touch_cst816s) in the
  "managed_components" directory were modified on the disk since the last run
  of the CMake.  Content of this directory is managed automatically.

  If you want to keep the changes, you can move the directory with the
  component to the "components"directory of your project.

  I.E.  for "espressif__esp_lcd_touch_cst816s" run:

  mv
  C:\Users\petrikas.lu\Desktop\WORK\ESP32\T-Display-S3-test\T-Display-S3-esp-idf\managed_components\espressif__esp_lcd_touch_cst816s
  C:\Users\petrikas.lu\Desktop\WORK\ESP32\T-Display-S3-test\T-Display-S3-esp-idf\components\espressif__esp_lcd_touch_cst816s


  Or, if you want to discard the changes remove the ".component_hash" file
  from the component's directory.

  I.E.  for "espressif__esp_lcd_touch_cst816s" run:

  rm
  C:\Users\petrikas.lu\Desktop\WORK\ESP32\T-Display-S3-test\T-Display-S3-esp-idf\managed_components\espressif__esp_lcd_touch_cst816s\.component_hash

It tells me to copy the cst816s managed component and place it to my components folder. I just manually cloned the whole espressif__esp_lcd_touch_cst816s folder and moved it into my components folder.

image

After building and flashing the device, It seems that it still does not work with the below esp_lcd_touch_config_t

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 1,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };
[1B][0;32mI (557) gpio: GPIO[16]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2 [1B][0m
[1B][0;32mI (567) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;31mE (597) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (597) CST816S: read_id(176): I2C read failed[1B][0m
[1B][0;31mE (597) CST816S: esp_lcd_touch_new_i2c_cst816s(86): Read version failed[1B][0m
[1B][0;32mI (597) gpio: GPIO[16]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (607) gpio: GPIO[21]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;31mE (617) CST816S: Initialization failed![1B][0m

@krupis
Copy link
Author

krupis commented Jun 13, 2023

There seems to be an issue with the rst pin.

The below works without any issues

   esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = -1,
        .int_gpio_num = 16,
        .levels = {
            //.reset = 1,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

However, this one do not:

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 1,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

Keep in mind that I still have my:

#define PIN_TOUCH_RES                  21
    gpio_config_t touch_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << PIN_TOUCH_RES};
    ESP_ERROR_CHECK(gpio_config(&touch_gpio_config));
    gpio_set_level(PIN_TOUCH_RES, 1);

at the beggining of the lvgl_setup

I have updated the code in my repository. You can have a look for full source code there

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 13, 2023

@krupis Please remove:

#define PIN_TOUCH_RES                  21
    gpio_config_t touch_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << PIN_TOUCH_RES};
    ESP_ERROR_CHECK(gpio_config(&touch_gpio_config));
    gpio_set_level(PIN_TOUCH_RES, 1);

And try the code (.reset = 0):

    esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 0,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

@krupis
Copy link
Author

krupis commented Jun 13, 2023

I tried your suggestion. My lvgl_setup:


void lvgl_setup()
{
    gpio_config_t pwr_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_POWER};
    ESP_ERROR_CHECK(gpio_config(&pwr_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_POWER, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    gpio_config_t input_conf =
        {
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pin_bit_mask = 1ULL << PIN_LCD_RD};
    ESP_ERROR_CHECK(gpio_config(&input_conf));

    gpio_config_t bk_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    //CST816 TOUCH TESTING FUNCTION
    // gpio_config_t touch_gpio_config =
    //     {
    //         .mode = GPIO_MODE_OUTPUT,
    //         .pin_bit_mask = 1ULL << PIN_TOUCH_RES};
    // ESP_ERROR_CHECK(gpio_config(&touch_gpio_config));
    // gpio_set_level(PIN_TOUCH_RES, 1);
    //END OF CST816 TOUCH TESTING FUNCTION



    static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
    static lv_disp_drv_t disp_drv;      // contains callback functions

    ESP_LOGI(TAG, "Initialize Intel 8080 bus");
    esp_lcd_i80_bus_handle_t i80_bus = NULL;
    esp_lcd_i80_bus_config_t bus_config = {
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .dc_gpio_num = EXAMPLE_PIN_NUM_DC,
        .wr_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            EXAMPLE_PIN_NUM_DATA3,
            EXAMPLE_PIN_NUM_DATA4,
            EXAMPLE_PIN_NUM_DATA5,
            EXAMPLE_PIN_NUM_DATA6,
            EXAMPLE_PIN_NUM_DATA7,
        },
        .bus_width = 8,
        .max_transfer_bytes = LVGL_LCD_BUF_SIZE * sizeof(uint16_t)
        //.psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
        //.sram_trans_align = 4,
    };
    ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_i80_config_t io_config = {
        .cs_gpio_num = EXAMPLE_PIN_NUM_CS,
        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
        .trans_queue_depth = 20,
        .dc_levels = {
            .dc_idle_level = 0,
            .dc_cmd_level = 0,
            .dc_dummy_level = 0,
            .dc_data_level = 1,
        },

        .on_color_trans_done = example_notify_lvgl_flush_ready,
        .user_ctx = &disp_drv,
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));

    esp_lcd_panel_handle_t panel_handle = NULL;

    ESP_LOGI(TAG, "Install LCD driver of st7789");
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
        .rgb_endian = ESP_LCD_COLOR_SPACE_RGB,
        .bits_per_pixel = 16,
    };
    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_ERROR_CHECK(esp_lcd_panel_invert_color(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_swap_xy(panel_handle, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_mirror(panel_handle, false, true));
    // ESP_ERROR_CHECK(esp_lcd_panel_set_gap(panel_handle, 0, 35));

    esp_lcd_panel_invert_color(panel_handle, true);
    esp_lcd_panel_swap_xy(panel_handle, true);
    esp_lcd_panel_mirror(panel_handle, false, true);
    // the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
    esp_lcd_panel_set_gap(panel_handle, 0, 35);

    esp_lcd_panel_io_tx_param(io_handle, 0xF2, (uint8_t[]){0}, 1); // 3Gamma function disable
    esp_lcd_panel_io_tx_param(io_handle, 0x26, (uint8_t[]){1}, 1); // Gamma curve 1 selected
    esp_lcd_panel_io_tx_param(io_handle, 0xE0, (uint8_t[]){        // Set positive gamma
                                                           0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00},
                              15);
    esp_lcd_panel_io_tx_param(io_handle, 0xE1, (uint8_t[]){// Set negative gamma
                                                           0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F},
                              15);

    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

    //CST816 TOUCH TESTING FUNCTION
    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;

    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_I2C_SDA,
        .scl_io_num = EXAMPLE_I2C_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    ESP_LOGI(TAG,"Initializing I2C for display touch");
    /* Initialize I2C */
    ESP_ERROR_CHECK(i2c_param_config(EXAMPLE_I2C_NUM, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(EXAMPLE_I2C_NUM, i2c_conf.mode, 0, 0, 0));

    i2c_cmd_handle_t cmd;
    for (int i = 0; i < 0x7f; i++) {
        cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        if (i2c_master_cmd_begin(EXAMPLE_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK) {
            ESP_LOGW("I2C_TEST", "%02X", i);
        }
        i2c_cmd_link_delete(cmd);
    }

    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();


    ESP_LOGI(TAG,"esp_lcd_new_panel_io_i2c");
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_I2C_NUM, &tp_io_config, &tp_io_handle));


        esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 0,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    }

    ESP_LOGI(TAG,"esp_lcd_touch_new_i2c_cst816s");
    esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &tp);



    //END OF CST816 TOUCH TESTING FUNCTION


    lv_init();

    // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
    lv_color_t *buf1 = heap_caps_malloc(LVGL_LCD_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_disp_draw_buf_init(&disp_buf, buf1, NULL, LVGL_LCD_BUF_SIZE);

    ESP_LOGI(TAG, "Register display driver to LVGL");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb = example_lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.user_data = panel_handle;
    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);

    ESP_LOGI(TAG, "Install LVGL 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 = &example_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, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

    xTaskCreatePinnedToCore(lvgl_timer_task, "lvgl Timer", 10000, NULL, 4, NULL, 1);

}

Unfortunately same results:

[1B][0;32mI (401) LVGL_SETUP: Initialize Intel 8080 bus[1B][0m
[1B][0;32mI (411) LVGL_SETUP: Install LCD driver of st7789[1B][0m
[1B][0;32mI (411) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (541) LVGL_SETUP: Initializing I2C for display touch[1B][0m
[1B][0;32mI (551) LVGL_SETUP: esp_lcd_new_panel_io_i2c[1B][0m
[1B][0;32mI (551) LVGL_SETUP: esp_lcd_touch_new_i2c_cst816s[1B][0m
CUSTON COMPONENT CST816S config 
[1B][0;32mI (551) gpio: GPIO[16]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2 [1B][0m
[1B][0;32mI (561) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;31mE (591) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (591) CST816S: read_id(177): I2C read failed[1B][0m
[1B][0;31mE (591) CST816S: esp_lcd_touch_new_i2c_cst816s(87): Read version failed[1B][0m
[1B][0;32mI (591) gpio: GPIO[16]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (601) gpio: GPIO[21]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;31mE (611) CST816S: Initialization failed![1B][0m
[1B][0;32mI (621) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (631) LVGL_SETUP: Install LVGL tick timer[1B][0m

I dont think the esp_lcd_touch_new_i2c_cst816s pulls the RES pin high hence it does not work. I can try put a scope on that pin if I can

@krupis
Copy link
Author

krupis commented Jun 13, 2023

@Lzw655
Il do a scope measurement tommorow. In the meantine, can you try with your custom CST816 device to see if yours is working?

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 13, 2023

@Lzw655 Il do a scope measurement tommorow. In the meantine, can you try with your custom CST816 device to see if yours is working?

Yeah, of course!

@C-basstien
Copy link

C-basstien commented Jun 13, 2023

I managed to make it work. The issue is related to reset / init timing of the CST816 component.
I saw that in arduino touchlib the reset setup hold and release timing setting was 200 ms.
Maybe 200ms is quite and can be set down, but one has to experiment this since there is not reset timing info in the CST816 datasheet (https://www.buydisplay.com/download/ic/DS-CST816S_DS_V1.3.pdf)
Here is the trick:

static esp_err_t reset(esp_lcd_touch_handle_t tp)
{
    if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
        ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
        vTaskDelay(pdMS_TO_TICKS(200));
        ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
        vTaskDelay(pdMS_TO_TICKS(200));
    }

    return ESP_OK;
}

Do not forget to configure an interrupt callback in the esp_lcd_touch_config_t structure and it should work.
Let me know, if it is working on your side too.

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

Nice work! I'll fix it according to your code.

Lzw655 added a commit to Lzw655/esp-bsp that referenced this issue Jun 14, 2023
@krupis
Copy link
Author

krupis commented Jun 14, 2023

Nice work! I'll fix it according to your code.

I am glad you guys have managed to find a fix but I still cannot get the touch to work properly (perhaps this time it is no longer the driver issue but my code issue?)

After making a modification :

static esp_err_t reset(esp_lcd_touch_handle_t tp)
{
    if (tp->config.rst_gpio_num != GPIO_NUM_NC) {
        ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, tp->config.levels.reset), TAG, "GPIO set level failed");
        vTaskDelay(pdMS_TO_TICKS(200));
        ESP_RETURN_ON_ERROR(gpio_set_level(tp->config.rst_gpio_num, !tp->config.levels.reset), TAG, "GPIO set level failed");
        vTaskDelay(pdMS_TO_TICKS(200));
    }

    return ESP_OK;
}

In my custom esl_lcd_touch_cst816s.c component (I cloned it from the managed component to make changes).
I was able to build the code without any issues with the following code commented out:

     gpio_config_t touch_gpio_config =
         {
             .mode = GPIO_MODE_OUTPUT,
             .pin_bit_mask = 1ULL << PIN_TOUCH_RES};
     ESP_ERROR_CHECK(gpio_config(&touch_gpio_config));
     gpio_set_level(PIN_TOUCH_RES, 1);

and using the following esp_lcd_touch_config_t: (Not sure why it does not work if I set .reset = 1. I must use .reset = 0.)

        esp_lcd_touch_config_t tp_cfg = {
        .x_max = 320,
        .y_max = 170,
        .rst_gpio_num = 21,
        .int_gpio_num = 16,
        .levels = {
            .reset = 0,
            .interrupt = 0,
        },
        .flags = {
            .swap_xy = 0,
            .mirror_x = 0,
            .mirror_y = 0,
        },
    };

I have then added the following callback:

static void example_lvgl_touch_cb(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
    uint16_t touchpad_x[1] = {0};
    uint16_t touchpad_y[1] = {0};
    uint8_t touchpad_cnt = 0;
    /* Read touch controller data */
    esp_lcd_touch_read_data(drv->user_data);

    /* Get coordinates */
    bool touchpad_pressed = esp_lcd_touch_get_coordinates(drv->user_data, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);

    if (touchpad_pressed && touchpad_cnt > 0) {
        data->point.x = touchpad_x[0];
        data->point.y = touchpad_y[0];
        data->state = LV_INDEV_STATE_PRESSED;
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}

and the following functions at the bottom of my lvgl_setup:

    static lv_indev_drv_t indev_drv;    // Input device driver (Touch)
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.disp = disp;
    indev_drv.read_cb = example_lvgl_touch_cb;
    indev_drv.user_data = tp;
    lv_indev_drv_register(&indev_drv);

The result:

[1B][0;32mI (122) esp_image: segment 3: paddr=00030020 vaddr=4200000m
[1B][0;32mI (235) cpu_start: Compile time:     Jun 13 2023 12:16:03[1B][0m
[1B][0;32mI (241) cpu_start: ELF file SHA256:  ed8ab6f2674b1c7a...[1B][0m
[1B][0;32mI (247) cpu_start: ESP-IDF:          v5.0.1-dirty[1B][0m
[1B][0;32mI (252) cpu_start: Min chip rev:     v0.0[1B][0m
[1B][0;32mI (257) cpu_start: Max chip rev:     v0.99 [1B][0m
[1B][0;32mI (262) cpu_start: Chip rev:         v0.1[1B][0m
[1B][0;32mI (266) heap_init: Initializing. RAM available for dynamic allocation:[1B][0m
[1B][0;32mI (274) heap_init: At 3FC967B8 len 00052F58 (331 KiB): D/IRAM[1B][0m
[1B][0;32mI (280) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM[1B][0m
[1B][0;32mI (287) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM[1B][0m
[1B][0;32mI (293) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM[1B][0m
[1B][0;32mI (300) spi_flash: detected chip: winbond[1B][0m
[1B][0;32mI (304) spi_flash: flash io: dio[1B][0m
[1B][0;33mW (308) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.[1B][0m
[1B][0;32mI (322) cpu_start: Starting scheduler on PRO CPU.[1B][0m
[1B][0;32mI (0) cpu_start: Starting scheduler on APP CPU.[1B][0m
This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision v0.1, 2MB external flash
Minimum free heap size: 379292 bytes
[1B][0;32mI (383) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (393) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (393) gpio: GPIO[38]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (403) LVGL_SETUP: Initialize Intel 8080 bus[1B][0m
[1B][0;32mI (413) LVGL_SETUP: Install LCD driver of st7789[1B][0m
[1B][0;32mI (413) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (543) LVGL_SETUP: Initializing I2C for display touch[1B][0m
[1B][0;32mI (553) LVGL_SETUP: esp_lcd_new_panel_io_i2c[1B][0m
[1B][0;32mI (553) LVGL_SETUP: esp_lcd_touch_new_i2c_cst816s[1B][0m
[1B][0;32mI (553) gpio: GPIO[16]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2 [1B][0m
[1B][0;32mI (563) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (973) CST816S: IC id: 181[1B][0m
[1B][0;32mI (973) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (973) LVGL_SETUP: Install LVGL tick timer[1B][0m
[1B][0;31mE (1313) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1313) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1343) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1343) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1373) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1373) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1403) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1403) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1433) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1433) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1463) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1463) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1493) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1493) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1523) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1523) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1553) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1553) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1583) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1583) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1613) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1613) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1643) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1643) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1673) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1673) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1703) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1703) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1733) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1733) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1763) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1763) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1793) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1793) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1823) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m

I have updated my repository if you would like to view the full source code as usual.

@C-basstien
Mentioned that I may need to configure interrupt callback in esp_lcd_touch_config_t but in the i80_controller esp-idf example they do not do that. They just use:

    static lv_indev_drv_t indev_drv;    // Input device driver (Touch)
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.disp = disp;
    indev_drv.read_cb = example_lvgl_touch_cb;
    indev_drv.user_data = tp;
    lv_indev_drv_register(&indev_drv);

Is configuring callback in esp_lcd_touch_config_t required for cst816?

@krupis
Copy link
Author

krupis commented Jun 14, 2023

UPDATE

So it turns out the touch funcionality actually works. I have added a debug printf statement inside touch callback:

    if (touchpad_pressed && touchpad_cnt > 0) {
        data->point.x = touchpad_x[0];
        data->point.y = touchpad_y[0];
        data->state = LV_INDEV_STATE_PRESSED;
        printf("data->point.x = %u \n",data->point.x);
        printf("data->point.y = %u \n",data->point.y);
    }

and when I click on the display, the callback executes and prints the coordinates.
However, I cant stop the

[1B][0;31mE (1700) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1700) CST816S: read_data(115): I2C read failed[1B][0m

logs from popping up.

[1B][0;32mI (105) esp_image: segment 1: paddr=000215a4 vaddr=3fc934[1B][0;32mI (183) esp_image: segment 4: paddr=0007f2bc vaddr=40380634 size=02d6ch ( 11628) load[1B][0m
[1B][0;32mI (192) boot: Loaded app from partition at offset 0x10000[1B][0m
[1B][0;32mI (192) boot: Disabling RNG early entropy source...[1B][0m
[1B][0;32mI (203) cpu_start: Pro cpu up.[1B][0m
[1B][0;32mI (203) cpu_start: Starting app cpu, entry point is 0x403753cc[1B][0m
[1B][0;32mI (0) cpu_start: App cpu up.[1B][0m
[1B][0;32mI (218) cpu_start: Pro cpu start user code[1B][0m
[1B][0;32mI (218) cpu_start: cpu freq: 160000000 Hz[1B][0m
[1B][0;32mI (218) cpu_start: Application information:[1B][0m
[1B][0;32mI (221) cpu_start: Project name:     i80_controller[1B][0m
[1B][0;32mI (227) cpu_start: App version:      21d1c86-dirty[1B][0m
[1B][0;32mI (232) cpu_start: Compile time:     Jun 14 2023 07:57:57[1B][0m
[1B][0;32mI (238) cpu_start: ELF file SHA256:  70ff9de2385d389f...[1B][0m
[1B][0;32mI (244) cpu_start: ESP-IDF:          v5.0.1-dirty[1B][0m
[1B][0;32mI (249) cpu_start: Min chip rev:     v0.0[1B][0m
[1B][0;32mI (254) cpu_start: Max chip rev:     v0.99 [1B][0m
[1B][0;32mI (259) cpu_start: Chip rev:         v0.1[1B][0m
[1B][0;32mI (264) heap_init: Initializing. RAM available for dynamic allocation:[1B][0m
[1B][0;32mI (271) heap_init: At 3FC967B8 len 00052F58 (331 KiB): D/IRAM[1B][0m
[1B][0;32mI (277) heap_init: At 3FCE9710 len 00005724 (21 KiB): STACK/DRAM[1B][0m
[1B][0;32mI (284) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM[1B][0m
[1B][0;32mI (290) heap_init: At 600FE010 len 00001FF0 (7 KiB): RTCRAM[1B][0m
[1B][0;32mI (297) spi_flash: detected chip: winbond[1B][0m
[1B][0;32mI (301) spi_flash: flash io: dio[1B][0m
[1B][0;33mW (305) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.[1B][0m
[1B][0;32mI (319) cpu_start: Starting scheduler on PRO CPU.[1B][0m
[1B][0;32mI (0) cpu_start: Starting scheduler on APP CPU.[1B][0m
This is esp32s3 chip with 2 CPU core(s), WiFi/BLE, silicon revision v0.1, 2MB external flash
Minimum free heap size: 379292 bytes
[1B][0;32mI (380) gpio: GPIO[15]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (390) gpio: GPIO[9]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (390) gpio: GPIO[38]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (400) LVGL_SETUP: Initialize Intel 8080 bus[1B][0m
[1B][0;32mI (410) LVGL_SETUP: Install LCD driver of st7789[1B][0m
[1B][0;32mI (410) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (540) LVGL_SETUP: Initializing I2C for display touch[1B][0m
[1B][0;32mI (550) LVGL_SETUP: esp_lcd_new_panel_io_i2c[1B][0m
[1B][0;32mI (550) LVGL_SETUP: esp_lcd_touch_new_i2c_cst816s[1B][0m
[1B][0;32mI (550) gpio: GPIO[16]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:2 [1B][0m
[1B][0;32mI (560) gpio: GPIO[21]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 [1B][0m
[1B][0;32mI (970) CST816S: IC id: 181[1B][0m
[1B][0;32mI (970) LVGL_SETUP: Register display driver to LVGL[1B][0m
[1B][0;32mI (970) LVGL_SETUP: Install LVGL tick timer[1B][0m
[1B][0;31mE (1310) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1310) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1340) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1340) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1370) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1370) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1400) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1400) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1430) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1430) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1460) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1460) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1490) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1490) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1520) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1520) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1550) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1550) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1580) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1580) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1610) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1610) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1640) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1640) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1670) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1670) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1700) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1700) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1730) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1730) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1760) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1760) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1790) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1790) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1820) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1820) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1850) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1850) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1880) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1880) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1910) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1910) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1940) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1940) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (1970) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (1970) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (2000) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (2000) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (2030) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (2030) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (2060) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (2060) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (2090) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (2090) CST816S: read_data(115): I2C read failed[1B][0m
data->point.x = 67 
data->point.y = 229 
data->point.x = 67 
data->point.y = 229 
data->point.x = 67 
data->point.y = 229 
data->point.x = 67 
data->point.y = 229 
data->point.x = 56 
data->point.y = 215 
data->point.x = 56 
data->point.y = 215 
data->point.x = 56 
data->point.y = 215 
data->point.x = 56 
data->point.y = 215 
[1B][0;31mE (5270) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5270) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5300) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5300) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5330) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5330) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5360) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5360) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5390) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5390) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5420) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5420) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5450) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5450) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5480) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5480) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5510) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5510) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5540) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5540) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5570) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5570) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5600) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5600) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5630) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5630) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5660) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5660) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5690) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5690) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5720) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5720) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5750) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m
[1B][0;31mE (5750) CST816S: read_data(115): I2C read failed[1B][0m
[1B][0;31mE (5780) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

@krupis Oh, I get the same error logs as below. But the touch function works well, I can control my screen correctly. Can't you?

[1B][0;31mE (1793) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1823) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m

I think the error reason maybe is caused by the work mode (datasheet Page Four) of CST816. And its I2C can't work when not in dynamic mode.

And I find a doc that also mentions that.
image

So we should call esp_lcd_touch_get_coordinates() when get a signal through interrupt callback.

@krupis
Copy link
Author

krupis commented Jun 14, 2023

@krupis Oh, I get the same error logs as below. But the touch function works well, I can control my screen correctly. Can't you?

[1B][0;31mE (1793) CST816S: read_data(112): I2C read failed[1B][0m
[1B][0;31mE (1823) lcd_panel.io.i2c: panel_io_i2c_rx_buffer(135): i2c transaction failed[1B][0m

I think the error reason maybe is caused by the work mode (datasheet Page Four) of CST816. And its I2C can't work when not in dynamic mode.

And I find a doc that also enhances that. image

So we should call esp_lcd_touch_get_coordinates() when get a signal through interrupt callback.

Yeah I just figured out that the touch callback actually works but its constantly printing those i2c error messages. I have made an update at the same time you wrote your response :)

Would you be able to show how to properly handle it in this case (only calling the get_coordinates upon the interrupt)?

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

Yeah, let me try.

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

Good news, I finish it. You can refer to the following steps (code):

First, use a mutex for touch and create it before init touch:

static SemaphoreHandle_t touch_mux;                 // Touch mutex

touch_mux = xSemaphoreCreateBinary();

Then, create a callback which used to send mutex and install it:

static void touch_callback(esp_lcd_touch_handle_t tp)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(touch_mux, &xHigherPriorityTaskWoken);

    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR();
    }
}

const esp_lcd_touch_config_t tp_cfg = {
       ...
    .interrupt_callback = touch_callback,
};

Finally, take mutex before read_data:

static void bsp_touchpad_read(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
    esp_lcd_touch_handle_t tp = (esp_lcd_touch_handle_t) indev_drv->user_data;
    uint16_t touchpad_x[1] = {0};
    uint16_t touchpad_y[1] = {0};
    uint8_t touchpad_cnt = 0;

    assert(tp);

    /* Read data from touch controller into memory */
    if (xSemaphoreTake(touch_mux, 0) == pdTRUE) {
        esp_lcd_touch_read_data(tp);
    }

    /* Read data from touch controller */
    bool touchpad_pressed = esp_lcd_touch_get_coordinates(tp, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);

    if (touchpad_pressed && touchpad_cnt > 0) {
        data->point.x = touchpad_x[0];
        data->point.y = touchpad_y[0];
        data->state = LV_INDEV_STATE_PRESSED;
    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

You can refer to this file or just simply replace them with ESP_ERROR_CHECK() or assert().

@C-basstien
Copy link

Hi,
the indev_drv->read_cb (here bsp_touchpad_read) is never called on my side, how is it supposed to be triggered by an lvgl timer or manually with an example ? I am polling the indev_drv->read_cb upon a timer, but I am not sure it is the intended way to do it. Could you provide me an example ?

@krupis
Copy link
Author

krupis commented Jun 14, 2023

@Lzw655
Thank you very much, what a legend you are!

I have got it to work. The updated code for the Lilygo T-3 Display is on my repository.

Just one quick question:

Whenever I want to draw a widget, do I need to call bsp_display_lock(0); and after I finished drawing bsp_display_unlock();
Is that how it supposed to be?

@krupis
Copy link
Author

krupis commented Jun 14, 2023

@C-basstien Try my example code, perhaps that will help. It seems to be working on my side. The lvgl meter widget is displayed and I can touch the screen and get the coordinates.

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

Whenever I want to draw a widget, do I need to call bsp_display_lock(0); and after I finished drawing bsp_display_unlock(); Is that how it supposed to be?

@krupis In any function that is not processed by the LVGL task (which runs lv_timer_handler()). And you shouldn't call them in LVGL's event or timer callback.

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

Hi, the indev_drv->read_cb (here bsp_touchpad_read) is never called on my side, how is it supposed to be triggered by an lvgl timer or manually with an example ? I am polling the indev_drv->read_cb upon a timer, but I am not sure it is the intended way to do it. Could you provide me an example ?

Are you using esp_lvgl_port component?

@krupis
Copy link
Author

krupis commented Jun 14, 2023

@Lzw655
Thanks, sounds good. Glad we got it working in the end. It was a tough one 👍
I am sure this will be very helpful for other people as well! I know at least a couple of people who struggled with Lilygo CST816 touch on the esp-idf

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

@Lzw655 Thanks, sounds good. Glad we got it working in the end. It was a tough one 👍 I am sure this will be very helpful for other people as well! I know at least a couple of people who struggled with Lilygo CST816 touch on the esp-idf

Yeah, thank you for helping us to test it!

@krupis
Copy link
Author

krupis commented Jun 14, 2023

Should I close this issue for the time being and reopen it if having any other issues with the CST816S touch?

@Lzw655
Copy link
Collaborator

Lzw655 commented Jun 14, 2023

Should I close this issue for the time being and reopen it if having any other issues with the CST816S touch?

Not necessary. It'll be closed when this PR is merged.

@krupis
Copy link
Author

krupis commented Aug 11, 2023

@Lzw655

Hello. I know this issue has been completed but I have been coming back to it and it haunts me. I hope you can clarify to me.

Its been a while but you have helped me solve the issue with the touch callback.

Current solution is as following: (pseudocode)


SemaphoreHandle_t touch_mux;                 // Touch mutex

esp_lcd_touch_config_t tp_cfg = {
            .x_max = 320,
            .y_max = 170,
            .rst_gpio_num = 21,
            .int_gpio_num = 16,
            .levels = {
                .reset = 0,
                .interrupt = 0,
            },
            .flags = {
                .swap_xy = 1,
                .mirror_x = 0,
                .mirror_y = 0,
            },
            .interrupt_callback = touch_callback,
        };



        static lv_indev_drv_t indev_drv;    // Input device driver (Touch)
        lv_indev_t *indev_touchpad;
        lv_indev_drv_init(&indev_drv);
        indev_drv.type = LV_INDEV_TYPE_POINTER;
        indev_drv.disp = disp;
        indev_drv.read_cb = bsp_touchpad_read;
        indev_drv.user_data = tp;
        indev_touchpad = lv_indev_drv_register(&indev_drv);
        BSP_NULL_CHECK(indev_touchpad, ESP_ERR_NO_MEM);



static void bsp_touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
    uint16_t touchpad_x[1] = {0};
    uint16_t touchpad_y[1] = {0};
    uint8_t touchpad_cnt = 0;
    /* Read data from touch controller into memory */
    if (xSemaphoreTake(touch_mux, 0) == pdTRUE) {
        esp_lcd_touch_read_data(drv->user_data);
    }
    /* Get coordinates */
    bool touchpad_pressed = esp_lcd_touch_get_coordinates(drv->user_data, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
    if (touchpad_pressed && touchpad_cnt > 0) {
        data->point.x = touchpad_x[0];
        data->point.y = touchpad_y[0];
        data->state = LV_INDEV_STATE_PRESSED;
        printf("data->point.x = %u \n",data->point.x);
        printf("data->point.y = %u \n",data->point.y);

    } else {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}

static void touch_callback(esp_lcd_touch_handle_t tp)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(touch_mux, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken) {
        portYIELD_FROM_ISR();
    }
}

Question1

As you can see from above, in lv_indev_drv_t we create callback bsp_touchpad_read.
I cannot wrap my head around what is the reason of using touch_callback in esp_lcd_touch_config_t . Why can't we not do anything in bsp_touchpad_read?

Question2

Lets say I have connected an I2C sensor to the same I2C bus that I2C touch and its collecting data in a seperate FreeRTOS task.
How can I ensure that my sensor does not collect data at the same time the touch is triggered. Do I need to wrap touch_mux in another semaphore called i2c_mux ?

@Lzw655
Copy link
Collaborator

Lzw655 commented Aug 11, 2023

Hi @krupis , hope the answers can be helpful.

Answer 1

LVGL will periodically call touch_callback in esp_lcd_touch_config_t to obtain the state and coordinates of a touch point. We need to update the lv_indev_data_t * data in this function.

Answer 2

Yes, you need to perform synchronization, and using the same semaphore is the correct approach.

@krupis
Copy link
Author

krupis commented Aug 11, 2023

@Lzw655

Thanks for a quick response

Regarding Question1:
but indev_drv.read_cb = bsp_touchpad_read; Ensures that bsp_touchpad_read is called immediatelly when touch is detected. Why cannot update lv_indev_data_t * data directly in bsp_touchpad_read and why use touch_callback at all?

Regarding Question2:
I dont really understand how would that be possible with the current logic. The semaphore is taken in bsp_touchpad_read. and only released after touch event. That means that no one else can take this semaphore.

Could you provide some pseudo code how could I synchronize it using the same semaphore touch_mux.

My I2C sensor function that I use:


float ADS7828_Read_Current(enum ADS7828_channel_e channel,uint8_t device_address,uint8_t coeff){
        //need to implement semaphore here
	uint16_t read_adc = I2C_read_ads7828(channel,device_address);
	return read_adc ;
}

@Lzw655
Copy link
Collaborator

Lzw655 commented Aug 12, 2023

@krupis

  1. As we talked before, the CST816S needs to wait for the interrupt signal to arrive before it can read the coordinates. This signal can be obtained through the touch_callback() function.

  2. I'm sorry, I misunderstood your intention. The touch_mux can only be used to obtain the interrupt signal from the CST816S. You need to create another semaphore called i2c_mux to synchronize the operations of devices on the same I2C bus. Like below:

SemaphoreHandle_t i2c_mux;               

static void bsp_touchpad_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
    uint16_t touchpad_x[1] = {0};
    uint16_t touchpad_y[1] = {0};
    uint8_t touchpad_cnt = 0;
    /* Read data from touch controller into memory */
    if ((xSemaphoreTake(touch_mux, 0) == pdTRUE) && (xSemaphoreTake(i2c_mux, your_wait_time) == pdTRUE)) {
        esp_lcd_touch_read_data(drv->user_data);
        xSemaphoreGive(i2c_mux);
    }
   ...
}

float ADS7828_Read_Current(enum ADS7828_channel_e channel,uint8_t device_address,uint8_t coeff){
        //need to implement semaphore here
	uint16_t read_adc = 0;
        if (xSemaphoreTake(i2c_mux, your_wait_time) == pdTRUE ) {
                I2C_read_ads7828(channel,device_address);
                xSemaphoreGive(i2c_mux);
        }
	return read_adc ;
}

@krupis
Copy link
Author

krupis commented Aug 12, 2023

@Lzw655
I understood. Thank you very much !

@krupis
Copy link
Author

krupis commented Sep 15, 2023

@Lzw655 Sorry to bring this back again after such a long time. My project was on hold for a while since I had some other urgent projects to develop.

I have tried your suggestion regarding synchronizing multiple I2C devices on the same I2C bus and it does not seem to work as expected.

In my Display component I have the following:


SemaphoreHandle_t i2c_mux;
SemaphoreHandle_t lvgl_mux;  // LVGL mutex
SemaphoreHandle_t touch_mux; // Touch mutex






static void bsp_touchpad_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
{
    uint16_t touchpad_x[1] = {0};
    uint16_t touchpad_y[1] = {0};
    uint8_t touchpad_cnt = 0;
    if ((xSemaphoreTake(touch_mux, 0) == pdTRUE) && (xSemaphoreTake(i2c_mux, 100) == pdTRUE)) {
        esp_lcd_touch_read_data(drv->user_data);
        xSemaphoreGive(i2c_mux);
    }
    /* Get coordinates */
    bool touchpad_pressed = esp_lcd_touch_get_coordinates(drv->user_data, touchpad_x, touchpad_y, NULL, &touchpad_cnt, 1);
    if (touchpad_pressed && touchpad_cnt > 0)
    {
        data->point.x = touchpad_x[0];
        data->point.y = touchpad_y[0];
        data->state = LV_INDEV_STATE_PRESSED;
        printf("data->point.x = %u \n", data->point.x);
        printf("data->point.y = %u \n", data->point.y);
    }
    else
    {
        data->state = LV_INDEV_STATE_RELEASED;
    }
}

static void touch_callback(esp_lcd_touch_handle_t tp)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(touch_mux, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken)
    {
        portYIELD_FROM_ISR();
    }
}



void lvgl_setup()
{

    static lv_disp_draw_buf_t disp_buf; // contains internal graphic buffer(s) called draw buffer(s)
    static lv_disp_drv_t disp_drv;      // contains callback functions

    gpio_config_t pwr_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_POWER};
    ESP_ERROR_CHECK(gpio_config(&pwr_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_POWER, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    gpio_config_t input_conf =
        {
            .mode = GPIO_MODE_INPUT,
            .pull_up_en = GPIO_PULLUP_ENABLE,
            .pin_bit_mask = 1ULL << PIN_LCD_RD};
    ESP_ERROR_CHECK(gpio_config(&input_conf));

    gpio_config_t bk_gpio_config =
        {
            .mode = GPIO_MODE_OUTPUT,
            .pin_bit_mask = 1ULL << EXAMPLE_PIN_NUM_BK_LIGHT};
    ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
    gpio_set_level(EXAMPLE_PIN_NUM_BK_LIGHT, EXAMPLE_LCD_BK_LIGHT_ON_LEVEL);

    ESP_LOGI(TAG, "Initialize Intel 8080 bus");
    esp_lcd_i80_bus_handle_t i80_bus = NULL;
    esp_lcd_i80_bus_config_t bus_config = {
        .clk_src = LCD_CLK_SRC_DEFAULT,
        .dc_gpio_num = EXAMPLE_PIN_NUM_DC,
        .wr_gpio_num = EXAMPLE_PIN_NUM_PCLK,
        .data_gpio_nums = {
            EXAMPLE_PIN_NUM_DATA0,
            EXAMPLE_PIN_NUM_DATA1,
            EXAMPLE_PIN_NUM_DATA2,
            EXAMPLE_PIN_NUM_DATA3,
            EXAMPLE_PIN_NUM_DATA4,
            EXAMPLE_PIN_NUM_DATA5,
            EXAMPLE_PIN_NUM_DATA6,
            EXAMPLE_PIN_NUM_DATA7,
        },
        .bus_width = 8,
        .max_transfer_bytes = LVGL_LCD_BUF_SIZE * sizeof(uint16_t)
        //.psram_trans_align = EXAMPLE_PSRAM_DATA_ALIGNMENT,
        //.sram_trans_align = 4,
    };
    ESP_ERROR_CHECK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
    esp_lcd_panel_io_handle_t io_handle = NULL;
    esp_lcd_panel_io_i80_config_t io_config = {
        .cs_gpio_num = EXAMPLE_PIN_NUM_CS,
        .pclk_hz = EXAMPLE_LCD_PIXEL_CLOCK_HZ,
        .trans_queue_depth = 20,
        .dc_levels = {
            .dc_idle_level = 0,
            .dc_cmd_level = 0,
            .dc_dummy_level = 0,
            .dc_data_level = 1,
        },

        .on_color_trans_done = example_notify_lvgl_flush_ready,
        .user_ctx = &disp_drv,
        .lcd_cmd_bits = EXAMPLE_LCD_CMD_BITS,
        .lcd_param_bits = EXAMPLE_LCD_PARAM_BITS,
    };
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80(i80_bus, &io_config, &io_handle));

    esp_lcd_panel_handle_t panel_handle = NULL;

    ESP_LOGI(TAG, "Install LCD driver of st7789");
    esp_lcd_panel_dev_config_t panel_config = {
        .reset_gpio_num = EXAMPLE_PIN_NUM_RST,
        .rgb_endian = ESP_LCD_COLOR_SPACE_RGB,
        .bits_per_pixel = 16,
    };
    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, true);
    esp_lcd_panel_swap_xy(panel_handle, true);
    esp_lcd_panel_mirror(panel_handle, false, true);
    // the gap is LCD panel specific, even panels with the same driver IC, can have different gap value
    esp_lcd_panel_set_gap(panel_handle, 0, 35);

    esp_lcd_panel_io_tx_param(io_handle, 0xF2, (uint8_t[]){0}, 1); // 3Gamma function disable
    esp_lcd_panel_io_tx_param(io_handle, 0x26, (uint8_t[]){1}, 1); // Gamma curve 1 selected
    esp_lcd_panel_io_tx_param(io_handle, 0xE0, (uint8_t[]){        // Set positive gamma
                                                           0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00},
                              15);
    esp_lcd_panel_io_tx_param(io_handle, 0xE1, (uint8_t[]){// Set negative gamma
                                                           0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F},
                              15);

    ESP_ERROR_CHECK(esp_lcd_panel_disp_on_off(panel_handle, true));

// CST816 TOUCH TESTING FUNCTION
#if USE_TOUCH_DISPLAY
    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;

    i2c_config_t i2c_conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = EXAMPLE_I2C_SDA,
        .scl_io_num = EXAMPLE_I2C_SCL,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = 400000,
    };
    ESP_LOGI(TAG, "Initializing I2C for display touch");
    /* Initialize I2C */
    ESP_ERROR_CHECK(i2c_param_config(EXAMPLE_I2C_NUM, &i2c_conf));
    ESP_ERROR_CHECK(i2c_driver_install(EXAMPLE_I2C_NUM, i2c_conf.mode, 0, 0, 0));

    i2c_cmd_handle_t cmd;
    for (int i = 0; i < 0x7f; i++)
    {
        cmd = i2c_cmd_link_create();
        i2c_master_start(cmd);
        i2c_master_write_byte(cmd, (i << 1) | I2C_MASTER_WRITE, true);
        i2c_master_stop(cmd);
        if (i2c_master_cmd_begin(EXAMPLE_I2C_NUM, cmd, portMAX_DELAY) == ESP_OK)
        {
            ESP_LOGW("I2C_TEST", "%02X", i);
        }
        i2c_cmd_link_delete(cmd);
    }

    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();

    ESP_LOGI(TAG, "esp_lcd_new_panel_io_i2c");
    ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)EXAMPLE_I2C_NUM, &tp_io_config, &tp_io_handle));

    // if display is rotated 270 degrees
         esp_lcd_touch_config_t tp_cfg = {
         .x_max = 170,
         .y_max = 320,
         .rst_gpio_num = 21,
         .int_gpio_num = 16,
         .levels = {
             .reset = 0,
             .interrupt = 0,
         },
         .flags = {
             .swap_xy = 1,
             .mirror_x = 0,
             .mirror_y = 1,
         },
         .interrupt_callback = touch_callback,
     };

    // esp_lcd_touch_config_t tp_cfg = {
    //     .x_max = 170,
    //     .y_max = 320,
    //     .rst_gpio_num = 21,
    //     .int_gpio_num = 16,
    //     .levels = {
    //         .reset = 0,
    //         .interrupt = 0,
    //     },
    //     .flags = {
    //         .swap_xy = 1,
    //         .mirror_x = 0,
    //         .mirror_y = 1,
    //     },
    //     .interrupt_callback = touch_callback,
    // };

    ESP_LOGI(TAG, "esp_lcd_touch_new_i2c_cst816s");
    esp_lcd_touch_new_i2c_cst816s(tp_io_handle, &tp_cfg, &tp);
#endif

    // END OF CST816 TOUCH TESTING FUNCTION

    lv_init();

    lvgl_mux = xSemaphoreCreateMutex();
    BSP_NULL_CHECK(lvgl_mux, NULL);

    touch_mux = xSemaphoreCreateBinary();
    BSP_NULL_CHECK(touch_mux, NULL);

    i2c_mux = xSemaphoreCreateMutex();
    BSP_NULL_CHECK(i2c_mux, NULL);

    // it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized
    lv_color_t *buf1 = heap_caps_malloc(LVGL_LCD_BUF_SIZE * sizeof(lv_color_t), MALLOC_CAP_DMA);
    assert(buf1);
    lv_disp_draw_buf_init(&disp_buf, buf1, NULL, LVGL_LCD_BUF_SIZE);

    ESP_LOGI(TAG, "Register display driver to LVGL");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = EXAMPLE_LCD_H_RES;
    disp_drv.ver_res = EXAMPLE_LCD_V_RES;
    disp_drv.flush_cb = example_lvgl_flush_cb;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.user_data = panel_handle;
    disp_drv.sw_rotate = 1;
    lv_disp_t *disp = lv_disp_drv_register(&disp_drv);

    ESP_LOGI(TAG, "Install LVGL 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 = &example_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, EXAMPLE_LVGL_TICK_PERIOD_MS * 1000));

#if USE_TOUCH_DISPLAY
    static lv_indev_drv_t indev_drv; // Input device driver (Touch)
    lv_indev_t *indev_touchpad;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.disp = disp;
    indev_drv.read_cb = bsp_touchpad_read;
    indev_drv.user_data = tp;
    indev_touchpad = lv_indev_drv_register(&indev_drv);
    BSP_NULL_CHECK(indev_touchpad, ESP_ERR_NO_MEM);
#endif

    xTaskCreatePinnedToCore(lvgl_timer_task, "lvgl Timer", 10000, NULL, 4, NULL, 1);
}

and in my other I2C temperature/humidity sensor I do the following:


extern SemaphoreHandle_t touch_mux; 
extern SemaphoreHandle_t i2c_mux;



esp_err_t Measure_temp_humidity(uint8_t precision)
{
    uint8_t read_buffer[6];
    uint8_t write_command[1] = {precision};
    esp_err_t err;
    err = i2c_master_write_to_device(I2C_MASTER_NUM, SHT40_SENSOR_ADDR, &write_command, 1, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    if (err != ESP_OK)
    {
        printf("Error in writing to SHT40 device \n");
        return err;
    }
    vTaskDelay(20 / portTICK_PERIOD_MS);

    err = i2c_master_read_from_device(I2C_MASTER_NUM, SHT40_SENSOR_ADDR, &read_buffer, 6, I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS);
    if (err != ESP_OK)
    {
        printf("Error in reading from SHT40 device \n");
        return err;
    }

    float t_ticks = read_buffer[0] * 256 + read_buffer[1];
    float rh_ticks = read_buffer[3] * 256 + read_buffer[4];

    float t_degC = -45 + 175 * t_ticks / 65535;
    float rh_pRH = -6 + 125 * rh_ticks / 65535;
    printf("temperature = %.2f \n", t_degC);
    printf("humidity = %.2f \n", rh_pRH);

    return ESP_OK;
}


//SHT40_task is a free rtos task that is being created in my main.c.
void SHT40_task(void *argument)
{
    for (;;)
    {
        if ((xSemaphoreTake(touch_mux, 0) == pdTRUE) && (xSemaphoreTake(i2c_mux, 100) == pdTRUE))
        {
            Measure_temp_humidity(SHT40_TEMP_HUMID_REG_HIGH_PREC);
            xSemaphoreGive(i2c_mux);
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

As you can see from the SHT40_task, it should capture temperature and humidity readings every 100ms.

I think the issue lies somewhere within touch_mux. Instead of taking a temperature reading every 100ms, it only captures a temperature/humidity reading every time I touch on the display. See the logs below:

2023/09/15 08:27:21: data->point.x = 217 
data->point.y = 35 
data->point.x = 217 
data->point.y = 35 
temperature = 26.43 
humidity = 45.33 
2023/09/15 08:27:23: data->point.x = 155 
data->point.y = 114 
data->point.x = 155 
data->point.y = 114 
temperature = 26.42 
humidity = 44.88 
2023/09/15 08:27:27: data->point.x = 166 
data->point.y = 97 
data->point.x = 166 
data->point.y = 97 
temperature = 26.40 
humidity = 43.70 

Perhaps you have any ideas why that might happen and how to overcome this to ensure proper synchronization between multiple I2C devices? I really appreciate your help!

My guess is that touch_mux is only given in touch_callback (whenever the touch is detected)

static void touch_callback(esp_lcd_touch_handle_t tp)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(touch_mux, &xHigherPriorityTaskWoken);
    if (xHigherPriorityTaskWoken)
    {
        portYIELD_FROM_ISR();
    }
}

Since it is only given when touch is detected, in SHT40_task the condition:

if ((xSemaphoreTake(touch_mux, 0) == pdTRUE) && (xSemaphoreTake(i2c_mux, 100) == pdTRUE))

is never going to be true because we cannot take the touch_mux semaphore unless it is given

@Lzw655
Copy link
Collaborator

Lzw655 commented Sep 18, 2023

@krupis Yeah, your guess is right. The touch_mux shouldn't be taken in SHT40_task(). And your SHT40_task() should like below:

//SHT40_task is a free rtos task that is being created in my main.c.
void SHT40_task(void *argument)
{
    for (;;)
    {
        if (xSemaphoreTake(i2c_mux, 100) == pdTRUE)
        {
            Measure_temp_humidity(SHT40_TEMP_HUMID_REG_HIGH_PREC);
            xSemaphoreGive(i2c_mux);
        }
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }
}

@tao-a-man
Copy link

hii @Lzw655 I have same issue like picture bellow, Help me plss , I config like
#define LCD_TOUCH_SDA 18 #define LCD_TOUCH_SCL 17 #define LCD_TOUCH_RST 21 #define LCD_TOUCH_INT 16 #define LCD_TOUCH_I2C_CLK_SPEED_HZ 400000 #define LCD_TOUCH_I2C_NUM 0....
`ESP_ERROR_CHECK(i2c_param_config(LCD_TOUCH_I2C_NUM, &i2c_conf));
ESP_ERROR_CHECK(i2c_driver_install(LCD_TOUCH_I2C_NUM, i2c_conf.mode, 0, 0, 0));

esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_CST816S_CONFIG();
ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)LCD_TOUCH_I2C_NUM, &io_config, &io_handle));`

Screenshot 2024-01-19 103211

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants