【DigiKey“智造万物,快乐不停”创意大赛】3、使用lv_port_esp32适配1.69寸触摸屏
[复制链接]
本帖最后由 walker2048 于 2023-11-28 12:37 编辑
前言
我们这次使用的屏幕是淘宝上可以买到的IPS液晶屏,带触摸。由于很多小伙伴都想知道如何快速驱动这款屏幕和触摸,就写了这篇文章。
这款屏幕使用的屏幕驱动是st7789v,触摸驱动是CST816D。
一、下载源码并配置st7789屏幕显示
其实LVGL官方是有适配esp32的专用仓库的,虽然也有一年多没更新了,也能用。这个版本使用的是 LVGL 7.9版本,ESP-IDF是4.2版本(我自己电脑上是5.1版本,根据编译错误提示改几个函数就行了)。
1.1 直接使用命令下载源码,下载后获取子仓源码,全部完成后就可以开始配置了。
- git clone --recursive https:
1.2 进入源码目录后,先激活esp-idf环境。加载环境提示如下图
1.3 环境加载成功后,将目标设置成esp32-s3
- idf.py set-target esp32-s3
1.4 设置完毕后,开启配置模式
1.4.1 选择屏幕驱动芯片
从前言的描述可以看到,我们使用的这款触摸屏的屏幕驱动是st7789,所以这里选择st7789
1.4.2 激活反色模式,自定义SPI速度(若不修改SPI速度,默认是20MHz,会有点点卡)
1.4.3 设置屏幕引脚,这里需要配置6个屏幕引脚,其中RST是不会影响屏幕驱动情况的,大部分情况下不设置问题也不大(未设置时需将屏幕RST引脚接电阻到3.3V拉高)。
1.4.4 设置屏幕分辨率,开启颜色转换(就是RGB颜色排序问题,反正开启了颜色就正常了,这里不去讲解原理了,我也不会)
1.4.5 设置屏幕旋转方向。这里选择最后一个(最后跟触摸屏数据要匹配,要么调屏幕,要么改触屏驱动计算方式)
1.4.5 关闭默认demo的自动滑动效果。接下来我们就要移植触屏驱动了,自己滑就行,没必要开这个。
这样改完,直接编译,烧录到设备上,就能看到屏幕亮起来啦。
二、添加触摸屏驱动
添加触摸屏驱动其实没这么复杂,我们可以去抄袭一下成品的Arduino库,通过阅读库源码,可以看出初始化这个触摸屏并不需要折腾什么,上电后给一个复位信号,然后读取设备ID即可。
其实读取设备ID只是方便调试,例如读取不到ID可能是线接错了之类的。然后就可以定期从触摸屏寄存器里读取触摸数据就行了。
[](https://www.arduinolibraries.info/libraries/cst816-s)
按lvgl驱动的风格写好的代码如下:
2.1 添加cst816.h文件(components/lvgl_esp32_drivers/lvgl_touch/cst816.h)
- #ifndef __CST816T_H
- #define __CST816T_H
-
- #include <stdint.h>
- #include <stdbool.h>
- #ifdef LV_LVGL_H_INCLUDE_SIMPLE
- #include "lvgl.h"
- #else
- #include "lvgl/lvgl.h"
- #endif
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- typedef struct {
- bool inited;
- char product_id[1];
- uint16_t max_x_coord;
- uint16_t max_y_coord;
- uint8_t i2c_dev_addr;
- } cst816t_status_t;
-
-
- #define CST816T_ADDR 0X15
- #define CST816T_I2C_SLAVE_ADDR 0x15
-
-
-
- void cst816t_init(uint16_t dev_addr);
- bool cst816t_read(lv_indev_drv_t *drv, lv_indev_data_t *data);
-
- #endif
-
- #ifdef __cplusplus
- }
-
- #endif /* __CST816T_H */
2.2 添加cst816.c文件
- #include "cst816.h"
-
- #include <driver/i2c.h>
- #include <esp_log.h>
- #ifdef LV_LVGL_H_INCLUDE_SIMPLE
- #include <lvgl.h>
- #else
- #include <lvgl/lvgl.h>
- #endif
-
- #include "../lvgl_i2c_conf.h"
- #include "tp_i2c.h"
-
- #define TAG "CST816T"
-
- static cst816t_status_t cst816t_status;
- uint8_t cst816t_read_len(uint16_t reg_addr, uint8_t *data, uint8_t len) {
- uint8_t res = 0;
- res = i2c_master_write_read_device(TOUCH_I2C_PORT, CST816T_ADDR, ®_addr, 1,
- data, len, 1000 / portTICK_PERIOD_MS);
-
- return res;
- }
-
- uint8_t cst816t_chipId(void) { return 0; }
- static esp_err_t cst816t_get_touch_points_num(uint8_t *touch_points_num) {
- uint8_t res = 0;
- res = cst816t_read_len(0x02, touch_points_num, 1);
- return res;
- }
-
- esp_err_t cst816t_read_pos(uint8_t *touch_points_num, uint16_t *x,
- uint16_t *y) {
- uint8_t data[4];
-
- cst816t_get_touch_points_num(touch_points_num);
- if (0 == *touch_points_num) {
- *x = 0;
- *y = 0;
- return 1;
- } else {
- cst816t_read_len(0x03, data, 4);
-
- *x = ((data[0] & 0x0f) << 8) | data[1];
- *y = ((data[2] & 0x0f) << 8) | data[3];
- }
-
- return ESP_OK;
- }
-
- esp_err_t cst816t_i2c_read(uint8_t slave_addr, uint16_t register_addr,
- uint8_t *data_buf, uint8_t len) {
- i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
-
- i2c_master_start(i2c_cmd);
- i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true);
- i2c_master_write_byte(i2c_cmd, register_addr, I2C_MASTER_ACK);
-
- i2c_master_start(i2c_cmd);
- i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_READ, true);
-
- i2c_master_read_byte(i2c_cmd, data_buf, I2C_MASTER_NACK);
- i2c_master_stop(i2c_cmd);
- esp_err_t ret =
- i2c_master_cmd_begin(TOUCH_I2C_PORT, i2c_cmd, 1000 / portTICK_PERIOD_MS);
- i2c_cmd_link_delete(i2c_cmd);
- return ret;
- }
-
- esp_err_t cst816t_i2c_write8(uint8_t slave_addr, uint16_t register_addr,
- uint8_t data) {
- i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
-
- i2c_master_start(i2c_cmd);
- i2c_master_write_byte(i2c_cmd, (slave_addr << 1) | I2C_MASTER_WRITE, true);
- i2c_master_write_byte(i2c_cmd, register_addr, I2C_MASTER_ACK);
-
- i2c_master_start(i2c_cmd);
- i2c_master_write_byte(i2c_cmd, data, true);
-
- i2c_master_stop(i2c_cmd);
- esp_err_t ret =
- i2c_master_cmd_begin(TOUCH_I2C_PORT, i2c_cmd, 1000 / portTICK_PERIOD_MS);
- i2c_cmd_link_delete(i2c_cmd);
- return ret;
- }
-
- void cst816t_init(uint16_t dev_addr) {
- if (!cst816t_status.inited) {
- cst816t_status.i2c_dev_addr = dev_addr;
- uint8_t data_buf[10];
- esp_err_t ret;
-
- ESP_LOGI(TAG, "Checking for CST816T Touch Controller ");
-
- if ((ret = cst816t_i2c_read(dev_addr, 0x15, &data_buf, 1) != ESP_OK)) {
- vTaskDelay(pdMS_TO_TICKS(10));
- ESP_LOGE(TAG, "Error reading from device: %s",
- esp_err_to_name(ret));
-
- }
- if ((ret = cst816t_i2c_read(dev_addr, 0xa7, &data_buf, 1) != ESP_OK)) {
- ESP_LOGE(TAG, "Error reading from device: %s",
- esp_err_to_name(ret));
- ESP_LOGE(TAG, "device ID: %02x", data_buf[0]);
-
- }
-
- cst816t_status.inited = true;
- }
- }
-
- bool cst816t_read(lv_indev_drv_t *drv, lv_indev_data_t *data) {
-
- uint8_t touch_points_num = 0;
- uint16_t x = 0;
- uint16_t y = 0;
-
- cst816t_read_pos(&touch_points_num, &x, &y);
-
- #if CONFIG_LV_TOUCH_INVERT_X
- x = LV_HOR_RES_MAX - x;
- #endif
- #if 1
- y = 280 - y;
- #endif
- #if 1
- int16_t swap_buf = x;
- x = y;
- y = swap_buf;
- #endif
-
- data->point.x = x;
- data->point.y = y;
- if (touch_points_num > 0) {
- data->state = LV_INDEV_STATE_PR;
- ESP_LOGI(TAG, "X=%u Y=%u", data->point.x, data->point.y);
- ESP_LOGV(TAG, "X=%u Y=%u", data->point.x, data->point.y);
- } else {
- data->state = LV_INDEV_STATE_REL;
- }
-
- return false;
- }
2.3 在touch_driver.c文件里添加对应的初始化代码和触屏读取函数调用,如果不添加,就没办法获取到触屏数据。
components/lvgl_esp32_drivers/lvgl_touch/touch_driver.c
- void touch_driver_init(void)
- {
- #if defined (CONFIG_LV_TOUCH_CONTROLLER_XPT2046)
- xpt2046_init();
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT6X06)
- ft6x06_init(FT6236_I2C_SLAVE_ADDR);
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610)
- stmpe610_init();
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW)
- adcraw_init();
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT81X)
-
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_RA8875)
- ra8875_touch_init();
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_CST816)
- cst816t_init(CST816T_I2C_SLAVE_ADDR);
- #endif
- }
-
- bool touch_driver_read(lv_indev_drv_t *drv, lv_indev_data_t *data)
- {
- bool res = false;
-
- #if defined (CONFIG_LV_TOUCH_CONTROLLER_XPT2046)
- res = xpt2046_read(drv, data);
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT6X06)
- res = ft6x36_read(drv, data);
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610)
- res = stmpe610_read(drv, data);
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW)
- res = adcraw_read(drv, data);
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT81X)
- res = FT81x_read(drv, data);
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_RA8875)
- res = ra8875_touch_read(drv, data);
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_CST816)
- res = cst816t_read(drv, data);
- #endif
-
- return res;
- }
2.4 touch_driver.h 添加cst816.h头文件引用。如果不添加会有编译错误,提示找不到上一步加到代码里的两个函数。
components/lvgl_esp32_drivers/lvgl_touch/touch_driver.h
- #if defined (CONFIG_LV_TOUCH_CONTROLLER_XPT2046)
- #include "xpt2046.h"
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT6X06)
- #include "ft6x36.h"
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_STMPE610)
- #include "stmpe610.h"
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_ADCRAW)
- #include "adcraw.h"
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_FT81X)
- #include "FT81x.h"
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_RA8875)
- #include "ra8875_touch.h"
- #elif defined (CONFIG_LV_TOUCH_CONTROLLER_CST816)
- #include "cst816.h"
- #endif
2.5 在构建系统配置文件里添加cst816驱动文件配置,如果不添加,在链接阶段会提示找不到cst816t_read和cst816t_init这两个符号
components/lvgl_esp32_drivers/CMakeLists.txt
-
- if(CONFIG_LV_TOUCH_CONTROLLER)
- list(APPEND SOURCES "lvgl_touch/touch_driver.c")
- list(APPEND LVGL_INCLUDE_DIRS lvgl_touch)
-
-
-
- if(CONFIG_LV_TOUCH_CONTROLLER_XPT2046)
- list(APPEND SOURCES "lvgl_touch/xpt2046.c")
- elseif(CONFIG_LV_TOUCH_CONTROLLER_FT6X06)
- list(APPEND SOURCES "lvgl_touch/ft6x36.c")
- elseif(CONFIG_LV_TOUCH_CONTROLLER_STMPE610)
- list(APPEND SOURCES "lvgl_touch/stmpe610.c")
- elseif(CONFIG_LV_TOUCH_CONTROLLER_ADCRAW)
- list(APPEND SOURCES "lvgl_touch/adcraw.c")
- elseif(CONFIG_LV_TOUCH_CONTROLLER_FT81X)
- list(APPEND SOURCES "lvgl_touch/FT81x.c")
- elseif(CONFIG_LV_TOUCH_CONTROLLER_RA8875)
- list(APPEND SOURCES "lvgl_touch/ra8875_touch.c")
- elseif(CONFIG_LV_TOUCH_CONTROLLER_CST816)
- list(APPEND SOURCES "lvgl_touch/cst816.c")
- endif()
-
- if(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_SPI)
- list(APPEND SOURCES "lvgl_touch/tp_spi.c")
- elseif(CONFIG_LV_TOUCH_DRIVER_PROTOCOL_I2C)
- list(APPEND SOURCES "lvgl_touch/tp_i2c.c")
- endif()
- endif()
三、修改Kconfig文件
由于我们添加了CST816的相关源码 ,按LVGL的风格配置好Kconfig信息,用来添加触摸屏的引脚和部分配置。
(文件路径components/lvgl_esp32_drivers/lvgl_touch/Kconfig)
将第3行到40行修改成以下内容,主要就是添加CST816的配置信息
- config LV_TOUCH_CONTROLLER
- int
- default 0 if LV_TOUCH_CONTROLLER_NONE
- default 1 if LV_TOUCH_CONTROLLER_XPT2046
- default 2 if LV_TOUCH_CONTROLLER_FT6X06
- default 3 if LV_TOUCH_CONTROLLER_STMPE610
- default 4 if LV_TOUCH_CONTROLLER_ADCRAW
- default 5 if LV_TOUCH_CONTROLLER_FT81X
- default 6 if LV_TOUCH_CONTROLLER_RA8875
- default 7 if LV_TOUCH_CONTROLLER_CST816
-
- choice
- prompt "Select a touch panel controller model."
- default LV_TOUCH_CONTROLLER_NONE
- help
- Select the controller for your touch panel.
-
- config LV_TOUCH_CONTROLLER_NONE
- bool "None"
- config LV_TOUCH_CONTROLLER_XPT2046
- select LV_TOUCH_DRIVER_PROTOCOL_SPI
- bool "XPT2046"
- config LV_TOUCH_CONTROLLER_FT6X06
- select LV_TOUCH_DRIVER_PROTOCOL_I2C
- bool "FT6X06"
- config LV_TOUCH_CONTROLLER_STMPE610
- select LV_TOUCH_DRIVER_PROTOCOL_SPI
- bool "STMPE610"
- config LV_TOUCH_CONTROLLER_ADCRAW
- select LV_TOUCH_DRIVER_ADC
- bool "ADCRAW"
- config LV_TOUCH_CONTROLLER_FT81X
- select LV_TOUCH_DRIVER_PROTOCOL_SPI
- bool "FT81X"
- config LV_TOUCH_CONTROLLER_RA8875
- select LV_TOUCH_DRIVER_DISPLAY
- bool "RA8875"
- config LV_TOUCH_CONTROLLER_CST816
- select LV_TOUCH_DRIVER_PROTOCOL_I2C
- bool "CST816"
- select LV_TOUCH_DRIVER_DISPLAY
- bool "CST816"
- endchoice
在倒数第二行添加 CST816的额外配置内容,并按原理图的引脚指定好默认引脚。
-
- menu "Touchpanel Configuration (CST816)"
- depends on LV_TOUCH_CONTROLLER_CST816
-
- config LV_TOUCH_I2C_SDA
- int
- prompt "GPIO for SDA (I2C)"
- range 0 39 if IDF_TARGET_ESP32
- range 0 43 if IDF_TARGET_ESP32S2
-
- default 14
- help
- Configure the I2C touchpanel SDA pin here.
-
- config LV_TOUCH_I2C_SCL
- int "GPIO for clock signal SCL (I2C)"
- range 0 39 if IDF_TARGET_ESP32
- range 0 43 if IDF_TARGET_ESP32S2
-
- default 13
- help
- Configure the I2C touchpanel SCL pin here.
-
- config LV_TOUCH_PIN_IRQ
- int "GPIO for IRQ (Interrupt Request)"
- range 0 39 if IDF_TARGET_ESP32
- range 0 43 if IDF_TARGET_ESP32S2
-
- default 21 if LV_PREDEFINED_PINS_38V4
- default 21
- help
- Configure the touchpanel IRQ pin here.
-
- config LV_TOUCH_INVERT_X
- bool
- prompt "Invert X coordinate value"
- default n
-
- config LV_TOUCH_INVERT_Y
- bool
- prompt "Invert Y coordinate value"
- default n
-
- endmenu
然后编译好源码,就可以上传到板子上测试了。测试视频如下,触摸还是比较流畅的。
|