Highly optimized ILI9341 (320x240 TFT color display) library

Noob here and I scanned as much as I could in this thread but I couldn't seem to find a clear answer. Did these optimizations find their way into the ST7735 library?
I got directed here because of the https://hackaday.io/project/6038-pdqgfx-optimzed-avr-lcd-graphics project.
Seems a LOT quicker on an arduino then the ST7735 library with the teensy 3.1 that im using. Does the installed library set include the optimizations? Did the fonts make it into this version?

Thanks!
 
Problems accessing SD card when using Audio & High Speed Graphics Lib

I have a number of T3 with Audio Shields and both touch and non touch displays from the PJRC store. I have them wired up (2 of the sets anyway) and If I load the wave player example I can get the player to work, also if I load the graphics example I can get the graphics to work. however If I merge the two samples together I get an error 'cannot access SD card' I just D/L'd Arduino 1.6.8 & TD 1.2.8 B2 and I'm getting the same results. I'm not sure where to look for the problem next. I was hoping to get some advice here on what to look into.

Here's a sample 'minimal merge' where I took the wave player example and started adding in accelrated graphics code until the sketch won't access the SD card anymore. it happens with call to tft.begin. If I use the Adafruit 'sloooow' lib I can merge the two sketches successfully the graphics and audio work but the graphics are of course not accelerated. Has anyone run into this and solved it or could someone point me at what to look into?

Thanks Kb

Here's my merged 'sample' of course it's dependent on the sample audio files to fully work but you can see the issue by simply uncommenting the line
//#define T3_ACCEL 1

To use Acclerated library and that causes the problem, neither Touch nor SD work if using the accelrated graphics lib

Code:
/***************************************************
  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
  
  5/10/2015 Modified to run on Teensy 3.1 with audio card
 ****************************************************/
//#define T3_ACCEL 1

#include <Audio.h>
#include <Wire.h>
#include <XPT2046_Touchscreen.h>
#include <SPI.h>
#include <SD.h>
#define CS_PIN  8


XPT2046_Touchscreen ts(CS_PIN);

//#include "SPI.h"
#ifdef T3_ACCEL 
#include "ILI9341_t3.h"
#endif
#ifndef T3_ACCEL
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#endif
// For the Teensy with audio shield, these are the default.
#define TFT_DC 20
#define TFT_CS 21

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
#ifndef T3_ACCEL 
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#endif
#ifdef T3_ACCEL 
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC,255,7,14,8);
#endif
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

// GUItool: begin automatically generated code
AudioPlaySdWav           playWav1;       //xy=154,78
AudioOutputI2S           i2s1;           //xy=334,89
AudioConnection          patchCord1(playWav1, 0, i2s1, 0);
AudioConnection          patchCord2(playWav1, 1, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=240,153
// GUItool: end automatically generated code

void setup() {

  // Audio connections require memory to work.  For more
  // detailed information, see the MemoryAndCpuUsage example
  AudioMemory(5);

  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  
  SPI.setMOSI(7);
  SPI.setSCK(14);

  Serial.begin(115200);
  delay(2000);
  Serial.println("ILI9341 Test!");
  
    if (!ts.begin()) {
    Serial.println("Could Not Initialize Touch");
    delay(3000);
  } else {
    Serial.println("Initialized Touch");
    delay(3000);
    
  } 
 
  tft.begin();

    if (!(SD.begin(10))) {
    // stop here, but print a message repetitively
    //while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    //}
  }
  
  //testGraphics();

  Serial.println(F("Done!"));
}

void loop(void) {
  tft.setRotation(3);
  tft.fillScreen(ILI9341_BLACK);
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_GREEN);    tft.setTextSize(4);
  tft.println("SDTEST1.WAV");
  playFile("SDTEST1.WAV");
  tft.println("SDTEST2.WAV");
  playFile("SDTEST2.WAV");
  tft.println("SDTEST3.WAV");
  playFile("SDTEST3.WAV");
  tft.println("SDTEST4.WAV");
  playFile("SDTEST4.WAV");
#ifdef T3_ACCEL 
    if (ts.touched()) {
    TS_Point p = ts.getPoint();
    Serial.print("Pressure = ");
    Serial.print(p.z);
    Serial.print(", x = ");
    Serial.print(p.x);
    Serial.print(", y = ");
    Serial.println(p.y);
    }

#endif
  delay(250);

#ifndef T3_ACCEL
  delay(1000);
#endif

}

