ILI9341 and XPT2046 for Teensy Touchscreen 320x240 display

Status
Not open for further replies.
Yes, yes...I see what you mean...that is more efficient but less understandable for newbies...I will work on a second sketch using your structure suggestion...then folks can choose which one they want to look at and see how the colors work.
 
How do I make use of a given font? I'm looking over the sample fonts on the PJRC site for this color screen, but how do I prepare to use a given font? Do I need both the .h and .c files? Do I just add an include for the font .h file?

I'm not clear on what I need to do to actually start using a different font.

Thanks...
 
First, either add this entire library, or copy just the .c and .h file for the font you need into your sketch. Either way is fine.

https://github.com/PaulStoffregen/ILI9341_fonts

Then add a #include line for the .h file in your sketch.

Then use tft.setFont() with any of the font names defined in that .h file. All the font names include the size. When using the new fonts, tft.setTextSize() has no effect.

Once you've set the font, tft.print() will use it.
 
When I execute the code below, the lines all bunch up on line 0...so I can see the text stepping on top of each other.

UPDATE: I added tft.setCursor(80, 0); and that seems to have fixed the problem. I thought println() would move the cursor but I guess not.

Code:
  #include "font_Georgia.h"

  tft.setRotation(3);  
  tft.setFont(Georgia_12);
  tft.setTextColor(ILI9341_YELLOW);
  tft.println("FS1000 FTD");
  tft.println("182 Aircraft Ver 1.0");
 
Last edited:
Now I'm trying to add toucn to my TFT Screen.

I'm trying to copy touch code parts into my sketch but am not sure what I am missing still.

I'm getting this compile error: 'p' was not declared in this scope.

Thank you for any help.

Code:
void loop(void)
{
  if (!ts.bufferEmpty())
  {   
    // Retrieve a point  
err-->  TS_Point p = ts.getPoint(); 
    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;
  }  
    //Serial.print(p.x);
    //Serial.println(p.y);
}
 
So, I decided to reduce my sketch to just the code to verify if Touch is working -- or -- not in my current case!

Here is my small sketch...I see nothing in the serial monitor.

I'm using a Teensy 3.2 board with the Color 320x240 TFT Display, ILI9341 Controller Chip.

Thank you for any help to get my touch sketch working.

Code:
#include "SPI.h"
#include "ILI9341_t3.h"
#include "font_Georgia.h"
#include <Wire.h>      // this is needed for FT6206
#include <Adafruit_FT6206.h>

// The FT6206 uses hardware I2C (SCL/SDA)
Adafruit_FT6206 ts = Adafruit_FT6206();

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 130
#define TS_MAXX 3800
#define TS_MAXY 4000

// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10

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

void setup()
{
  tft.begin();
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("ILI9341 Test!"); 

  if (!ts.begin())
  { 
    Serial.println("Unable to start touchscreen.");
  } 
  else
  { 
    Serial.println("Touchscreen started."); 
  }
}

void loop(void)
{
  if (ts.touched())
  {
    TS_Point p = ts.getPoint(); 
    //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;
    Serial.print(p.x);
    Serial.println(p.y);
  }
}
 
Yeah - that example is busted - I had to add a few things and remove a few things. I don't have the font file, the touch code header and creator weren't there, for minimal take out the adafruit - leave wire. Start with a working example and then add from there.

if not one of the others I linked - then perhaps :: XPT2046_Touchscreen\examples\TouchTest
 
Yeah, TouchTest works.

Question: when I run this and am not touching the screen, why does the serial window scroll values like 1621 2303? I don't quite understand that since nothing is touching the screen?


Code:
#include <XPT2046_Touchscreen.h>
#include <SPI.h>

#define CS_PIN  8
// MOSI=11, MISO=12, SCK=13

XPT2046_Touchscreen ts(CS_PIN);

void setup()
{
  ts.begin();
}

void loop()
{
  TS_Point p = ts.getPoint();
  if (ts.touched())
  {
    Serial.print(p.x);
    Serial.print(" ");
    Serial.println(p.y);
  }
  delay(250);
}
 
OK, I fixed the seemingly random serial window displays for x,y when nothing was touching the screen.

I didn't like from the get go that the Class TS_Point constructor for p was always being created inside the Loop(). This just didn't make any sense to me. So, I moved the TS_Point constructor of p outside of the Loop where it really belongs. Now inside the Loop, the same constructor object of p can receive the touch updates for x,y and z. There was just no need to keep creating a new object of p inside the loop. Just use the same p object over and over. This change stopped the random values from displaying in the serial window but I don't know exactly why.

Code:
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
#include "ILI9341_t3.h"

