Problem with IL9341 and XPT2046 - Phantom Touch

Hello,

I am using a 2.4" IL9341-based display with XPT2046 touch controller (this one) connected to ESP32 WROOM32 board.

Using Adafruit_GFX.h with U8g2_for_Adafruit_GFX.h adaptation, and the display itself works fine.

However, I can’t get touch functionality to work using XPT2046_Touchscreen.h. No matter what I do, touch() is constantly triggered, even though there is nothing touching the screen. I get constant reporting of touch coordinates (0,0)

Loop():

void loop() {         
   //if (touch.tirqTouched()){
    //Serial.println("is IRQ getting tripped?");
    if (touch.touched()) {
      Serial.println("is touched event happening?");
      rawLocation = touch.getPoint();
      Serial.print("X = ");
      Serial.print(rawLocation.x);
      Serial.print("  Y = ");
      Serial.println(rawLocation.y);
      ParseTouchData(rawLocation.x , rawLocation.y );      
    }
  //}
}

Output:

23:12:24.317 -> is touched event happening?
23:12:24.317 -> X = 0  Y = 0
23:12:24.452 -> is touched event happening?
23:12:24.452 -> X = 0  Y = 0
23:12:24.588 -> is touched event happening?
23:12:24.588 -> X = 0  Y = 0

Below is my connection chart:

ESP-WROOM-32 2.4" TFT ILI9341
Signal Pin Name
TOUCH_IRQ GPIO 17
HSPI TOUCH_MISO GPIO 12
HSPI TOUCH_MOSI GPIO 13
HSPI TOUCH_CS GPIO 15
HSPI TOUCH_CLK GPIO 14
VSPI TFT_MISO GPIO 19
TFT_BL GPIO 16
VSPI TFT_CLK GPIO 18
VSPI TFT_MOSI GPIO 23
TFT_DC GPIO 2
TFT_RST GPIO 4
VSPI TFT_CS GPIO 5
GND
3.3V

I’ve tried three types of configurations:

  1. Single SPI bus connection (VSPI) to the display board, and T_CS connected to GPIO15
  2. Separate SPI bus connection (HSPI) to the touch SPI pins - as per table above. I used the following code to bind the touch driver to the HSPI bus:
 SPI.begin(TOUCH_CLK, TOUCH_MISO, TOUCH_MOSI);
 SPI.setClockDivider(1);
 SPI.beginTransaction(SPISettings(60000000, MSBFIRST, SPI_MODE0));
 SPI.endTransaction();  
 touch.begin();
  1. Separate SPI bus connection (HSPI) to the touch SPI pins + T_IRQ connected to GPIO 17

Attached is the full ino file - most of it not relevant to the touch functionality.

sensor_guage_alpha.ino (9.3 KB)

I strongly advise using TFT_eSPI library.
It supports GFX graphics, many Fonts, …
It supports XPT2046 Touch

Yes, Adafruit_ILI9341 will “work” on ESP32.
XPT2046_TouchScreen will work on ESP32. I find it easier to use 255 for T_IRQ with XPT2046_TouchScreen

David.

I will try the TFT_eSPI library

What do you you mean:

I find it easier to use 255 for T_IRQ with XPT2046_TouchScreen

What is 255 in this context?

Update - I tried the TFT_eSPI library, but still no louch.

I do not get any coordinates from the screen

Here are relevant portions of my user setup file:

// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP32 SETUP   ######

// For ESP32 Dev board (only tested with ILI9341 display)
// The hardware SPI can be mapped to any pins

#define TFT_MISO 19
#define TFT_MOSI 23
#define TFT_SCLK 18
#define TFT_CS    5  // Chip select control pin
#define TFT_DC    0  // Data Command control pin
#define TFT_RST   2  // Reset pin (could connect to RST pin)
//#define TFT_RST  -1  // Set TFT_RST to -1 if display RESET is connected to ESP32 board RST

#define TOUCH_CS 15     // Chip select pin (T_CS) of touch screen


[...]

// ##################################################################################
//
// Section 4. Other options
//
// ##################################################################################

