ESP32 Resistive Touch Kalibration

Hallo,
folgende Situation: Mit einem ESP32 möchte ich unter anderem folgenden Touchscreen steuern: 2.8 TFT LCD with Touchscreen Breakout Board w/MicroSD Socket [ILI9341] : ID 1770 : $29.95 : Adafruit Industries, Unique & fun DIY electronics and kits

Bei dem Display kann man zwischen SPI und 8Bit-parallel-Interface wählen. Ich hab mich für SPI-entschieden, obwohl es langsamer ist, da mir es einfach unkomplizierter erschien.
Das ganze dabei mit der von Adafruit bereitgestellten Bibliothek. Da diese jedoch für den Arduino ausgelegt ist, habe ich im Code(siehe weiter unten) bereits einige Anpassungen gemacht. Um die Funktionalität zu prüfen, wollte ich zu aller erst den Sketch breakouttouchpaint.ino ausprobiert. Fazit: Das Display funktioniert, der Touch gewissermaßen auch, jedoch völlig falsch kalibriert. Um es so auszudrücken: Im unteren Linken Bereich reagiert das Display auf Berührungen und "zeichnet" diese dann jedoch an einer komplett anderen Stelle...
Das ist der von mir angepasste Code, Verkabelung kann man daran ebenfalls ablesen.

 /***************************************************
  This is our touchscreen painting example for the Adafruit ILI9341 Breakout
  ----> http://www.adafruit.com/products/1770

  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/

/** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/

#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>
#include <Adafruit_ILI9341.h>
#include "TouchScreen.h"

// These are the four touchscreen analog pins
#define YP 33  // must be an analog pin, use "An" notation!
#define XM 32  // must be an analog pin, use "An" notation!
#define YM 22  // can be any digital pin
#define XP 21   // can be any digital pin

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940
#define MINPRESSURE 10
#define MAXPRESSURE 1000
#define TFT_RST 4
// The display uses hardware SPI, plus #9 & #10
#define TFT_CS 15
#define TFT_DC 16
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC,TFT_RST);

// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 325);

// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;

void setup(void) {
 // while (!Serial);     // used for leonardo debugging
 
  Serial.begin(115200);
  Serial.println(F("Touch Paint!"));
  
  tft.begin();
  tft.setRotation(0);
  tft.fillScreen(ILI9341_BLACK);
  
  // make the color selection boxes
  tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
  tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
  tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
  tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
  tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
  tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
 
  // select the current color 'red'
  tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
  currentcolor = ILI9341_RED;
}


void loop()
{
  // Retrieve a point  
  TSPoint p = ts.getPoint();
  pinMode(XM, INPUT);
  pinMode(XP, OUTPUT);
  pinMode(YM, OUTPUT);
  pinMode(YP, INPUT);
 
  Serial.print("X = "); Serial.print(p.x);
  Serial.print("\tY = "); Serial.print(p.y); /*
  Serial.print("\tPressure = "); Serial.println(p.z);  
 */
  
  // we have some minimum pressure we consider 'valid'
  // pressure of 0 means no pressing!
  if (p.z < MINPRESSURE || p.z > MAXPRESSURE) {
     return;
  }
  
  // Scale from ~0->1000 to tft.width using the calibration #'s
  p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
  Serial.print(tft.height());
  Serial.println(tft.width());
  /*
  Serial.print("("); Serial.print(p.x);
  Serial.print(", "); Serial.print(p.y);
  Serial.println(")");
  */

    
  if (p.y < BOXSIZE) {
     oldcolor = currentcolor;

     if (p.x < BOXSIZE) { 
       currentcolor = ILI9341_RED; 
       tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
     } else if (p.x < BOXSIZE*2) {
       currentcolor = ILI9341_YELLOW;
       tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
     } else if (p.x < BOXSIZE*3) {
       currentcolor = ILI9341_GREEN;
       tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
     } else if (p.x < BOXSIZE*4) {
       currentcolor = ILI9341_CYAN;
       tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
     } else if (p.x < BOXSIZE*5) {
       currentcolor = ILI9341_BLUE;
       tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
     } else if (p.x < BOXSIZE*6) {
       currentcolor = ILI9341_MAGENTA;
       tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
     }

     if (oldcolor != currentcolor) {
        if (oldcolor == ILI9341_RED) 
          tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
        if (oldcolor == ILI9341_YELLOW) 
          tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
        if (oldcolor == ILI9341_GREEN) 
          tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
        if (oldcolor == ILI9341_CYAN) 
          tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
        if (oldcolor == ILI9341_BLUE) 
          tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
        if (oldcolor == ILI9341_MAGENTA) 
          tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
     }
  }
  if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
    tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
  }
}

