ILI9341_t3 Touch Screen Trouble

Status
Not open for further replies.

Arctic_Eddie

Well-known member
I just got my PJRC display with touch screen yesterday. It's now wired up to a T36 and tested. All of the graphic tests work but none of the touch screeen. I am using IDE 1.6.12, TyQt, and the libraries that come with TeensyDuino 1.31 and also KurtE's latest. Neither cause the TS program to run successfully. The programs compile but when run I get the error on the serial monitor of "Couldn't start touchscreen controller". If I comment out the while( !ts.begin() ) the program runs with colored boxes on the left and a continually changing vertical panel of colored small circles near the middle of the screen. If I also skip the 'ts.begin()' then the touch screen works touching anyplace but still get the colored band.

What libraries and example should I be using to test the touch screen?
 
I'm using the one mentioned in your product link and originally the library in TeensyDuino 1.31. However, both fail to run the touch test successfully. I'm using the pin connections mention just below the photo. The examples comes from the library.

PS
What is the display supposed to do when touching one of the colored buttons?
 
Just ran the ILI9341Test that is under the XPT2046 library, I had to modify it for my board as I am using non-default pin numbers, but comes up fine.
When it is launched, the screen shows "No Touch" text in the display.
When you start touching, the text changes to "Touch" and gives you X, Y positions of the touch.
 
I just installed the XPT2046 library and got the same results as you. That at least confirms my hardware is working correctly. The other failed example with the colored squares does not work and I assume it was intended for the Adafruit board. I'll lift the code from that example as my menu system will look something like that.

Which side should the connector row be on when no rotation is used. The touch test is inverted relative to the DemoSauce example.
 
The Examples that are part of several libraries like the ILI9341_t3 are probably still just the Adafruit version of the test programs, that were setup for their touch displays. Not sure if they are supporting all of their displays now or not.

I soon will be playing around with doing some of my well monitor stuff, probably with buttons and the like.

Not sure what your question is on connector row? You can update the display for 4 different directions with the setRotation item. Have not played around much yet with the touch to know what type of mapping that will need to be done, but should not be too hard.

Kurt
 
The touch example uses setRotation(1) while the DemoSauce uses (3) so that explains the difference. If the touch coordinates start at the upper-left corner then setRotation(1) appears to be the one to use. Will do some more testing tomorrow.

Thanks for the help.
E
 
I did some work on the XPT2046 Library and extended it to have the INT detection to stop polling SPI transfer queries when there was no touch.

If you add the PARAM for the INT it must be connected. If you leave off the PARAM for that then any touch request hits the SPI to check for touch.

I think my examples got put in as well and at least one should have the MAP function I wrote that is rotation aware. Some 'newer' displays have calibration that didn't match what I put in there - but I never got followed up to see if there was a new variant out there. If not in samples I have a thread for the XPT2046 that had samples as I worked it out.

I got as far as a button demo that responded to button Hit Testing compiled in structs that worked in all rotations.
 
I don't see any calibration points in the library files. Later today, I'll determine the values for my display and put a label on the back for reference. In my code, I'll map the raw screen coordinates to the display coordinates. This will support the boxed button part of my menu system. The test program in the Adafruit library is apparently not compatible with the PJRC hardware.
 
For the fun of it and also because I will want something working later for me... I hacked up a version of the touchpaint program to use the XPT2046 library. Which appears to be working for me.

I was finding the X had a range of about 337-3729 and Y had a range of about 529-3711
These work when the Display is in setOrientation(1), so things have to be mapped differently for different modes. Example for Orientation 0 I have the code doing:
Code:
 uint16_t px = map(p.y, TS_MAXY, TS_MINY, 0, tft.width());
  p.y = map(p.x, TS_MINX, TS_MAXX, 0, tft.height());
  p.x = px;

Warning this is setup for my display which is using alternate pins for SPI...
Code:
/***************************************************
  This is our touchscreen painting example for the Adafruit ILI9341 Shield
  ----> http://www.adafruit.com/products/1651

  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
 ****************************************************/


#include <XPT2046_Touchscreen.h>

#include <ILI9341_t3.h>

// This is calibration data for the raw touch data to the screen coordinates
// Warning, These are
#define TS_MINX 337
#define TS_MINY 529
#define TS_MAXX 3729
#define TS_MAXY 3711