// Define the SPI clock frequency, this affects the graphics rendering speed. Too
// fast and the TFT driver will not keep up and display corruption appears.
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
// With an ILI9163 display 27 MHz works OK.

#define SPI_FREQUENCY  27000000
// #define SPI_FREQUENCY  40000000

// Optional reduced SPI frequency for reading TFT
//#define SPI_READ_FREQUENCY  20000000

// The XPT2046 requires a lower SPI clock rate of 2.5MHz so we define that here:
#define SPI_TOUCH_FREQUENCY  2500000

// The ESP32 has 2 free SPI ports i.e. VSPI and HSPI, the VSPI is the default.
// If the VSPI port is in use and pins are not accessible (e.g. TTGO T-Beam)
// then uncomment the following line:
//#define USE_HSPI_PORT

// Comment out the following #define if "SPI Transactions" do not need to be
// supported. When commented out the code size will be smaller and sketches will
// run slightly faster, so leave it commented out unless you need it!

// Transaction support is needed to work with SD library but not needed with TFT_SdFat
// Transaction support is required if other SPI devices are connected.

// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
// so changing it here has no effect

// #define SUPPORT_TRANSACTIONS

I am using basic example code from the library

#include <SPI.h>
#include <TFT_eSPI.h>
TFT_eSPI tft = TFT_eSPI();

//====================================================================
void setup(void) {
  Serial.begin(115200);
  Serial.println("\n\nStarting...");
  tft.init();
}
//====================================================================

void loop() {
  uint16_t x, y;
  tft.getTouchRaw(&x, &y); 
  Serial.printf("x: %i     ", x);
  Serial.printf("y: %i     ", y);
  Serial.printf("z: %i \n", tft.getTouchRawZ());
  delay(250);
}

Your link in #0 shows a Red SPI Display pcb with mounted XPT2046.

If the Screen on your desk does not have a Touch Panel or Touch chip, you are not going to get any Touch functionality.

I have Touch applications working fine on that type of Red SPI Display. (obviously with mounted XPT2046)

  1. Adafruit_ILI9341 and XPT2046_TouchScreen
  2. TFT_eSPI

I can only suggest that you copy one of Bodmer’s wiring schemes and run his examples.

What is 255 in this context?

From XPT2046_TouchScreen.h

	constexpr XPT2046_Touchscreen(uint8_t cspin, uint8_t tirq=255)
		: csPin(cspin), tirqPin(tirq) { }

The tirq argument is optional. It defaults to 255 (which means ignore interrupt pin)

David.

Thank you, David.

As far as I can tell, the display board has the XPT2046 chip mounted on the PCB, with leads from running to a separate SPI pins, and also has the touch overlay on the screen. (see photos)

Do you think it's possible that the XPT2046 board requires a separate SPI bus to work?

You have a Touch Panel and you have a Touch controller chip.
It was a stab in the dark. Punters often buy the version without Touch because it is cheaper.

Personally, I put TFT, SD and XPT2046 all onto the same hardware SPI bus.
Note that the XPT2046 runs at 2.5MHz whereas the ILI9341 can run up to 40MHz. You should enable transactions in the User Setup.

TFT_eSPI does not use the T_IRQ pin.

I strongly recommend that you use one of Bodmer's ready made User_Setup files.
Hundreds of people have got the same Red SPI display as you, and use TFT_eSPI.

David.

aah the answer was idiotically obvious and so of course I missed it.
The 3 SPI lines on the TFT and XPT2046 need to be wired to the same bus. Literally. Using a breadboard as a splitter so that CLK (GPIO 18) goes to SCK and T_CLK on the display board, etc.
According to user-setup template, transaction support is enabled by default for ESP32 boards and cannot be changed.

// Comment out the following #define if "SPI Transactions" do not need to be
// supported. When commented out the code size will be smaller and sketches will
// run slightly faster, so leave it commented out unless you need it!

// Transaction support is needed to work with SD library but not needed with TFT_SdFat
// Transaction support is required if other SPI devices are connected.

// Transactions are automatically enabled by the library for an ESP32 (to use HAL mutex)
// so changing it here has no effect

#define SUPPORT_TRANSACTIONS