void playFile(const char *filename)
{
  Serial.print("Playing file: ");
  Serial.println(filename);

  // Start playing the file.  This sketch continues to
  // run while the file plays.
  playWav1.play(filename);

  // A brief delay for the library read WAV info
  delay(5);

  // Simply wait for the file to finish playing.
  while (playWav1.isPlaying()) {
    // uncomment these lines if you audio shield
    // has the optional volume pot soldered
    float vol = analogRead(15);
    vol = vol / 1024;
    sgtl5000_1.volume(vol);
    if (ts.touched()) {
    TS_Point p = ts.getPoint();
    Serial.print("Pressure = ");
    Serial.print(p.z);
    Serial.print(", x = ");
    Serial.print(p.x);
    Serial.print(", y = ");
    Serial.println(p.y);
    }

  }
}

unsigned long testFillScreen() {
    tft.setRotation(1);
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  delay(200);
  tft.fillScreen(ILI9341_RED);
  delay(200);
  tft.fillScreen(ILI9341_GREEN);
  delay(200);
  tft.fillScreen(ILI9341_BLUE);
  delay(200);  
  tft.fillScreen(ILI9341_BLACK);
  delay(20);  
  return micros() - start;
}

unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(0, 0);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}

unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();

  tft.fillScreen(ILI9341_BLACK);

  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing

  tft.fillScreen(ILI9341_BLACK);

  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(ILI9341_BLACK);

  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;

  tft.fillScreen(ILI9341_BLACK);

  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);

  return micros() - start;
}

unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);

  return micros() - start;
}

unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }

  return micros() - start;
}

unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height());
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
  }

  return t;
}

unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;

  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }

  return micros() - start;
}

unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      ILI9341_RED); //tft.color565(0, 0, i)); // change color to debug this code
      // its not the color
  }

  return micros() - start;
}

unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i, i));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i, i, 0));
  }

  return t;
}

unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  w     = min(tft.width(), tft.height());
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
  }

  return micros() - start;
}

unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;

  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()); i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
  }

  return micros() - start;
}

void testGraphics() {

  // 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(500);

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

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

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

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

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

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

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

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

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

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

  Serial.print(F("Rounded rects (filled)   "));
  //Serial.println(testFilledRoundRects());
  delay(500);
}
 
Last edited:
I just purchased a couple of Teensy 3.2's and i'm doing my best to get this all worked out with an ILI9341 2.4" TFT Touchscreen. I've read everything i could find on getting the text to overwrite the previous text by using the posted solution: tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK); but no matter what i try, the background is never overwritten. I just downloaded the latest version from pjrc.com of the ILI9341_t3 lib and use it with the UTouch lib... can anyone shed anymore light on this?

p.s. a calibration sketch and perhaps a method to adjust for a 2.4 TFT would be nice... just saying.

i ran a bunch of tests and see the problem only occurs with external fonts. That's to say, the method of specifying the background color works only if you're not using any external fonts... does anyone have any idea on how to work around this issue?

i guess there answer is... no one knows or this topic is dead
 
Last edited:
That's to say, the method of specifying the background color works only if you're not using any external fonts...

Correct, background drawing only happens with Adafruit's original fixed-size font.

does anyone have any idea on how to work around this issue?

You can "erase" the text 2 ways:

1: Print the exact same text again, at the exact same position, with the color set to your background.

2: Draw a filled rectangle large enough to overwrite the entire previously printed text.
 
I tried clearing a rectangular area behind the text before drawing but this resulted in very noticable flickering. Unfortunately when the ILI9341 is in SPI mode there is no blanking period so anything that is transferred to the screen is seen immediately. Regardless of how fast you can draw it. I'm currently using the DMA controller in my LPC1769 at 40Mhz to fill rects, so speed definitely isn't the issue there either.

