欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

使用 ESP32S3+LVGL+GT911+ILI9488 进行屏幕反转设置

最编程 2024-03-20 19:03:10
...

环境条件:VScode + IDF4.4.3
硬件:ESP32S3
LCD:ili9488 320*480TFT
Touch:GT911 驱动

驱动程序使用了 espressif__esp_lcd_touch 和 espressif__esp_lcd_touch_gt911 的集成驱动,又在这个驱动的上层增加了 一个板级驱动程序用于初始化和加载LVGL。
bsp_touch.c 的源文件如下:


//-------------------------------------------------------------
//-初始化I2C端口
//-------------------------------------------------------------
void init_i2c(void)
{
    ESP_LOGI(TAGA, "Initialize I2C");

    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,
    };
    /* 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));
}


//-------------------------------------------------------------
//- 触摸芯片回调函数 读取触摸位置和按键状态
//-------------------------------------------------------------
#if CONFIG_EXAMPLE_LCD_TOUCH_ENABLED
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;
    }
}

//-------------------------------------------------------------
//-初始化触摸芯片
//-------------------------------------------------------------

void init_touch(void)
{
    init_i2c();

    esp_lcd_touch_handle_t tp = NULL;
    esp_lcd_panel_io_handle_t tp_io_handle = NULL;

    esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();

    ESP_LOGI(TAGA, "Initialize touch IC IO (I2C)");

    /* Touch IO handle */
    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 = EXAMPLE_LCD_H_RES,
        .y_max = EXAMPLE_LCD_V_RES,
        .rst_gpio_num = -1, //不用的引脚使用-1表示
        .int_gpio_num = -1, //同上
        .flags = {
            .swap_xy = 0,  //xy x旋转 是长宽反转
            .mirror_x = 1, //X是左右反转  0 is normal
            .mirror_y = 1, //Y是上下反转  0 is normal   //20230517 屏幕上下反转时需要对X和Y同时设定为1另外要求将X_max 和 Y_max 
        },
    };
    /* Initialize touch */
    ESP_LOGI(TAGA, "Initialize touch controller GT911");
    ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
    ESP_LOGI(TAGA, "Init touch ic GT911 OK..");

    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);

    ESP_LOGI(TAGA, "LVGL TCP register OK");
}

以上是触摸屏的基本设置参数,与之匹配的LCD显示参数需要修改LCD 的初始化参数。实现整体的反转。
LCD 的驱动采用了ILI9488 在ESP环境中都提供了成套的驱动程序,需要找到LCD的设置参数并对其修改可以实现显示的控制。

void lv_port_disp_init()
{
    /* 申请lvgl渲染缓冲区 */
    lv_color_t *lvgl_draw_buff1 = heap_caps_malloc(LVGL_BUFF_SIZE*sizeof(lv_color_t), MALLOC_CAP_DMA);
    lv_color_t *lvgl_draw_buff2 = heap_caps_malloc(LVGL_BUFF_SIZE*sizeof(lv_color_t), MALLOC_CAP_DMA);
    /* 向lvgl注册缓冲区 */
    static lv_disp_draw_buf_t draw_buf_dsc; //需要全程生命周期,设置为静态变量
    lv_disp_draw_buf_init(&draw_buf_dsc, lvgl_draw_buff1, lvgl_draw_buff2, LVGL_BUFF_SIZE);

    /* 创建并初始化用于在lvgl中注册显示设备的结构 */
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv); //使用默认值初始化该结构
    /* 设置屏幕分辨率 */
    disp_drv.hor_res = LCD_X_PIXELS;
    disp_drv.ver_res = LCD_Y_PIXELS;
    /* 初始化LCD总线 */
    static esp_lcd_panel_io_handle_t panel_io; //需要全程生命周期,设置为静态变量    .max_transfer_bytes = EXAMPLE_LCD_H_RES * EXAMPLE_LCD_V_RES * sizeof(uint16_t)
    panel_io = lcd_i80_bus_io_init(CONFIG_LVGL_LCD_PCLK_FREQ, LVGL_BUFF_SIZE*sizeof(lv_color_t)); //初始化8080并行总线
   // panel_io = lcd_i80_bus_io_init(CONFIG_LVGL_LCD_PCLK_FREQ, 480 * 320 * sizeof(uint16_t)); //初始化8080并行总线
    /* 将总线句柄放入lv_disp_drv_t中用户自定义段 */
    disp_drv.user_data = panel_io;

    /* 初始化寄存器 */
#if defined(CONFIG_LVGL_LCD_PANEL_W350CE024A_40Z)
    lcd_init_reg(panel_io, panel_st7796s_w350ce024a_40z_reg_table);
#elif defined(CONFIG_LVGL_LCD_PANEL_CL35BC1017_40A)
    lcd_init_reg(panel_io, panel_st7796s_cl35bc1017_40a_reg_table);