Ich gehe davon aus, dass es an diesen Zeilen liegt, durch die werden ja die Ecken des Displays definiert. Die sind übrigens standardmäßig so.

#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940

Gibt es hier eine "bessere" Alternative als zufällig mit den Werten herumzuspielen und darauf zu hoffen, dass die Kalibrierung irgendwann passt? Oder liegt das Problem wo anders und es geht vielleicht sogar einfacher?

Ich bedanke mich schonmal im Voraus an jeden, der versucht zu helfen...

Google Translate says:
Hello,
Following situation: With an ESP32 I would like to control the following touchscreen: 2.8 TFT LCD with Touchscreen Breakout Board w/MicroSD Socket [ILI9341] : ID 1770 : $29.95 : Adafruit Industries, Unique & fun DIY electronics and kits

You can choose between SPI and 8-bit parallel interface for the display. I chose SPI, even though it's slower, because it just seemed less complicated to me.
All this with the library provided by Adafruit. However, since this is designed for the Arduino, I have already made some adjustments to the code (see below). To check the functionality, I wanted to try the breakouttouchpaint.ino sketch first. Conclusion: The display works, the touch does as well, but calibrated completely wrong. To put it this way: In the lower left area, the display reacts to touches and then "draws" them in a completely different place...
This is the code I have adapted, you can also read the wiring from it.Hello,
Following situation: With an ESP32 I would like to control the following touchscreen: 2.8 TFT LCD with Touchscreen Breakout Board w/MicroSD Socket [ILI9341] : ID 1770 : $29.95 : Adafruit Industries, Unique & fun DIY electronics and kits

Adafruit "TouchScreen.h" does not work very well on ESP32.

Thanks for your reply,
which other library do you suggest?

:warning:
Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden.
Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.
mfg ein Moderator.

Update:
Ich habe ein wenig weiter recherchiert und bin auf folgende Bibliothek gekommen:
GitHub - dracir9/ESP_TouchScreen: Resistive touch screen controller optimized for ESP32

Alle Anweisungen zur Verkabelung dort habe ich vorgenommen, den Calibrate-Sketch geladen und siehe da: Die Kalibrierung funktioniert. Die Werte, die mir dann am Ende der Kalibrierung ausgegeben werden in die TouchSetup.h eingetragen und den Touch_demo Sketch geladen. Dieser konnte ebenfalls kompiliert und hochgeladen werden, jedoch hat sich der Touchscreen dauerhaft selbst resettet und Guru Meditation Error: Core 1 panic'ed (IntegerDivideByZero). Exception was unhandled ausgegeben. Ich bin dem ganzen auf den Grund gegangen und darauf gestoßen, dass es an der Zeile liegt, in der Code sich die Koordinaten des Touchpunktes holt. Im Demo-Sketch erfolgt dies durch
TSPoint p = ts.getPoint(tft.width(), tft.height());

während es im Calibrate-Sketch

ts.getTouchRaw(x, y, z);

ist.
Also hab ich den ganzen Code umgeschrieben bzw. an den Stil, wie er in der Calibrate steht, angepasst:


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

// adjust pressure sensitivity - note works 'backwards'
#define MINPRESSURE 10
#define MAXPRESSURE 10000

uint16_t pointsX[16]={0};
uint16_t pointsY[16]={0};
uint8_t divX;
uint8_t divY;
#define TOUCH_PIN_YP 34
#define TOUCH_PIN_XM 33
#define TOUCH_PIN_YM 26
#define TOUCH_PIN_XP 27

TFT_eSPI tft = TFT_eSPI();
TouchScreen ts(TOUCH_PIN_XP, TOUCH_PIN_YP, TOUCH_PIN_XM, TOUCH_PIN_YM, 315);