I'll try inverting the characters as you first suggested. I thought of this too but assumed that it would result in the same issue as the background blanking. If the character is drawn all in one rect with the blanking happening at the same time as the font pixels it results in a much smoother transition.

Edit: Inverting the characters worked much better than blanking the entire label at once. Though there is still a lot of flicker. Is the font format documented anywhere in more detail or is it a custom format?

I submitted a patch with flicker-free background color drawing for external fonts, text measuring methods, as well as a bunch of fixes for clipping bugs (and the ability to do global clipping in a subset of the screen).

It's here:

https://github.com/PaulStoffregen/ILI9341_t3/pull/13

You can also pull it from my fork here:

https://github.com/blackketter/ILI9341_t3

Let me know if you try it and have any issues with it!
 
thanks Paul and blackketter, i was racking my brain trying to find a clear answer, although the forum is very comprehensive, it's massive and not always easy to sift through the collection of tangents that seem to fill each topic...

I will definitely try the patch and get back to you on it as it would certainly be great to be able to use the myriad of external fonts without having to write overwriting routines that cause the digits to flicker and make for painful minutia.

Using the Teensy 3.2:

I also have another issue with using the ILI9341 SPI at anything greater than 24MHz optimized.. seems the screen doesn't map properly or the touch event is occurring too quickly or something, but it is a problem.

BTW, the SD card reader on the TFT works very well at 24MHz as well without having to do any soldering or mods as outlined in anther post i've seen.

here is the screen i'm using: http://www.ebay.com/itm/171983887298?_trksid=p2057872.m2749.l2648&ssPageName=STRK:MEBIDX:IT
Here is an abbreviated version of my code
Code:
#include <SPI.h>
#include <ILI9341_t3.h>
#include <UTouch.h>
#define TFT_RST    255                                      // 255 = unused, connect to 3.3V
#define TFT_DC       9
#define TFT_CS      10
#define TFT_MOSI    11
#define TFT_MISO    12
#define TFT_SCLK    13
ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_MISO);

UTouch  myTouch(7, 6, 5, 4, 3);
int x,y;

void setup(){
  Serial.begin(9600);
  tft.begin();
  
  myTouch.InitTouch();
  myTouch.setPrecision(PREC_MEDIUM);
  tft.fillRoundRect(40, 80, 250, 40, 4, ILI9341_DARKGREEN); // Button:
  tft.setTextColor(ILI9341_WHITE, ILI9341_DARKGREEN);
  tft.setCursor(95,92);
  tft.setTextSize(2);
  tft.println("Button");

}

void loop {
  if (myTouch.dataAvailable()){
    myTouch.read();
    x = myTouch.getX();
    y = myTouch.getY();
  
    // If we press the first button
    if ((x>=40) && (x<=290) && (y>=80) && (y<=120)) {
     Serial.println("touched");
    }
  }
}
 
Last edited:
I also have another issue with using the ILI9341 SPI at anything greater than 24MHz optimized.. seems the screen doesn't map properly or the touch event is occurring too quickly or something, but it is a problem.

Perhaps your cables are too long ?
 
I hope not! :confused:

t3_ili9341.jpg
 
@zeek - I see you have a 2.4" version of the TFT - where PJRC sells and others I've seen have all been the 2.8" version. It looks to be the same circuitry on a smaller board. Not sure if that has anything to do with the SD, I never tried the SD until I did the mods - it may 'work' - but the mod removes resistors for bridges that were determined to have an unwanted effect by those before me.

I see you are using "#include <UTouch.h>" not the PJRC "#include <XPT2046_Touchscreen.h>" library, not sure if that makes a difference. In the PJRC you instantiate the TS with "XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);" to get interrupt gated Touch detection - this cuts down on extra SPI traffic when a touch is tested for but not recorded by the hardware no SPI transmissions occur. I don't know what other differences you might get from <UTOUCH>, as I've not used it or seen it used here after Paul created a version for PJRC.

Looking at this is odd "myTouch(7, 6, 5, 4, 3);" as it suggests [without my looking at UTouch] that it might be doing bitbanged SPI on alternate pins - and I see you have those extra pins wired. The XPT2046_Touchscreen.h uses hardware SPI on the common pins with just the unique CS_PIN, and optionally used TIRQ_PIN. The XPT2046 library has samples and I've posted some more at: XPT2046_Touch_Examples
 
