ILI9341 and XPT2046 for Teensy Touchscreen 320x240 display

Status
Not open for further replies.

defragster

Senior Member+
I got some of these PJRC displays that are in common use - mine wired up as indicated on these pages:

Color 320x240 Touchscreen, 2.8 inch, ILI9341 Controller

> this unit is the same smaller screen controller but without the XPT2046 TOUCH controller:
Color 320x240 Display, 2.2 inch, ILI9341 Controller

My current example set of Touch enabled ILI9341 sketches:
https://github.com/Defragster/XPT2046_Touch_Examples

There are two other active threads with Touch posts - hoping to merge activity on this to here from:
2.8 ILI9341 restive touch miso not connected ?

Highly optimized ILI9341 (320x240 TFT color display) library
 
<edit>: Last update 1/1/2016
From GitHub ReadMe::

Examples using the Teensy XPT2046_Touchscreen

MARK3 examples are the latest. ButtonCode moved to separate file. Button mapping struct evolved. Stored the Mapping Data in 'sketch'.h header file so it isn't always in the way.

The examples here develop a uniform structured way to implement and handle TOUCH BUTTONS

There is interrupt awareness in PJRC XPT2046_Touchscreen library starting in TeensyDuino 1.27b2: \hardware\teensy\avr\libraries\XPT2046_Touchscreen

Purged some older samples - it was an evolving project - started buttons - started in sketch interrupts - moved interrupt code to core library - if you are looking start with the MARK3 and any later examples. Any code with attachInterrupt is deprecatated with the release of TeensyDuino 1.27

Feedback or questions at: https://forum.pjrc.com/threads/31634-ILI9341-and-XPT2046-for-Teensy-Touchscreen-320x240-display.

If you get a compile error on "XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);" you don't have the interrupt aware code, comment that line and remove comment from the other line: //XPT2046_Touchscreen ts(CS_PIN); // Param 2 - NULL - No interrupts and TeensyDuino version 1.26 libs

To use on Teensy LC you must use the Adafruit_ILI9341 library not the ILI9341_t3 library, and "Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);"
 
Last edited:
Much thanks for your hard work.

Touch_Test works fine with my Teensy 3.2 and your code from GitHub.
onoffbutton works great also.
TouchPaint works but I'm sure correctly...as I draw lines, in the same color, pixels color up outside of the line I'm drawing. Other times the line draws for about an inch and then stops coloring as I continue to move my plastic pencil tip. I don't need the capabilities in this sketch but thought I'd report my findings anyway.

Touch_Test and onoffbutton sketches I need to dive into and learn how they are working. I need to display text on my screen and some buttons with text labels on them...the buttons I need to be able to touch and detect. So that's what I'll be looking over in your sketches.

Much thanks again.
 
@rfresh737 did you have the serial monitor up while you used touchpaint? If not try it with a monitor window open and let me know what happens.
 
@cartere: I don't see a note on which doesn't work without the Serial Monitor open? When I ran off battery with no usb - what I tried worked.

Also I 'hid' the odd behavior in the buttons on TouchPaint - but it is odd with x,y not as expected. I didn't look at that - somebody did on another thread - if that fix applies to touch paint here let me know and I'll turn it around. When I did the debug version it got in the way - but I just dealt with it.

@rfresh737 - the interrupt code is having an issue with losing touch I didn't see for a long time. But you say 'TouchPaint' - I see that uses the interrupt - not sure when I did that as it does not have the backup timer when interrupt not provided. I wanted to get these cleaned up before starting this thread - but the other two threads were getting too many hits to track - so I did it and put all code in one place - not sure what is what just now, thanks for the post.

The OnOffButton is the best so far as far as where the button 'language' is headed - but uses polling. I saw a post about the button hits streaming in - that is expected because the touch is still happening. That is for the user code to deal with I think as hiding ongoing touches would end up bothering other uses: like a VOL UP and VOL DOWN button could time the length of the button and adjust the volume. Also Frank wants a potentiometer like slider that would track the user adjusting edge to edge on the button and the returned value could be important to track in real time.

