ILI9341 and XPT2046 for Teensy Touchscreen 320x240 display

Status
Not open for further replies.
And the answer is . . . 42 . . . lines of code to activate interrupts on the Touch Driver.

UPDATED SAMPLE: onoffbutton3i/onoffbutton3i.ino

> Using PIN Interrupt results in NO POLLING when there is no touch, sets flag to allow reading/polling on next request.
> Using Timer Interrupt supports 'timed' POLLING to detect touch, sets flag to allow reading/polling on next request.
BOTH: Once touch detected the user code can call/poll as desired to track the touch while present.

Given Paul's dire warning - I really overthought this! When I took out the extra steps and checks - I don't see missed touches on T3.1.

Simplified:
> Use Pin Interrupt if specified (no time wasted to deactivate it)
> Or use Timer interrupt if specified
> Interrupt is either WAIT'ing or ACTIVE
> Two state flag for Interrupt: WAIT or ACTIVE
> no extra logic or code to slow the process
> This may explain why I never saw it until I plugged in a Teensy LC, will test again on LC.
> And on T_3.1 it explains why the more code and debug spew I added the worse it got.

Will post updated copy of driver lib code that handles this transparently [with edit to .begin()] to my Examples GitHub for testing ASAP.
 
I need some help with CPP doing :: attachInterrupt( PinInt, TS_isrPin, FALLING ); Is there a similar solution in an included library that I didn't find?

Where "void TS_isrPin(void)" needs to be callable during on the interrupt and have access to a class variable isrWake ?

So it can't be a CPP class member? But needs a way to access the private isrWake?

Code:
bool XPT2046_Touchscreen::begin()
{
	SPI.begin();
	pinMode(csPin, OUTPUT);
	digitalWrite(csPin, HIGH);
	if (255 != tirqPin) {
		pinMode( tirqPin, INPUT );
		[B]attachInterrupt( tirqPin, XPT2046_Touchscreen::TS_isrPin(void), FALLING );[/B]
	}
	return true;
}

[B]void XPT2046_Touchscreen::TS_isrPin( void )[/B]
{
    [B]isrWake [/B]= true;
}

Other than this - dropping my 42 lines of code into the XPT2046_TOUCH library is trivial; and under like 20 lines of code - I decided to forgo the TimerInterrupt I put in for testing as I didn't want to require #include <TimerOne.h>, the user can easily enough duplicate this behavior.
 
I need some help with CPP doing :: attachInterrupt( PinInt, TS_isrPin, FALLING ); Is there a similar solution in an included library that I didn't find?

Where "void TS_isrPin(void)" needs to be callable during on the interrupt and have access to a class variable isrWake ?

So it can't be a CPP class member? But needs a way to access the private isrWake?

That's a bit tricky.
I had the same problem with the audiocodecs. perhaps you want to look here.
My ISR is a normal C function. I have a global pointer to the object ("AudioPlaySdMp3 *mp3objptr;") and use that pointer to access the variables in it.
There might be better ways, but that worked for me.
 
Thank you Frank! Your example followed my expectations - and what I found on the web as noted - but gave a clean example to follow - and make sure it was as 'legitimate' a hack as possible. The last link in this post will be the updated XPT2046_Touchscreen library code.

I modified the TeensyDuino library to have native Interrupt detection and prevent user polling over SPI unless a Touch interrupt has been recorded.

See: XPT2046_Touch_Examples/tree/master

I have converted a single sample ready to use the modified library - once you update the library any old code can enable the interrupts during 'ts' creation:

onoffbutton4_Pull

This documents the change needed to
Code:
#define CS_PIN 8
XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
// Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
#define TIRQ_PIN  2
//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
// Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library

These two files have been modified to allow the hardware interrupt pin to refuse SPI POLL requests when no TOUCH interrupt has been detected:
https://github.com/Defragster/XPT2046_Touch_Examples/tree/master/XPT2046_Touchscreen

If anyone pulls this code down and tries it let me know - I'll adjust the default library examples so PJRC can consider a pull request. Anyone who wants to see how simple it was I checked in the 1.26 source files so the DIFF you see is all I changed.

How you know it is working? The Teensy LED in the default configuration sits on the SPI bus and flickers with any transfer - screen update or Touch poll request. Run one of the samples without the interrupt aware code and your LED will be lit with the intensity of the testing for a touch. Once you install the updated library code and enable the interrupt on your wired pin - you should see a DARK LED - until the touch happens no matter how often you use any of these functions. While you touch the screen - these functions will hit the SPI bus as fast as every 3 ms and the LED will become very bright.

Code:
	TS_Point getPoint();
	bool touched();
	void readData(uint16_t *x, uint16_t *y, uint8_t *z);
 
@Paul - if you are watching this development and are interested I'll be doing a pull request soon - you can see the code and preview the DIFFs if you have time. I was modifying the exisiting library examples and decided to offer a loop() with no delay on polling to show the value in this mod to take the LED from all but on to OFF until untouched.

