From 3a08cb5119005c197b8b847e785b23cea78d1530 Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Thu, 29 Jan 2026 14:16:19 -0500 Subject: [PATCH] improve touch with pooling --- basic1.cpp | 225 ++++++++++++++++++++++++++++++------------ lib/ft6336u/ft6336u.c | 178 ++++++++++++++++++++++++++++++--- lib/ft6336u/ft6336u.h | 70 +++++++++++++ 3 files changed, 398 insertions(+), 75 deletions(-) diff --git a/basic1.cpp b/basic1.cpp index 291efd5..f66db34 100644 --- a/basic1.cpp +++ b/basic1.cpp @@ -8,6 +8,7 @@ #include "pico/stdlib.h" #include "pico/binary_info.h" +#include "hardware/sync.h" #include "board_config.h" // Board-specific pin configuration #include "sd_card.h" #include @@ -24,6 +25,67 @@ bi_decl(bi_program_description("4.0\" TFT ST7796 with Touch and SD Card Demo")); bi_decl(bi_program_version_string("0.1")); bi_decl(bi_program_build_date_string(__DATE__)); +// Touch interrupt handling +volatile bool touch_interrupt_flag = false; +volatile bool touch_event_down = false; +LowLevelTouch* touch = nullptr; + +/** + * @brief Touch interrupt callback handler + * + * Called automatically by hardware when INT pin changes state: + * - Falling edge: Touch detected (INT goes LOW) + * - Rising edge: Touch released (INT goes HIGH) + * + * This runs in interrupt context, so keep it fast - just set a flag + * + * @param gpio GPIO pin number that triggered the interrupt + * @param events Event mask (GPIO_IRQ_EDGE_FALL and/or GPIO_IRQ_EDGE_RISE) + */ +void touch_interrupt_handler(uint gpio, uint32_t events) { + // Set flag to indicate touch event occurred + // Main loop will handle the actual touch reading + touch_interrupt_flag = true; + + // Optional: track which edge triggered (for debugging) + if (events & GPIO_IRQ_EDGE_FALL) { + touch_event_down = true; + printf("Touch DOWN event detected\n"); + } + if (events & GPIO_IRQ_EDGE_RISE) { + touch_event_down = false; + printf("Touch UP event detected\n"); + } + TouchData touch_data; + touch->read_touch(&touch_data); + + + int16_t x = touch_data.points[0].x; + int16_t y = touch_data.points[0].y; + uint8_t event = touch_data.points[0].event; + uint8_t id = touch_data.points[0].id; + uint8_t weight = touch_data.points[0].pressure; + uint8_t gesture = touch_data.gesture; + + // Display detailed touch information including weight and gesture + printf("Touch: X=%d Y=%d Event=%d ID=%d Weight=%d\n", + x, y, event, id, weight); + + // Display gesture if detected (non-zero) + if (gesture != 0) { + const char* gesture_name = "Unknown"; + switch(gesture) { + case 0x10: gesture_name = "Move Up"; break; + case 0x14: gesture_name = "Move Right"; break; + case 0x18: gesture_name = "Move Down"; break; + case 0x1C: gesture_name = "Move Left"; break; + case 0x48: gesture_name = "Zoom In"; break; + case 0x49: gesture_name = "Zoom Out"; break; + } + printf(" Gesture=0x%02X (%s)\n", gesture, gesture_name); + } +} + // Screen dimensions and configuration from board_config.h const int V_WIDTH = DISPLAY_WIDTH; const int V_HEIGHT = DISPLAY_HEIGHT; @@ -91,12 +153,17 @@ int main() refresh_screen(bit_buffer, display); // Initialize touch screen using abstraction - LowLevelTouch* touch = LowLevelTouch::create((TouchType)TOUCH_TYPE_SELECTED, V_WIDTH, V_HEIGHT, + touch = LowLevelTouch::create((TouchType)TOUCH_TYPE_SELECTED, V_WIDTH, V_HEIGHT, TOUCH_SWAP_XY, TOUCH_INVERT_X, TOUCH_INVERT_Y); if (touch) { printf("Touch initialized successfully\n"); + // Set up interrupt-driven touch detection + printf("Setting up touch interrupt callback...\n"); + touch->set_interrupt_callback(touch_interrupt_handler); + printf("Touch interrupt enabled on INT pin (falling and rising edges)\n"); + // Run communication test if available // Note: Commented out as it may hang on some hardware configurations printf("\nRunning touch reliability test...\n"); @@ -107,11 +174,11 @@ int main() } // Test SD card and FatFS - if (sd_card_init_with_board_config()) { - sd_card_test_fatfs(); - } else { - printf("SD Card initialization failed or no card present\n"); - } + // if (sd_card_init_with_board_config()) { + // sd_card_test_fatfs(); + // } else { + // printf("SD Card initialization failed or no card present\n"); + // } // Main loop - handle touch events int last_x = -1, last_y = -1; @@ -124,74 +191,108 @@ int main() int touch_success_count = 0; printf("Entering main touch loop...\n"); + printf("Touch system uses interrupt-driven detection:\n"); + printf(" - Hardware interrupt triggers on INT pin state changes\n"); + printf(" - Falling edge (HIGH->LOW) = Touch detected\n"); + printf(" - Rising edge (LOW->HIGH) = Touch released\n"); + printf(" - No CPU polling needed - interrupt wakes us up!\n"); + printf(" - Gesture support enabled in trigger mode\n"); while (1) { - // Always sleep to prevent tight loop and allow other operations - sleep_us(100); + // Sleep until interrupt wakes us up (very power efficient!) + // Te(); // Wait For Event - CPU sleeps until interrupt or evenurs + __wfi(); // Wait For Interrupt - CPU sleeps until any interrupt - // Check INT pin directly (LOW = touch detected, no I2C transaction needed!) - // Much faster than I2C read and doesn't interfere with other operations - bool int_pin_low = !gpio_get(TOUCH_INT_PIN); + // Check if our touch interrupt flag was set + if (!touch_interrupt_flag) { + continue; // Woken by different interrupt, go back to sleep + } - // Only process if INT pin indicates touch data available - if (int_pin_low) { + // Clear the flag + touch_interrupt_flag = false; + + while(touch_event_down){ uint32_t now = to_ms_since_boot(get_absolute_time()); - + // Check if enough time has passed since last touch check (debounce) if (now - last_touch_time < debounce_ms) { //continue; } - // Now read full touch data via I2C - TouchData touch_data; - if (!touch->read_touch(&touch_data) || touch_data.touch_count == 0) { - // Read failed or no actual touch data - touch_fail_count++; - was_touched = false; - last_x = -1; - last_y = -1; - last_touch_time = now; - continue; - } + //printf("Touch interrupt event detected (event_down=%d)\n", touch_event_down); - touch_success_count++; - - int16_t x = touch_data.points[0].x; - int16_t y = touch_data.points[0].y; - uint8_t event = touch_data.points[0].event; - uint8_t id = touch_data.points[0].id; - uint8_t weight = touch_data.points[0].pressure; - uint8_t gesture = touch_data.gesture; - - printf("Touch: X=%d Y=%d Event=%d ID=%d Weight=%d Gesture=0x%02X [S:%d F:%d]\n", - x, y, event, id, weight, gesture, - touch_success_count, touch_fail_count); - - - // Check if touch is in title area to clear screen - - // Draw line from last position (for smooth drawing) - if (last_x >= 0 && last_y >= 0) { - int dx = abs(x - last_x); - int dy = abs(y - last_y); - // Only draw line if movement is reasonable (filter noise) - if (dx < 50 && dy < 50) { - renderer.draw_line(last_x, last_y, x, y, true); - refresh_screen(bit_buffer, display); - } + // Touch interrupt occurred - read the data + // is_touched() will check INT pin and confirm via I2C if needed + //if (touch && touch->is_touched()) { + // Now read full touch data via I2C (already confirmed by INT pin) + TouchData touch_data; + if (!touch->read_touch(&touch_data)) { + // Read failed or no actual touch data + touch_fail_count++; + //was_touched = false; + //last_x = -1; + //last_y = -1; + //last_touch_time = now; + continue; } - last_x = x; - last_y = y; - - was_touched = true; - last_touch_time = now; - } else { - // Reset last position when not touching - if (was_touched) { - last_x = -1; - last_y = -1; - was_touched = false; - } + touch_success_count++; + + int16_t x = touch_data.points[0].x; + int16_t y = touch_data.points[0].y; + uint8_t event = touch_data.points[0].event; + uint8_t id = touch_data.points[0].id; + uint8_t weight = touch_data.points[0].pressure; + uint8_t gesture = touch_data.gesture; + + // Display detailed touch information including weight and gesture + // printf("Touch: X=%d Y=%d Event=%d ID=%d Weight=%d", + // x, y, event, id, weight); + + // Display gesture if detected (non-zero) + if (gesture != 0) { + const char* gesture_name = "Unknown"; + switch(gesture) { + case 0x10: gesture_name = "Move Up"; break; + case 0x14: gesture_name = "Move Right"; break; + case 0x18: gesture_name = "Move Down"; break; + case 0x1C: gesture_name = "Move Left"; break; + case 0x48: gesture_name = "Zoom In"; break; + case 0x49: gesture_name = "Zoom Out"; break; + } + printf(" Gesture=0x%02X (%s)", gesture, gesture_name); + } + + // printf(" [Success:%d Fail:%d]\n", touch_success_count, touch_fail_count); + + + // Check if touch is in title area to clear screen + + // Draw line from last position (for smooth drawing) + if (last_x >= 0 && last_y >= 0) { + int dx = abs(x - last_x); + int dy = abs(y - last_y); + // Only draw line if movement is reasonable (filter noise) + //if (dx < 50 && dy < 50) { + renderer.draw_line(last_x, last_y, x, y, true); + + //} + } + + last_x = x; + last_y = y; + + was_touched = true; + last_touch_time = now; + //} else { + // INT pin triggered but no touch data (likely release event) + + //} + } + if (was_touched) { + last_x = -1; + last_y = -1; + was_touched = false; + refresh_screen(bit_buffer, display); } } diff --git a/lib/ft6336u/ft6336u.c b/lib/ft6336u/ft6336u.c index 46319a4..acd6c56 100644 --- a/lib/ft6336u/ft6336u.c +++ b/lib/ft6336u/ft6336u.c @@ -137,17 +137,54 @@ bool ft6336u_init(const ft6336u_config_t *config) { printf("[FT6336U] WARNING: Failed to set device mode\n"); } - // Enable trigger mode for better gesture and interrupt support - printf("[FT6336U] Enabling trigger mode...\n"); - if (!ft6336u_write_reg(FT6336U_REG_G_MODE, FT6336U_G_MODE_TRIGGER)) { + // Set CTRL mode to keep active (better interrupt responsiveness) + printf("[FT6336U] Setting CTRL mode to keep active...\n"); + if (!ft6336u_write_reg(FT6336U_REG_CTRL, FT6336U_CTRL_KEEP_ACTIVE_MODE)) { + printf("[FT6336U] WARNING: Failed to set CTRL mode\n"); + } + + // Enable polling mode - INT pin stays LOW while touched, goes HIGH when released + printf("[FT6336U] Enabling polling mode...\n"); + if (!ft6336u_write_reg(FT6336U_REG_G_MODE, FT6336U_G_MODE_POLLING)) { printf("[FT6336U] WARNING: Failed to set G_MODE\n"); } - // Verify gesture mode was set + // Configure gesture parameters for better detection + printf("[FT6336U] Configuring gesture detection parameters...\n"); + + // Radian value: smaller = stricter angles (default ~16, using 10 for easier detection) + ft6336u_set_radian_value(10); + + // Offset values: starting point for gesture detection (using 20 pixels) + ft6336u_set_offset_left_right(20); + ft6336u_set_offset_up_down(20); + + // Distance thresholds: minimum movement for gesture (using 40 pixels for easier detection) + ft6336u_set_distance_left_right(40); + ft6336u_set_distance_up_down(40); + + // Zoom distance: minimum pinch/spread distance (using 80) + ft6336u_set_distance_zoom(80); + + // Verify modes and gesture parameters were set + uint8_t ctrl_mode = ft6336u_get_ctrl_mode(); uint8_t g_mode = ft6336u_get_g_mode(); + printf("[FT6336U] CTRL_MODE: 0x%02X (%s)\n", + ctrl_mode, ctrl_mode == FT6336U_CTRL_KEEP_ACTIVE_MODE ? "keep active" : "monitor"); printf("[FT6336U] G_MODE: 0x%02X (%s mode)\n", g_mode, g_mode == FT6336U_G_MODE_TRIGGER ? "trigger" : "polling"); + // Display gesture parameter values + printf("[FT6336U] Gesture Parameters:\n"); + printf(" Radian: %d, Offset LR: %d, Offset UD: %d\n", + ft6336u_get_radian_value(), + ft6336u_get_offset_left_right(), + ft6336u_get_offset_up_down()); + printf(" Distance LR: %d, Distance UD: %d, Zoom: %d\n", + ft6336u_get_distance_left_right(), + ft6336u_get_distance_up_down(), + ft6336u_get_distance_zoom()); + printf("[FT6336U] Initialization complete!\n"); return true; } @@ -226,15 +263,21 @@ bool ft6336u_read_touch(ft6336u_touch_data_t *data) { bool ft6336u_is_touched(void) { if (g_config == NULL) return false; - // More reliable: Read TD_STATUS register directly - // INT pin can be unreliable due to timing/noise - uint8_t td_status; - if (!ft6336u_read_reg(FT6336U_REG_TD_STATUS, &td_status)) { - return false; // I2C error, assume not touched + // In trigger mode, INT pin goes LOW when touched + // This is faster than reading via I2C + if (!gpio_get(g_config->gpio_int)) { + return true; + //INT pin is LOW, likely touched - confirm with I2C read + uint8_t td_status; + if (!ft6336u_read_reg(FT6336U_REG_TD_STATUS, &td_status)) { + return false; // I2C error, assume not touched + } + uint8_t touch_count = td_status & 0x0F; + return touch_count > 0; } - uint8_t touch_count = td_status & 0x0F; - return touch_count > 0; + // INT pin is HIGH, no touch + return false; } uint8_t ft6336u_get_chip_id(void) { @@ -260,9 +303,12 @@ uint8_t ft6336u_get_firmware_version(void) { void ft6336u_set_interrupt_callback(void (*callback)(uint gpio, uint32_t events)) { if (g_config == NULL || callback == NULL) return; - // Enable interrupt on falling edge (touch detected) + // In trigger mode: + // - INT pin goes LOW (falling edge) when touch is detected + // - INT pin goes HIGH (rising edge) when touch is released + // Enable interrupts on both edges for full touch lifecycle tracking gpio_set_irq_enabled_with_callback(g_config->gpio_int, - GPIO_IRQ_EDGE_FALL, + GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, callback); } @@ -329,3 +375,109 @@ uint8_t ft6336u_get_power_mode(void) { } return pwr_mode; } + +bool ft6336u_set_ctrl_mode(uint8_t mode) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_CTRL, mode); +} + +uint8_t ft6336u_get_ctrl_mode(void) { + if (g_config == NULL) return 0xFF; + + uint8_t ctrl_mode; + if (!ft6336u_read_reg(FT6336U_REG_CTRL, &ctrl_mode)) { + return 0xFF; + } + return ctrl_mode; +} + +bool ft6336u_get_int_pin_state(void) { + if (g_config == NULL) return true; // Default to HIGH (no interrupt) + // In trigger mode: LOW = touch active, HIGH = no touch + return gpio_get(g_config->gpio_int); +} + +// Gesture parameter configuration functions +uint8_t ft6336u_get_radian_value(void) { + if (g_config == NULL) return 0xFF; + uint8_t value; + if (!ft6336u_read_reg(FT6336U_REG_RADIAN_VALUE, &value)) { + return 0xFF; + } + return value; +} + +bool ft6336u_set_radian_value(uint8_t value) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_RADIAN_VALUE, value); +} + +uint8_t ft6336u_get_offset_left_right(void) { + if (g_config == NULL) return 0xFF; + uint8_t value; + if (!ft6336u_read_reg(FT6336U_REG_OFFSET_LEFT_RIGHT, &value)) { + return 0xFF; + } + return value; +} + +bool ft6336u_set_offset_left_right(uint8_t value) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_OFFSET_LEFT_RIGHT, value); +} + +uint8_t ft6336u_get_offset_up_down(void) { + if (g_config == NULL) return 0xFF; + uint8_t value; + if (!ft6336u_read_reg(FT6336U_REG_OFFSET_UP_DOWN, &value)) { + return 0xFF; + } + return value; +} + +bool ft6336u_set_offset_up_down(uint8_t value) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_OFFSET_UP_DOWN, value); +} + +uint8_t ft6336u_get_distance_left_right(void) { + if (g_config == NULL) return 0xFF; + uint8_t value; + if (!ft6336u_read_reg(FT6336U_REG_DISTANCE_LEFT_RIGHT, &value)) { + return 0xFF; + } + return value; +} + +bool ft6336u_set_distance_left_right(uint8_t value) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_DISTANCE_LEFT_RIGHT, value); +} + +uint8_t ft6336u_get_distance_up_down(void) { + if (g_config == NULL) return 0xFF; + uint8_t value; + if (!ft6336u_read_reg(FT6336U_REG_DISTANCE_UP_DOWN, &value)) { + return 0xFF; + } + return value; +} + +bool ft6336u_set_distance_up_down(uint8_t value) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_DISTANCE_UP_DOWN, value); +} + +uint8_t ft6336u_get_distance_zoom(void) { + if (g_config == NULL) return 0xFF; + uint8_t value; + if (!ft6336u_read_reg(FT6336U_REG_DISTANCE_ZOOM, &value)) { + return 0xFF; + } + return value; +} + +bool ft6336u_set_distance_zoom(uint8_t value) { + if (g_config == NULL) return false; + return ft6336u_write_reg(FT6336U_REG_DISTANCE_ZOOM, value); +} diff --git a/lib/ft6336u/ft6336u.h b/lib/ft6336u/ft6336u.h index f51400e..bfc65cd 100644 --- a/lib/ft6336u/ft6336u.h +++ b/lib/ft6336u/ft6336u.h @@ -37,12 +37,25 @@ extern "C" { #define FT6336U_REG_P2_WEIGHT 0x0D #define FT6336U_REG_P2_MISC 0x0E +// Gesture parameter registers (for tuning gesture detection) +#define FT6336U_REG_RADIAN_VALUE 0x91 // Gesture angle threshold +#define FT6336U_REG_OFFSET_LEFT_RIGHT 0x92 // Horizontal gesture offset +#define FT6336U_REG_OFFSET_UP_DOWN 0x93 // Vertical gesture offset +#define FT6336U_REG_DISTANCE_LEFT_RIGHT 0x94 // Horizontal distance threshold +#define FT6336U_REG_DISTANCE_UP_DOWN 0x95 // Vertical distance threshold +#define FT6336U_REG_DISTANCE_ZOOM 0x96 // Zoom gesture distance + +#define FT6336U_REG_CTRL 0x86 // Control mode register #define FT6336U_REG_CHIPID 0xA3 // Chip ID (should read 0x64) #define FT6336U_REG_G_MODE 0xA4 // Interrupt mode (polling or trigger) #define FT6336U_REG_POWER_MODE 0xA5 // Power mode #define FT6336U_REG_FIRMID 0xA6 #define FT6336U_REG_VENDID 0xA8 +// CTRL_MODE values +#define FT6336U_CTRL_KEEP_ACTIVE_MODE 0x00 // Stay in active mode (better for interrupts) +#define FT6336U_CTRL_SWITCH_TO_MONITOR 0x01 // Auto-enter monitor mode (lower power) + // G_MODE values #define FT6336U_G_MODE_POLLING 0x00 #define FT6336U_G_MODE_TRIGGER 0x01 @@ -150,6 +163,63 @@ uint8_t ft6336u_get_g_mode(void); */ uint8_t ft6336u_get_power_mode(void); +/** + * Set CTRL mode (active vs monitor mode) + * @param mode FT6336U_CTRL_KEEP_ACTIVE_MODE or FT6336U_CTRL_SWITCH_TO_MONITOR + * @return true if successful + */ +bool ft6336u_set_ctrl_mode(uint8_t mode); + +/** + * Get current CTRL mode + * @return Current CTRL mode or 0xFF on error + */ +uint8_t ft6336u_get_ctrl_mode(void); + +/** + * Read the INT pin state directly + * @return true if HIGH (no touch), false if LOW (touch active) + * Note: In trigger mode, INT pin is active LOW + */ +bool ft6336u_get_int_pin_state(void); + +// Gesture parameter configuration (for tuning gesture detection) +/** + * Get/Set radian value (gesture angle threshold) + */ +uint8_t ft6336u_get_radian_value(void); +bool ft6336u_set_radian_value(uint8_t value); + +/** + * Get/Set horizontal gesture offset + */ +uint8_t ft6336u_get_offset_left_right(void); +bool ft6336u_set_offset_left_right(uint8_t value); + +/** + * Get/Set vertical gesture offset + */ +uint8_t ft6336u_get_offset_up_down(void); +bool ft6336u_set_offset_up_down(uint8_t value); + +/** + * Get/Set horizontal distance threshold for gestures + */ +uint8_t ft6336u_get_distance_left_right(void); +bool ft6336u_set_distance_left_right(uint8_t value); + +/** + * Get/Set vertical distance threshold for gestures + */ +uint8_t ft6336u_get_distance_up_down(void); +bool ft6336u_set_distance_up_down(uint8_t value); + +/** + * Get/Set zoom gesture distance threshold + */ +uint8_t ft6336u_get_distance_zoom(void); +bool ft6336u_set_distance_zoom(uint8_t value); + #ifdef __cplusplus } #endif