diff --git a/common/src/c/grid_module.c b/common/src/c/grid_module.c index fe4fc03d..06346117 100644 --- a/common/src/c/grid_module.c +++ b/common/src/c/grid_module.c @@ -13,6 +13,7 @@ #include "grid_ui_lcd.h" #include "grid_ui_potmeter.h" #include "grid_ui_system.h" +#include "grid_ui_touch.h" extern struct luaL_Reg* grid_lua_api_gui_lib_reference; @@ -60,6 +61,9 @@ void grid_lua_ui_init(struct grid_lua_model* lua) { case GRID_PARAMETER_ELEMENT_LCD: { GRID_LUA_UI_INIT_ASSIGN(GRID_LUA_L); } break; + case GRID_PARAMETER_ELEMENT_TOUCH: { + GRID_LUA_UI_INIT_ASSIGN(GRID_LUA_T); + } break; default: assert(0); break; @@ -255,3 +259,18 @@ void grid_module_octv_ui_init(struct grid_ain_model* ain, struct grid_led_model* ui->lua_ui_init_callback = grid_lua_ui_init; } + +void grid_module_xy_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui) { + + grid_led_init(led, 25); + grid_led_lookup_alloc_identity(led, 0, 25); + + grid_ui_model_init(ui, 6); + + for (uint8_t i = 0; i < 5; i++) { + grid_ui_element_touch_init(grid_ui_element_model_init(ui, i)); + } + grid_ui_element_system_init(grid_ui_element_model_init(ui, 5)); + + ui->lua_ui_init_callback = grid_lua_ui_init; +} diff --git a/common/src/c/grid_module.h b/common/src/c/grid_module.h index 10c9fe1b..584ed128 100644 --- a/common/src/c/grid_module.h +++ b/common/src/c/grid_module.h @@ -13,5 +13,6 @@ void grid_module_pbf4_ui_init(struct grid_ain_model* ain, struct grid_led_model* void grid_module_en16_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); void grid_module_ef44_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); void grid_module_octv_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); +void grid_module_xy_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); #endif /* GRID_MODULE_H */ diff --git a/common/src/c/grid_sys.c b/common/src/c/grid_sys.c index 768318ec..86a2f837 100644 --- a/common/src/c/grid_sys.c +++ b/common/src/c/grid_sys.c @@ -240,6 +240,16 @@ int grid_hwcfg_module_is_octv(struct grid_sys_model* sys) { } } +int grid_hwcfg_module_is_xy(struct grid_sys_model* sys) { + + switch (grid_sys_get_hwcfg(sys)) { + case GRID_MODULE_XY_RevH: + return 1; + default: + return 0; + } +} + int grid_hwcfg_module_is_pbf4(struct grid_sys_model* sys) { switch (grid_sys_get_hwcfg(sys)) { diff --git a/common/src/c/grid_sys.h b/common/src/c/grid_sys.h index ee0c35c9..a49c02e4 100644 --- a/common/src/c/grid_sys.h +++ b/common/src/c/grid_sys.h @@ -99,6 +99,7 @@ int grid_hwcfg_module_is_bu16(struct grid_sys_model* sys); int grid_hwcfg_module_is_ef44(struct grid_sys_model* sys); int grid_hwcfg_module_is_en16(struct grid_sys_model* sys); int grid_hwcfg_module_is_octv(struct grid_sys_model* sys); +int grid_hwcfg_module_is_xy(struct grid_sys_model* sys); int grid_hwcfg_module_is_pbf4(struct grid_sys_model* sys); int grid_hwcfg_module_is_po16(struct grid_sys_model* sys); int grid_hwcfg_module_is_tek2(struct grid_sys_model* sys); diff --git a/common/src/c/grid_ui.c b/common/src/c/grid_ui.c index 406882d6..5e383528 100644 --- a/common/src/c/grid_ui.c +++ b/common/src/c/grid_ui.c @@ -64,6 +64,7 @@ void grid_ele_eve_to_value_idx_init(uint8_t map[GRID_PARAMETER_ELEMENT_COUNT][GR map[GRID_PARAMETER_ELEMENT_ENCODER][GRID_PARAMETER_EVENT_ENCODER] = GRID_LUA_FNC_E_ENCODER_VALUE_index; map[GRID_PARAMETER_ELEMENT_ENDLESS][GRID_PARAMETER_EVENT_BUTTON] = GRID_LUA_FNC_EP_BUTTON_VALUE_index; map[GRID_PARAMETER_ELEMENT_ENDLESS][GRID_PARAMETER_EVENT_ENDLESS] = GRID_LUA_FNC_EP_ENDLESS_VALUE_index; + map[GRID_PARAMETER_ELEMENT_TOUCH][GRID_PARAMETER_EVENT_TOUCH] = GRID_LUA_FNC_T_TOUCH_X_index; } struct grid_ui_model grid_ui_state = {0}; diff --git a/d51n20a/gcc/Makefile b/d51n20a/gcc/Makefile index 7e2a11c8..4c2d3355 100644 --- a/d51n20a/gcc/Makefile +++ b/d51n20a/gcc/Makefile @@ -89,6 +89,7 @@ SRCS = \ common/src/c/grid_ui_lcd.c \ common/src/c/grid_ui_potmeter.c \ common/src/c/grid_ui_system.c \ + common/src/c/grid_ui_touch.c \ common/src/c/grid_usb.c \ common/src/c/grid_utask.c \ common/dep/lua-5.4.3/src/dirent.c \ diff --git a/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c b/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c index e5358d6a..e98f91f7 100644 --- a/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c +++ b/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c @@ -22,6 +22,7 @@ #include "grid_esp32_adc.h" #include "grid_esp32_encoder.h" +#include "rom/ets_sys.h" // static const char* TAG = "module_octv"; diff --git a/esp32s3/components/grid_esp32_module_xy/CMakeLists.txt b/esp32s3/components/grid_esp32_module_xy/CMakeLists.txt new file mode 100644 index 00000000..990e7e28 --- /dev/null +++ b/esp32s3/components/grid_esp32_module_xy/CMakeLists.txt @@ -0,0 +1,8 @@ +idf_component_register( + SRCS + "grid_esp32_module_xy.c" + INCLUDE_DIRS + "." + REQUIRES + "grid_common" "grid_esp32_touch" +) diff --git a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c new file mode 100644 index 00000000..b4a1d349 --- /dev/null +++ b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c @@ -0,0 +1,52 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "grid_esp32_module_xy.h" + +#include + +#include "grid_sys.h" +#include "grid_ui.h" +#include "grid_ui_touch.h" + +#include "grid_esp32_touch.h" + +#define XY_I2C_PORT I2C_NUM_0 +#define XY_I2C_SCL_GPIO 40 +#define XY_I2C_SDA_GPIO 41 +#define XY_I2C_FREQ_HZ 100000 + +#define XY_SENSOR_RESET_GPIO 39 +#define XY_SENSOR_INT_GPIO 42 + +void grid_esp32_module_xy_handle_touch(void) { + TOUCHINFO ti = {}; + if (!grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti)) { + return; + } + + for (uint8_t i = 0; i < 5; i++) { + struct grid_ui_element* ele = grid_ui_element_find(&grid_ui_state, i); + if (!ele) { + continue; + } + struct grid_ui_touch_state* state = grid_ui_touch_get_state(ele); + + if (i < ti.count) { + grid_ui_touch_store_input(state, ti.x[i], ti.y[i], ti.area[i]); + } else if (state->area > 0) { + grid_ui_touch_store_input(state, state->x, state->y, 0); + } + } +} + +void grid_esp32_module_xy_init(struct grid_sys_model* sys, struct grid_ui_model* ui) { + + grid_esp32_touch_init(&grid_esp32_touch_state, XY_I2C_PORT, XY_I2C_SCL_GPIO, XY_I2C_SDA_GPIO, XY_SENSOR_RESET_GPIO, XY_SENSOR_INT_GPIO, XY_I2C_FREQ_HZ, NULL); + + grid_ui_bulk_start_with_state(ui, grid_ui_bulk_conf_read, 0, 0, NULL); + grid_ui_bulk_flush(ui); +} diff --git a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h new file mode 100644 index 00000000..6fc056ed --- /dev/null +++ b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "grid_sys.h" +#include "grid_ui.h" + +void grid_esp32_module_xy_init(struct grid_sys_model* sys, struct grid_ui_model* ui); +void grid_esp32_module_xy_handle_touch(void); + +#ifdef __cplusplus +} +#endif diff --git a/esp32s3/components/grid_esp32_port/grid_esp32_port.c b/esp32s3/components/grid_esp32_port/grid_esp32_port.c index 15936239..c776eaf6 100644 --- a/esp32s3/components/grid_esp32_port/grid_esp32_port.c +++ b/esp32s3/components/grid_esp32_port/grid_esp32_port.c @@ -407,6 +407,7 @@ void grid_esp32_port_task(void* arg) { // Watchdog-style tracking for the rolling ID uint8_t watchdog_rollid_last_recv = rollid.last_recv; + uint8_t watchdog_rollid_last_errors = rollid.errors; uint64_t watchdog_rollid_last_time = grid_platform_rtc_get_micros(); // Allocate custom SPI transaction queue @@ -446,25 +447,24 @@ void grid_esp32_port_task(void* arg) { while (1) { - // When the rolling ID changes, reset watchdog + // When the rolling ID changes without error, reset watchdog if (rollid.last_recv != watchdog_rollid_last_recv) { watchdog_rollid_last_time = grid_platform_rtc_get_micros(); - watchdog_rollid_last_recv = rollid.last_recv; - rp2040_active = true; - } + // Only mark RP2040 active if the byte was the expected next value (no new error) + if (rollid.errors == watchdog_rollid_last_errors) { + rp2040_active = true; + } - // Rolling ID watchdog expiration - if (grid_platform_rtc_get_elapsed_time(watchdog_rollid_last_time) > 100000) { + watchdog_rollid_last_recv = rollid.last_recv; + watchdog_rollid_last_errors = rollid.errors; + } - grid_platform_printf("ERROR: SPI frozen\n"); + // Rolling ID watchdog expiration (only if RP2040 was ever seen) + if (rp2040_active && grid_platform_rtc_get_elapsed_time(watchdog_rollid_last_time) > 100000) { watchdog_rollid_last_time = grid_platform_rtc_get_micros(); - - grid_alert_all_set(&grid_led_state, GRID_LED_COLOR_PURPLE, 50); - grid_alert_all_set_frequency(&grid_led_state, -4); - grid_alert_all_set_phase(&grid_led_state, 100); } // Check if USB is connected and start animation diff --git a/esp32s3/components/grid_esp32_touch/CMakeLists.txt b/esp32s3/components/grid_esp32_touch/CMakeLists.txt new file mode 100644 index 00000000..8d7aa5aa --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/CMakeLists.txt @@ -0,0 +1,8 @@ +idf_component_register( + SRCS + "grid_esp32_touch.c" + INCLUDE_DIRS + "." + REQUIRES + "driver" "esp_driver_gpio" "freertos" +) diff --git a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.c b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.c new file mode 100644 index 00000000..5497adee --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.c @@ -0,0 +1,250 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "grid_esp32_touch.h" + +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/ets_sys.h" + +#define MXT_I2C_ADDR 0x4A + +#define MXT_ID_BLOCK_SIZE 7 +#define MXT_OBJ_ENTRY_SIZE 6 + +#define MXT_OBJ_T5 5 +#define MXT_OBJ_T44 44 +#define MXT_OBJ_T100 100 + +DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; + +static struct grid_esp32_touch_model* s_touch_ptr = NULL; + +static void IRAM_ATTR mxt_chg_isr(void* arg) { s_touch_ptr->pending = true; } + +static esp_err_t mxt_write_addr(i2c_port_t port, uint16_t addr) { + uint8_t buf[2] = {(uint8_t)(addr & 0xFF), (uint8_t)(addr >> 8)}; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (MXT_I2C_ADDR << 1) | I2C_MASTER_WRITE, true); + i2c_master_write(cmd, buf, 2, true); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(port, cmd, pdMS_TO_TICKS(100)); + i2c_cmd_link_delete(cmd); + return ret; +} + +static esp_err_t mxt_read_block(i2c_port_t port, uint16_t addr, uint8_t* dest, size_t len) { + esp_err_t ret = mxt_write_addr(port, addr); + if (ret != ESP_OK) + return ret; + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (MXT_I2C_ADDR << 1) | I2C_MASTER_READ, true); + if (len > 1) { + i2c_master_read(cmd, dest, len - 1, I2C_MASTER_ACK); + } + i2c_master_read_byte(cmd, dest + len - 1, I2C_MASTER_NACK); + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(port, cmd, pdMS_TO_TICKS(100)); + i2c_cmd_link_delete(cmd); + return ret; +} + +void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, + grid_process_touch_t process_touch) { + + touch->i2c_port = i2c_port; + touch->scl_gpio = scl_gpio; + touch->sda_gpio = sda_gpio; + touch->reset_gpio = reset_gpio; + touch->int_gpio = int_gpio; + touch->i2c_freq_hz = i2c_freq_hz; + touch->process_touch = process_touch; + touch->t5_addr = 0; + touch->t5_size = 0; + touch->t44_addr = 0; + touch->t100_first_report_id = 0; + + // I2C master + i2c_config_t conf = {0}; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = sda_gpio; + conf.scl_io_num = scl_gpio; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = i2c_freq_hz; + i2c_param_config(i2c_port, &conf); + esp_err_t ret = i2c_driver_install(i2c_port, I2C_MODE_MASTER, 0, 0, 0); + if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { + ets_printf("MXT i2c_driver_install failed: %d\r\n", ret); + return; + } + + // RST as output, INT/CHG as input with pull-up + gpio_config_t io_conf = {0}; + io_conf.pin_bit_mask = (1ULL << reset_gpio); + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.intr_type = GPIO_INTR_DISABLE; + gpio_config(&io_conf); + + io_conf.pin_bit_mask = (1ULL << int_gpio); + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); + + // Reset sequence — hold RST low 100ms, then wait 300ms for chip to initialise + gpio_set_level(reset_gpio, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(reset_gpio, 1); + vTaskDelay(pdMS_TO_TICKS(300)); + + // Check CHG state as a diagnostic (not a hard gate) + ets_printf("MXT CHG after reset: %s\r\n", gpio_get_level(int_gpio) == 0 ? "LOW (ready)" : "HIGH"); + + // Scan I2C bus to confirm device is visible + grid_esp32_touch_scan(touch); + + // Read ID block at address 0 + uint8_t id[MXT_ID_BLOCK_SIZE]; + ret = mxt_read_block(i2c_port, 0, id, MXT_ID_BLOCK_SIZE); + if (ret != ESP_OK) { + ets_printf("MXT ID block read failed: %d\r\n", ret); + return; + } + ets_printf("MXT family=0x%02X variant=0x%02X fw=%d.%d.%02X matrix=%dx%d objects=%d\r\n", id[0], id[1], id[2] >> 4, id[2] & 0x0F, id[3], id[4], id[5], id[6]); + + // Parse object table to find T5, T44, T100 + uint8_t num_objects = id[6]; + uint16_t table_ptr = MXT_ID_BLOCK_SIZE; + uint8_t report_id = 1; + + for (uint8_t i = 0; i < num_objects; i++) { + uint8_t entry[MXT_OBJ_ENTRY_SIZE]; + ret = mxt_read_block(i2c_port, table_ptr, entry, MXT_OBJ_ENTRY_SIZE); + if (ret != ESP_OK) { + ets_printf("MXT object table read failed at entry %d\r\n", i); + return; + } + table_ptr += MXT_OBJ_ENTRY_SIZE; + + uint8_t obj_type = entry[0]; + uint16_t obj_addr = entry[1] | ((uint16_t)entry[2] << 8); + uint8_t num_inst = entry[4]; // stored as instances-1 + uint8_t num_rids = entry[5]; + + if (obj_type == MXT_OBJ_T5) { + touch->t5_addr = obj_addr; + touch->t5_size = entry[3]; // read size-1 bytes, skipping trailing checksum + } else if (obj_type == MXT_OBJ_T44) { + touch->t44_addr = obj_addr; + } else if (obj_type == MXT_OBJ_T100) { + touch->t100_first_report_id = report_id; + } + + if (num_rids > 0) { + report_id += (num_inst + 1) * num_rids; + } + } + + if (touch->t5_addr && touch->t44_addr && touch->t100_first_report_id) { + ets_printf("MXT init OK: T5@0x%04X(sz=%d) T44@0x%04X T100 first_rid=%d\r\n", touch->t5_addr, touch->t5_size, touch->t44_addr, touch->t100_first_report_id); + + } else { + ets_printf("MXT init FAILED: T5=0x%04X T44=0x%04X T100_rid=%d\r\n", touch->t5_addr, touch->t44_addr, touch->t100_first_report_id); + return; + } + + // Interrupt on falling edge of CHG — sets pending flag, serviced in main loop + s_touch_ptr = touch; + esp_err_t isr_ret; + isr_ret = gpio_install_isr_service(0); + ets_printf("MXT gpio_install_isr_service: %d\r\n", isr_ret); + isr_ret = gpio_set_intr_type(int_gpio, GPIO_INTR_NEGEDGE); + ets_printf("MXT gpio_set_intr_type: %d\r\n", isr_ret); + isr_ret = gpio_isr_handler_add(int_gpio, mxt_chg_isr, NULL); + ets_printf("MXT gpio_isr_handler_add: %d\r\n", isr_ret); + isr_ret = gpio_intr_enable(int_gpio); + ets_printf("MXT gpio_intr_enable: %d\r\n", isr_ret); + touch->pending = true; +} + +void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { + + ets_printf("I2C scan (SCL=GPIO%d SDA=GPIO%d):\r\n", touch->scl_gpio, touch->sda_gpio); + int found = 0; + for (uint8_t addr = 0x08; addr < 0x78; addr++) { + 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); + esp_err_t ret = i2c_master_cmd_begin(touch->i2c_port, cmd, pdMS_TO_TICKS(10)); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + ets_printf(" found device at 0x%02X\r\n", addr); + found++; + } + } + if (found == 0) { + ets_printf(" no devices found\r\n"); + } +} + +int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI) { + if (!pTI) + return 0; + pTI->count = 0; + + if (!touch->t44_addr || !touch->t5_addr || !touch->t100_first_report_id) { + return 0; + } + + if (!touch->pending) { + return 0; + } + touch->pending = false; + + uint8_t msg_count = 0; + esp_err_t ret = mxt_read_block(touch->i2c_port, touch->t44_addr, &msg_count, 1); + if (ret != ESP_OK || msg_count == 0) { + return 0; + } + + uint8_t msg[10]; + uint8_t finger_start = touch->t100_first_report_id + 2; + + for (uint8_t i = 0; i < msg_count; i++) { + ret = mxt_read_block(touch->i2c_port, touch->t5_addr, msg, touch->t5_size); + if (ret != ESP_OK) + break; + + uint8_t report_id = msg[0]; + + if (report_id >= finger_start && report_id < finger_start + 5) { + uint8_t finger_idx = report_id - finger_start; + uint8_t event = msg[1] & 0x0F; + + if (finger_idx + 1 > pTI->count) { + pTI->count = finger_idx + 1; + } + pTI->x[finger_idx] = msg[2] | ((uint16_t)msg[3] << 8); + pTI->y[finger_idx] = msg[4] | ((uint16_t)msg[5] << 8); + + if (event == 4 || event == 1) { // touch down or move + pTI->area[finger_idx] = 50; + } else if (event == 5) { // touch up + pTI->area[finger_idx] = 0; + } + } + } + + return (pTI->count > 0); +} diff --git a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h new file mode 100644 index 00000000..70bed729 --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h @@ -0,0 +1,61 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "driver/gpio.h" +#include "driver/i2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __TOUCHINFO_STRUCT__ +#define __TOUCHINFO_STRUCT__ +typedef struct _fttouchinfo { + int count; // number of pressed keys + uint32_t key_state; // T15 key bitmap (1 bit per key, up to 32 keys) + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; +} TOUCHINFO; +#endif + +typedef void (*grid_process_touch_t)(void); + +struct grid_esp32_touch_model { + i2c_port_t i2c_port; + gpio_num_t scl_gpio; + gpio_num_t sda_gpio; + gpio_num_t reset_gpio; + gpio_num_t int_gpio; + uint32_t i2c_freq_hz; + grid_process_touch_t process_touch; + + uint16_t t5_addr; + uint8_t t5_size; + uint16_t t44_addr; + uint8_t t100_first_report_id; + + volatile bool pending; +}; + +extern struct grid_esp32_touch_model grid_esp32_touch_state; + +void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, + grid_process_touch_t process_touch); + +void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch); + +int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI); + +#ifdef __cplusplus +} +#endif diff --git a/esp32s3/main/grid_esp32s3.c b/esp32s3/main/grid_esp32s3.c index 0145293a..c5bc7341 100644 --- a/esp32s3/main/grid_esp32s3.c +++ b/esp32s3/main/grid_esp32s3.c @@ -48,6 +48,8 @@ #include "grid_esp32_module_pbf4.h" #include "grid_esp32_module_po16.h" #include "grid_esp32_module_vsnx.h" +#include "grid_esp32_module_xy.h" +#include "grid_esp32_touch.h" #include "pico_firmware.h" #include "grid_esp32_trace.h" @@ -445,6 +447,8 @@ void app_main(void) { grid_module_ef44_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state); } else if (grid_hwcfg_module_is_octv(&grid_sys_state)) { grid_module_octv_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state); + } else if (grid_hwcfg_module_is_xy(&grid_sys_state)) { + grid_module_xy_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state); } else if (grid_hwcfg_module_is_tek2(&grid_sys_state) || grid_hwcfg_module_is_vsnx(&grid_sys_state)) { grid_module_vsnx_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state, &grid_sys_state); } else { @@ -558,6 +562,8 @@ void app_main(void) { grid_esp32_module_ef44_init(&grid_sys_state, &grid_ui_state, &grid_esp32_adc_state, &grid_esp32_encoder_state, &grid_config_state, &grid_cal_state); } else if (grid_hwcfg_module_is_octv(&grid_sys_state)) { grid_esp32_module_octv_init(&grid_sys_state, &grid_ui_state, &grid_esp32_adc_state, &grid_esp32_encoder_state, &grid_config_state, &grid_cal_state); + } else if (grid_hwcfg_module_is_xy(&grid_sys_state)) { + grid_esp32_module_xy_init(&grid_sys_state, &grid_ui_state); } else if (grid_hwcfg_module_is_tek2(&grid_sys_state) || grid_hwcfg_module_is_vsnx(&grid_sys_state)) { grid_esp32_module_vsnx_init(&grid_sys_state, &grid_ui_state, &grid_esp32_adc_state, &grid_config_state, &grid_cal_state, grid_esp32_lcd_states); } else { @@ -619,6 +625,10 @@ void app_main(void) { vmp_flushed = true; } + if (grid_hwcfg_module_is_xy(&grid_sys_state) && grid_esp32_touch_state.pending) { + grid_esp32_module_xy_handle_touch(); + } + // Run microtasks grid_esp32_utask_led(&timer_led); diff --git a/mxt144.pdf b/mxt144.pdf new file mode 100644 index 00000000..6d3d5c90 Binary files /dev/null and b/mxt144.pdf differ