Now next issue is that I seem to be getting very odd readings at idle (i.e. nothing touching the screen. For example:

21:50:36.625 -> x: 338 y: 3384 z: 6
 21:50:36.866 -> x: 0 y: 3763 z: 16
 21:50:37.104 -> x: 0 y: 2932 z: 12
 21:50:37.374 -> x: 0 y: 3991 z: 27
 21:50:37.610 -> x: 389 y: 3393 z: 28
 21:50:37.848 -> x: 626 y: 3150 z: 21
 21:50:38.116 -> x: 64 y: 3535 z: 32
 21:50:38.352 -> x: 0 y: 3983 z: 27
 21:50:38.623 -> x: 344 y: 3383 z: 24
 21:50:38.861 -> x: 344 y: 3382 z: 24
 21:50:39.097 -> x: 0 y: 2916 z: 12
 21:50:39.368 -> x: 0 y: 3331 z: 25
 21:50:39.604 -> x: 0 y: 3711 z: 30
 21:50:39.872 -> x: 0 y: 3832 z: 23

That is perfectly normal. You should check that the Z value is above a threshold.

Bear in mind that the controller chip is reading a resistive Touch Panel with an ADC.
In real life you get occasional false readings. It is wise to use a sensible threshold and also to check for stable reading. Much like you do with scanning buttons on a keyboard.

David.

Hi @trailsurfer604,

Only just seen this thread and as I have used the same touch setup on my existing ESP32 Wroom projects though this little test routine might help, works fine for me.

As @david_prentice mentions that TFT_eSPI sound interesting so have downloaded that and will give that a try as it sounds more flexible.

#include "SPI.h"					// tft screen and touch control
#include "XPT2046_Touchscreen.h"


#define _sclk              25
#define _mosi              32 
#define _miso              39
#define TOUCH_CS_PIN       33 
#define TOUCH_IRQ_PIN      35

XPT2046_Touchscreen touch( TOUCH_CS_PIN, TOUCH_IRQ_PIN );

TS_Point rawLocation;

void setup() {

Serial.begin(115200);
	
SPI.begin( _sclk, _miso, _mosi );
SPI.setFrequency( 60000000 );

touch.begin();

Serial.println( "Touch screen ready." );

}

void loop() {

TouchScreen();
	
delay(1000);

}  //loop end


//---------------------------------------
//---TOUCH SCREEN ROUTINE for ILI9341
//---------------------------------------


void TouchScreen() {
	
while (touch.touched())
{

rawLocation = touch.getPoint();
int x =  rawLocation.x;
int y = rawLocation.y;
		
//     SERIAL PRINT OUT TOUCH  X & Y LOCATIONS  ******
		
Serial.print(x);
Serial.print(" x    y ");
Serial.println(y);
	}

}  // end of Touch Function

XPT2046 will be happier at 2.5MHz. 6MHz is too fast.

Tuning the code so that the serial screen does not crash:

#include "SPI.h"          // tft screen and touch control
#include "XPT2046_Touchscreen.h"

#define _sclk              25
#define _mosi              32
#define _miso              39
#define TOUCH_CS_PIN       33  //5 teensy 4
#define TOUCH_IRQ_PIN      35  //2 teensy 4

XPT2046_Touchscreen touch( TOUCH_CS_PIN, TOUCH_IRQ_PIN );
TS_Point rawLocation;

void setup() {
Serial.begin(115200);
SPI.begin( _sclk, _miso, _mosi );
SPI.setFrequency( 60000000 );

touch.begin();
Serial.println( "Touch screen ready." );
}

void loop() {
TouchScreen();
//delay(1000);  //if it goes here the delay blocks the serial port
}  //loop end


//---------------------------------------
//---TOUCH SCREEN ROUTINE for ILI9341
//---------------------------------------

void TouchScreen() {
while (touch.touched())
{
rawLocation = touch.getPoint();
int x =  rawLocation.x;
int y = rawLocation.y;
   
//     SERIAL PRINT OUT TOUCH  X & Y LOCATIONS  ******
    
Serial.print(x);
Serial.print(" x    y ");
Serial.println(y);
delay(30);  //the delay must be here!
  }
}  // end of Touch Function

The key is the way in which the data that the touch panel displays when we touch it is used. Another factor to consider is that the panel can rotate:

touch.begin ();
touch.setRotation (3); //0,1,2,3

In addition, we must link the rotation of the screen, so that the data of the touch panel corresponds to the length and height of the TFT. The map function can help us.

For the teensy 4 or 4.1, the SPI frequency for the touch panel in this library is set to 2000000

I share with you the sketch with which I was able to calibrate the touch panel of an ILI9488. With some minor adjustments it can be adapted to other GFX-based control libraries

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

#define CS_PIN  5  //touch
#define TFT_RST 8
#define TFT_DC  9
#define TFT_CS 10  //ftf
// MOSI=11, MISO=12, SCK=13

#define TIRQ_PIN  2
XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);