#elif defined(CONFIG_LVGL_LCD_PANEL_CL35BC106_40A)
    lcd_init_reg(panel_io, panel_ili9488_cl35bc106_40a_reg_table);
    ESP_LOGI(TAG, "Init LCD_panel_ili9488\n");
#endif

    ESP_LOGI(TAG, "lcd clock: %dMHz, mininal fps: %d", CONFIG_LVGL_LCD_PCLK_FREQ,
        CONFIG_LVGL_LCD_PCLK_FREQ*1000000/(LCD_X_PIXELS*LCD_Y_PIXELS));

    /* 设置显示矩形函数,用于将矩形缓冲区刷新到屏幕上 */
    disp_drv.flush_cb = disp_flush;
    /* 设置缓冲区 */
    disp_drv.draw_buf = &draw_buf_dsc;
    /* 注册显示设备 */
    lv_disp_drv_register(&disp_drv);

    /* 开启显示 */
    lcd_disp_switch(panel_io, true);
}

//--------------------------------------------------------------------------
//- ILI9488初始化参数
const lcd_panel_reg_t panel_ili9488_cl35bc106_40a_reg_table[] = {
      { 0x11, NULL, 0 }, //退出休眠模式
    { 0xF7, (uint8_t[]){0xA9, 0x51, 0x2C, 0x82}, 4 },
    { 0xEC, (uint8_t[]){0x00, 0x02, 0x03, 0x7A}, 4 },
    { 0xC0, (uint8_t[]){0x13, 0x13}, 2 },
    { 0xC1, (uint8_t[]){0x41}, 1 },
    { 0xC5, (uint8_t[]){0x00, 0x28, 0x80}, 3 },
    { 0xB1, (uint8_t[]){0xB0, 0x11}, 2 },
    { 0xB4, (uint8_t[]){0x02}, 1 },
    { 0xB6, (uint8_t[]){0x02, 0x22}, 2 },
    { 0xB7, (uint8_t[]){0xC6}, 1 },
    { 0xBE, (uint8_t[]){0x00, 0x04}, 2 },
    { 0xE9, (uint8_t[]){0x00}, 1 },
    { 0xF4, (uint8_t[]){0x00, 0x00, 0x0F}, 3 },
    { 0xE0, (uint8_t[]){0x00, 0x04, 0x0E, 0x08, 0x17, 0x0A, 0x40, 0x79, 0x4D, 0x07, 0x0E, 0x0A, 0x1A, 0x1D, 0x0F}, 16 },
    { 0xE1, (uint8_t[]){0x00, 0x1B, 0x1F, 0x02, 0x10, 0x05, 0x32, 0x34, 0x43, 0x02, 0x0A, 0x09, 0x33, 0x37, 0x0F}, 16 },
    { 0xF4, (uint8_t[]){0x00, 0x00, 0x0F}, 3 },
    { 0x36, (uint8_t[]){0xC8}, 1 }, //0x08  See ili9488 page 192
    { 0x3A, (uint8_t[]){0x55}, 1 },

    { 0, NULL, 0xFF } //寄存器列表结束

};
以上的两个程序是可以配合正常使用的,现在需要对显示屏做180度的旋转,并保持显示正常和触摸正常。

首先修改显示180度旋转,下图中是显示控制寄存器的设置和对应的显示模式:0X36地址:


显示寄存器0x36H.png

实际使用中,不能单独修改MY的设置,需要MX的配合,因此需要将MY和MX都设置为0;
如上面的显示屏初始化参数中只对0X36做修改:

    { 0x36, (uint8_t[]){0x08}, 1 }, //0x08  See ili9488 page 192

修改后,重新编译并烧录后,显示旋转了180度,满足要求。
下面修改触摸屏的旋转,在ESP的库函数中有对x和y的镜像设置,因此不需要对GT911的寄存器做修改,改为修改上层驱动即可,如下面的程序中


    esp_lcd_touch_config_t tp_cfg = {
        .x_max = EXAMPLE_LCD_V_RES,
        .y_max = EXAMPLE_LCD_H_RES,
        .rst_gpio_num = -1, //不用的引脚使用-1表示
        .int_gpio_num = -1, //同上
        .flags = {
            .swap_xy = 0,  //xy x旋转 是长宽反转
            .mirror_x = 0, //X是左右反转  0 is normal
            .mirror_y = 0, //Y是上下反转  0 is normal   //20230517 屏幕上下反转时需要对X和Y同时设定为1另外要求将X_max 和 Y_max 

通过反复试验: 除了修改mirror.x和mirror.y的设置后,同时需要修改.x_max 和 .y_max的值,这样就可以实现对触摸屏的整体旋转180度。

测试通过,留下笔记供今后使用;
该文档未使用lvgl自带的rotation功能,减少rotation功能带来的内存消耗。

推荐阅读