Had a windstorm here - been running house on a generator the last 24 hours now - a bit of added distraction.
 
@defragster

In the button structure definition, what is the 7th parameter for? TS_FBUTN, TS_TOGON + 1, TS_TOGOFF +1 etc. etc.

EDIT: the 5th and 6th parameters are colors for the buttons but it looks like one is for when the button has the focus and the other color for when it doesn't have the focus?
 
Last edited:
Looking at : GitHub\XPT2046_Touch_Examples\onoffbutton - struct below. That needs to be cleaned up, was supposed to have added elements by now.

... I started to make a simple button - then there was another button type - then another - so I overloaded the fields without making it right in order to support ever more button styles going forward.

fgc - is forground color for text
bgc is the button background fill color. { the union .togval was a quick fix where FRAME button are just a border connecting the indexed sub-buttons }
info should become two values - now that is ButtonType tracking toggle button state and the index number to its owner frame

That kludge is TOGGLE specific - where a FRAME holds two TOGGLE sides. For simple touch select buttons that isn't used.

Code:
//        { tx, ty, ww, hh, fgc, {bgc_togval}, info, text[8], bId }    << Struct looks like this
 
I see...my button requirement is dead simple: I just need to paint a button with text on it and be able to touch it and then have my code do some thing after detecting the touch...so I don't need to use the FRAME toggle structure.

Just curious, does your button code support round corner buttons or just square buttons at this time?

EDIT: BTW I don't know how important this is or if it even matters, but when I touch the Clr button, the whole screen refreshes...when I touch Hi! it just toggles back nicely without the whole screen refreshing.

Thanks...
 
Last edited:
Right now all the frames are square. It could do a rounded rectangle easily enough - of course then you have to define the corner radius.

But the hit test area should be a rectangle - that would need to include the fill area outside the rounded corners
 
Yeah...I can live with square buttons.

I'm trying to use your code and start off by making just one button and then detecting a touch on it.

1. So below here I am defining one button. It displays correctly in the x,y location. The fill color is working but the text fgc is not...no matter what colors I try, it doesn't change the text color.

2. The touch area is off...I think because I am using rotation #3. I don't need to rotate the display. I can actually touch in the lower right corner and see the serial window display print the results of the touch. But my button is in the upper left corner of the screen!

3. My text is short, only "PFD", is there anyway I can center that text in the button face?

4. For clarification, TS_FBUTN defines this item as a stand alone button?

Code:
TS_BUTTON buttons[] = {
  {10, 25, 100, 50, ILI9341_BLACK, ILI9341_CYAN, TS_FBUTN, "PFD", 200 },
/*  {10, 80, 100, 50, ILI9341_BLACK, 0, TS_FRAME + 1, "???", 101 },
  {10, 80, 50, 50, ILI9341_RED, ILI9341_BLUE, TS_TOGON + 1, "ROT", 1 }, {60, 80, 50, 50, ILI9341_GREEN, ILI9341_BLUE, TS_TOGOFF + 1, "SIT", 51 },
  {10, 135, 100, 50, ILI9341_RED, 1, TS_FRAME + 2, "???", 102 },
  {60, 135, 50, 50, ILI9341_ORANGE, ILI9341_BLACK, TS_TOGOFF + 2, "yyy", 2 }, {10, 135, 50, 50, ILI9341_CYAN, ILI9341_BLACK, TS_TOGON + 2, "xxx", 52 },
  {115, 25, 50, 105, ILI9341_YELLOW, 0, TS_FRAME + 3, "???", 103 },
  {115, 25, 50, 55, ILI9341_CYAN, ILI9341_BLACK, TS_TOGOFF + 3, "Clr", 3 }, {115, 80, 50, 50, ILI9341_CYAN, ILI9341_NAVY, TS_TOGON + 3, "Hi!", 53 },
  {165, 25, 50, 105, ILI9341_CYAN, ILI9341_PINK, TS_FBUTN, "Dbo", 201 },
  {115, 135, 100, 50, ILI9341_BLACK, ILI9341_DARKCYAN, TS_FBUTN, "BOUNCE", 202 },
  */
};
 
