Touch problem with GSL1680 capacitive touch and LVGL (Squareline)

Description

I just replaced my old 3.5" SPI TFT Touch display with a larger 5" parallel display (SSD1963) with GSL1680 capacitive touch panel. When I implement the code into my existing project made from Squareline (LVGL + TFT_eSPI), display is fine but I get a ~900ms lag between touch readings so LVGL thinks that I “untouch” the screen instantly then re-read a touch almost a second later, making any slider (or any long press actions) impossible to use.

What MCU/Processor/Board and compiler are you using?

ESP32S3-N32R8 / Arduino IDE 2.2.1

What LVGL version are you using?

8.3.10

What SquareLine version are you using?

1.3.2

What do you want to achieve?

Be able to drag slider smoothly and use long-press options

What have you tried so far?

1- Created a timer (10ms intervals) to get the INTRPT pin status and when HIGH, put global touched bool variable to true and put X and Y values in global variables accessible by the my_touchpad_read function.

2- Adapt the code directly in the my_touchpad_read function without using global variables.

Code to reproduce (MY CODE)

#include <GSL1680.h>

#define WAKE 19
#define INTRPT 18

GSL1680 TS = GSL1680();

...

void my_touchpad_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data) {
    if (digitalRead(INTRPT) == HIGH) {
      TS.dataread();
      data->state = LV_INDEV_STATE_PR;
      data->point.x = TS.ts_event.x1 & 0x0fff;
      data->point.y = TS.ts_event.y1 & 0x0fff;
      Serial.println("X=" + (String)TS.ts_event.x1 + " Y=" + (String)TS.ts_event.y1); //Display touch coordinates 
    }else{
      data->state = LV_INDEV_STATE_REL;
      Serial.println("NO DATA"); //Display when no touch is detected
    }
}

...

void setup() {
  Serial.begin(115200); /* prepare for possible serial debug */

  TS.begin(WAKE, INTRPT);

...

```cpp
## Code to reproduce (DEMO CODE)
```c
#include <SPI.h>
#include <GSL1680.h>
// Touch Screen Pins - modify acording to connections
#define WAKE 19
#define INTRPT 18
GSL1680 TS = GSL1680(true,true); // Serial debug active
// GSL1680 TS = GSL1680();      No serial debug
void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.println(""); 
  Serial.println(" Arduino DUE + GSL1680 library ");
  Serial.println("");
  TS.begin(WAKE, INTRPT);  // Initialize GSL1680
}

void loop() {
  if (digitalRead(INTRPT) == HIGH) {
    TS.dataread();
    int X1 = TS.ts_event.x1 & 0x0fff;
    int Y1 = TS.ts_event.y1 & 0x0fff;
    if (TS.ts_event.fingers >= 1) {
        Serial.print("Fingers : ");
        Serial.print(TS.ts_event.fingers); // Fingers counter
        Serial.print(" - ");
        Serial.print(X1);                  // X1 coordinate
        Serial.print(" - ");
        Serial.print(Y1);                  // Y1 coordinate
        Serial.println("");
    }
  }
}

Serial output with MY code while continuously touching display

09:49:30.358 -> X=722 Y=4219
09:49:30.358 -> NO DATA
09:49:30.390 -> NO DATA
09:49:30.422 -> NO DATA
09:49:30.455 -> NO DATA
09:49:30.487 -> NO DATA
09:49:30.519 -> NO DATA
09:49:30.552 -> NO DATA
09:49:30.585 -> NO DATA
09:49:30.618 -> NO DATA
09:49:30.651 -> NO DATA
09:49:30.684 -> NO DATA
09:49:30.717 -> NO DATA
09:49:30.750 -> NO DATA
09:49:30.783 -> NO DATA
09:49:30.816 -> NO DATA
09:49:30.849 -> NO DATA
09:49:30.882 -> NO DATA
09:49:30.915 -> NO DATA
09:49:30.947 -> NO DATA
09:49:30.947 -> NO DATA
09:49:30.980 -> NO DATA
09:49:31.012 -> NO DATA
09:49:31.044 -> NO DATA
09:49:31.076 -> NO DATA
09:49:31.109 -> NO DATA
09:49:31.143 -> NO DATA
09:49:31.175 -> NO DATA
09:49:31.208 -> NO DATA
09:49:31.242 -> X=725 Y=4217
09:49:31.274 -> NO DATA
09:49:31.307 -> NO DATA
09:49:31.340 -> NO DATA
09:49:31.373 -> NO DATA
09:49:31.406 -> NO DATA
09:49:31.438 -> NO DATA
09:49:31.471 -> NO DATA
09:49:31.504 -> NO DATA
09:49:31.537 -> NO DATA
09:49:31.570 -> NO DATA
09:49:31.602 -> NO DATA
09:49:31.602 -> NO DATA
09:49:31.634 -> NO DATA
09:49:31.666 -> NO DATA
09:49:31.700 -> NO DATA
09:49:31.733 -> NO DATA
09:49:31.767 -> NO DATA
09:49:31.798 -> NO DATA
09:49:31.831 -> NO DATA
09:49:31.864 -> NO DATA
09:49:31.897 -> NO DATA
09:49:31.930 -> NO DATA
09:49:31.963 -> NO DATA
09:49:31.996 -> NO DATA
09:49:32.029 -> NO DATA
09:49:32.062 -> NO DATA
09:49:32.095 -> NO DATA
09:49:32.128 -> NO DATA
09:49:32.161 -> X=725 Y=4217
09:49:32.193 -> NO DATA
09:49:32.193 -> NO DATA
09:49:32.226 -> NO DATA
09:49:32.289 -> X=726 Y=4217
09:49:32.289 -> NO DATA
09:49:32.321 -> NO DATA
09:49:32.354 -> NO DATA
09:49:32.387 -> NO DATA
09:49:32.420 -> NO DATA
09:49:32.453 -> NO DATA
09:49:32.487 -> NO DATA

