Cannot get touchscreen working with XPT2046 (works with eSPI though)

Description

I can get display and touchscreen working with eSPI.
I can get the display working with LVGL.
I cannot get the touchscreen working with XPT2046.
Hence I cannot have LVGL working with the touchscreen.

As far as I can see, LVGL only works with XPT2046 for touchscreens, or am I already wrong here?
So I basically have a XPT2046 problem, I guess, it’s only that seemingly LVGL requires it :confused:
Funny enough, I read somewhere TFT_eSPI is also working with XPT2046 under the hood…

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

A 3.5" no name CYD with ESP32-WROOM-32 (Board name ESP32-035). Schematic attached.
I am using VScode and Arduino Framework.

What do you want to achieve?

Either: Have Display and touchscreen handled by LVGL / XPT2046.
Or: Have LVGL recognize the inputs detected by eSPI.

What have you tried so far?

I am total noob with ESP32, only did some arduino stuff so far.

  • I tried to have display and touchscreen working with TFT_eSPI and XPT2046, but without success (LVGL not even involved here).
    Touch is continously detected, random coordinates, no change when touching the screen.
    I cannot fathom what settings I have to put there.

  • I tried to have LVGL pick up the touch data from eSPI.
    Basically i tried to create an XPT2046 touchscreen, in the hope “touchscreen_read” gets called by LVGL and I could pass the coordinates read by eSPI tft.
    Unfortunately it seems “touchscreen_read” never gets called.
    I think this is anyway a completely wrong approach.

Code to reproduce

This code works (Display and touchscreen handled by eSPI)

#include "FS.h"
#include <SPI.h>
#include <TFT_eSPI.h>

#define CALIBRATION_FILE "/calibrationData"

TFT_eSPI tft = TFT_eSPI();

#define RUNCALIBNOW 0

uint16_t color565 (uint8_t r, uint8_t g, uint8_t b){
  return ((r)<<11) + ((g)<<6)+(b);
}

void fill()
{
  for (int i = 320; i >= 0; i--) {
  tft.drawFastHLine(0, i, tft.width(), color565(10,0,int((320-i)/10)));
  }
}

void setup(void) {
  uint16_t calibrationData[5];
  uint8_t calDataOK = 0;

  Serial.begin(115200);

  tft.init();
  tft.setRotation(3);
  tft.fillScreen((0xFFFF));
  tft.setCursor(20, 0, 2);
  tft.setTextColor(TFT_WHITE);  
  tft.setTextSize(4);
  tft.println("calibration run");

  // check file system
  if (!SPIFFS.begin()) {
    SPIFFS.format();
    SPIFFS.begin();
  }

  // check if calibration file exists
  if (SPIFFS.exists(CALIBRATION_FILE)) {
    File f = SPIFFS.open(CALIBRATION_FILE, "r");
    if (f) {
      if (f.readBytes((char *)calibrationData, 14) == 14) calDataOK = 1;
      f.close();
    }
  }

  if (calDataOK && !RUNCALIBNOW) {
    // calibration data valid
    tft.setTouch(calibrationData);
  } else {
    // data not valid. recalibrate
    tft.calibrateTouch(calibrationData, TFT_WHITE, TFT_RED, 15);
    // store data
    File f = SPIFFS.open(CALIBRATION_FILE, "w");
    if (f) {
      f.write((const unsigned char *)calibrationData, 14);
      f.close();
    }
  }
  fill();
}

void loop() {
  uint16_t x, y;
  if (tft.getTouch(&x, &y)) {
    fill();
    tft.setCursor(160, 100, 2);
    tft.printf("x: %i     ", x);
    tft.setCursor(160, 160, 2);
    tft.printf("y: %i    ", y);
    tft.drawCircle(x,y,6,color565(31,31,31));
  }
}

with following setup.h settings

#define ILI9486_DRIVER
#define ESP32_DMA
#define TFT_MISO 12
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS   15
#define TFT_DC   2
#define TFT_RST  -1
#define TFT_BL   27
#define TOUCH_CS 33