Last edited:
opps - That is a BUGBUG - the frame border is one color FBC and the Frame Fill color - the button text is indeed always hardcoded as WHITE.

I've been away from buttons too long . . .

Code:
        tft.setTextColor(ILI9341_WHITE);  // BUGBUG - this to come from struct!
        tft.setTextSize(2);  // BUGBUG - this to come from struct!
        tft.println(buttons[ii].text);

I should clean that up and the overloaded toggle .... the interrupt coding has been longer than I thought
 
I'm having difficulty finding the API documentation for the TFT graphics functions such as fillRoundRect(), drawRect(), fillCircle() etc.

I want to read up on the arguments...what they are, etc.

Does anyone where I can find the technical docs for these kinds of graphics calls?

Thanks...
 
All I've ever seen is this: "\hardware\teensy\avr\libraries\ILI9341_t3\ILI9341_t3.cpp" and the associated header file. Then look for 'r' to be radius.

There may be something more where it came from before being T3 tweaked.

I thought you could live without rounded buttons?

<edit> @rfresh737 - I could make a quick change to use FGC on the FRAME and the text - that almost makes sense?
 
Last edited:
Updated onoffbutton1 with text color as FGC and made a rounded button with radius half the height - draws right but changed button behavior in loop()???

Code:
          tft.fillRoundRect(buttons[ii].tx, buttons[ii].ty, buttons[ii].ww, buttons[ii].hh,buttons[ii].hh/2, buttons[ii].bgc);
 
>I thought you could live without rounded buttons?

Yes, I can...square buttons are fine...I'm just trying to learn about the other graphics functions, how they work, etc.

I'm still trying to figure out what that 5th argument is for in tft.drawRoundRect(x, y, w, h, 5, color) ?

Thanks for making that change in onoffbutton1 for controlling the text color.
 
Good morning rfresh.

I had the same question the other day for myself. I went back to the documentation that Henning put together for the TFT and TFT Button libraries and found an answer that worked for me. The 5th argument should be the radius desired for the rounded rectangle function. It isn't there for the drawRect function as of course the corner radius is a square.
Matadormac
 
From the keywords.txt file of the ILI9341_t3 library Paul contributed I found this list and have used it for my buttons. I don't know of a color swatch matching for each but I guess setting it up on your display wouldn't be too difficult.

ILI9341_BLACK LITERAL1
ILI9341_NAVY LITERAL1
ILI9341_DARKGREEN LITERAL1
ILI9341_DARKCYAN LITERAL1
ILI9341_MAROON LITERAL1
ILI9341_PURPLE LITERAL1
ILI9341_OLIVE LITERAL1
ILI9341_LIGHTGREY LITERAL1
ILI9341_DARKGREY LITERAL1
ILI9341_BLUE LITERAL1
ILI9341_GREEN LITERAL1
ILI9341_CYAN LITERAL1
ILI9341_RED LITERAL1
ILI9341_MAGENTA LITERAL1
ILI9341_YELLOW LITERAL1
ILI9341_WHITE LITERAL1
ILI9341_ORANGE LITERAL1
ILI9341_GREENYELLOW LITERAL1
ILI9341_PINK LITERAL1
 
OK...here is my sketch.

This code will paint 19 squares on the TFT LCD screen, with each square displaying a different color.

Use the index number to associate the actual color name.

If there are more colors please let me know and I will modify the sketch to show them.