Library used for capacitive touch

Datasheets for display and capacitive touch

After playing around I finally got it to work! So for anyone experiencing the same issue, here is my fix (not perfect but 99% better than original post):

#include <GSL1680.h>

#define WAKE 19
#define INTRPT 18

GSL1680 TS = GSL1680();

// added these variables
volatile uint16_t last_x_touched = 0;
volatile uint16_t last_y_touched = 0;
volatile int touch_timer_start = 0;

...

// Made the "my_touchpad_read" function read touch data continuously 
// regardless of the INTRPT pin state and created a "timer" to check whenever
//  touch is inactive (since when not touched, touch values stay the
// same as last reading so can't just tell "if x and y are 0 then release touch").
void my_touchpad_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data) {
  TS.dataread();
  if(TS.ts_event.x1 != last_x_touched || TS.ts_event.y1 != last_y_touched){
    last_x_touched = TS.ts_event.x1;
    last_y_touched = TS.ts_event.y1;
    touch_timer_start = millis();
    data->state = LV_INDEV_STATE_PR;
    data->point.x = TS.ts_event.x1 & 0x0fff;
    data->point.y = TS.ts_event.y1 & 0x0fff;
  }else{
    if(millis() > touch_timer_start + 200){
      data->state = LV_INDEV_STATE_REL;
    }
  }
}

...

void setup() {
  Serial.begin(115200); /* prepare for possible serial debug */

  TS.begin(WAKE, INTRPT);

...

Now my problem is that the touch is too responsive :rofl:
In my GUI I have buttons that change screens with other buttons at the same place so when I click the first button, it opens the second screen then clicks the button on thats second screen… I managed to reduce the effect by adding a delay(50) there but that slightly makes the GUI laggy :

void my_touchpad_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data) {
  TS.dataread();
  if(TS.ts_event.x1 != last_x_touched || TS.ts_event.y1 != last_y_touched){
    last_x_touched = TS.ts_event.x1;
    last_y_touched = TS.ts_event.y1;
    touch_timer_start = millis();
    data->state = LV_INDEV_STATE_PR;
    data->point.x = TS.ts_event.x1 & 0x0fff;
    data->point.y = TS.ts_event.y1 & 0x0fff;
    delay(50);   //<-------------------------------- New delay
  }else{
    if(millis() > touch_timer_start + 250){
      Serial.println("Touch released");
      data->state = LV_INDEV_STATE_REL;
    }
  }
}

Any suggestion is welcome ! Thanks

Your idea with timer and release plus pool method isnt ideal. Im not GSL expert, but touch ICs have good systems to handle this.
Try manage with lvconf

/*====================
   HAL SETTINGS
 *====================*/

/*Default display refresh period. LVG will redraw changed areas with this period time*/
#define LV_DISP_DEF_REFR_PERIOD 17      /*[ms]*/

/*Input device read period in milliseconds*/
#define LV_INDEV_DEF_READ_PERIOD 30     /*[ms]*/

I removed the delay(50) and used the lv_conf settings like you said. It’s a tiny bit better and will do the job but no long press available… only sliding things like sliders are working and even there, after couple of seconds, it drops the touch like if I removed my finger from the digitizer…

I kept my timer, no choice, otherwise nothing works.

Here’s what it looks like now:

void my_touchpad_read(lv_indev_drv_t* indev_driver, lv_indev_data_t* data) {
  TS.dataread();
  if(TS.ts_event.x1 != last_x_touched || TS.ts_event.y1 != last_y_touched){
    last_x_touched = TS.ts_event.x1;
    last_y_touched = TS.ts_event.y1;
    touch_timer_start = millis();
    data->state = LV_INDEV_STATE_PR;
    data->point.x = TS.ts_event.x1 & 0x0fff;
    data->point.y = TS.ts_event.y1 & 0x0fff;
  }else{
    if(millis() > touch_timer_start + 250){
      data->state = LV_INDEV_STATE_REL;
    }
  }
}

And in the lv_conf file:

/*Default display refresh period. LVG will redraw changed areas with this period time*/
#define LV_DISP_DEF_REFR_PERIOD 50      /*[ms]*/

/*Input device read period in milliseconds*/
#define LV_INDEV_DEF_READ_PERIOD 80     /*[ms]*/

I’m still interested if someone has an idea for the long press problem :stuck_out_tongue:

long is impossible by your code… You need other method for touch / release detection based on …

My example

/*Read the touchpad*/
void my_touchpad_read( lv_indev_drv_t * indev_driver, lv_indev_data_t * data )
{
  if (i2cRXbuff[0]) {
    data->state = LV_INDEV_STATE_PR;
    data->point.x = i2cRXbuff[2];
    data->point.y = i2cRXbuff[4];
  } else
  {
    data->state = LV_INDEV_STATE_REL;
  }
}

values in buff is managed in loop

@mmar22 Where do I declare i2cRXbuff array and where/when do I set the values? I kinda get your point but not sure how to implement it to my code… Thanks by the way for your help :slight_smile:

hmm this is example when you dont use lib and write own touch code based on datasheets. If you stay on

GSL1680 - For anthology, this is my first real piece …

then you need understand how it works. On Skallwar src exist sample ino and here you see loop handle interrupt. Use it and in lvgl only use results.

@mmar22 I understand but I already tried with interrupt option and it did not work at all…
Can you elaborate how you would use the interrupt in this case?