void drawBoard()
{
    tft.fillScreen(TFT_BLACK);
    tft.drawLine(0, 0, 40, 40, TFT_RED);
    tft.drawLine(0, 40, 40, 0, TFT_RED);
    tft.fillRect(40, 0, 40, 40, TFT_RED);
    tft.fillRect(80, 0, 40, 40, TFT_GREEN);
    tft.fillRect(120, 0, 40, 40, TFT_BLUE);
    tft.fillRect(160, 0, 50, 40, TFT_YELLOW);
    tft.fillRect(200, 0, 40, 40, TFT_BLACK);
    tft.fillRect(240, 0, 40, 40, TFT_ORANGE);
    tft.fillRect(280, 0, 40, 40, TFT_PINK);
}

void setup()
{
    Serial.begin(115200);
    tft.begin();
    pinMode(TOUCH_PIN_XM, INPUT);
    pinMode(TOUCH_PIN_XP, OUTPUT);
    pinMode(TOUCH_PIN_YM, OUTPUT);
    pinMode(TOUCH_PIN_YP, INPUT);
    ts.enableRestore();

    tft.setRotation(1);

    drawBoard();
    
}

void map2Screen(uint16_t &x, uint16_t &y)
{
    // Map X
    uint8_t i = 0;
    while (x < (pointsX[i + 1] >> 4) && i <= divX - 1) i++; 
    x = map(x, pointsX[i]>>4, pointsX[i + 1]>>4, (pointsX[i]&15) * tft.width()/15, (pointsX[i + 1]&15) * tft.width()/15);

    // Map Y
    i = 0;
    while (y < (pointsY[i + 1] >> 4) && i <= divY - 1) i++; 
    y = map(y, pointsY[i]>>4, pointsY[i + 1]>>4, (pointsY[i]&15) * tft.height()/15, (pointsY[i + 1]&15) * tft.height()/15);
}

uint32_t brushColor = TFT_YELLOW;
uint32_t cnt = 0;
int64_t trigger = 0;
void loop()
{
    uint16_t x,y,z;
    // getPoint(x_max, y_max) reads the touchscreen and maps the returned x and y 
    // coordinates between 0 and x_max/y_max respectively.
    // If the touchscreen wasn't touched while reading the returned x and y values are invalid.
    // Serial.println(tft.width());
    //Serial.println(tft.height());
    //TSPoint p = ts.getPoint(tft.width(), tft.height());
   // TSPoint p = ts.getPoint(320, 240);
    ts.getTouchRaw(x, y, z);
     if (z > MINPRESSURE && z < MAXPRESSURE) // Check if screen was touched
    {
       map2Screen(x,y);
        if (y < 40)
        {
         
          if (x < 40)
          {
            
            drawBoard();
          }
          else if (x < 80)
          {
            
            brushColor = TFT_RED;
          }
          else if (x < 120)
          {
            
            brushColor = TFT_GREEN;
          }
          else if (x < 160)
          {
            
            brushColor = TFT_BLUE;
          }
          else if (x < 200)
          {
            
            brushColor = TFT_YELLOW;
          }
          else if (x < 240)
          {
            
            brushColor = TFT_BLACK;
          }
          else if (x < 280)
          {
            
            brushColor = TFT_ORANGE;
          }
          else
          {
            
            brushColor = TFT_PINK;
          }
        }
        else
        {
          tft.fillCircle(x, y, 2, brushColor);
        }
         Serial.print("X: ");
         Serial.print(x);
         Serial.print(" Y: ");
         Serial.println(y);
         Serial.println(z);
    }

    cnt++;
    if (esp_timer_get_time() > trigger)
    {
        trigger = esp_timer_get_time() + 1000000LL;
        Serial.printf("Readings per second: %d\n", cnt);
        cnt = 0;
    }
}

Der Code kompiliert und das Display resettet nun die ganze Zeit nicht mehr. Erstmal gut. Wenn ich jedoch mir die Koordinaten ausgeben lasse, sind es immer diesselben...

Ich hab das Display an den Uno gehängt und alles funktioniert perfekt, am Display liegt es also nicht, Warum ich kein Uno sondern den ESP32 verwende? Das Display ist nicht das einzige, was ich an den Mikrocontroller anschließen will, und da hat der ESP32 halt einfach mehr Pins :slight_smile:

Wenn irgendwer eine Idee hat oder schon Erfahrungen mit so einem DIsplay gemacht hat, würd ich mich sehr über Hilfe freuen!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.