Code:
/*******************************************************************
  This sletch displays all the (known to me at this time)
  Colors for the Color 320x240 TFT Display, ILI9341 Controller Chip.
  Screen URL Link: https://www.pjrc.com/store/display_ili9341.html
  Developed using a Teensy 3.2 Board
  Written by Ralph Freshour
  Version 1.0 11/19/2015

  Index     Color Name
  1 ILI9341_BLACK
  2 ILI9341_NAVY
  3 ILI9341_DARKGREEN
  4 ILI9341_DARKCYAN
  5 ILI9341_MAROON

  6 ILI9341_PURPLE
  7 ILI9341_OLIVE
  8 ILI9341_LIGHTGREY
  9 ILI9341_DARKGREY
  10 ILI9341_BLUE

  11 ILI9341_GREEN
  12 ILI9341_CYAN
  13 ILI9341_RED
  14 ILI9341_MAGENTA
  15 ILI9341_YELLOW

  16 ILI9341_WHITE
  17 ILI9341_ORANGE
  18 ILI9341_GREENYELLOW
  19 ILI9341_PINK
*******************************************************************/

#include "SPI.h"
#include "ILI9341_t3.h"

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

int intButtonRadius = 5;  
  
void setup()
{
  tft.begin();
  tft.setRotation(3); // normal landscape orientation
  tft.fillScreen(ILI9341_WHITE);
  //Serial.begin(9600);
  // Note: Serial Window prints are working but not really needed so I have remmed them out
  //while (!Serial) ; // wait for Arduino Serial Monitor
  //Serial.println("Color LCD Samples Started!"); 
  paint_Color_Samples();
  //Serial.println("Done!");
}

void loop(void)
{
  // nothing to do here really
}

