Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/PaulStoffregen/XPT2046_Touchscreen/llms.txt

Use this file to discover all available pages before exploring further.

The TouchTestIRQ example demonstrates a two-stage touch-detection pattern that is strictly more efficient than calling touched() directly on every loop() iteration. The first stage calls ts.tirqTouched(), which reads a boolean flag that the interrupt service routine (ISR) sets whenever the T_IRQ pin falls — no SPI transaction required. Only when that flag is true does the sketch proceed to the second stage: ts.touched(), which performs the actual SPI read and pressure check. The result is that the SPI bus is left completely idle whenever nothing is touching the screen.

Hardware Required

The T_IRQ interrupt pin must be physically connected for this example to work as described. Connect the T_IRQ (or TIRQ) pad on your TFT module to pin 2 on your Arduino-compatible board.
If pin 2 is left disconnected, the isrWake flag inside the library defaults to true and is never cleared by a real interrupt. In that state tirqTouched() always returns true, making the two-stage check functionally identical to — but no faster than — calling touched() directly every iteration.

Default Pin Assignments

SignalArduino Pin
CS (T_CS)8
MOSI11
MISO12
SCK13
TIRQ (required)2

Full Source Code

#include <XPT2046_Touchscreen.h>
#include <SPI.h>

#define CS_PIN  8
// MOSI=11, MISO=12, SCK=13

// The TIRQ interrupt signal must be used for this example.
#define TIRQ_PIN  2
XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling

void setup() {
  Serial.begin(38400);
  ts.begin();
  // ts.begin(SPI1); // use alternate SPI port
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000));
}

void loop() {

  // tirqTouched() is much faster than touched().  For projects where other SPI chips
  // or other time sensitive tasks are added to loop(), using tirqTouched() can greatly
  // reduce the delay added to loop() when the screen has not been touched.
  if (ts.tirqTouched()) {
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      Serial.print("Pressure = ");
      Serial.print(p.z);
      Serial.print(", x = ");
      Serial.print(p.x);
      Serial.print(", y = ");
      Serial.print(p.y);
      delay(30);
      Serial.println();
    }
  }
}

Code Walkthrough

1

Constructor — Interrupt Pin Required

Unlike the plain TouchTest example, this sketch does not offer a commented-out no-IRQ constructor. The TIRQ pin is mandatory:
#define TIRQ_PIN  2
XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);
Passing TIRQ_PIN to the constructor causes begin() to call attachInterrupt() on that pin. The ISR simply sets the isrWake volatile boolean to true on each falling edge, which happens the moment a finger contacts the screen.
2

Stage 1 — ts.tirqTouched()

tirqTouched() reads the isrWake flag and returns its value. This is a plain memory read with no SPI transaction:
if (ts.tirqTouched()) {
  // T_IRQ fired since the last check — a touch may be present
}
Because isrWake is volatile, the compiler will not cache it in a register; every call reads the current value written by the ISR. The flag is cleared internally when touched() or getPoint() performs a real read.
3

Stage 2 — ts.touched()

Once tirqTouched() confirms that the interrupt fired, touched() performs the SPI read and returns true only if the measured pressure value is ≥ 300:
if (ts.touched()) {
  TS_Point p = ts.getPoint();
  // print coordinates...
}
If the T_IRQ signal was a transient glitch and no real pressure is detected, touched() returns false and getPoint() is never called — the SPI bus is released immediately.
4

Reading and Printing the Point

Inside the guarded block the code is identical to the plain TouchTest example: getPoint() returns a TS_Point with x, y, and z members each in the 0–4095 range, and the 30 ms delay throttles serial output during a sustained press.
TS_Point p = ts.getPoint();
Serial.print("Pressure = ");
Serial.print(p.z);
Serial.print(", x = ");
Serial.print(p.x);
Serial.print(", y = ");
Serial.print(p.y);
delay(30);
Serial.println();

Performance Advantage

In a loop() that also drives an SD card, a display, a radio module, or any other time-sensitive task, the cost of a single SPI transaction to the XPT2046 is non-trivial — typically several microseconds of bus occupancy plus the overhead of SPI.beginTransaction() / SPI.endTransaction(). Multiplied across hundreds of loop() calls per second when nothing is being touched, this adds up. The two-stage pattern collapses that cost to a single boolean load on the vast majority of iterations:
ConditiontirqTouched() costtouched() cost
Screen idle~1 ns (flag read)~50–200 µs (SPI)
Screen touched~1 ns (flag read)~50–200 µs (SPI)
When nothing is touching the screen, the inner ts.touched() call is skipped entirely, leaving the SPI bus free for other peripherals without any added latency.
tirqTouched() is especially valuable on Teensy boards driving multiple SPI peripherals simultaneously (e.g., ILI9341 display + SD card + XPT2046 touch), and on ESP32 projects where SPI.beginTransaction() can carry additional RTOS scheduling overhead. Use it any time your loop() contains other work that should not be blocked by touchscreen polling.
The delay(30) inside the touched block prevents the Serial Monitor from being flooded during a sustained press. It does not block tirqTouched() from firing on the next loop() iteration — if the user is still touching when the delay expires, isrWake will already be true again and the read will proceed immediately.

Build docs developers (and LLMs) love