环境条件: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功能带来的内存消耗。