Buttons on my tft display sometimes don't work

Hello, i am trying to make some project with TFT touch display ST7796 and i have there buttons, it is like multiple page tablet or something like that. When i press and hold the buttons i want them to change the page just once, but when i hold them it skips through every page very quickly.

I think it's because of my display, i am not really sure because when i tried btn.justPressed and btn.justReleased and held finger on button it said in serial monitor repeatedly that it was pressed and released even though it should say it only once.

I tried making latching code for it but because of what it did with btn.justPressed and btn.justReleased it didn't work so last thing I tried was IRQ pin on my display. It made it work, but the thing is when I try to press the button i have to press it multiple times to make it work, it's like because of the IRQ logic it only finds the position of the button once and if it doesn't match it wont work unless i try it multiple times.

I am stuck on this for hours and i can't seem to figure it out myself so i came here.

If there are some questions to clarify my issue I can answer them. Sorry if something didn't make sense but I am just learning about these things and this is my first time making bigger project with this kind of display.

The code i will show is missing #include of TFT_espi library and declaring those buttons and the display, but it is only because I am using Lopaka for design and i have very long variables for some images, also there might be some variables that are unnecessary but i don't want to change them because i want solve some problems my way and even if it is not the correct way i don't really care right now, my only problem is with thoes buttons and I really can't solve that problem.

int value = 1000;
int oldValue = 1000;
int screen = 0;
int oldScreen = 0;
int pocasi = 0;
int oldPocasi = 0;
volatile bool touchFlag = false; 
uint16_t calData[5] = { 292, 3663, 214, 3630, 7 };
bool btnPressed = false;
bool btn2Pressed = false;

#define IRQ_PIN 33  

void IRAM_ATTR onTouchIRQ() {
  touchFlag = true;  
}

void setup() {
  Serial.begin(9600);

  tft.init();
  tft.setRotation(1);
  tft.fillScreen(0x0);
  tft.setTouch(calData);
  

  btn.initButton(&tft, 450 , 165, 70, 320, TFT_BLACK, TFT_BLACK, TFT_BLACK, "", 1);
  btn.drawButton();

  btn2.initButton(&tft, 20 , 165, 50, 320, TFT_BLACK, TFT_BLACK, TFT_BLACK, "", 1);
  btn2.drawButton();

  tft.pushImage(0, 32, 20, 256, image_download_3_pixels);
  tft.pushImage(460, 32, 20, 256, image_download_copy_pixels);

  pinMode(IRQ_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(IRQ_PIN), onTouchIRQ, FALLING);

  screen0();
}

void loop() {
  setScreen();
}

void setScreen(){
  if(touchFlag){
    uint16_t x = 0, y = 0; 
    bool touch = tft.getTouch(&x, &y);

    if(touch){
        
        if(btn.contains(x, y)){
            if(!btnPressed){ 
                if(screen < 2){
                    screen++;
                }
                btnPressed = true;
            }
        } else {
            btnPressed = false;
        }

        // Tlačítko 2
        if(btn2.contains(x, y)){
            if(!btn2Pressed){
                if(screen > 0){
                    screen--;
                }
                btn2Pressed = true;
            }
        } else {
            btn2Pressed = false;
        }

    } else {
       
        btnPressed = false;
        btn2Pressed = false;
    }

    touchFlag = false; 
  }
  
  
  if(oldScreen != screen){
    switch(screen){
      case 0:
        tft.fillScreen(TFT_BLACK);
        screen0();
        btn.drawButton();
        btn2.drawButton();
        tft.pushImage(0, 32, 20, 256, image_download_3_pixels);
        tft.pushImage(460, 32, 20, 256, image_download_copy_pixels);
        break;
      case 1:
        tft.fillScreen(TFT_BLACK);
        screen1();
        btn.drawButton();
        btn2.drawButton();
        tft.pushImage(0, 32, 20, 256, image_download_3_pixels);
        tft.pushImage(460, 32, 20, 256, image_download_copy_pixels);
        break;
      case 2:
        tft.fillScreen(TFT_BLACK);
        screen2();
        btn.drawButton();
        btn2.drawButton();
        tft.pushImage(0, 32, 20, 256, image_download_3_pixels);
        tft.pushImage(460, 32, 20, 256, image_download_copy_pixels);
        break;
      default:
        tft.fillScreen(TFT_BLACK);
        screen0();
        btn.drawButton();
        btn2.drawButton();
        tft.pushImage(0, 32, 20, 256, image_download_3_pixels);
        tft.pushImage(460, 32, 20, 256, image_download_copy_pixels);
        break;
    }
    oldScreen = screen;
  }
}