This is not working (Always touch detected, random coordinates, no change whether touched or not)

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

TFT_eSPI tft = TFT_eSPI();

// Touchscreen pins
#define XPT2046_IRQ 36   // T_IRQ
#define XPT2046_MOSI 12  // T_DIN
#define XPT2046_MISO 13  // T_OUT
#define XPT2046_CLK 14   // T_CLK
#define XPT2046_CS 33    // T_CS

SPIClass touchscreenSPI = SPIClass(VSPI);
XPT2046_Touchscreen touchscreen(XPT2046_CS, XPT2046_IRQ);

#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 320
#define FONT_SIZE 2

// Touchscreen coordinates: (x, y) and pressure (z)
int x, y, z;

// Print Touchscreen info about X, Y and Pressure (Z) on the Serial Monitor
void printTouchToSerial(int touchX, int touchY, int touchZ) {
  Serial.print("X = ");
  Serial.print(touchX);
  Serial.print(" | Y = ");
  Serial.print(touchY);
  Serial.print(" | Pressure = ");
  Serial.print(touchZ);
  Serial.println();
}

// Print Touchscreen info about X, Y and Pressure (Z) on the TFT Display
void printTouchToDisplay(int touchX, int touchY, int touchZ) {
  // Clear TFT screen
  tft.fillScreen(TFT_WHITE);
  tft.setTextColor(TFT_BLACK, TFT_WHITE);

  int centerX = SCREEN_WIDTH / 2;
  int textY = 80;
 
  String tempText = "X = " + String(touchX);
  tft.drawCentreString(tempText, centerX, textY, FONT_SIZE);

  textY += 20;
  tempText = "Y = " + String(touchY);
  tft.drawCentreString(tempText, centerX, textY, FONT_SIZE);

  textY += 20;
  tempText = "Pressure = " + String(touchZ);
  tft.drawCentreString(tempText, centerX, textY, FONT_SIZE);
}

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

  // Start the SPI for the touchscreen and init the touchscreen
  touchscreenSPI.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS);
  touchscreen.begin(touchscreenSPI);
  // Set the Touchscreen rotation in landscape mode
  // Note: in some displays, the touchscreen might be upside down, so you might need to set the rotation to 3: touchscreen.setRotation(3);
  touchscreen.setRotation(1);

  // Start the tft display
  tft.init();
  // Set the TFT display rotation in landscape mode
  tft.setRotation(1);

  // Clear the screen before writing to it
  tft.fillScreen(TFT_WHITE);
  tft.setTextColor(TFT_BLACK, TFT_WHITE);
  
  // Set X and Y coordinates for center of display
  int centerX = SCREEN_WIDTH / 2;
  int centerY = SCREEN_HEIGHT / 2;

  tft.drawCentreString("Hello, world!", centerX, 30, FONT_SIZE);
  tft.drawCentreString("Touch screen to test", centerX, centerY, FONT_SIZE);
}

void loop() {
  // Checks if Touchscreen was touched, and prints X, Y and Pressure (Z) info on the TFT display and Serial Monitor
  if (touchscreen.tirqTouched() && touchscreen.touched()) {
    // Get Touchscreen points
    TS_Point p = touchscreen.getPoint();
    // Calibrate Touchscreen points with map function to the correct width and height
    x = map(p.x, 200, 3700, 1, SCREEN_WIDTH);
    y = map(p.y, 240, 3800, 1, SCREEN_HEIGHT);
    z = p.z;

    printTouchToSerial(x, y, z);
    printTouchToDisplay(x, y, z);

    delay(100);
  }
}

Schematic diagram

OK, finally got it working.
Changing

SPIClass touchscreenSPI = SPIClass(VSPI);

to

SPIClass touchscreenSPI = SPIClass(HSPI);

did the trick.

Not really intuitive, since the pins are specified further down, but whatever… it works.