int x=0, y=0, Rotacion=2; //0,1,2,3
char PXY[40];
boolean wastouched = true;
boolean istouched = false;

ILI9488_t3 tft = ILI9488_t3(TFT_CS, TFT_DC, TFT_RST);

void setup() {
  tft.begin();
  tft.setRotation(Rotacion); 
  tft.fillScreen(ILI9488_BLUE);
  tft.setTextSize(2);
  tft.setCursor(130, 120); tft.setTextColor(ILI9488_WHITE);  tft.println("Iniciando TFT SPI");
  tft.setCursor(130, 140); tft.setTextColor(ILI9488_WHITE);  tft.println("  ILI9488 3.5'''");
  delay(1500);
  tft.setTextSize(1);
  tft.fillScreen(ILI9488_BLACK);

  ts.begin();
  ts.setRotation(Rotacion);
  

  MP();
}
void loop(){}

void MP()
{
 tft.setCursor(20, 140); tft.setTextColor(ILI9488_YELLOW);  tft.println("Testing...");
 while(1)
  {
  //Touch instructios
          istouched = ts.touched();
          if (istouched) {
              TouchP(Rotacion);
              
  // Button test
        //if ((y>=y21) && (y<=y22)) 
        //   {      
        //  if ((x>=x21) && (x<=x22)) 
        //     {        
                //Redbox24SPI(x21,y21,x22,y22);
                //MP();
        //     }
        //   }    
  //End Button test
  
  }else {
    if (wastouched) {
    }
  }
  x=-1,y=-1;
  wastouched = istouched;
 } 
}

void TouchP(int Rotn)
{    
    TS_Point p = ts.getPoint();
    if (!wastouched) {
    }
    tft.fillRect(0, 290, 75, 10, ILI9488_RED);   
    tft.fillRect(0, 310, 60, 10, ILI9488_RED);   
    tft.setTextColor(ILI9488_YELLOW);

    if (Rotn==0)
     {
     x = map (p.x, 3900, 250, 0, 319);
     y = map (p.y, 3900, 250, 0, 479);
     }

    if (Rotn==2)
     {
     x = map (p.x, 3900, 250, 0, 319);
     y = map (p.y, 3900, 250, 0, 479);
     }

     if (Rotn==1)
     {
     x = map (p.x, 3900, 226, 0, 479);
     y = map (p.y, 3900, 219, 0, 319);
     }

     if (Rotn==3)
     {
     x = map (p.x, 3900, 226, 0, 479);
     y = map (p.y, 3900, 219, 0, 319);
     }

    sprintf(PXY,"(%d, %d)",p.x,p.y); tft.setCursor(1, 291); tft.print(PXY);
    sprintf(PXY,"(%d, %d)",x,y);  tft.setCursor(1, 311); tft.print(PXY);

    Serial.print("Pressure = ");
    Serial.print(p.z);
    Serial.print(", px = ");
    Serial.print(p.x);
    Serial.print(", py = ");
    Serial.print(p.y);
    Serial.print(", x = ");
    Serial.print(x);
    Serial.print(", y = ");
    Serial.print(y);
    delay(30);
    Serial.println();
}

The IRQ pin can be omitted to use the library:

//#define TIRQ_PIN  2
XPT2046_Touchscreen ts(CS_PIN);
//XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);
//XPT2046_Touchscreen ts(CS_PIN, 255);