#define KURTS_FLEXI
#ifdef KURTS_FLEXI
#define TFT_DC 22
#define TFT_CS 15
#define TFT_RST -1
#define TFT_SCK 14
#define TFT_MISO 12
#define TFT_MOSI 7
#define DEBUG_PIN 13
#else
#define TFT_DC  9
#define TFT_CS 10
#define TFT_RST 7
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#endif

#define TOUCH_CS  8

XPT2046_Touchscreen ts(TOUCH_CS);
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCK, TFT_MISO);

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

void setup(void) {
  while (!Serial && (millis() <= 1000));

  Serial.begin(9600);
  Serial.println(F("Touch Paint!"));

  tft.begin();

  if (!ts.begin()) {
    Serial.println("Couldn't start touchscreen controller");
    while (1);
  }
  Serial.println("Touchscreen started");

  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()
{
  // See if there's any  touch data for us
  if (ts.bufferEmpty()) {
    return;
  }

  // You can also wait for a touch
  /*
  if (! ts.touched()) {
    return;
  }
*/

  // Retrieve a point
  TS_Point p = ts.getPoint();

  // p is in ILI9341_t3 setOrientation 1 settings. so we need to map x and y differently.
/*
  Serial.print("X = "); Serial.print(p.x);
  Serial.print("\tY = "); Serial.print(p.y);
  Serial.print("\tPressure = "); Serial.print(p.z);
*/

  // Scale from ~0->4000 to tft.width using the calibration #'s
#ifdef SCREEN_ORIENTATION_1
  p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
  p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
#else
  
  uint16_t px = map(p.y, TS_MAXY, TS_MINY, 0, tft.width());
  p.y = map(p.x, TS_MINX, TS_MAXX, 0, tft.height());
  p.x = px;
#endif
/*  
    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);
  }
}

Paul: Wondering if the XPT library should have the ability to set Orientation, and maybe have defined MIN/MAX values... Also wonder if I should remove my ifdef for my board and add as an example program for the ILI9341_t3 library.
 
Here is code I think I wrote - last update 11 months ago: https://github.com/Defragster/XPT2046_Touch_Examples/blob/master/ColorButtonsMark3/ButtonMap.cpp#L39

It comes from this post and sample: ILI9341-and-XPT2046-for-Teensy-Touchscreen-320x240-display

It has Screen size in four orientations and uses that to flip the fixed position returned by "ts.getPoint();".
It can look to read twice 'near' the same point so single random touch values won't click a button. And TS_iiSlide is an outside variable that allows slide detection IIRC. Also rejects reading too fast (for a reason that was good at the time?).:
Code:
// Zero is calibration for mapping to pixel, 1-4 follow screen rotation for mapping math
TS_MAP tsMap[5] = { {200, 3700, 325, 3670 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
int16_t TS_xMax = 0; // Current Screen orientation x,y Max values
int16_t TS_yMax = 0;

int TS_bCount = 0;  // Set at run time from sizeof()
int16_t TS_Rotate = 1;
static int16_t TS_iiSlide = -1;

boolean TS_GetMap( int16_t &xx, int16_t &yy, boolean twoHits )
{
  static int16_t lastxx = 500, lastyy = 500; // if twoHits: require two hits same point
  static TS_Point pp;
  static elapsedMillis tsLimit;
  static int16_t xxo = 500, yyo = 500;  // Store old/last returned x,y point
  if ( tsLimit < TS_LIMIT ) return false;
  if (!ts.touched()) return false;
  if ( tsLimit >= TS_SLIDET ) TS_iiSlide = -1;
  tsLimit = 0;
  pp = ts.getPoint();
  if ( pp.z < TS_MINPRESS ) return false;
  xx = map(pp.x, tsMap[0].xt, tsMap[0].xb, tsMap[TS_Rotate].xt, tsMap[TS_Rotate].xb);
  yy = map(pp.y, tsMap[0].yl, tsMap[0].yr, tsMap[TS_Rotate].yl, tsMap[TS_Rotate].yr);
  if (!(TS_Rotate % 2)) {
    int16_t swap = xx;
    xx = yy;
    yy = swap;
  }
  // Debounce by +/-# pixel to minimize point jitter
  if ( ((xxo - TS_DEBOUNCE) <= xx) && ((xxo + TS_DEBOUNCE) >= xx) ) xx = xxo; else xxo = xx;
  if ( ((yyo - TS_DEBOUNCE) <= yy) && ((yyo + TS_DEBOUNCE) >= yy) ) yy = yyo; else yyo = yy;
  if (  twoHits && (xx != lastxx || yy != lastyy) ) {
    lastxx = xx; lastyy = yy;
  }
  if ( 500 == lastyy) TS_iiSlide = -1;
  lastxx = 500; lastyy = 500;
  return true;
}
 
Last edited:
This is a simpler non-button oriented mapping after rotation version: ILI9341TouchTest/ILI9341TouchTest.ino

See :: boolean TS_getMap( int16_t &xx, int16_t &yy )

Calibration data is element [0] of the array - and the other four are screen rotation sizes:

TS_MAP tsMap[5] = { {200, 3700, 325, 3670 }, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };
 
Last edited:
Hi Defragster,

Looks good. As I mentioned wondering what Paul would think of doing two things:

a) Update the XPT20... library to have some default calibration information for the touch screen they sell. Add method to class to set the orientation, and have mapping built-in. ts.getScreenPoint()
b) Replace or add examples like touchpaint to the ili9341_t3 library that uses this touch screen...
 
On which side of the display is the row of pins located when setRotation(0) is set to? The header file shows width as 240 and height as 320. This is reverse from what I expected. I'm using orientation setRotation(1) with the pins on the right side.
 
Here's my calibrate procedure. Use a pointed plastic or wooden stylus and locate the touch screen values for the upper-left and lower-right corners centered over each of the two small white squares. Enter these values in the #define statements for TS_XMIN ... TS_YMAX. The second number after the '/' is the display screen coordinates for the point touched. These values can then be used to determine which menu rectangle was touched. Some of the constants in the code is fixed to the screen size at setRotation(1). There are a few changes needed to make it work at all rotations.
Code:
// ILI9341_TouchCal  20161119
// Original work by 'defragster' and modified by 'Arctic_Eddie'
// tft.fillRect( xorigin, yorigin, xwidth yheight, ILI9341_WHITE ); // Sample argument order

/* Calibration procedure
 *  Record the X and Y values at both the upper-left and lower-right white dot
 *  Enter these values
 * 
 */

#include <ILI9341_t3.h>
#include <font_Arial.h>                             // from ILI9341_t3
#include <XPT2046_Touchscreen.h>                    // Includes call to SPI.h
//#include <SPI.h>                                  // Not needed as it's called by above

// Define your touch screen min and max readout val at the white dots
// They will be mapped to display screen coordinates
#define TS_XMIN     155                             // Touch screen X-min
#define TS_XMAX     3740                            // Touch screen X-max
#define TS_YMIN     265                             // Touch screen Y-min
#define TS_YMAX     3880                            // Touch screen Y-max

// Mapping values for center of cal dots
#define DS_XMIN     1                               // Touch screen X-min
#define DS_XMAX     318                             // Touch screen X-max
#define DS_YMIN     1                               // Touch screen Y-min
#define DS_YMAX     238                             // Touch screen Y-max

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

#define TIRQ_PIN  2
//XPT2046_Touchscreen ts( CS_PIN );                 // Param 2 - NULL - No interrupts
//XPT2046_Touchscreen ts( CS_PIN, 255 );            // Param 2 - 255 - No interrupts
XPT2046_Touchscreen ts( CS_PIN, TIRQ_PIN );         // Param 2 - Touch IRQ Pin - interrupt enabled polling

ILI9341_t3 tft = ILI9341_t3( TFT_CS, TFT_DC );      // Create display object

void setup() 
{
    Serial.begin( 115200 );
    while( !Serial && millis() < 2000 );
  
    tft.begin();
    tft.setRotation( 1 );                                   // Connector on right side
    tft.fillScreen( ILI9341_BLACK );
    ts.begin();
    Serial.println( F( "ILI9341_TouchCal  20161119" ) );    // Print the loaded sketch
}

boolean wastouched = true;

void loop() 
{
    boolean istouched = ts.touched();
    TS_Point dp;                                            // Display point coordinate, 0-319 and 0-239           

    // Put calibration marks in min/min and max/max corners
    tft.fillRect( 0, 0, 3, 3, ILI9341_WHITE );              // Upper-left
    tft.fillRect( 317, 237, 3, 3, ILI9341_WHITE );          // Lower-right
    
    if( istouched  ) 
    {
        TS_Point p = ts.getPoint();
        if( !wastouched  ) 
        {
            tft.fillScreen( ILI9341_BLACK );
            tft.setTextColor( ILI9341_YELLOW );
            tft.setFont( Arial_60 );
            tft.setCursor( 60, 80 );
            tft.print( "Touch" );
        }
        tft.fillRect( 80, 150, 195, 60, ILI9341_BLACK );
        tft.setTextColor( ILI9341_GREEN );
        tft.setFont( Arial_24 );
        tft.setCursor( 80, 150 );
        tft.print( "X = " );
        tft.print( p.x );
        tft.print( "/" );
        uint16_t scx = map( p.x, TS_XMIN, TS_XMAX, DS_XMIN, DS_XMAX );  // Map X to display size
        scx = constrain( scx, 0, 319 );                                 // Keep X in range
        tft.print( scx );
        tft.setCursor( 80, 180 );
        tft.print( "Y = " );
        tft.print( p.y );
        tft.print( "/" );
        uint16_t scy = map( p.y, TS_YMIN, TS_YMAX, DS_YMIN, DS_YMAX );  // Map Y display size
        scy = constrain( scy, 0, 239 );                                 // Keep Y in range
        tft.print( scy );
        Serial.print( " x = " );
        Serial.print( p.x );
        Serial.print( "/" );
        Serial.print( scx );
        Serial.print( ",    y = " );
        Serial.print( p.y );
        Serial.print( "/" );
        Serial.println( scy );
    } 
    else 
    {
        if ( wastouched ) 
        {
            tft.fillScreen( ILI9341_BLACK );
            tft.setTextColor( ILI9341_RED );
            tft.setFont( Arial_48 );
            tft.setCursor( 120, 50 );
            tft.print( "No" );
            tft.setCursor( 80, 120 );
            tft.print( "Touch" );
        }
        Serial.println( "no touch" );
    }
    wastouched = istouched;
    delay( 500 );
}
 
Hi Defragster,

Looks good. As I mentioned wondering what Paul would think of doing two things:

a) Update the XPT20... library to have some default calibration information for the touch screen they sell. Add method to class to set the orientation, and have mapping built-in. ts.getScreenPoint()
b) Replace or add examples like touchpaint to the ili9341_t3 library that uses this touch screen...