void screen2(){
  tft.setTextColor(0xF800);
  tft.setTextSize(10);
  tft.setFreeFont();
  if(oldValue != value){
    tft.fillRect(125,125, 233, 74, TFT_BLACK);
    tft.drawString((String)value, 160, 136);
    oldValue = value;
  }
  else{
    tft.drawString((String)value, 160, 136);
  }
  tft.setTextColor(0xFFFF);
  tft.setTextSize(4);
  tft.drawString("PPM", 206, 222);
}

void screen1(){
  tft.fillRect(72, 218, 336, 7, 0xFFFF);
  tft.setTextColor(0xFFFF);
  tft.setTextSize(7);
  tft.setFreeFont();
  tft.drawString("23.8 C", 118, 136);
  if(oldPocasi != pocasi){
    if(pocasi == 0){
      tft.fillRect(28, 20, 74, 68, 0x0);
      tft.pushImage(50, 20, 68, 64, image_download_pixelss);
    }
  }
  else{
    tft.pushImage(50, 20, 68, 64, image_download_pixelss);
  }
  tft.fillEllipse(309, 143, 7, 7, 0xFFFF);
  tft.fillEllipse(309, 143, 5, 5, 0x0);
  tft.setTextSize(5);
  tft.drawString("41%", 198, 245);
}

void screen0(){
  tft.setTextColor(0xFFFF);
  tft.setTextSize(7);
  //tft.setFreeFont();
  tft.drawString("69:69", 139, 139);
  tft.fillRect(76, 218, 329, 7, 0xFFFF);
  tft.setTextSize(5);
  tft.drawString("WED", 89, 250);
  tft.drawString("22.OCT", 217, 250);
}

Please do us and yourself a favour. Edit your first post and split the large slab of text into paragraphs separated by blank lines.

Doing this will make it easier to read and follow what you are saying. As it is many users will not bother to read and understand it

Your "touch" interrupt continually, rapidly, services touch-interrupts (by setting a flag). Have your program ignore further touch-interrupts until your program has completely serviced the current touch interrupt (before servicing the next interrupt).

That is exactly what I tried with the IRQ pin, but i had the problem that the buttons sometimes didn't work.

What is? I showed nothing exact.

What does that mean?

Your interrupt is working perfectly (too well).
When you start to service the interrupt flag, disable interrupts or ignore further interrupt flags.

You didn't show anything, but I am using the IRQ pin as interrupt flag. And it works, but because of the interrupt flag the program finds the position of my finger only once and for some reason, like 80% of the time it doesn't register as succesful button press. I have button that is aproximatly 50x320 that has height as big as the screen but the pressing the buttons works only sometimes.

Have you read your post?

i think you didnt read my post, i was saying i dont want to change the things that works, and i want only to change the thing that i said didnt work as planned. I also said if you have questions about the post, just ask, because i know it is not that understantable, but i dont know how else to write it.

Does replacing the above with this make a difference ?

void IRAM_ATTR onTouchIRQ() {
  static uint32_t lastCallAtMs = 0 ;
  if ( millis() - lastCallAtMs > 400 ) {  // ignore rapid button repeats
    lastCallAtMs = millis() ;  
    touchFlag = true;  
  }
}