NOTE: Problem area identified and addressed. The failure to register touch on interrupt was easily fixed running within the library. That simplification I noted a couple of posts back was working on the symptom. In doing an no delay() extreme test to show the interrupt usefulness in stopping SPI polling/thrashing I came across a repeatable touch that left the touch unseen until re-touched.

That correction is made here using a lesser threshold to ignore the interrupt - but not change the value returned to the user: XPT2046_Touchscreen/XPT2046_Touchscreen.cpp#L137

Here is the ugly sample that was behind the change: TouchTest/TouchTest.ino
Using the proposed code as indicated then watch the non-interrupt code - then enable interrupt and LED goes from bright to black and doesn't miss a touch - versus the delay(100) version for sure.
 
The ISR code is pretty simple:

Code:
[URL="https://github.com/Defragster/XPT2046_Touch_Examples/blob/master/XPT2046_Touchscreen/XPT2046_Touchscreen.cpp#L57"]void isrPin( void )
{
	XPT2046_Touchscreen *o = isrPinptr;
	o->isrWake = true;
}[/URL]

Credit to Frank for writing half this function.
 
Implemented Code suggested in post #25: User code loops and draws colored buttons on screen.

t3butn20.jpg

USB Prints the needed struct data to match it with simple buttons.

Putting that struct data back into code uses it as modified

Button #1 rotates screen clockwise, buttons are redrawn and those buttons leaving the screen are clipped.

The struct version in the code on GitHub currently clips 8 buttons in portrait, the USB output shifts buttons left and only 4 are clipped when in portrait layout. If you take the structure output and replace in the sketch it will change that.

ColorButtonsTest/ColorButtonsTest.ino

All displayed buttons will respond with Serial.print of the button number.

Constant press on SAME button registers once until 50ms between touches

SWIPING the buttons will register them in turn as pressed

Setting "#define LC 1" will use slower Adafruit driver and work on the Teensy LC (or T_3.x)

As saved expects to use interrupt pin code :: XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling
If changed to not specify the interrupt it works the same as the "TS_LIMIT" POLLING rate is 10ms and the LED will be BRIGHT
 
Last edited:
Really Nice Work!

Working well on Teensy 3.2 with Arduino1.6.6 & Teensyduino1.26-b3
Also works with the enhanced ILI4391_T3 Fonts I'm using DroidSans_24_Bold
IMG_20151127_114725a.jpg

Constant press on SAME button registers once until 50ms between touches

Since the XTP2046 registers touch pressure, it would be interesting to use pressure sense to regulate the rate, for example:

  1. Quick tap increments or decrements by one
  2. Light continuous touch counts up or down slowly
  3. Firm continuous touch counts up or down quickly
 
Last edited:
Rfresh737 & Wozzy - Thanks. Did you try it - with the INT code or without? It works 'the same' both ways - but no SPI noise trusting the touch int.

Wozzy - Looks nicer with your font. Let me know if you cut and paste the left adjust into the code to see the button clipping. Did this on the way to making an alpha keyboard and other edits - started there just to answer the prior post.

Run a pressure display example like TouchTest and watch the pressure as you touch - let me know if there is any usable info there.

By the way Teensduino 1.26 has left beta.
 
I'm getting a compile error on line 20:

Arduino: 1.6.5 (Windows 7), TD: 1.26-beta3, Board: "Teensy 3.2 / 3.1, Serial, 96 MHz optimized (overclock), US English"