#define CS_PIN  8
// MOSI=11, MISO=12, SCK=13
// For the Adafruit shield, these are the default.
#define TFT_DC  9
#define TFT_CS 10

XPT2046_Touchscreen ts(CS_PIN);
TS_Point p;
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC);
  
void setup()
{
  ts.begin();
}

void loop()
{
  tft.setRotation(1);
  p = ts.getPoint();
  if (ts.touched())
  {
    Serial.println(p.x);
    Serial.print(" ");
    Serial.println(p.y);
  }
  delay(250);
}
 
That TouchTest sample works as it to show the hardware and software are working - but it isn't a good example of general usage. Especially since it uses delay(100). It does need to prevent over polling the touch device - but should use elapsedMillis.

There is a touch threshold below which a touch is not reported and pressure will always return ZERO when ts.touched() returns false.
At or above the threshold the code can display returned values indicating a usable touch - this includes the pressure.

A general usage example for 'polling' the touch device the code should call more like :

Code:
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
#include <elapsedMillis.h> // Not needed on Teensy

#define CS_PIN  8
// MOSI=11, MISO=12, SCK=13
XPT2046_Touchscreen ts(CS_PIN);

void setup() {
  ts.begin();
  while ( !Serial && (millis() < 2000)) ;
  Serial.println("Touchscreen started.");
}

elapsedMillis waitTouch;
elapsedMillis noTouch;
TS_Point p;

void loop() {
  if (waitTouch > 100) {
    if ( ts.touched()) {
      p = ts.getPoint();
      Serial.print("Pressure = ");
      Serial.print(p.z);
      Serial.print(", x = ");
      Serial.print(p.x);
      Serial.print(", y = ");
      Serial.print(p.y);
      Serial.println();
      noTouch = 0;
    }
    waitTouch = 0;
  }
  if (noTouch > 10000) {
    noTouch = 0;
    Serial.println("Touchscreen Not touched for 10 seconds.");
  }
}
 
Last edited:
I'll take a closer look at your modified code (which I like) but I have a question about map().

With my code snippet below, I have a square on the screen at a known x,y. With my plastic pencil point, I touch the corners and read the x,y.

It's always off by 10, 20, 30 or more (I realize its never going to be EXACTLY spot on). I thought I needed to add the map() function (because I saw another example using it) but now I'm really confused. If the screen is 320x240 why did the other example use 3800 and 4000? And do I need to use map() at all?

Code:
    //#define TS_MINX 150
    //#define TS_MINY 130
    //#define TS_MAXX 3800
    //#define TS_MAXY 4000
    //      value, fromLow, fromHigh, toLow, toHigh
    p.x = map(p.x,       0,     4000,     0,     320);
    p.y = map(p.y,       0,     3800,     0,     240);
    Serial.print(p.x);
    Serial.print(" ");
    Serial.println(p.y);
 
The MIN&MAX values used in the map function are critical to the proper conversion from raw point values to pixel points.
You are mixing and matching code snippets and those values do not match what I discovered to work and use in my samples.
My samples are evolving - slowly as I got diverted - but you may do better to start with one of them and understand the incorporated details to save rediscovering things piecemeal that are being 'hidden' if I can get back to it.

I took away the #defines and put it programmatically into the other samples you started using:

Code:
// Zero is calibration for mapping to pixal, 1-4 follow screen rotation for mapping math
TS_MAP tsMap[5] = { {[B][U]200, 3700, 325, 3670[/U] [/B]}, { 0, 319, 0, 239 }, { 319, 0, 0, 239 }, { 319, 0, 239, 0 }, { 0, 319, 239, 0 } };

  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);

That relies on the other development I made to handle the mapping on any of the 4 screen rotations - as the screen rotates it used one of the 4 other subsets to correct for the rotation in effect. Then based on the rotation in the rest of the mapping code in my samples adjusts the x and y to align as needed:
Code:
int16_t TS_Rotate = 4;

void  ButtonRotate( int setrotate )
{
  TS_Rotate = setrotate;
  if ( TS_Rotate > 4 ) TS_Rotate = 1;
  if ( TS_Rotate < 1 ) TS_Rotate = 4;
  tft.setRotation(TS_Rotate);
  tft.fillScreen(ILI9341_BLACK);
  PaintInit( currentcolor );
}
 
Well, I'm trying to dig into this slowly...I'm only using one screen orientation, #1. So, for now, I'm ignoring the screen rotation stuff as it is just mixing me up.

Don't we need a map for x and a map for y? Your array[0] below can only be used for x or y but not both?

I'm sorry I'm slow on getting this but isn't map() to map low point 1 to low point 2 as in point to pixel values AND high point 1 to high point 2 but all 4 values for one axis such as x? So don't we need a different set of map() values for y?