I did, or I could not have responded with the information that you did not want, because you want to solve the problems regardless of advice.

I did...

if(touchFlag) is immediately servicing the (very fast) interrupt.

Post #9 is showing one way to ignore interrupts.

Another way could be if(touchFlag && millis() - lastCallAtMs > delayTime)... but then I read your post again...

Sorry if it sounded wrong. With the "You didn't show anything"(sorry idk how to make thoes quotes as you are doing) i was pointing on your message about "I showed nothing exact" that i was agreeing with. And the "I don't want to change them because i want to solve some problems my way" is meant as the unprofessional stuff like some variables that might be pointless or could be done better I don't want to change, but this particular problem that i am asking I am more then enough to change.

So i tried this right now. I also changed little bit my code with if(touchflag)

if(touch){
      if(btn.contains(x, y)){
          if(touchFlag){ 
            if(!btnPressed){
              if(screen < 2){
                screen++;
              }
              btnPressed = true;
            }
          }
          touchFlag = false; 
      } else {
          btnPressed = false;
      }

      // Tlačítko 2
      if(btn2.contains(x, y)){
          if(touchFlag){
            if(!btn2Pressed){
              if(screen > 0){
                  screen--;
              }
              btn2Pressed = true;
            }
          }
          touchFlag = false;
      } else {
          btn2Pressed = false;
      }

  } else {
      
      btnPressed = false;
      btn2Pressed = false;
  }

This works that way that i can push anywhere on the button and it works, but again it doesn't stop the fast changing of pages.. i tried to write in serial monitor the touchflag and i saw that when button is pushed it is most of the time 0, but sometimes there is 1 for no reason and i don't know what to do with that.

I think if i could get rid of the 1s that doesn't belong there it would work just fine. But i don't know how to get rid of them.

Because the interrupt is being serviced too often (too fast). See post #9.

interrupt flag a full speed:    1    1    1    1    1    1    1    1    1
wait 400 ms between service:    yes  no   no   no   yes  no   no   no   yes

The 400 ms was still to fast for me, I used 1000ms and it still isn't best, it still changes the page after a while, but it is much slower then when i started, so I would call it good enough. If you have some idea how to get rid of the page scrolling on hold entirely, I'd love to hear it. But for now I thank y'all for help :slight_smile:

Where? (show full sketch)

I used it here.

void IRAM_ATTR onTouchIRQ() {
  static uint32_t lastCallAtMs = 0 ;
  if ( millis() - lastCallAtMs > 1000 ) {  // ignore rapid button repeats
    lastCallAtMs = millis() ;  
    touchFlag = true;  
  }
}

Try this code when you test for if (touchFlag == true) rather than in the ISR... see if there is a difference.

I have learned to leave the ISR as simple/fast as possible.... enter the ISR... set a flag... leave the ISR... then do your testing (and slowing... which defeats the quickness/purpose of the ISR) in the sketch. Interrupts were not easy for me to "ignore" and seemed to be there long after they should have been un-set.

Maybe there is a TFT button library like there is a digital pin button library. If so, use the library to capture your "one button, one time" until you can inspect the library for how it does the work.

The thing with changing where i put the delay maybe works better, still isn't the thing i wanted but the wait time is longer so i guess better. And i will surely try to look at that library.

At full speed (no slowing), count the number of interrupts you get on a TFT button press. That will help narrow how much slowing is needed. Or, don't use interrupts.

In principle, when you detect a press on one of the push buttons, you can process that button press, but you must then also wait before the button is explicitly released before accepting a new button press.

The problem can be that a new button, which is displayed on the screen, can be under the area on the screen where the user's finger is still detectable from the last button press. Hence this unwanted rapid display of other screens.

The delay 400ms to 1000ms pause that you have been experimenting with is a crude method of achieving this. Better is, after processing a button press, to watch for an explicit release of the button before considering any new button press.