/**************************************************************************
  This function paints 19 color samples with an index number because there is
  not enough room to paint the color name in most cases.
***************************************************************************/
void paint_Color_Samples()
{
  int int1Left = 15;
  int int1Top = 5;
  int int2Top = 65;  
  int int3Top = 125;  
  int int4Top = 185;  
  int int1Width = 50;    
  int int1Height = 50;  
  int int1TextLeft = 0;
  int int1TextTop = int1Top + 10;
  int int2TextTop = int2Top + 10;
  int int3TextTop = int3Top + 10;
  int int4TextTop = int4Top + 10;
      
  tft.setRotation(3); // normal landscape orientation
  tft.fillScreen(ILI9341_WHITE);
  tft.setTextSize(2);

  // Row 1
  tft.fillRoundRect(int1Left, int1Top, int1Width, int1Height, 0, ILI9341_BLACK);
  tft.setCursor(int1TextLeft+34, int1TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("1");

  tft.fillRoundRect(int1Left + 60, int1Top, int1Width, int1Height, 0, ILI9341_NAVY);
  tft.setCursor(int1TextLeft+94, int1TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("2");

  tft.fillRoundRect(int1Left + 120, int1Top, int1Width, int1Height, 0, ILI9341_DARKGREEN);
  tft.setCursor(int1TextLeft+154, int1TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("3");

  tft.fillRoundRect(int1Left + 180, int1Top, int1Width, int1Height, 0, ILI9341_DARKCYAN);
  tft.setCursor(int1TextLeft+214, int1TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("4");

  tft.fillRoundRect(int1Left + 240, int1Top, int1Width, int1Height, 0, ILI9341_MAROON);
  tft.setCursor(int1TextLeft+274, int1TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("5");



  // Row 2
  tft.fillRoundRect(int1Left, int2Top, int1Width, int1Height, 0, ILI9341_PURPLE);
  tft.setCursor(int1TextLeft+34, int2TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("6");

  tft.fillRoundRect(int1Left + 60, int2Top, int1Width, int1Height, 0, ILI9341_OLIVE);
  tft.setCursor(int1TextLeft+94, int2TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("7");

  tft.fillRoundRect(int1Left + 120, int2Top, int1Width, int1Height, 0, ILI9341_LIGHTGREY);
  tft.setCursor(int1TextLeft+154, int2TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("8");

  tft.fillRoundRect(int1Left + 180, int2Top, int1Width, int1Height, 0, ILI9341_DARKGREY);
  tft.setCursor(int1TextLeft+214, int2TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("9");

  tft.fillRoundRect(int1Left + 240, int2Top, int1Width, int1Height, 0, ILI9341_BLUE);
  tft.setCursor(int1TextLeft+268, int2TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("10");



  // Row 3
  tft.fillRoundRect(int1Left, int3Top, int1Width, int1Height, 0, ILI9341_GREEN);
  tft.setCursor(int1TextLeft+28, int3TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("11");

  tft.fillRoundRect(int1Left + 60, int3Top, int1Width, int1Height, 0, ILI9341_CYAN);
  tft.setCursor(int1TextLeft+88, int3TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("12");

  tft.fillRoundRect(int1Left + 120, int3Top, int1Width, int1Height, 0, ILI9341_RED);
  tft.setCursor(int1TextLeft+148, int3TextTop+8);
  tft.setTextColor(ILI9341_WHITE);
  tft.println("13");

  tft.fillRoundRect(int1Left + 180, int3Top, int1Width, int1Height, 0, ILI9341_MAGENTA);
  tft.setCursor(int1TextLeft+208, int3TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("14");

  tft.fillRoundRect(int1Left + 240, int3Top, int1Width, int1Height, 0, ILI9341_YELLOW);
  tft.setCursor(int1TextLeft+268, int3TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("15");



  // Row 4
  tft.fillRoundRect(int1Left, int4Top, int1Width, int1Height, 0, ILI9341_WHITE);
  tft.setCursor(int1TextLeft+28, int4TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("16");

  tft.fillRoundRect(int1Left + 60, int4Top, int1Width, int1Height, 0, ILI9341_ORANGE);
  tft.setCursor(int1TextLeft+88, int4TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("17");

  tft.fillRoundRect(int1Left + 120, int4Top, int1Width, int1Height, 0, ILI9341_GREENYELLOW);
  tft.setCursor(int1TextLeft+148, int4TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("18");

  tft.fillRoundRect(int1Left + 180, int4Top, int1Width, int1Height, 0, ILI9341_PINK);
  tft.setCursor(int1TextLeft+208, int4TextTop+8);
  tft.setTextColor(ILI9341_BLACK);
  tft.println("19");

}
 
Colors are an RGB variant -
From the source it maps like this 5 bits, 6 bits, 5 bits
> color565(uint8_t r, uint8_t g, uint8_t b)

@rfresh - I worked on cleaning my button code - added struct elements - a bit but ran out of time getting the slider detection. If you did your post #22 'programmatically' it would take less space - at the same time you could USB PRINT the formatted structure details to put them into a button structure. I saw why the rounded button I got to draw wasn't active - but that fix is held up in my structure rewrite.
 
Last edited:
>If you did your post #22 'programmatically' it would take less space.

How does one do it that way?

>you could USB PRINT the formatted structure details to put them into a button structure.

Right...but I wanted to do it in a very simple manner so other newbies could follow it easier. But I do like your button structure idea. I'll hold off a bit downloading your new button code until you get more time to finish it. Thanks.
 
@rfresh - gotta run - new phone waiting on me . . .

You'd need to put the colors in an array : Numbers work to use them but would be cryptic in the structure - so maybe the text names too for USB output.

Then have two loops - to replicate what you have - a quick attempt - you need to adjust for setcursor as noted

Code:
kk=0; // index for the color array
for ( ii=int1Left; ii<300; ii+=60 )
  for (jj=int1Top; jj<240; jj+=60)
{
  tft.fillRoundRect( ii , jj , int1Width, int1Height, 0, ILI9341_BLACK);
  tft.setCursor( ii + ???, jj + ??? );  // EDIT THIS FOR TEXT OFFSET from ii, jj
  tft.setTextColor(array_colors[ kk ]);
  kk++;
  tft.println(kk);
}
 
Status
Not open for further replies.
Back
Top