在实际应用中,电阻触摸屏必须在使用前进行校准,而电容触摸屏则一般由控制芯片完成该工作,无需额外的校准步骤。驱动中已经集成了电阻触摸屏的校准算法,校准过程使用了三个点来校准,用一个点来验证,当最后验证的误差大于某个阈值将导致校准失败,然后自动重新进行校准,直到校准成功。
调用校准函数 calibration_run() 将会在屏幕上开始校准的过程,校准完成后,参数将 保存在 NVS
中用于下次启动,避免每次使用前的重复校准。
触摸屏按下:不论是电阻还是电容触摸屏,通常的触摸屏控制芯片会有一个用于 通知触摸事件的中断引脚
。但是驱动中没有使用该信号,一方面是因为对于有屏幕的应用需要尽量节省出 IO 给其他外设;另一方面是触摸控制器给出的该信号 不如程序通过寄存器数据判断的准确性高
。对于电阻触摸屏来说,判断按下的依据是 Z 方向的压力大于配置的阈值;对于电容触摸屏则是判断至少有一个触摸点存在。
触摸屏的旋转:触摸屏具有与显示屏一样的 8 个方向
,定义在 touch_panel_dir_t 中。这里的旋转是通过软件换算来实现的,通常把二者的方向设置为相同。但这并不是一成不变的,例如:在使用电容触摸屏时,有可能触摸屏固有的方向与显示屏原始显示方向不一致,如果简单的将这两个方向设置为相同后,将无法正确的点击屏幕内容,这时需要根据实际情况调整。
触摸屏的分辨率设置也是很重要的,因为触摸屏旋转后的换算依赖于触摸屏的宽和高分辨率大小,设置不当将无法得到正确的旋转效果。
电阻触摸:需要校正;
电容触摸:不需要校正,支持多点触摸,而且有些支持固定速率的触摸按钮。
NS2009 电阻触摸:提供 press + position 功能; FT6X36: 电容触摸:只能提供 position 功能;
初始化:
// https://docs.espressif.com/projects/espressif-esp-iot-solution/zh_CN/latest/input_device/touch_panel.html#id5
touch_panel_driver_t touch; // a touch panel driver
i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = 35,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = 36,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
i2c_bus_handle_t i2c_bus = i2c_bus_create(I2C_NUM_0, &i2c_conf);
touch_panel_config_t touch_cfg = {
.interface_i2c = {
.i2c_bus = i2c_bus,
.clk_freq = 100000,
.i2c_addr = 0x38,
},
.interface_type = TOUCH_PANEL_IFACE_I2C,
.pin_num_int = -1,
.direction = TOUCH_DIR_LRTB,
.width = 800,
.height = 480,
};
/* Initialize touch panel controller FT5x06 */
touch_panel_find_driver(TOUCH_PANEL_CONTROLLER_FT5X06, &touch);
touch.init(&touch_cfg);
/* start to run calibration */
touch.calibration_run(&lcd, false);
获取触摸屏是否按下及其触点坐标:
touch_panel_points_t points;
touch.read_point_data(&points);
int32_t x = points.curx[0];
int32_t y = points.cury[0];
if(TOUCH_EVT_PRESS == points.event) {
ESP_LOGI(TAG, "Pressed, Touch point at (%d, %d)", x, y);
}
ESP32 Flappy Bird:https://github.com/Makerfabs/Project_ESP32-Flappy-Bird/tree/master
- LCD 3.5 inch Amorphous-TFT-LCD (Thin Film Transistor Liquid Crystal Display) for mobile-phone or handy electrical equipments.
- NS2009 is A 4-wire resistive touch screen control circuit with I2C interface, which contains A 12-bit resolution A/D converter.
- The FT6X36 Series ICs are single-chip capacitive touch panel controller IC with a built-in 16 bit enhanced Micro-controller unit (MCU).
touch controller 一般是通过 I2C/SPI 接口来读取的:
- SPI 接口: 如 STMPE610 ,一般和 LCD SPI 接口复用,通过 CS 信号来区分;
#include "NS2009.h"
//I2C receive
void ns2009_recv(const uint8_t *send_buf, size_t send_buf_len, uint8_t *receive_buf,
size_t receive_buf_len)
{
Wire.beginTransmission(NS2009_ADDR);
Wire.write(send_buf, send_buf_len);
Wire.endTransmission();
Wire.requestFrom(NS2009_ADDR, receive_buf_len);
while (Wire.available())
{
*receive_buf++ = Wire.read();
}
}
//read 12bit data
unsigned int ns2009_read(uint8_t cmd)
{
uint8_t buf[2];
ns2009_recv(&cmd, 1, buf, 2);
return (buf[0] << 4) | (buf[1] >> 4);
}
//Press maybe not correct
int ns2009_get_press()
{
return ns2009_read(NS2009_LOW_POWER_READ_Z1);
}
int ns2009_pos(int pos[2])
{
int press = ns2009_read(NS2009_LOW_POWER_READ_Z1);
int x, y = 0;
x = ns2009_read(NS2009_LOW_POWER_READ_X);
y = ns2009_read(NS2009_LOW_POWER_READ_Y);
pos[0] = x * SCREEN_X_PIXEL / 4096; //4096 = 2 ^ 12
pos[1] = y * SCREEN_Y_PIXEL / 4096;
//pos[0] = x;
//pos[1] = y;
return press;
}
FT6236:
// https://github.com/Makerfabs/Makerfabs-ESP32-S3-Parallel-TFT-with-Touch/blob/main/example/touch_keyboard_v2/FT6236.cpp
#include "FT6236.h"
int readTouchReg(int reg)
{
int data = 0;
Wire.beginTransmission(TOUCH_I2C_ADD);
Wire.write(reg);
Wire.endTransmission();
Wire.requestFrom(TOUCH_I2C_ADD, 1);
if (Wire.available())
{
data = Wire.read();
}
return data;
}
/*
int getTouchPointX()
{
int XL = 0;
int XH = 0;
XH = readTouchReg(TOUCH_REG_XH);
XL = readTouchReg(TOUCH_REG_XL);
return ((XH & 0x0F) << 8) | XL;
}
*/
int getTouchPointX()
{
int XL = 0;
int XH = 0;
XH = readTouchReg(TOUCH_REG_XH);
//Serial.println(XH >> 6,HEX);
if(XH >> 6 == 1)
return -1;
XL = readTouchReg(TOUCH_REG_XL);
return ((XH & 0x0F) << 8) | XL;
}
int getTouchPointY()
{
int YL = 0;
int YH = 0;
YH = readTouchReg(TOUCH_REG_YH);
YL = readTouchReg(TOUCH_REG_YL);
return ((YH & 0x0F) << 8) | YL;
}
int ft6236_pos(int pos[2])
{
int XL = 0;
int XH = 0;
int YL = 0;
int YH = 0;
XH = readTouchReg(TOUCH_REG_XH);
if(XH >> 6 == 1)
{
pos[0] = -1;
pos[1] = -1;
return 0;
}
XL = readTouchReg(TOUCH_REG_XL);
YH = readTouchReg(TOUCH_REG_YH);
YL = readTouchReg(TOUCH_REG_YL);
pos[0] = ((XH & 0x0F) << 8) | XL;
pos[1] = ((YH & 0x0F) << 8) | YL;
return 1;
}
Makerfabs ESP32-S3 Parallel TFT with Touch: https://github.com/Makerfabs/Makerfabs-ESP32-S3-Parallel-TFT-with-Touch
ESP32 3.5" TFT Touch with Camera: https://wiki.makerfabs.com/ESP32_3.5_TFT_Touch_with_Camera.html
大量 LCD+Touch 的例子:https://github.com/Makerfabs/Project_Touch-Screen-Camera
GT911 #
触摸板配置参数:
- GT911 触摸板支持多点触摸 Touch Point 和 4 个固定数量的 Touch Button:例如 ESP32-S3-BOX-3 屏幕下方 的红色圆环即为屏幕的触摸按钮;
- ESP32-S3-BOX-3 的 Touch 和 LCD 共享 reset pin,在 LCD 初始化过程中已经做了 reset,这样 Touch 就不 能再配置和使用 reset,否则会导致 LCD 显示异常:https://esphome.io/components/touchscreen/tt21100.html
esp-bps 中定义的多点触摸 Touch Point 数量为 5,使用的触摸按钮数量为 1;
- 虽然支持多点触摸,但是 Slint/LVGL 只使用单点,所以实际只使用 touch driver 返回的 Touch Point 数组 的第一个;
// https://github.com/espressif/esp-bsp/blob/master/components/lcd_touch/esp_lcd_touch/Kconfig
menu "ESP LCD TOUCH"
config ESP_LCD_TOUCH_MAX_POINTS
int "Maximum count of the touch points"
range 1 10
default 5 // 多点触摸:5 个点
config ESP_LCD_TOUCH_MAX_BUTTONS
int "Maximum count of the touch buttons supported"
range 0 10
default 1 // 固定按钮:屏幕上的 1 个圆环按钮
endmenu
ESP LCD Touch GT911 Controller driver 位于 esp-bps: [[https://github.com/espressif/esp-bsp/tree/master/components/lcd_touch/esp_lcd_touch_gt911][components/lcd_touch/esp_lcd_touch_gt911]]
- GT911 的各寄存器地址和功能参考:[[https://www.crystalfontz.com/controllers/GOODIX/GT911ProgrammingGuide/478/][GT911 Programming Guide_v0.1.pdf]]
// https://github.com/espressif/esp-bsp/blob/master/components/lcd_touch/esp_lcd_touch_gt911/esp_lcd_touch_gt911.c
/* GT911 registers */
#define ESP_LCD_TOUCH_GT911_READ_KEY_REG (0x8093) // 4 个固定触摸按钮开始的地址:0 表示没有 key
#define ESP_LCD_TOUCH_GT911_READ_XY_REG (0x814E) // 触摸点数量和按钮有效指示
#define ESP_LCD_TOUCH_GT911_CONFIG_REG (0x8047)
#define ESP_LCD_TOUCH_GT911_PRODUCT_ID_REG (0x8140) // 读取产品 ID 信息
#define ESP_LCD_TOUCH_GT911_ENTER_SLEEP (0x8040)
/* GT911 support key num */
#define ESP_GT911_TOUCH_MAX_BUTTONS (4) // 驱动支持 4 个固定 Button,但是开发版只用了一个。
ESP_LCD_TOUCH_GT911_READ_XY_REG 地址 0X814E 读取到的是检测到的触摸点数量: #+ATTR_HTML: :width 400 :align center [[file:static/images/esp-box/2024-05-12_22-04-02_screenshot.png]]
而 ESP_LCD_TOUCH_GT911_READ_XY_REG + 1 == 0x814F 地址开始,保存 trackid + XY 坐标等信息,所以读取所 有触摸点数据时从这个地址开始: #+ATTR_HTML: :width 400 :align center [[file:static/images/esp-box/2024-05-12_22-01-53_screenshot.png]]
stm32-gt911 驱动不关注各触摸点的 trackid,所以定义的 P1-P5 的读取地址都是从 trackid 后的 X 坐标位置 开始,如
- #define GT911_P1_XL_REG 0x8150U
- #define GT911_P2_XL_REG 0x8158U
- GT911 寄存器详细列表:https://github.com/STMicroelectronics/stm32-gt911/blob/main/gt911_reg.h
ESP_LCD_TOUCH_GT911_READ_XY_REG 地址 0x814E 读取到的 u8 含义: #+ATTR_HTML: :width 400 :align center [[file:static/images/esp-box/2024-05-12_22-08-15_screenshot.png]]
GT911 驱动核心逻辑:esp_err_t esp_lcd_touch_gt911_read_data(), 它读取 ESP_LCD_TOUCH_GT911_READ_XY_REG 寄存器值,根据返回的 buf[0] 来进一步判断:
- buf[0] & 0x80) == 0x00:无按键或触摸
- 清理 touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
- buf[0] & 0x10) == 0x10:有按键
- 读取 MAX Button 个按键数据:touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_KEY_REG, &buf[0], key_max);
- 清理 touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
- 将 tp->data.button[i].status 设置为 1 或 0
- buf[0] & 0x80) == 0x80:有触摸或按键
- 将所有 tp->data.button[i].status 设置为 0
- 读取所有触摸点 err = touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG + 1, &buf[1], touch_cnt * 8);
- 清理: err = touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
// https://github.com/espressif/esp-bsp/blob/master/components/lcd_touch/esp_lcd_touch_gt911/esp_lcd_touch_gt911.c
// 驱动函数定义
// 读取设备寄存器值
static esp_err_t esp_lcd_touch_gt911_read_data(esp_lcd_touch_handle_t tp);
// 从 read_data 中获得触摸点位置
static bool esp_lcd_touch_gt911_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y, uint16_t *strength, uint8_t *point_num, uint8_t max_point_num);
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
// 从 read_data 中获得触摸按钮状态
static esp_err_t esp_lcd_touch_gt911_get_button_state(esp_lcd_touch_handle_t tp, uint8_t n, uint8_t *state);
#endif
static esp_err_t esp_lcd_touch_gt911_read_data(esp_lcd_touch_handle_t tp)
{
esp_err_t err;
uint8_t buf[41];
uint8_t touch_cnt = 0;
uint8_t clear = 0;
size_t i = 0;
assert(tp != NULL);
// 先读取 XY 数据, 注意:读取一个 u8 大小;
err = touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, buf, 1);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
if ((buf[0] & 0x80) == 0x00) {
// 1. 多点触摸 或者 触摸按钮 的数据 notready,这时应该清零
touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
} else if ((buf[0] & 0x10) == 0x10) {
// 2. 表示触摸按钮按下或释放
// 读取所有数量 key_max 个的触摸按钮的状态保存到 &buf[0] 开始的位置。
/* Read all keys */
uint8_t key_max = ((ESP_GT911_TOUCH_MAX_BUTTONS < CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS) ? \
(ESP_GT911_TOUCH_MAX_BUTTONS) : (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS));
err = touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_KEY_REG, &buf[0], key_max);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
/* Clear all */
touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
ESP_RETURN_ON_ERROR(err, TAG, "I2C write error!");
portENTER_CRITICAL(&tp->data.lock);
/* Buttons count */
tp->data.buttons = key_max;
for (i = 0; i < key_max; i++) {
// 只使用 buf[0] 即第一个触摸按钮的状态来更新所有按钮,0 没有按下,其他值(非0)按下。
tp->data.button[i].status = buf[0] ? 1 : 0;
}
portEXIT_CRITICAL(&tp->data.lock);
#endif
} else if ((buf[0] & 0x80) == 0x80) {
// 3. 多点触摸 或者 触摸按钮 的数据 ready,可以读取
#if (CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS > 0)
portENTER_CRITICAL(&tp->data.lock);
// 清空触摸按钮状态
for (i = 0; i < CONFIG_ESP_LCD_TOUCH_MAX_BUTTONS; i++) {
tp->data.button[i].status = 0;
}
portEXIT_CRITICAL(&tp->data.lock);
#endif
/* Count of touched points */
// 从 buf[0] 获得多点触摸的触摸点数量
touch_cnt = buf[0] & 0x0f;
if (touch_cnt > 5 || touch_cnt == 0) {
touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
return ESP_OK;
}
/* Read all points */
// 注意:从 ESP_LCD_TOUCH_GT911_READ_XY_REG + 1 地址读取所有触摸点 XY 数据,
// 存入 buf[1] 及以后的空间,buf[0] 是当前第一个触摸点
err = touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG + 1, &buf[1], touch_cnt * 8);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
/* Clear all */
err = touch_gt911_i2c_write(tp, ESP_LCD_TOUCH_GT911_READ_XY_REG, clear);
ESP_RETURN_ON_ERROR(err, TAG, "I2C read error!");
portENTER_CRITICAL(&tp->data.lock);
/* Number of touched points */
touch_cnt = (touch_cnt > CONFIG_ESP_LCD_TOUCH_MAX_POINTS ? CONFIG_ESP_LCD_TOUCH_MAX_POINTS : touch_cnt);
tp->data.points = touch_cnt;
/* Fill all coordinates */
for (i = 0; i < touch_cnt; i++) {
tp->data.coords[i].x = ((uint16_t)buf[(i * 8) + 3] << 8) + buf[(i * 8) + 2];
tp->data.coords[i].y = (((uint16_t)buf[(i * 8) + 5] << 8) + buf[(i * 8) + 4]);
tp->data.coords[i].strength = (((uint16_t)buf[(i * 8) + 7] << 8) + buf[(i * 8) + 6]);
}
portEXIT_CRITICAL(&tp->data.lock);
}
return ESP_OK;
}
static esp_err_t touch_gt911_read_cfg(esp_lcd_touch_handle_t tp)
{
uint8_t buf[4];
assert(tp != NULL);
ESP_RETURN_ON_ERROR(touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_PRODUCT_ID_REG, (uint8_t *)&buf[0], 3), TAG, "GT911 read error!");
ESP_RETURN_ON_ERROR(touch_gt911_i2c_read(tp, ESP_LCD_TOUCH_GT911_CONFIG_REG, (uint8_t *)&buf[3], 1), TAG, "GT911 read error!");
ESP_LOGI(TAG, "TouchPad_ID:0x%02x,0x%02x,0x%02x", buf[0], buf[1], buf[2]);
ESP_LOGI(TAG, "TouchPad_Config_Version:%d", buf[3]);
return ESP_OK;
}
// 其中的 esp_lcd_panel_io_rx_param 定义
// https://github.com/espressif/esp-idf/blob/master/components/esp_lcd/src/esp_lcd_panel_io.c
esp_err_t esp_lcd_panel_io_rx_param(esp_lcd_panel_io_handle_t io, int lcd_cmd, void *param, size_t param_size)
{
ESP_RETURN_ON_FALSE(io, ESP_ERR_INVALID_ARG, TAG, "invalid panel io handle");
ESP_RETURN_ON_FALSE(io->rx_param, ESP_ERR_NOT_SUPPORTED, TAG, "rx_param is not supported yet");
return io->rx_param(io, lcd_cmd, param, param_size);
}
// https://github.com/espressif/esp-idf/blob/master/components/esp_lcd/include/esp_lcd_types.h
typedef struct esp_lcd_panel_io_t *esp_lcd_panel_io_handle_t;
/**
,* @brief LCD panel IO interface
,*/
struct esp_lcd_panel_io_t {
/**
,* @brief Transmit LCD command and receive corresponding parameters
,*
,* @note This is the panel-specific interface called by function `esp_lcd_panel_io_rx_param()`.
,*
,* @param[in] io LCD panel IO handle, which is created by other factory API like `esp_lcd_new_panel_io_spi()`
,* @param[in] lcd_cmd The specific LCD command, set to -1 if no command needed
,* @param[out] param Buffer for the command data
,* @param[in] param_size Size of `param` buffer
,* @return
,* - ESP_ERR_INVALID_ARG if parameter is invalid
,* - ESP_ERR_NOT_SUPPORTED if read is not supported by transport
,* - ESP_OK on success
,*/
esp_err_t (*rx_param)(esp_lcd_panel_io_t *io, int lcd_cmd, void *param, size_t param_size);
// 。。。
};
// 而上面的 rx_param/tx_param 的具体实现从 I2C 读取数据
// https://github.com/espressif/esp-idf/blob/master/components/esp_lcd/i2c/esp_lcd_panel_io_i2c_v2.c
static esp_err_t panel_io_i2c_rx_buffer(esp_lcd_panel_io_t *io, int lcd_cmd, void *buffer, size_t buffer_size)
{
esp_err_t ret = ESP_OK;
lcd_panel_io_i2c_t *i2c_panel_io = __containerof(io, lcd_panel_io_i2c_t, base);
bool send_param = (lcd_cmd >= 0);
int write_size = 0;
uint8_t write_buffer[CONTROL_PHASE_LENGTH + CMD_LENGTH] = {0};
if (send_param) {
if (i2c_panel_io->control_phase_enabled) {
write_buffer[0] = i2c_panel_io->control_phase_cmd;
write_size += 1;
}
uint8_t cmds[4] = {BYTESHIFT(lcd_cmd, 3), BYTESHIFT(lcd_cmd, 2), BYTESHIFT(lcd_cmd, 1), BYTESHIFT(lcd_cmd, 0)};
size_t cmds_size = i2c_panel_io->lcd_cmd_bits / 8;
if (cmds_size > 0 && cmds_size <= sizeof(cmds)) {
memcpy(write_buffer + write_size, cmds + (sizeof(cmds) - cmds_size), cmds_size);
write_size += cmds_size;
}
}
// 发起实际的 I2C 接收操作
ESP_GOTO_ON_ERROR(i2c_master_transmit_receive(i2c_panel_io->i2c_handle, write_buffer, write_size, buffer, buffer_size, -1), err, TAG, "i2c transaction failed");
return ESP_OK;
err:
return ret;
}
eps-box-3 配置参数:
- ESP32-S3-BOX-3 使用的 I2C 地址是 0x14;
// 配置参数来源于:https://github.com/espressif/esp-bsp/blob/master/bsp/esp-box-3/Kconfig
menu "Board Support Package(ESP-BOX-3)"
config BSP_ERROR_CHECK
bool "Enable error check in BSP"
default y
help
Error check assert the application before returning the error code.
menu "I2C"
config BSP_I2C_NUM
int "I2C peripheral index"
default 1 // I2C Touch 使用的是 peripherals.I2C1(1 为 number)
range 0 1
help
ESP32S3 has two I2C peripherals, pick the one you want to use. 另一个 I2C 是扩展板的 I2C
config BSP_I2C_FAST_MODE
bool "Enable I2C fast mode"
default y
help
I2C has two speed modes: normal (100kHz) and fast (400kHz).
config BSP_I2C_CLK_SPEED_HZ
int
default 400000 if BSP_I2C_FAST_MODE // I2C 使用的时钟频率 400KHZ
default 100000
endmenu
// https://github.com/espressif/esp-bsp/blob/master/components/lcd_touch/esp_lcd_touch_gt911/include/esp_lcd_touch_gt911.h#L34C1-L40C4
/**
,* @brief I2C address of the GT911 controller
,*
,* @note When power-on detects low level of the interrupt gpio, address is 0x5D.
,* @note Interrupt gpio is high level, address is 0x14.
,*
,*/
#define ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS (0x5D)
#define ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP (0x14) // 实际测试 ESP32-S3-BOX-3 使用该地址
/**
,* @brief Touch IO configuration structure
,*
,*/
#define ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG() \
{ \
.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS, \
.control_phase_bytes = 1, \
.dc_bit_offset = 0, \
.lcd_cmd_bits = 16, \
.flags = \
{ \
.disable_control_phase = 1, \
} \
}
// https://github.com/espressif/esp-bsp/blob/master/bsp/esp-box-3/include/bsp/esp-box-3.h
/**************************************************************************************************
* ESP-BOX pinout
**************************************************************************************************/
/* I2C */
#define BSP_I2C_SCL (GPIO_NUM_18)
#define BSP_I2C_SDA (GPIO_NUM_8)
#define BSP_LCD_TOUCH_INT (GPIO_NUM_3) // 中断引脚,和 LCD 复用
// https://github.com/espressif/esp-bsp/blob/master/bsp/esp-box-3/include/bsp/esp-box-3.h
/**************************************************************************************************
,*
,* I2C interface
,*
,* There are multiple devices connected to I2C peripheral:
,* - Codec ES8311 (configuration only)
,* - ADC ES7210 (configuration only)
,* - Encryption chip ATECC608A (NOT populated on most boards)
,* - LCD Touch controller
,* - Inertial Measurement Unit ICM-42607-P
,*
,* After initialization of I2C, use BSP_I2C_NUM macro when creating I2C devices drivers ie.:
,* \code{.c}
,* icm42670_handle_t imu = icm42670_create(BSP_I2C_NUM, ICM42670_I2C_ADDRESS);
,* \endcode
,**************************************************************************************************/
#define BSP_I2C_NUM CONFIG_BSP_I2C_NUM // 主板为 1,扩展板 I2C 为 0
Touch Controller 和 LCD Controller 共享相同的 RST,当 LCD 初始化时已经 RESET,所以不能再给 Touch Controller 配置 RST 参数:
// https://github.com/espressif/esp-bsp/blob/master/bsp/esp-box-3/esp-box-3.c
esp_err_t bsp_i2c_init(void)
{
/* I2C was initialized before */
if (i2c_initialized) {
return ESP_OK;
}
const i2c_config_t i2c_conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = BSP_I2C_SDA,
.sda_pullup_en = GPIO_PULLUP_DISABLE,
.scl_io_num = BSP_I2C_SCL,
.scl_pullup_en = GPIO_PULLUP_DISABLE,
.master.clk_speed = CONFIG_BSP_I2C_CLK_SPEED_HZ // 400K
};
BSP_ERROR_CHECK_RETURN_ERR(i2c_param_config(BSP_I2C_NUM, &i2c_conf));
BSP_ERROR_CHECK_RETURN_ERR(i2c_driver_install(BSP_I2C_NUM, i2c_conf.mode, 0, 0, 0));
i2c_initialized = true;
return ESP_OK;
}
static esp_err_t bsp_i2c_device_probe(uint8_t addr)
{
esp_err_t ret = ESP_ERR_NOT_FOUND;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
i2c_master_stop(cmd);
if (i2c_master_cmd_begin(BSP_I2C_NUM, cmd, 1000) == ESP_OK) {
ret = ESP_OK;
}
i2c_cmd_link_delete(cmd);
return ret;
}
esp_err_t bsp_touch_new(const bsp_touch_config_t *config, esp_lcd_touch_handle_t *ret_touch)
{
/* Initilize I2C */
BSP_ERROR_CHECK_RETURN_ERR(bsp_i2c_init());
/* Initialize touch */
esp_lcd_touch_config_t tp_cfg = {
.x_max = BSP_LCD_H_RES,
.y_max = BSP_LCD_V_RES,
.rst_gpio_num = GPIO_NUM_NC, // Shared with LCD reset,不能设置!
.int_gpio_num = BSP_LCD_TOUCH_INT,
.levels = {
.reset = 0, // 低电平复位
.interrupt = 0, // 低电平中断
},
.flags = {
.swap_xy = 0,
.mirror_x = 0,
.mirror_y = 0,
},
};
esp_lcd_panel_io_handle_t tp_io_handle = NULL;
esp_lcd_panel_io_i2c_config_t tp_io_config;
if (ESP_OK == bsp_i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS)) {
esp_lcd_panel_io_i2c_config_t config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
memcpy(&tp_io_config, &config, sizeof(config));
} else if (ESP_OK == bsp_i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP)) {
esp_lcd_panel_io_i2c_config_t config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG(); // 使用该配置类型
config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP; // 使用 BACKUP 地址 0x14
memcpy(&tp_io_config, &config, sizeof(config));
} else if (ESP_OK == bsp_i2c_device_probe(ESP_LCD_TOUCH_IO_I2C_TT21100_ADDRESS)) {
esp_lcd_panel_io_i2c_config_t config = ESP_LCD_TOUCH_IO_I2C_TT21100_CONFIG();
memcpy(&tp_io_config, &config, sizeof(config));
tp_cfg.flags.mirror_x = 1;
} else {
ESP_LOGE(TAG, "Touch not found");
return ESP_ERR_NOT_FOUND;
}
ESP_RETURN_ON_ERROR(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t)BSP_I2C_NUM, &tp_io_config, &tp_io_handle), TAG, "");
if (ESP_LCD_TOUCH_IO_I2C_TT21100_ADDRESS == tp_io_config.dev_addr) {
ESP_RETURN_ON_ERROR(esp_lcd_touch_new_i2c_tt21100(tp_io_handle, &tp_cfg, ret_touch), TAG, "New tt21100 failed");
} else {
ESP_RETURN_ON_ERROR(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, ret_touch), TAG, "New gt911 failed");
}
return ESP_OK;
}
实际结果:
# 按压 touch key
pointInfo = 90, bufferStatus: 1, haveKey: 1 touches: 0
read_touch_key: [31, 0, 0, 0]
read_touch key: TouchKey { id: 0, pressed: true }
pointInfo = 0, bufferStatus: 0, haveKey: 0 touches: 0
read_touch None: laste_touch: None
pointInfo = 0, bufferStatus: 0, haveKey: 0 touches: 0
read_touch None: laste_touch: None
pointInfo = 80, bufferStatus: 1, haveKey: 0 touches: 0
read_touch None: laste_touch: None
pointInfo = 0, bufferStatus: 0, haveKey: 0 touches: 0
read_touch None: laste_touch: None
pointInfo = 0, bufferStatus: 0, haveKey: 0 touches: 0
read_touch None: laste_touch: None
pointInfo = 80, bufferStatus: 1, haveKey: 0 touches: 0
read_touch None: laste_touch: None
pointInfo = 0, bufferStatus: 0, haveKey: 0 touches: 0
read_touch None: laste_touch: None
pointInfo = 0, bufferStatus: 0, haveKey: 0 touches: 0
read_touch None: laste_touch: None