diff --git a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp index d1b0bdf..f24c67a 100644 --- a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp +++ b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.cpp @@ -8,81 +8,97 @@ #include "Arduino.h" #include "XPT2046_touch.h" +XPT2046_touch::XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan) : cs_pin(_cs_pin), my_SPI(_spiChan){ + setOversampling(); + setThreshold(); +} -/****************************************************************************/ - XPT2046_touch::XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan) : cs_pin(_cs_pin), my_SPI(_spiChan){ - } - - -/****************************************************************************/ - - void XPT2046_touch::begin(){ +void XPT2046_touch::begin(){ pinMode(cs_pin, OUTPUT); digitalWrite(cs_pin, HIGH); my_SPI.begin(); - } +} - /****************************************************************************/ +uint16_t XPT2046_touch::gatherSamples(uint8_t command) { + uint32_t sample_sum = 0; + uint16_t samples[MAX_OVERSAMPLING]; - boolean XPT2046_touch::read_XY(uint16_t *xy){ - int z1, z2, tmpH, tmpL; + my_SPI.transfer16(command); // discard first reading after switching MUX + for (int i = 0; i < oversampling; ++i) { + samples[i] = my_SPI.transfer16(command); + sample_sum += samples[i]; + } + int32_t avg = sample_sum / oversampling; + if (oversampling < 3) { + return avg >> 3; + } + + // occasionally, we get a reading that is a _far_ outlier. + // checking for, and removing those improves quality a lot. + uint8_t n = oversampling; + for (int i = 0; i < oversampling; ++i) { + if (abs(avg - samples[i]) > 80) { // NOTE: data is left shifted by 3 at this point. I.e. the test is for 10+ pixels deviation from average + sample_sum -= samples[i]; + --n; + } + } + if (n < 2) return avg >> 3; + else return (sample_sum / n) >> 3; +} + +TS_Point XPT2046_touch::getPoint() { + uint16_t z1, z2; + + my_SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); // max clock freq for XPT2046 digitalWrite(cs_pin, LOW); + TS_Point ret; //Check if touch screen is pressed. - SPI.transfer(B10110011); // Z1 - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - z1 = tmpH | tmpL; + my_SPI.transfer(B10110011); // trigger Z1 reading + z1 = my_SPI.transfer16(B11000011) >> 3; // read Z1, and trigger Z2 reading + z2 = my_SPI.transfer16(B10010011) >> 3; // read Z2, and trigger Y reading + ret.z = z1 + 4095 - z2; - SPI.transfer(B11000011); // Z2 - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - z2 = tmpH | tmpL; - - if((z2 - z1) < Z_THRESHOLD){ //If the touch screen is pressed, read the X,Y coordinates from XPT2046. - my_SPI.transfer(B11010011); // X - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - xy[0] = tmpH | tmpL; - - my_SPI.transfer(B10010011); // Y - delay(10); - tmpH = (my_SPI.transfer(0) << 5); - tmpL = (my_SPI.transfer(0) >> 3); - xy[1] = tmpH | tmpL; - digitalWrite(cs_pin, HIGH); - return true; + if(ret.z >= threshold){ //If the touch screen is pressed, read the X,Y coordinates from XPT2046. + ret.x = gatherSamples(B10010011); + ret.y = gatherSamples(B11010011); + } else { + ret.z = 0; } + my_SPI.transfer(B00000000); // enter power saving (and IRQ enable) + digitalWrite(cs_pin, HIGH); - return false; - } - - /****************************************************************************/ - void XPT2046_touch::setButtonsNumber(byte columnButtons, byte rowButtons ){ - _rowButtons = rowButtons; - _columnButtons = columnButtons; - } - - /****************************************************************************/ - uint8_t XPT2046_touch::getButtonNumber(){ + my_SPI.endTransaction(); + return ret; +} + +boolean XPT2046_touch::read_XY(uint16_t *xy) { + TS_Point p = getPoint(); + xy[0] = p.x; + xy[1] = p.y; + return p.z > 0; +} + +////////////////// Buttons //////////////// +void XPT2046_touch::setButtonsNumber(byte columnButtons, byte rowButtons ){ + _rowButtons = rowButtons; + _columnButtons = columnButtons; +} + +uint8_t XPT2046_touch::getButtonNumber(){ uint16_t xy[2]; uint8_t tmp, buttonNum; int div; if(read_XY(xy)){ - - div = (X_MAX + X_MIN) / (_columnButtons + 1); - buttonNum = ((xy[1] / div)); - - div = (Y_MAX + Y_MIN) / _rowButtons; - tmp = ((xy[0] / div)); - - return ((buttonNum * _rowButtons) + tmp + 1); //Return the button number. + div = (X_MAX + X_MIN) / (_columnButtons + 1); + buttonNum = ((xy[1] / div)); + + div = (Y_MAX + Y_MIN) / _rowButtons; + tmp = ((xy[0] / div)); + + return ((buttonNum * _rowButtons) + tmp + 1); //Return the button number. } return 0; //Touch screen is not pressed. - } -/****************************************************************************/ +} diff --git a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h index 0830162..9fbea6a 100644 --- a/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h +++ b/STM32F1/libraries/Serasidis_XPT2046_touch/src/XPT2046_touch.h @@ -11,7 +11,8 @@ #include #include -#define Z_THRESHOLD 3000 +#define Z_THRESHOLD 3500 // Note: reversed for backwards compatiblity: 4095-x +#define MAX_OVERSAMPLING 32 // Pre-defined touch screen calibration for using the 2.4" ILI9341 LCD #define X_MIN 830 @@ -19,23 +20,54 @@ #define Y_MIN 550 #define Y_MAX 3550 + +class TS_Point { +public: + TS_Point(void) : x(0), y(0), z(0) {} + TS_Point(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {} + bool operator==(TS_Point p) { return ((p.x == x) && (p.y == y) && (p.z == z)); } + bool operator!=(TS_Point p) { return ((p.x != x) || (p.y != y) || (p.z != z)); } + int16_t x, y, z; +}; + /** * */ - -class XPT2046_touch{ +class XPT2046_touch { private: uint8_t cs_pin; SPIClass my_SPI; uint8_t _rowButtons = 1; uint8_t _columnButtons = 1; + uint8_t oversampling; + uint16_t threshold; + uint16_t gatherSamples(uint8_t command); public: - XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan); //Contructor. + /** c'tor. Note that no IRQ pin is supported, here. You can easily do that yourself: + * \code if(digitalRead(irq_pin)) { + * // no press: skip + * } else { + * // _may_ be touched, but not necessarily reach the threshold + * TS_Point p = ts.getPoint(); + * if (p.z > 0) { + * // do something + * } + * } + * \endcode */ + XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan); //Contructor void begin(); void setButtonsNumber(byte rowButtons, byte columnButtons); + /** Number of samples to average per point 0..32 */ + void setOversampling(uint8_t num_readings = 7) { + oversampling = max(1, min(num_readings, MAX_OVERSAMPLING)); + } + void setThreshold(uint16_t threshold = 4095 - Z_THRESHOLD) { + XPT2046_touch::threshold = threshold; + } uint8_t getButtonNumber(); boolean read_XY(uint16_t *xy); + TS_Point getPoint(); }; #endif