...The XPT2046 library has samples and I've posted some more at: XPT2046_Touch_Examples

great thanks for the link, I'll definitely give that a go... as for the UTouch lib, this is actually part of a legacy Arduino project that used UTouch, and i had problems getting the XPT2046 lib to work in my project... i may have been swamped with other details and didn't think to try to get the lib Paul provided to work as the UTouch worked well enough...

thanks again for all the help.. will get back with updates as soon as i have a chance to apply them.
 
Good luck zeek - somehow it worked perfectly for me and I managed all the code right enough to work for me and provide help for others more than a couple times.

I spent a lot of hours with the XPT_Touch device and code - added the interrupt handling and using the PJRC XPT2046 code it was always just there - Paul did a faithful job on the command set and SPI details to make it work as I found it right after he posted it - I did optimize with the INT support - and before that detecting the non touched state in half the SPI command words - and then again trying to take three readings and average to the best two. Then I saw it for use as a Button UI that I started then got distracted from before making that a perfect clean idea - but those are in the Examples link. Very cool - but not cleaned into any sort of Library, just secondary files and only implemented some half of the button types that seemed cool - and the struct to define the buttons is a bit programmer centric - though I made a sketch sample to auto generate them.

Oh - in testing did you try writing an alternate color than FG or BG color when overwriting the old text? You may have been out of position when you rewrote. I made a forum note about the many steps to do that the other month - drawing a rect is slower - but seems there may be newer code that addresses that.
 
I tried getting the XPT2604 lib to work with my ts to no avail... here's the result, basically the screen display x=8191 y=8191 and flickers to no end. no touch events captured. the code i used was the ILI9341TEST that came with the lib i downloaded from the link from defragster (thanks btw) here is a pic and the code from the sketch i used
IMG_0868.JPG.jpeg

Code:
#include <ILI9341_t3.h>
#include <font_Arial.h> // from ILI9341_t3
#include <XPT2046_Touchscreen.h>
#include <SPI.h>

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

//XPT2046_Touchscreen ts(CS_PIN);
#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);

void setup() {
  Serial.begin(38400);
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(ILI9341_BLACK);
  ts.begin();
  while (!Serial && (millis() <= 1000));
}

boolean wastouched = true;

void loop() {
  boolean istouched = ts.touched();
  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(100, 150, 140, 60, ILI9341_BLACK);
    tft.setTextColor(ILI9341_GREEN);
    tft.setFont(Arial_24);
    tft.setCursor(100, 150);
    tft.print("X = ");
    tft.print(p.x);
    tft.setCursor(100, 180);
    tft.print("Y = ");
    tft.print(p.y);
    Serial.print(", x = ");
    Serial.print(p.x);
    Serial.print(", y = ");
    Serial.println(p.y);
  } 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(100);
}
here is the back of the screen, i've connected the t_cs to pin 8 and t_irq to pin 2. I don;t know what i'm doing wrong, and i most obviously am, but any help would be appreciated as i'd like to run the teensy 3.2 at at least 72MHz optimized as opposed to 24MHz to stay synced with the UTouch lib

IMG_0871.JPG.jpeg
 
Last edited:
Dropped that code on the unit here and it runs perfectly. Both handwired and the OSH_PJRC purple test boards.

I got another 128x128 display only unit, and like yours it had a yellow header spacer (the PJRC 2.8 and similar have black) - on that unit it came with a modified display driver chip sumotoy had to account for in code - but that was a video map offset. I'm wondering if on your board they changed the touch controller?

Having written the above - and thinking of the library code - it is quite likely with the change in display area - and thus the resistive sensing area the limits and values measured are changed. Your touches are being SEEN, but need different math to map them to the display area.

I don't see a source point for your UTouch library . . . if I saw that I might see if that is the case. Please link me to the code you are using.

Up for a challenge?:
I see some debug prints commented out in PJRC the library code. If you went to (...\hardware\teensy\avr\libraries\XPT2046_Touchscreen) and did a

copy XPT2046_Touchscreen.cpp XPT2046_Touchscreen.cpp.txt
> then you can restore the file or start over - it must not be a source code extension I learned

