ILI9341 GraphicsTest works, Touch paint demo not so much

Status
Not open for further replies.

paynterf

Well-known member
Hi,

Just got a couple of the very nice ILI9341 displays to play with. I got the 'graphicstest' example working very nicely, but I can't get the 'touchpaint' one to work. The wiring for the graphics is obviously correct, and I'm pretty sure I've got the wiring for the touch support pins also correct. I am using the pinouts described here

When I ran the touchpaint demo, I got the color selector bar at the top and sort of a 'blob' in the lower lefthand corner of the screen. When I modified the demo code to show the coordinates and the corresponding touch pressures, it seems those points showed a lot of pressure (in the 200-600 range), even without me touching the screen at all. In order to cut down on the printout volume, I had to raise MINPRESSURE to 500. When I did that, the 'blob' was still there, but reduced to just 5-10 points. Even pressing moderately hard with the stylus did not result in any pressure hits, and no visible drawing.

IMG_4011.jpg

Any idea what I'm doing wrong here?

TIA,

Frank
 
I also tried the onoffbutton_breakout.ino sketch. It works, but continually shifts from 'red button hit' to 'green button hit' without any input from me.
 
Hmm, same thing happens with a second brand-new display. Red/Green button presses detected randomly with no user input. Sure sounds like I'm doing something wrong, but don't know what it is
 
I modified the onoffbutton_breakout sketch to report the pressure at each coordinate. Most coordinates showed 0 pressure, but these didn't:


Code:
checking (173,785), press = 196
1
checking (193,801), press = 159
1

checking (178,824), press = 183
1
checking (172,735), press = 101
Red btn hit
0
checking (183,777), press = 129
Green btn hit
1
checking (182,817), press = 194
1
checking (202,786), press = 424
1
checking (194,763), press = 261
Red btn hit
0
checking (185,785), press = 317
Green btn hit
1
checking (196,826), press = 347
1
checking (187,804), press = 205
1
checking (194,792), press = 250
1
checking (191,781), press = 268
1

checking (184,782), press = 134
1
checking (198,784), press = 165
1
checking (207,812), press = 255
1
checking (207,801), press = 159
1
checking (195,793), press = 198
1
checking (184,793), press = 160
Green btn hit
1
checking (193,787), press = 105
1
checking (189,825), press = 330
1
checking (195,841), press = 256
1
 
Which library are you using? Which touchpaint are you using? In many cases like this it helps if you post either link to code or code example you are using...

The reason I ask, is if you are using the ILI9341_t3 library, most of the example sketches were adapted from the Adafruit_ili9341 library and as such are geared toward the hardware that Adafruit sells:
The Adafruit display, at least at the time used an STMPE610 controller for touch. So most of the examples in this project have lines in them like:
Code:
#include <Adafruit_STMPE610.h>