ColorButtonsTest:20: error: no matching function for call to 'XPT2046_Touchscreen::XPT2046_Touchscreen(int, int)'
ColorButtonsTest.ino:20:35: note: candidates are:
In file included from ColorButtonsTest.ino:14:0:
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\XPT2046_Touchscreen/XPT2046_Touchscreen.h:44:2: note: XPT2046_Touchscreen::XPT2046_Touchscreen(uint8_t)
XPT2046_Touchscreen(uint8_t cspin);
^
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\XPT2046_Touchscreen/XPT2046_Touchscreen.h:44:2: note: candidate expects 1 argument, 2 provided
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\XPT2046_Touchscreen/XPT2046_Touchscreen.h:42:7: note: constexpr XPT2046_Touchscreen::XPT2046_Touchscreen(const XPT2046_Touchscreen&)
class XPT2046_Touchscreen {
^
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\XPT2046_Touchscreen/XPT2046_Touchscreen.h:42:7: note: candidate expects 1 argument, 2 provided
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\XPT2046_Touchscreen/XPT2046_Touchscreen.h:42:7: note: constexpr XPT2046_Touchscreen::XPT2046_Touchscreen(XPT2046_Touchscreen&&)
C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\XPT2046_Touchscreen/XPT2046_Touchscreen.h:42:7: note: candidate expects 1 argument, 2 provided
Multiple libraries were found for "Adafruit_ILI9341.h"

Used: C:\Users\fresh1011\Documents\Arduino\libraries\Adafruit_ILI9341

Not used: C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\Adafruit_ILI9341

no matching function for call to 'XPT2046_Touchscreen::XPT2046_Touchscreen(int, int)'

This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
 
BUSTED - you haven't taken my Interrupt touch code so you need to read the comments and adjust accordingly. Thanks for testing - I never tried to compile with the 1.26 library.

Code:
[U]//XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts[/U]
// Second PARAM on XPT2046_Touchscreen [B]requires modified interrupt aware XPT2046_Touchscreen library[/B]
#define TIRQ_PIN  2
//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
// Second PARAM on XPT2046_Touchscreen [B]requires modified interrupt aware XPT2046_Touchscreen library[/B]

Are you using an LC? If you are not you can activate the "#include <ILI9341_t3.h>" instead of the slower adafruit SPI code.
 
I'm trying it without the interrupts. I'm using a Teensy 3.2 board.

Code:
#define CS_PIN 8
//XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
// Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
#define TIRQ_PIN  2
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
// Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
 
You'll get the same error with that.

Code:
//#define LC 1

XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
// Second PARAM on XPT2046_Touchscreen requires modified interrupt aware XPT2046_Touchscreen library
 
Does anyone know if the screen read function was ever implemented? That would make the possibility of pop-up keyboards ( numeric and alpha ) very interesting. Probably could do it anyway, would have to rebuild the screen from scratch each time. Great work defragster have the code running on a 3.0 at the moment.
 
Oh, looks like readRect() still has the fast SPI clock speed, so it's almost certainly not working. I only tested readPixel().

Please feel free to apply this fix and submit a pull request....
 
Great to know it works on the T_3 too! Are you using it with the INT coded version private library?

Does anyone know if the screen read function was ever implemented? That would make the possibility of pop-up keyboards ( numeric and alpha ) very interesting. Probably could do it anyway, would have to rebuild the screen from scratch each time. Great work defragster have the code running on a 3.0 at the moment.

I don't know that there was an effective screen read - the time and buffering memory and then restoring would probably be prohibitive? The buttons can be redrawn at any time - as you can see on rotation. On my list was drop down sub menus or alternate screens - by swapping TS_BUTTON buttons[.
 
Thanks Defragster,

Rfresh737 & Wozzy - Thanks. Did you try it - with the INT code or without?
Yes, I am using the T_IRQ interrupt on Pin 2

Let me know if you cut and paste the left adjust into the code to see the button clipping.
No I didn't need to change the left adjust
I simply included the custom font in the header:
Code:
#include "font_DroidSans_Bold.h"
And set the tft_font in the setup routine:
Code:
tft.setFont(DroidSans_24_Bold);

Run a pressure display example like TouchTest and watch the pressure as you touch - let me know if there is any usable info there.
Yes, the TS_Point p = ts.getPoint(); function returns a p.z value that ranges from about 1000 for a light touch to about 3400 for a firm touch.

By the way Teensduino 1.26 has left beta.
Thanks... I didn't see an announcement on the Forum, But I was able download the Final Teensyduino 1.26 from the Teensyduino Page http://www.pjrc.com/teensy/td_download.html
I then updated the XPT2046 library from your GitHub Repository https://github.com/Defragster/XPT2046_Touch_Examples/tree/master/XPT2046_Touchscreen
 
Last edited:
Thanks Defragster,

Yes, I am using the T_IRQ interrupt on Pin 2

No I didn't need to change the left adjust
I simply included the custom font in the header:
Code:
#include <XPT2046_Touchscreen.h>
And set the tft_font in the setup routine:
Code:
tft.setFont(DroidSans_24_Bold);


Yes, the TS_Point p = ts.getPoint(); function returns a p.z value that ranges from about 1000 for a light touch to about 3400 for a firm touch.


Thanks... I didn't see an announcement on the Forum, But I was able download the Final Teensyduino 1.26 from the Teensyduino Page http://www.pjrc.com/teensy/td_download.html
I then updated the XPT2046 library from your GitHub Repository https://github.com/Defragster/XPT2046_Touch_Examples/tree/master/XPT2046_Touchscreen

:) Good news on the T-IRQ use! Yeah - the finalizing of 1.26 from Beta was when Paul was heading to the ConHack thing and I only saw inadvertent note about it being live.

The code edit moves landscape off center - but proves the concept and keeps another row of buttons on screen in portrait rotations.

Will add a FONT size to the per button struct - will leave it up to the user to set the font as you did.

When I look at the p.z it varies wildly from side to side and top to bottom even doing your best to maintain constant pressure. It is a function of the cumulative resistive value across the X and Y planes so it varies - it would take a serious mapping effort to plot that and then apply it dynamically. For a given point yes, more pressure higher value - less pressure lower - but not edge to edge consistent in any way.

In that sample I pulled the ILI9341 color table into the array - the colors displayed are not all unique or in keeping with their names. I did math
(array_colors[ kk ] & 0xFFEF ) > 0x8419 ? ILI9341_BLACK : ILI9341_WHITE
to pick the forground color based on how 'white' the color was. I'm not sure my math is on the right 'bit field' boundaries - but it works to pick white or black in some general fashion as show in the pics.
 
Status
Not open for further replies.
Back
Top