EDIT: I think I can come up with the correct mapping if I know the raw point values...I already know the pixel values but am unsure of the point values.

Your array below, as I look at it (ignoring the other rotation elements) is only for one axis?

Code:
TS_MAP tsMap[5] = { {200, 3700, 325, 3670 },
 
That mapping DOES incorporate data for both the x and y axis as indicated in the post #37 and all the code using it - and in any of four rotations - you only need one of the four remaining groups to make the right determination - that is up to you but I did all four because how the device is held/mounted may dictate not using just one - also unless they are all accounted for it only works in a fixed orientation.

Pick a starting point - a working sample and follow through toward your goal. A few of the wheels have been invented - understand them and build on them. It looks like I should get a fresh minimal sample up to avoid confusion - but I keep spending the time I have posting ...
 
Sorry I just don't understand it yet...I'll have to read up on this screen mapping business some more until the light comes on...right now I can't follow what your code is doing...
 
Maybe draw a box on a clean sheet of paper. Put it in rotation #1. The Mapping function converts the RAW value to a usable pixel value.

Now rotate that sheet of paper and you should see how the mapping code and array values come in to play as the relative values of x,y change.

Any difference in the MIN / MAX to the display in use will result in 'that much' error reflected in the mapped values, those errors will grow from the center of the screen outward.

Now that I've done this it can be taken for granted and unless it is misused - it will work - though again I didn't leave behind a simple example.

Attached is an example of the drawing I suggested.

MapMath.jpg

<edit>: As the page rotates the x,y coordinates shift to the user view, the TOUCH hardware return values are always fixed to the device.
 
Last edited:
@defragster - as they say "One picture is worth a thousand words" -- Bingo!!! The light came on once I saw your drawing!! I got it working for my orientation and understand now how it must work for the other orientations.

Amazing...just amazing...thanks to you and I'm sure other new folks will appreciate your drawing.
 
Great :)
I had to fight with a bug in the core which was very hard to find because it occured in my app in rare cases only, randomly..., so the last days i could'nt do much with displays or touch...
I still have to find a way around that, because i don't want to patch the core-lib. With the next update, my patch is gone..
 
Last edited:
Frank - Hope you get to test it and it can work for you. I need to do the POT slider after the Interrupts get fully working.

I just printed and the button struct array is 288 bytes big. The 6 'individual' buttons take 12 elements with 3 framed slider/toggles - each element is now 24 bytes. I have fixed 8 bytes for text - i.e. 7 letters. I could make a scheme to just put a string pointer in the button struct - and then attach them from another text array during button Init since some buttons have no need for text and some will need more than 7 printable characters?
 
Interrupt version of OnOffButton3i posted on GitHub. All the same buttons - user calls are the SAME (as #2) - but polling can be on a timer to detect first touch, unless an interrupt is detected - then no polling is done unless the FALLING edge interrupt is recorded.

onoffbutton3i/onoffbutton3i.ino

This code will not attempt an SPI touch read on the interrupt, as ongoing SPI activity c(w)ould be impacted. The detected interrupt simply sets a flag that allows user polling to occur until the touch is removed. More details on the shared code commit text.

I have seen the touch interrupt miss a touch - and don't yet see why. I don't have a scope/analyser to see if the pin just fails to 'FALL' - or if the display just doesn't see the touch on occasion? Manually reading the pin seems to give false readings - at least using USB debug prints. It was doing this before when I had a more complicated version (IntTouchPaintDeb ) with the interrupt code nested in the button code. I rewrote this to leave the button code unchanged - except the calls alias Touch and Point calls that only read the device as noted, otherwise they report no touch.

If this 70 lines of code were to work it might be worthy to add to the XPT2046_Touch library itself?
 
Hi Tim,

that works very good for me. Esp. the slider is great.
Some bytes more or less is not a problem. We're not on Arduino :) That string pointer is a good idea!

Frank
 
that works very good for me. Esp. the slider is great.
Some bytes more or less is not a problem. We're not on Arduino :) That string pointer is a good idea!

Great to hear the feedback - glad you got to try it and found it to work.

Amazing how much cleaner the interrupt code is redone and not merged in the Mapping code. I'll see if I can't get it worked directly into the TouchScreen lib to offer as a PULL option.

I'll Look at the string issue, and extra data. Seems I should add a non-momentary button - like CapsLock [Checkbox], and the "Pot" button adjustable return value slider.

I see some button 'CrossTalk' - where I assume the Touch data returned 'jumps' and holding one button 'visually' will suddenly trigger another button? I should make a DEBUG version that 'buffers' returned Touch Data during a prolonged touch - then USB formats it on release.
 
Status
Not open for further replies.
Back
Top