However the ILI9341 that ships from PJRC(https://www.pjrc.com/store/display_ili9341_touch.html): uses an XPT2046 touch controller, which is different so many of the touch example sketches don't work this display.
I do have a version of touchapint in my ILI9341_t3n library that works with these displays: https://github.com/KurtE/ILI9341_t3n/blob/master/examples/touchpaint_xpt2046/touchpaint_xpt2046.ino

At one point I had a version of this that I had adapted back to the ILI9341_t3 library, but the Pull Request never was applied...
It appears to still build, but I have not tried to run it:
Code:
// To use Kurt's Flexiboard uncomment the line below:
#define KURTS_FLEXI

/***************************************************
  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 TFT_DC  9
#define TFT_CS 10
#define TFT_RST 7
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11

#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");
 #ifdef SCREEN_ORIENTATION_1
  Serial.println(" *** Screen Orientation 1 ***");
#endif   

  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);
  }
}
 
Kurt,

Thanks for the prompt and informative reply. Hmm, I am using the libraries recommended on the PJRC store page (or at least I think I am - sometimes its hard to tell), and the example files provided with the library. Here's the 'onoffbutton_breakout' example:

Code:
//This example implements a simple sliding On/Off button. The example
// demonstrates drawing and touch operations.
//
//Thanks to Adafruit forums member Asteroid for the original sketch!
//
#include <SPI.h>
#include <Wire.h>
#include <ILI9341_t3.h>
#include <TouchScreen.h>

//Touchscreen X+ X- Y+ Y- pins
#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 5   // can be a digital pin
#define XP 4   // can be a 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

// 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, 300);


#define TFT_CS 10
#define TFT_DC  9
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);

boolean RecordOn = false;

#define FRAME_X 210
#define FRAME_Y 180
#define FRAME_W 100
#define FRAME_H 50

#define REDBUTTON_X FRAME_X
#define REDBUTTON_Y FRAME_Y
#define REDBUTTON_W (FRAME_W/2)
#define REDBUTTON_H FRAME_H

#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
#define GREENBUTTON_Y FRAME_Y
#define GREENBUTTON_W (FRAME_W/2)
#define GREENBUTTON_H FRAME_H

void drawFrame()
{
  tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK);
}

void redBtn()
{ 
  tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED);
  tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE);
  drawFrame();
  tft.setCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2));
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.println("ON");
  RecordOn = false;
}

void greenBtn()
{
  tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN);
  tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE);
  drawFrame();
  tft.setCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2));
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.println("OFF");
  RecordOn = true;
}

void setup(void)
{
  Serial.begin(9600);
  tft.begin();

  tft.fillScreen(ILI9341_BLUE);
  // origin = left,top landscape (USB left upper)
  tft.setRotation(1); 
  redBtn();
}

void loop()
{
   // Retrieve a point  
  TSPoint p = ts.getPoint();

  Serial.printf("checking (%d,%d), press = %d\n", p.x, p.y, p.z);

  // See if there's any  touch data for us
  if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
  {   
    // Scale using the calibration #'s
    // and rotate coordinate system
    p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height());
    p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width());
    int y = tft.height() - p.x;
    int x = p.y;

    if (RecordOn)
    {
      if((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) {
        if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) {
          Serial.println("Red btn hit"); 
          redBtn();
        }
      }
    }
    else //Record is off (RecordOn == false)
    {
      if((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) {
        if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) {
          Serial.println("Green btn hit"); 
          greenBtn();
        }
      }
    }

    Serial.println(RecordOn);
  }  
}

When I right-clicked on <TouchScreen.h> and selected 'go to', it opened in C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\TouchScreen, which led me to believe it was the right library for the display from PJRC - Here is 'TouchScreen.h'

Code:
// Touch screen library with X Y and Z (pressure) readings as well
// as oversampling to avoid 'bouncing'
// (c) ladyada / adafruit
// Code under MIT License

#ifndef _ADAFRUIT_TOUCHSCREEN_H_
#define _ADAFRUIT_TOUCHSCREEN_H_
#include <stdint.h>


#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__) || defined(TEENSYDUINO) || defined(__AVR_ATmega2560__)
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
typedef volatile uint32_t RwReg;
#else
typedef volatile uint8_t RwReg;
#endif
#endif
#if defined(ARDUINO_STM32_FEATHER)
typedef volatile uint32 RwReg;
#endif
#if defined(ARDUINO_FEATHER52) || defined(ESP32)
typedef volatile uint32_t RwReg;
#endif

#if defined (__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_SAMD)
  #define USE_FAST_PINIO
#endif

class TSPoint {
 public:
  TSPoint(void);
  TSPoint(int16_t x, int16_t y, int16_t z);
  
  bool operator==(TSPoint);
  bool operator!=(TSPoint);

  int16_t x, y, z;
};

class TouchScreen {
 public:
  TouchScreen(uint8_t xp, uint8_t yp, uint8_t xm, uint8_t ym, uint16_t rx);

  bool isTouching(void);
  uint16_t pressure(void);
  int readTouchY();
  int readTouchX();
  TSPoint getPoint();
  int16_t pressureThreshhold;

private:
  uint8_t _yp, _ym, _xm, _xp;
  uint16_t _rxplate;

  volatile RwReg *xp_port, *yp_port, *xm_port, *ym_port;
  RwReg xp_pin, xm_pin, yp_pin, ym_pin;

};

#endif

I see from Paul's documentation that there is a 'XPT2046_Touchscreen library', but I can't tell from the documentation if it is to be used instead of, or in conjunction with, the other libraries. I made the rash assumption that since the 'onoffbutton_breakout' example didn't use the XPT2046 library, I didn't need it to operate the display. Paul's comment on the file was that it was used with 'some low-cost TFT displays', but didn't make it clear (at least to me) that what he was selling on his store was one of those 'low cost TFT displays' ;). So, I took out my handy magnifier and looked at the touch processor, and you are correct - it's a xpt2046 - oops!


I looked at your example and I will try it tomorrow morning when I have regained the ability to think (well, at least my version of 'think', anyways) ;-).

Frank
 
Quick note: in the example code you show above, the TouchScreen library requires 4 IO pins as shown here:

Code:
//This example implements a simple sliding On/Off button. The example
// demonstrates drawing and touch operations.
//
//Thanks to Adafruit forums member Asteroid for the original sketch!
//
#include <SPI.h>
#include <Wire.h>
#include <ILI9341_t3.h>
#include <TouchScreen.h>

[COLOR="#FF0000"]//Touchscreen X+ X- Y+ Y- pins
#define YP A3  // must be an analog pin, use "An" notation!
#define XM A2  // must be an analog pin, use "An" notation!
#define YM 5   // can be a digital pin
#define XP 4   // can be a digital pin[/COLOR]

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

// 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
[COLOR="#FF0000"]TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);[/COLOR]
Which the displays sold by PJRC I don't believe expose these.
But I think some by Adafruit do, like: https://www.adafruit.com/product/1770
Their shield version: https://www.adafruit.com/product/1651 uses the STMPE610 controller.
 
Kurt,

You are correct, the PJRC display doesn't expose those pins, which added to my confusion. Also, the documentation talks about measuring the resistance of the X & Y plates, but those don't seem to be available either.

I dl'd your ILI9341_t3n library and compiled your touchpaint_xpt2046.ino sketch, but all I'm getting is a blank (white) display. I'm pretty sure I've got the display wired correctly, because the display itself works fine with my clock sketch as shown below:

View attachment 23683

Code:
/*
    Name:       Teensy_LCDClockV2.ino
    Created:	2/11/2021 3:57:01 PM
    Author:     FRANKNEWXPS15\Frank
*/


/***************************************************
  This is our GFX example for the Adafruit ILI9341 Breakout and 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 <Wire.h>
#include "RTClib.h"
#include "SPI.h"
#include "ILI9341_t3.h"
#include "font_Arial.h"

#pragma region RTC Support
//#define FORCE_RTC_TO_LAST_COMPILE_TIME //uncomment to manually set RTC to last compile time

RTC_DS3231 rtc;

//char daysOfTheWeek[7][12] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
char daysOfTheWeek[7][12] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
DateTime now, lastTime;
char buffer[100];

struct tStamp
{
  unsigned long mSec;
  byte RTC_Status;
};

#define DS3231_ADDRESS 0x68   ///< I2C address for DS3231
#define DS3231_STATUSREG 0x0F ///< Status register

#define RTCStatArraySize 10
#define RTCStatTime_IntervalMsec 100
tStamp RTCStatArray[RTCStatArraySize];


#pragma endregion RTC Support

#pragma region TFT Display Support
// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10

#define N0_DIAGNOSTICS

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
#pragma endregion TFT Display Support

void setup() 
{
  Serial.begin(9600);
  unsigned long mSec = millis();
  while (!Serial && millis()-mSec < 3000) // wait for Arduino Serial Monitor
  {
    delay(100);
  }
  Serial.println("Teensy 3.2 TFT Clock Program");

#pragma region TFT INITIALIZATION
  Serial.println("Initializing TFT display");

  tft.begin();
  // Note: you can now set the SPI speed to any value
  // the default value is 30Mhz, but most ILI9341 displays
  // can handle at least 60Mhz and as much as 100Mhz
  //  tft.setClock(60000000);
  tft.fillScreen(ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setTextSize(2);
  tft.setRotation(1);
#pragma endregion region TFT INITIALIZATION

#pragma region TFT DIAGNOSTICS
#ifndef N0_DIAGNOSTICS

  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);

  Serial.println(F("Benchmark                Time (microseconds)"));

  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(200);

  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(600);

  Serial.print(F("Proportional Text        "));
  Serial.println(testProportionalText());
  delay(600);

  Serial.print(F("Lines                    "));
  Serial.println(testLines(ILI9341_CYAN));
  delay(200);

  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
  delay(200);

  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(ILI9341_GREEN));
  delay(200);

  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
  delay(200);

  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, ILI9341_MAGENTA));

  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, ILI9341_WHITE));
  delay(200);

  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(200);

  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(200);

  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(200);

  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(200);

  Serial.println(F("Done!"));
#endif // !N0_DIAGNOSTICS
#pragma endregion region TFT DIAGNOSTICS

#pragma region RTC_SETUP
    Serial.println("Initializing RTC...");
    tft.println("Initializing RTC...");
    delay(1000);

  if (!rtc.begin())
  {
    Serial.println("Couldn't find RTC");
    tft.println("Couldn't find RTC");
    while (1);
  }

  bool lp = rtc.lostPower();
  Serial.print("lostPower() reports "); Serial.println(lp);
  tft.printf("lostPower() = %d\n", lp);
  delay(1000);
  if (rtc.lostPower())
  {
    Serial.println("RTC lost power.  Setting RTC to last compile time");
    tft.println("RTC lost power.  Setting RTC to last compile time");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

#ifdef FORCE_RTC_TO_LAST_COMPILE_TIME
  Serial.println("Forcing RTC to last compile time");
  // following line sets the RTC to the date & time this sketch was compiled
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
#endif // 

  //DateTime now = rtc.now();
  now = rtc.now();
  //char buffer[100];
  memset(buffer, '\0', 100);
  GetDayDateTimeStringFromDateTime(now, buffer);
  Serial.println("Retrieving Date/Time from RTC....");
  Serial.print("Date String = "); Serial.println(buffer);
#pragma endregion RTC_SETUP

//DEBUG!!
  //tft.println("Setting time to just before midnight");
  //rtc.adjust(DateTime(2021, 02, 13, 07, 59, 45));
//DEBUG!!
}


void loop(void) 
{
  now = rtc.now();

  //Display day and date
  //tft.fillRect(0, 0, 290, 40, ILI9341_RED);
  tft.fillRect(0, 0, 290, 40, ILI9341_BLACK);
  tft.setTextColor(ILI9341_YELLOW);
  tft.setCursor(0, 0);
  tft.setFont(Arial_32);
  tft.printf("%s %02d/%02d/%02d\n", 
    daysOfTheWeek[now.dayOfTheWeek()], now.month(), now.day(), now.year());

  //Serial.printf("%d:%d:%02d\t%d:%d:%02d\n", now.hour(), now.minute(), now.second(),
  //lastTime.hour(), lastTime.minute(), lastTime.second());

  //Display time
  tft.setCursor(0, 100);
  tft.setTextColor(ILI9341_RED);
  tft.setFont(Arial_60);
  tft.fillRect(0, 100, 350, 65, ILI9341_BLACK);
  tft.setCursor(0, 100);
  int hournum = now.hour();
  hournum = (hournum > 12) ? hournum - 12 : hournum;
  tft.printf("%2d:%02d:%02d", hournum, now.minute(), now.second());
  lastTime = now;

  delay(1000);
}

#pragma region DATE_TIME_FUNCTIONS
void GetDayDateTimeStringFromDateTime(DateTime dt, char* bufptr)
{
  int mydayofweek = dt.dayOfTheWeek();
  //mydayofweek = (mydayofweek < 0) ? 0 : mydayofweek; //guard for return of 0 from weekday()
  int myday = dt.day();
  int mymonth = dt.month();
  int myyear = dt.year();
  int myhour = dt.hour();
  int mymin = dt.minute();
  int mysec = dt.second();
  char* dayofweek = (char*)daysOfTheWeek[mydayofweek];

  sprintf(bufptr, "%s %4d/%02d/%02d at %02d:%02d:%02d", dayofweek, mymonth, myday, myyear, myhour, mymin, mysec);
}


void HourStringFromDateTime(DateTime dt, char* bufptr)
{
  int hourval = dt.hour();
  if (hourval > 12)
  {
    hourval -= 12;
  }

  //sprintf(bufptr, "%02d", hourval);
  sprintf(bufptr, "%d", hourval);
}

void MinuteStringFromDateTime(DateTime dt, char* bufptr)
{
  sprintf(bufptr, "%02d", dt.minute());
}
#pragma endregion DATE_TIME_FUNCTIONS

Next, I tried to run some of the graphics test examples from your _t3n library. The 'graphicstest_aafonts.ino' example fails because SPIN.h cannot be found. It's not in the directory tree for the library, so I have no idea what to do with that. Is that something that should have been included? (I later found some code that explained that SPIN.h was no longer required, but apparently the attempt to keep it from trying to load anyway failed).

Next I tried 'graphicstest.ino', and this one compiled and worked on my display - YAY!! Unfortunately this one has only fixed-font text, and I need (or at least want) proportional text for my clock project. I also tried to get the 'ILI_Ada_FontTest3.ino' example to work without success, until I discovered that the example files hadn't been updated to change from "ILI9341_t3n_font_xyz.h" to "ILI9341_t3n_font_xyz.h" and the DroidSans, Michroma, Crystal, and ChanceryItalic fonts weren't supported. I finally got it to work with the limited set of fonts, and it looks OK.


So, at the end of the day I'm not any further along than when I started; the touch-screen code still doesn't work, and the display examples will need a lot of work to compile and run - ARGHH!!

Can I buy another clue?

Frank
 
With my touchpaint_xpt2046 - you may need to edit to match whatever your pin configuration is... Sorry many of these examples were setup to work as test cases and may not be in what is shown on PJRC displays page:
But for example look at this section:
Code:
//****************************************************************************
// Settings and objects
//****************************************************************************
#if defined(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
#define TOUCH_CS  8
#else
[COLOR="#FF0000"]#define TFT_DC  1
#define TFT_CS 0
#define TFT_RST 7
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#define TOUCH_CS  8[/COLOR]
#endif
Make sure the define for KURTS_FLEXI is still commented out (line 21)
To use default you can replace this whole part with the defaults like:
Code:
#define TFT_DC  9
#define TFT_CS 10
[COLOR="#FF0000"]#define TFT_RST 7[/COLOR]
#define TFT_SCK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#define TOUCH_CS  8
#endif
Not sure what pin you wired up to reset? if nothing probably set the RST to -1

I will take a look at the ones that still have spin mentioned. Spin is no longer needed in this library. Spin was a helper library (up on my github) that I did originally to make the library be able to work on different SPI ports during the T3.6 beta time frame. Later merged most of the SPIN capabilities into SPI and then worked to remove it's requirements from this library. Looks like 3 examples still include them. Will take a quick look...

As for using different fonts, the library supports all of the fonts that ILI9341_t3 handles plus it handles the Adafruit GFX fonts. There could be an issue or so on how some of these fonts may have explicit header files in conflict...
 
Quick update - I updated all of the example sketches that used SPIN.h to not use it any more. I also in some of sketches reduced the #ifdef for different configurations of pins and instead left it with in many
cases one configuration. Also with comment that says update to match your pins...

Hope that helps
 
Kurt,

Yep - resetting the pin assignments did the trick! Now I'm getting touch operation, but the the dots drawn in response to stylus input looks to be mirrored in both X & Y. IOW, when I touch the screen in the lower right-hand corner, the drawing occurs in the upper left-hand corner

I uncommented your debug code to print out the coordinate and the pressure, but that's not helping much, because apparently ts.bufferEmpty() always returns FALSE, leading to too much data. So I uncommented the guard for !ts.touched(), and that helped a lot. Now I can see the point coordinates and the retrieved pressure values.

So, it appears that when I touch inside the red color square, the point coordinate is something like (37xx,2xx), and the drawing occurs in the opposite corner from the red square. Conversely, If I want to change the color selection, I need to touch the screen along the opposite side from the color selection squares, and in the opposite direction in X.

I see from your code that you are using fillRect() to draw the squares at Y = 0 and X stepping from 0 to 5*BOXSIZE in BOXSIZE increments, so it looks like there is a mapping inversion somewhere?


I changed

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;

to

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;


And everything started lining up. Were you working with different display hardware, or am I missing something else?
 
Last edited:
Note: the Touch stuff. Returns the X and Y values at the same logical X and Y value that is in a different scale than the actual display is. Also it knows nothing about what orientation the TFT screen has been configured to.

SO it just does some simple mapping of value from one scale to another to convert to screen values...

That is it does:
Code:
 // 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
/
Which MAY be reasonably correct in two of the TFT orientations, but for sure not the other two. So you may need to change the mapping for other orientations and as you can see sometimes
Touch X maps to TFT Y values. Sometimes in will go MIN to MAX and others MAX to MIN.

At one point @defragster had a more complete mapping than this... Also sometimes the MIN/MAX touch values of specific display may be different:
Code:
//****************************************************************************
// 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
So those values may want to be adjusted...
Note in the first section of code I posted here, there are some Serial.print statements that are commented out. When I am debugging stuff like what values am I getting from the touch unit and what are they mapping to, I uncomment these prints.
 
Kurt,

What does

Code:
bool XPT2046_Touchscreen::bufferEmpty()
{
	return ((millis() - msraw) < MSEC_THRESHOLD);
}

Do?

I was looking for some way to debounce the touchscreen data from the screen, so I could start waiting for a new touch to occur. I thought this function might return true when that happened, but it appears to just be some kind of delay function. Have you used this before?

It looks like it might be some sort of startup delay, and returns FALSE when the millis() value becomes greater than msraw by 3msec.

For now I am debouncing the screen by doing this:

Code:
  tft.fillScreen(ILI9341_BLACK);
  tft.setRotation(1);
  tft.setCursor(50, 0);
  tft.printf("Touch the lower left corner\n");

  while (!ts.touched())
  {

  }

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

  //touch screen debounce
  while (ts.touched())
  {
    p = ts.getPoint();
    delay(10);
  }

Is there a better way of doing this?

TIA,

Frank
 
Kurt,

On another issue; I note that the mapping function

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;

appears to use TS Y extents for mapping the X-coordinate of the touch data, and TS X extents for mapping the Y-coordinate of the touch data. Is this intentional?
 
Sorry, I am not an expert on the XPT2046, with all of it's specifics.

There is some data up on Paul's Github readme: https://github.com/PaulStoffregen/XPT2046_Touchscreen

As for Touch X and Y versus Screen X and Y... Remember with the touch screen, when you touch a position on the physical sensor it will return the same values for X and Y regardless of what logical orientation the screen is configured to.

So for example if the logical touch display is sort of like:

+----------------------------------------------+
|TXMin, TYMin TXmax|
| |
| |
| |
|TYMAX TXmax, TYmax |
+----------------------------------------------+

Now suppose you logically rotate the TFT by setting tft.setOrientation(...) such that it
is logically rotated 90 degrees Counter clockwise...

Then the system would sort of logically be like:
+--------------------+
|TXMax TXmax,TYMax|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|TXMin,TYMin TYMax|
+--------------------+

Sorry, not very clear here, but sort of to show that as you logically rotate, how the Xs and Ys are...
And sometimes you swap which one is which and sometimes you may have to also map range of MAX to MIN instead of MIN to MAX...
 
It is not that complicated, the first thing is to get the touch panel to work using SPI. Then comes the calibration. The rotation of the screen must be considered and obtain the corresponding calibration.

The resistive film shows variations in the corners, however with the help of a fine-tipped touch pen, it is possible to obtain correct values to determine a value. You can independently map the x-axis and the y-axis. Variations can occur even with screens of different sizes and with the same rotation: 2.4 ", 2.8" and 3.2 ", even between different manufacturers.

Attached is an example with a 2.8 "ILI9341 screen.View attachment ILI9341 touch.zip
 
Status
Not open for further replies.
Back
Top