293 lines
8.0 KiB
C
293 lines
8.0 KiB
C
#include "capacitive_touch.h"
|
|
|
|
#include "driver/gpio.h"
|
|
#include "driver/i2c_master.h"
|
|
#include "esp_lcd_panel_io.h"
|
|
#include "esp_err.h"
|
|
#include "esp_lcd_io_i2c.h"
|
|
#include "esp_lcd_touch.h"
|
|
#include "esp_lcd_touch_gt911.h"
|
|
#include "esp_log.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/task.h"
|
|
|
|
#define TOUCH_I2C_PORT 0
|
|
#define TOUCH_I2C_TIMEOUT_MS 100
|
|
|
|
static const char *TAG = "gt911_touch";
|
|
static i2c_master_bus_handle_t touch_i2c_bus;
|
|
static esp_lcd_panel_io_handle_t touch_io;
|
|
static esp_lcd_touch_handle_t touch_handle;
|
|
static bool touch_ready;
|
|
static bool touch_active;
|
|
static uint8_t touch_count;
|
|
static uint8_t touch_id;
|
|
static uint8_t touch_addr;
|
|
|
|
static uint16_t clamp_coord(uint16_t value, uint16_t max)
|
|
{
|
|
return value > max ? max : value;
|
|
}
|
|
|
|
static void transform_touch_coord(uint16_t raw_x, uint16_t raw_y, uint16_t *x, uint16_t *y)
|
|
{
|
|
if (TOUCH_SWAP_XY) {
|
|
*x = raw_y;
|
|
*y = raw_x;
|
|
} else {
|
|
*x = raw_x;
|
|
*y = raw_y;
|
|
}
|
|
|
|
if (TOUCH_INVERT_X) {
|
|
*x = (*x >= TOUCH_WIDTH) ? 0 : (TOUCH_WIDTH - 1 - *x);
|
|
}
|
|
|
|
if (TOUCH_INVERT_Y) {
|
|
*y = (*y >= TOUCH_HEIGHT) ? 0 : (TOUCH_HEIGHT - 1 - *y);
|
|
}
|
|
|
|
*x = clamp_coord(*x, TOUCH_WIDTH - 1);
|
|
*y = clamp_coord(*y, TOUCH_HEIGHT - 1);
|
|
}
|
|
|
|
static void touch_irq_input_init(void)
|
|
{
|
|
gpio_config_t irq_config = {
|
|
.pin_bit_mask = 1ULL << TOUCH_PIN_INT,
|
|
.mode = GPIO_MODE_INPUT,
|
|
.pull_up_en = GPIO_PULLUP_ENABLE,
|
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
.intr_type = GPIO_INTR_DISABLE,
|
|
};
|
|
gpio_config(&irq_config);
|
|
}
|
|
|
|
static void touch_log_pin_levels(void)
|
|
{
|
|
int scl_level = gpio_get_level(TOUCH_PIN_SCL);
|
|
int sda_level = gpio_get_level(TOUCH_PIN_SDA);
|
|
int int_level = gpio_get_level(TOUCH_PIN_INT);
|
|
|
|
ESP_LOGI(TAG, "touch pins: SCL=GPIO%d level=%d, SDA=GPIO%d level=%d, INT=GPIO%d level=%d",
|
|
TOUCH_PIN_SCL, scl_level, TOUCH_PIN_SDA, sda_level, TOUCH_PIN_INT, int_level);
|
|
|
|
if (scl_level == 0 || sda_level == 0) {
|
|
ESP_LOGW(TAG, "I2C bus is not idle, SCL and SDA should both be high before communication");
|
|
}
|
|
}
|
|
|
|
static void touch_select_i2c_addr(uint8_t dev_addr)
|
|
{
|
|
gpio_config_t rst_config = {
|
|
.pin_bit_mask = 1ULL << TOUCH_PIN_RES,
|
|
.mode = GPIO_MODE_OUTPUT,
|
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
.intr_type = GPIO_INTR_DISABLE,
|
|
};
|
|
gpio_config_t int_output_config = {
|
|
.pin_bit_mask = 1ULL << TOUCH_PIN_INT,
|
|
.mode = GPIO_MODE_OUTPUT,
|
|
.pull_up_en = GPIO_PULLUP_ENABLE,
|
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
.intr_type = GPIO_INTR_DISABLE,
|
|
};
|
|
|
|
ESP_LOGI(TAG, "select GT911 address 0x%02x", dev_addr);
|
|
gpio_config(&rst_config);
|
|
gpio_config(&int_output_config);
|
|
|
|
gpio_set_level(TOUCH_PIN_RES, 0);
|
|
gpio_set_level(TOUCH_PIN_INT, dev_addr == ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP ? 1 : 0);
|
|
vTaskDelay(pdMS_TO_TICKS(20));
|
|
gpio_set_level(TOUCH_PIN_RES, 1);
|
|
vTaskDelay(pdMS_TO_TICKS(60));
|
|
|
|
touch_irq_input_init();
|
|
}
|
|
|
|
static bool touch_i2c_probe_addr(uint8_t dev_addr)
|
|
{
|
|
ESP_LOGI(TAG, "probe GT911 at 0x%02x", dev_addr);
|
|
esp_err_t err = i2c_master_probe(touch_i2c_bus, dev_addr, TOUCH_I2C_TIMEOUT_MS);
|
|
if (err == ESP_OK) {
|
|
ESP_LOGI(TAG, "GT911 responds at 0x%02x", dev_addr);
|
|
return true;
|
|
}
|
|
|
|
ESP_LOGW(TAG, "GT911 no ACK at 0x%02x: %s", dev_addr, esp_err_to_name(err));
|
|
return false;
|
|
}
|
|
|
|
static esp_err_t touch_i2c_init(void)
|
|
{
|
|
i2c_master_bus_config_t bus_config = {
|
|
.i2c_port = TOUCH_I2C_PORT,
|
|
.sda_io_num = TOUCH_PIN_SDA,
|
|
.scl_io_num = TOUCH_PIN_SCL,
|
|
.clk_source = I2C_CLK_SRC_DEFAULT,
|
|
.glitch_ignore_cnt = 7,
|
|
.flags.enable_internal_pullup = true,
|
|
};
|
|
|
|
esp_err_t err = i2c_new_master_bus(&bus_config, &touch_i2c_bus);
|
|
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
|
|
return err;
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t touch_driver_init_at_addr(uint8_t dev_addr)
|
|
{
|
|
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
|
|
esp_lcd_touch_io_gt911_config_t gt911_config = {
|
|
.dev_addr = dev_addr,
|
|
};
|
|
esp_lcd_touch_config_t touch_config = {
|
|
.x_max = TOUCH_WIDTH,
|
|
.y_max = TOUCH_HEIGHT,
|
|
.rst_gpio_num = TOUCH_PIN_RES,
|
|
.int_gpio_num = TOUCH_PIN_INT,
|
|
.levels = {
|
|
.reset = 0,
|
|
.interrupt = 0,
|
|
},
|
|
.flags = {
|
|
.swap_xy = false,
|
|
.mirror_x = false,
|
|
.mirror_y = false,
|
|
},
|
|
.driver_data = >911_config,
|
|
};
|
|
|
|
io_config.dev_addr = dev_addr;
|
|
|
|
esp_err_t err = esp_lcd_new_panel_io_i2c(touch_i2c_bus, &io_config, &touch_io);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "touch panel IO init failed at 0x%02x: %s", dev_addr, esp_err_to_name(err));
|
|
return err;
|
|
}
|
|
|
|
err = esp_lcd_touch_new_i2c_gt911(touch_io, &touch_config, &touch_handle);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGW(TAG, "GT911 driver init failed at 0x%02x: %s", dev_addr, esp_err_to_name(err));
|
|
esp_lcd_panel_io_del(touch_io);
|
|
touch_io = NULL;
|
|
touch_handle = NULL;
|
|
return err;
|
|
}
|
|
|
|
touch_addr = dev_addr;
|
|
return ESP_OK;
|
|
}
|
|
|
|
bool capacitive_touch_is_pressed(void)
|
|
{
|
|
return touch_active || gpio_get_level(TOUCH_PIN_INT) == 0;
|
|
}
|
|
|
|
bool capacitive_touch_read_raw(uint16_t *x, uint16_t *y)
|
|
{
|
|
esp_lcd_touch_point_data_t point_data[TOUCH_MAX_POINTS] = {0};
|
|
uint8_t point_count = 0;
|
|
|
|
if (!x || !y || !touch_ready) {
|
|
return false;
|
|
}
|
|
|
|
if (esp_lcd_touch_read_data(touch_handle) != ESP_OK) {
|
|
touch_active = false;
|
|
touch_count = 0;
|
|
return false;
|
|
}
|
|
|
|
if (esp_lcd_touch_get_data(touch_handle, point_data, &point_count, TOUCH_MAX_POINTS) != ESP_OK || point_count == 0) {
|
|
touch_active = false;
|
|
touch_count = 0;
|
|
return false;
|
|
}
|
|
|
|
*x = point_data[0].x;
|
|
*y = point_data[0].y;
|
|
touch_id = point_data[0].track_id;
|
|
touch_count = point_count;
|
|
touch_active = true;
|
|
return true;
|
|
}
|
|
|
|
bool capacitive_touch_read(capacitive_touch_point_t *point)
|
|
{
|
|
uint16_t raw_x;
|
|
uint16_t raw_y;
|
|
uint16_t x;
|
|
uint16_t y;
|
|
|
|
if (!point) {
|
|
return false;
|
|
}
|
|
|
|
point->pressed = false;
|
|
point->count = 0;
|
|
if (!capacitive_touch_read_raw(&raw_x, &raw_y)) {
|
|
return false;
|
|
}
|
|
|
|
point->raw_x = raw_x;
|
|
point->raw_y = raw_y;
|
|
point->id = touch_id;
|
|
point->count = touch_count;
|
|
|
|
transform_touch_coord(raw_x, raw_y, &x, &y);
|
|
point->x = x;
|
|
point->y = y;
|
|
point->pressed = true;
|
|
return true;
|
|
}
|
|
|
|
void capacitive_touch_init(void)
|
|
{
|
|
uint8_t detected_addr = 0;
|
|
|
|
touch_irq_input_init();
|
|
|
|
ESP_LOGI(TAG, "I2C init start");
|
|
esp_err_t err = touch_i2c_init();
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "I2C init failed: %s", esp_err_to_name(err));
|
|
return;
|
|
}
|
|
ESP_LOGI(TAG, "I2C init done");
|
|
|
|
touch_log_pin_levels();
|
|
|
|
touch_select_i2c_addr(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS);
|
|
touch_log_pin_levels();
|
|
if (touch_i2c_probe_addr(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS)) {
|
|
detected_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS;
|
|
} else {
|
|
touch_select_i2c_addr(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP);
|
|
touch_log_pin_levels();
|
|
if (touch_i2c_probe_addr(ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP)) {
|
|
detected_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP;
|
|
}
|
|
}
|
|
|
|
if (detected_addr == 0) {
|
|
ESP_LOGE(TAG, "GT911 not responding at 0x%02x or 0x%02x",
|
|
ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP);
|
|
return;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "GT911 driver init start at 0x%02x", detected_addr);
|
|
err = touch_driver_init_at_addr(detected_addr);
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "GT911 driver init failed at 0x%02x: %s", detected_addr, esp_err_to_name(err));
|
|
return;
|
|
}
|
|
|
|
touch_ready = true;
|
|
ESP_LOGI(TAG, "official GT911 driver started at 0x%02x", touch_addr);
|
|
}
|