m00n1i9ht_5h4d0w
Member
Hi,
i was posting a message into the adafruit forum https://forums.adafruit.com/viewtopic.php?f=47&t=109704 about using one of their touchscreens (3.5" TFT with ILI9341) with a Teensy 3.2 with 16bit instead of the standard 10bit ADC resolution. And i think it is usefull to link that here too...
The problem is that the adafruit touchscreen library works with the ADC and "thinks" that the resolution is always 10bit. So their data types and even used constants are optimized for 10bit too. But i am using 16bit ADC resolution in a critical timer-task and need to use the touchscreen at the same time. But the touchscreen functions return wrong values (negative values and 16bit-integer overflows (-32K<->32K) in the middle of the display). So i decided to change the touchscreen library so i can use it optimized for a special resolution or generally with 16bit ADC resolution as in the code below:
(If you want to use another resolution you only have to change _DATATYPE, _DATATYPE_MAX and _MAXDIFFERENCE as you need.)
touchscreen.h
touchscreen.cpp
If you find it helpfull please test it with different displays and ADC resolutions or please post optimizations.
Thanks.
i was posting a message into the adafruit forum https://forums.adafruit.com/viewtopic.php?f=47&t=109704 about using one of their touchscreens (3.5" TFT with ILI9341) with a Teensy 3.2 with 16bit instead of the standard 10bit ADC resolution. And i think it is usefull to link that here too...
The problem is that the adafruit touchscreen library works with the ADC and "thinks" that the resolution is always 10bit. So their data types and even used constants are optimized for 10bit too. But i am using 16bit ADC resolution in a critical timer-task and need to use the touchscreen at the same time. But the touchscreen functions return wrong values (negative values and 16bit-integer overflows (-32K<->32K) in the middle of the display). So i decided to change the touchscreen library so i can use it optimized for a special resolution or generally with 16bit ADC resolution as in the code below:
(If you want to use another resolution you only have to change _DATATYPE, _DATATYPE_MAX and _MAXDIFFERENCE as you need.)
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>
#define _DATATYPE uint16_t
#define _DATATYPE_MAX 65535 //1023 @ 10bit, 4095 @ 12bit, 65535 @ 16bit
#define _MAXDIFFERENCE 256 //4 @ 1024(10bit), 16 @ 4096(12bit), 256 @ 65535(16bit)
class TSPoint {
public:
TSPoint(void);
TSPoint(_DATATYPE x, _DATATYPE y, _DATATYPE z);
bool operator==(TSPoint);
bool operator!=(TSPoint);
_DATATYPE x, y, z;
};
class TouchScreen {
public:
TouchScreen(uint8_t xp, uint8_t yp, uint8_t xm, uint8_t ym);
TouchScreen(uint8_t xp, uint8_t yp, uint8_t xm, uint8_t ym, uint16_t rx);
bool isTouching(void);
_DATATYPE pressure(void);
_DATATYPE readTouchY();
_DATATYPE readTouchX();
TSPoint getPoint();
_DATATYPE pressureThreshhold;
private:
uint8_t _yp, _ym, _xm, _xp;
_DATATYPE _rxplate;
};
#endif
touchscreen.cpp
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
#include "Arduino.h"
#include "pins_arduino.h"
#ifdef __AVR
#include <avr/pgmspace.h>
#elif defined(ESP8266)
#include <pgmspace.h>
#endif
#include "TouchScreen_multiADC.h"
// increase or decrease the touchscreen oversampling. This is a little different than you make think:
// 1 is no oversampling, whatever data we get is immediately returned
// 2 is double-sampling and we only return valid data if both points are the same
// 3+ uses insert sort to get the median value.
// We found 2 is precise yet not too slow so we suggest sticking with it!
#define NUMSAMPLES 2
TSPoint::TSPoint(void) {
x = y = 0;
}
TSPoint::TSPoint(_DATATYPE x0, _DATATYPE y0, _DATATYPE z0) {
x = x0;
y = y0;
z = z0;
}
bool TSPoint::operator==(TSPoint p1) {
return ((p1.x == x) && (p1.y == y) && (p1.z == z));
}
bool TSPoint::operator!=(TSPoint p1) {
return ((p1.x != x) || (p1.y != y) || (p1.z != z));
}
#if (NUMSAMPLES > 2)
static void insert_sort(_DATATYPE array[], uint8_t size) {
uint8_t j;
_DATATYPE save;
for (int i = 1; i < size; i++) {
save = array[i];
for (j = i; j >= 1 && save < array[j - 1]; j--)
array[j] = array[j - 1];
array[j] = save;
}
}
#endif
TSPoint TouchScreen::getPoint(void) {
_DATATYPE x, y, z;
_DATATYPE samples[NUMSAMPLES];
uint8_t i, valid;
#if defined(ARDUINO_ARCH_SAM)
Pio* xp_port = digitalPinToPort(_xp);
Pio* yp_port = digitalPinToPort(_yp);
Pio* xm_port = digitalPinToPort(_xm);
Pio* ym_port = digitalPinToPort(_ym);
uint32_t xp_pin = digitalPinToBitMask(_xp);
uint32_t yp_pin = digitalPinToBitMask(_yp);
uint32_t xm_pin = digitalPinToBitMask(_xm);
uint32_t ym_pin = digitalPinToBitMask(_ym);
#elif defined(ARDUINO_ARCH_SAMD)
PortGroup* xp_port = digitalPinToPort(_xp);
PortGroup* yp_port = digitalPinToPort(_yp);
PortGroup* xm_port = digitalPinToPort(_xm);
PortGroup* ym_port = digitalPinToPort(_ym);
uint32_t xp_pin = digitalPinToBitMask(_xp);
uint32_t yp_pin = digitalPinToBitMask(_yp);
uint32_t xm_pin = digitalPinToBitMask(_xm);
uint32_t ym_pin = digitalPinToBitMask(_ym);
#else
uint8_t xp_port = digitalPinToPort(_xp);
uint8_t yp_port = digitalPinToPort(_yp);
uint8_t xm_port = digitalPinToPort(_xm);
uint8_t ym_port = digitalPinToPort(_ym);
uint8_t xp_pin = digitalPinToBitMask(_xp);
uint8_t yp_pin = digitalPinToBitMask(_yp);
uint8_t xm_pin = digitalPinToBitMask(_xm);
uint8_t ym_pin = digitalPinToBitMask(_ym);
#endif
valid = 1;
pinMode(_yp, INPUT);
pinMode(_ym, INPUT);
*portOutputRegister(yp_port) &= ~yp_pin;
*portOutputRegister(ym_port) &= ~ym_pin;
//digitalWrite(_yp, LOW);
//digitalWrite(_ym, LOW);
pinMode(_xp, OUTPUT);
pinMode(_xm, OUTPUT);
//digitalWrite(_xp, HIGH);
//digitalWrite(_xm, LOW);
*portOutputRegister(xp_port) |= xp_pin;
*portOutputRegister(xm_port) &= ~xm_pin;
#ifdef __arm__
delayMicroseconds(20); // Fast ARM chips need to allow voltages to settle
#endif
for (i=0; i<NUMSAMPLES; i++) {
samples[i] = analogRead(_yp);
}
#if NUMSAMPLES > 2
insert_sort(samples, NUMSAMPLES);
#endif
#if NUMSAMPLES == 2
// Allow small amount of measurement noise, because capacitive
// coupling to a TFT display's signals can induce some noise.
if (samples[0] - samples[1] < -_MAXDIFFERENCE || samples[0] - samples[1] > _MAXDIFFERENCE) {
valid = 0;
} else {
samples[1] = (samples[0] + samples[1]) >> 1; // average 2 samples
}
#endif
x = (_DATATYPE_MAX-samples[NUMSAMPLES/2]);
pinMode(_xp, INPUT);
pinMode(_xm, INPUT);
*portOutputRegister(xp_port) &= ~xp_pin;
//digitalWrite(_xp, LOW);
pinMode(_yp, OUTPUT);
*portOutputRegister(yp_port) |= yp_pin;
//digitalWrite(_yp, HIGH);
pinMode(_ym, OUTPUT);
#ifdef __arm__
delayMicroseconds(20); // Fast ARM chips need to allow voltages to settle
#endif
for (i=0; i<NUMSAMPLES; i++) {
samples[i] = analogRead(_xm);
}
#if NUMSAMPLES > 2
insert_sort(samples, NUMSAMPLES);
#endif
#if NUMSAMPLES == 2
// Allow small amount of measurement noise, because capacitive
// coupling to a TFT display's signals can induce some noise.
if (samples[0] - samples[1] < -_MAXDIFFERENCE || samples[0] - samples[1] > _MAXDIFFERENCE) {
valid = 0;
} else {
samples[1] = (samples[0] + samples[1]) >> 1; // average 2 samples
}
#endif
y = (_DATATYPE_MAX-samples[NUMSAMPLES/2]);
// Set X+ to ground
pinMode(_xp, OUTPUT);
*portOutputRegister(xp_port) &= ~xp_pin;
//digitalWrite(_xp, LOW);
// Set Y- to VCC
*portOutputRegister(ym_port) |= ym_pin;
//digitalWrite(_ym, HIGH);
// Hi-Z X- and Y+
*portOutputRegister(yp_port) &= ~yp_pin;
//digitalWrite(_yp, LOW);
pinMode(_yp, INPUT);
int z1 = analogRead(_xm);
int z2 = analogRead(_yp);
if (_rxplate != 0) {
// now read the x
float rtouch;
rtouch = z2;
rtouch /= z1;
rtouch -= 1;
rtouch *= x;
rtouch *= _rxplate;
rtouch /= (_DATATYPE_MAX+1);
z = rtouch;
} else {
z = (_DATATYPE_MAX-(z2-z1));
}
if (! valid) {
z = 0;
}
return TSPoint(x, y, z);
}
TouchScreen::TouchScreen(uint8_t xp, uint8_t yp, uint8_t xm, uint8_t ym) {
_yp = yp;
_xm = xm;
_ym = ym;
_xp = xp;
_rxplate = 0;
pressureThreshhold = 10;
}
TouchScreen::TouchScreen(uint8_t xp, uint8_t yp, uint8_t xm, uint8_t ym,
uint16_t rxplate) {
_yp = yp;
_xm = xm;
_ym = ym;
_xp = xp;
_rxplate = rxplate;
pressureThreshhold = 10;
}
_DATATYPE TouchScreen::readTouchX(void) {
pinMode(_yp, INPUT);
pinMode(_ym, INPUT);
digitalWrite(_yp, LOW);
digitalWrite(_ym, LOW);
pinMode(_xp, OUTPUT);
digitalWrite(_xp, HIGH);
pinMode(_xm, OUTPUT);
digitalWrite(_xm, LOW);
return (_DATATYPE_MAX-analogRead(_yp));
}
_DATATYPE TouchScreen::readTouchY(void) {
pinMode(_xp, INPUT);
pinMode(_xm, INPUT);
digitalWrite(_xp, LOW);
digitalWrite(_xm, LOW);
pinMode(_yp, OUTPUT);
digitalWrite(_yp, HIGH);
pinMode(_ym, OUTPUT);
digitalWrite(_ym, LOW);
return (_DATATYPE_MAX-analogRead(_xm));
}
_DATATYPE TouchScreen::pressure(void) {
// Set X+ to ground
pinMode(_xp, OUTPUT);
digitalWrite(_xp, LOW);
// Set Y- to VCC
pinMode(_ym, OUTPUT);
digitalWrite(_ym, HIGH);
// Hi-Z X- and Y+
digitalWrite(_xm, LOW);
pinMode(_xm, INPUT);
digitalWrite(_yp, LOW);
pinMode(_yp, INPUT);
_DATATYPE z1 = analogRead(_xm);
_DATATYPE z2 = analogRead(_yp);
if (_rxplate != 0) {
// now read the x
float rtouch;
rtouch = z2;
rtouch /= z1;
rtouch -= 1;
rtouch *= readTouchX();
rtouch *= _rxplate;
rtouch /= (_DATATYPE_MAX+1);
return rtouch;
} else {
return (_DATATYPE_MAX-(z2-z1));
}
}
If you find it helpfull please test it with different displays and ADC resolutions or please post optimizations.
Thanks.