That would be nice - I intended to get somewhere with that and my code - but apparently I lost a year without doing that - didn't even post an example to be added. I got onto my button code after doing the interrupt update - then months of PROTO and K66 beta and life stuff.

Nobody using my calibration numbers complained as they played along last year - but 2 or 3 have since, but never enough to correct or understand - so there may be a new variant. It could be hardcoded to work for me and have a way to send in alternate calibration data in setup(). Certainly an example I used for many hours to get the calibration right to return usable mapped data would be a good start.

I thought my integration of the calibration data in the Rotation coordinate array was very neat.
 
This is about the Audio Vector Nework Analyzer project, https://forum.pjrc.com/threads/41326-Update-Audio-Vector-Network-Analyzer?highlight=AVNA and http://www.janbob.com/electron/AVNA1/AVNA1.htm

Mine has always been fine. But, then, two more were built with the mechanical arrangement having the display upside-down from mine. So, no problem, we took my code
Code:
  tft.begin();           // 320x240 display
  tft.setRotation(1);
  ts.begin();            // XPT2046 Touch screen
  ts.setRotation(1);
and fixed it up through #define's to change BOTH 1's to 3's.

BUT, it did not work! The other two needed to have 3's for the display, and 1's for the touch screen. In the two cases, the display was proper and the touch screen needed to be 1 when it should have been 3.

We have checked versions of Arduino IDE (all 1.8.5) Teensyduino (all 1.41) ILI9341_t3 library (all 1.0.0 Installed) and XPT2046_touchscreen library (all 1.2.0 Installed).

Our work-around of experimentally setting the touch screen is quite fine. So, I'm here to see if any one has seen the same thing, and to ask the preposterous question, "Does the hardware vary between units?" Or, can anyone suggest something that is happening?

Thanks, Bob
 
Bob - there is apparently some variations in the display/touch unit. I've not bought any new ones - or worked with my old ones lately. Some reports said the scaling was different once - I didn't see follow up on that. Wouldn't be surprising if batches change over time from manufacturing or component changes I suppose given the base price and where they are sourced from … i.e. … cheap and no name.
 
Status
Not open for further replies.
Back
Top