Then you could edit the lines like this : "//Serial.printf ..." to remove the comment and see the touch output on the USB Serial Monitor. Don't miss the one orphan "data[]" line:
Serial.printf("p=%d, %d,%d %d,%d %d,%d", zraw,
data[0], data[1], data[2], data[3], data[4], data[5]);

Save that file then :: Edit your INO sketch about line #66 to remove the "NO TOUCH" print :: // Serial.println("no touch");

I get something like this with a quick touch on the four corners that shows the expected range pretty well:
z=2160 :: z1=137, z2=2072 z1=137,z2=2072 p=2160, 252,537 274,536 275,535 274,536
, x = 274, y = 536
z=15 :: z1=0, z2=4080 z=655 :: z1=192, z2=3632 z1=192,z2=3632 p=655, 3516,407 3580,372 3518,409 3517,408
, x = 3517, y = 408
z=7 :: z1=1, z2=4089 z=2378 :: z1=775, z2=2492 z1=775,z2=2492 p=2378, 310,3518 314,3535 320,3521 312,3519
, x = 312, y = 3519
z=22 :: z1=2, z2=4075 z=1395 :: z1=1079, z2=3779 z1=1079,z2=3779 p=1395, 3552,3503 3568,3487 3580,3503 3574,3503
, x = 3574, y = 3503
z=5 :: z1=2, z2=4092

<edit>: BTW - I've mostly only ever run this at 96MHz.
 
Last edited:
definitely up to the challenge, however ill equipped i may be ;)

here is the UTouch lib i am currently using in my sketches https://github.com/wilmsn/UTouch

BTW, I did purchase a 2.8" display form PJRC.com.. will test it when i get it but for now, i'm going to make the changes and see what it gives.. very curious to see what this does at 96MHz as well!

Thanks!
 
Last edited:
Quick question about the tft library. Is there a flag in the controller or a library function that allows synchronizing to the display refresh? Kind of how in crt days you'd try to update the display during vertical blank so you didn't have tearing of the display with animations?

Thanks if anyone knows this and can point me in the right direction.
 
Nope. In 8080 mode there is a pin that can be configured to go low in vblank, but it's not broken out on the board. In RGB mode you send the vblank, but again I'm not sure if the right pins are available, and the library uses SPI mode, so you're SOL.
 
Thanks for the feedback pepijndevos, I'll have to dig into the spec sheet for the controller and see if the vblank flag can be accessed via spi. I'm working on what amounts to an oscilloscope display, I've currently got it reading an A/D channel and displaying a nice waveform on a 10x10 grid over 300 x 200 pixels at about 25 updates a second, but the text for annotation at the bottom of the screen is kind of choppy.
 
... 25 updates a second, but the text for annotation at the bottom of the screen is kind of choppy.

Have you optimized he updates to the text? Not writing when it hasn't changed - only blanking out the old text to background when you want to update?

Writing text is expensive and doubly so when you clear out a region with a rectangle - only guessing of course with no code or other details.
 
As Defragster mentioned, kind of hard to say much without seeing the code. For example are you trying to output the text with the transparent set? If so if I remember correctly this can be much slower as you can not simply blast all of the pixels out in one stream.

Also depending on setup, I have seen some who updated the code to more or less do all graphic outputs to a memory buffer and then blast all of that to the screen....
 
I have seen some who updated the code to more or less do all graphic outputs to a memory buffer and then blast all of that to the screen....

I've been thinking about doing this.. could you please link some examples of this?
 
I've been thinking about doing this.. could you please link some examples of this?

I don't know of any off the top of my head. I remember someone did a modified version of the Adafruit GFX library to do this. I Also don't remember all of the details like if they first setup up a rectangle of the bounding area they wish to buffer and then updated that region or tried to do whole display. As 320x240x2=153,600 bytes of data... Assuming I typed this into calculator correctly....

Maybe someone else remembers the details and/or can point you to it. Otherwise you might be able to search for it.

Again my first step would be to make sure I am NOT using transparent text output, as this is a lot slower than doing non-transparent, which more or less does as straight serial stream out for the area of the text.
 
Back
Top