| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344 |
- // The following touch screen support code by maxpautsch was merged 1/10/17
- // https://github.com/maxpautsch
- // Define TOUCH_CS is the user setup file to enable this code
- // A demo is provided in examples Generic folder
- // Additions by Bodmer to double sample, use Z value to improve detection reliability
- // and to correct rotation handling
- // See license in root directory.
- /***************************************************************************************
- ** Function name: begin_touch_read_write - was spi_begin_touch
- ** Description: Start transaction and select touch controller
- ***************************************************************************************/
- // The touch controller has a low SPI clock rate
- inline void TFT_eSPI::begin_touch_read_write(void){
- DMA_BUSY_CHECK;
- CS_H; // Just in case it has been left low
- #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
- if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));}
- #else
- spi.setFrequency(SPI_TOUCH_FREQUENCY);
- #endif
- SET_BUS_READ_MODE;
- T_CS_L;
- }
- /***************************************************************************************
- ** Function name: end_touch_read_write - was spi_end_touch
- ** Description: End transaction and deselect touch controller
- ***************************************************************************************/
- inline void TFT_eSPI::end_touch_read_write(void){
- T_CS_H;
- #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS)
- if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}}
- #else
- spi.setFrequency(SPI_FREQUENCY);
- #endif
- //SET_BUS_WRITE_MODE;
- }
- /***************************************************************************************
- ** Function name: Legacy - deprecated
- ** Description: Start/end transaction
- ***************************************************************************************/
- void TFT_eSPI::spi_begin_touch() {begin_touch_read_write();}
- void TFT_eSPI::spi_end_touch() { end_touch_read_write();}
- /***************************************************************************************
- ** Function name: getTouchRaw
- ** Description: read raw touch position. Always returns true.
- ***************************************************************************************/
- uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){
- uint16_t tmp;
- begin_touch_read_write();
-
- // Start YP sample request for x position, read 4 times and keep last sample
- spi.transfer(0xd0); // Start new YP conversion
- spi.transfer(0); // Read first 8 bits
- spi.transfer(0xd0); // Read last 8 bits and start new YP conversion
- spi.transfer(0); // Read first 8 bits
- spi.transfer(0xd0); // Read last 8 bits and start new YP conversion
- spi.transfer(0); // Read first 8 bits
- spi.transfer(0xd0); // Read last 8 bits and start new YP conversion
- tmp = spi.transfer(0); // Read first 8 bits
- tmp = tmp <<5;
- tmp |= 0x1f & (spi.transfer(0x90)>>3); // Read last 8 bits and start new XP conversion
- *x = tmp;
- // Start XP sample request for y position, read 4 times and keep last sample
- spi.transfer(0); // Read first 8 bits
- spi.transfer(0x90); // Read last 8 bits and start new XP conversion
- spi.transfer(0); // Read first 8 bits
- spi.transfer(0x90); // Read last 8 bits and start new XP conversion
- spi.transfer(0); // Read first 8 bits
- spi.transfer(0x90); // Read last 8 bits and start new XP conversion
- tmp = spi.transfer(0); // Read first 8 bits
- tmp = tmp <<5;
- tmp |= 0x1f & (spi.transfer(0)>>3); // Read last 8 bits
- *y = tmp;
- end_touch_read_write();
- return true;
- }
- /***************************************************************************************
- ** Function name: getTouchRawZ
- ** Description: read raw pressure on touchpad and return Z value.
- ***************************************************************************************/
- uint16_t TFT_eSPI::getTouchRawZ(void){
- begin_touch_read_write();
- digitalWrite(PIN_D1, LOW);
- // Z sample request
- int16_t tz = 0xFFF;
- spi.transfer(0xb0); // Start new Z1 conversion
- tz += spi.transfer16(0xc0) >> 3; // Read Z1 and start Z2 conversion
- tz -= spi.transfer16(0x00) >> 3; // Read Z2
- end_touch_read_write();
- return (uint16_t)tz;
- }
- /***************************************************************************************
- ** Function name: validTouch
- ** Description: read validated position. Return false if not pressed.
- ***************************************************************************************/
- #define _RAWERR 20 // Deadband error allowed in successive position samples
- uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
- uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2;
- // Wait until pressure stops increasing to debounce pressure
- uint16_t z1 = 1;
- uint16_t z2 = 0;
- while (z1 > z2)
- {
- z2 = z1;
- z1 = getTouchRawZ();
- delay(1);
- }
- // Serial.print("Z = ");Serial.println(z1);
- if (z1 <= threshold) return false;
-
- getTouchRaw(&x_tmp,&y_tmp);
- // Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp);
- // Serial.print(", Z = ");Serial.println(z1);
- delay(1); // Small delay to the next sample
- if (getTouchRawZ() <= threshold) return false;
- delay(2); // Small delay to the next sample
- getTouchRaw(&x_tmp2,&y_tmp2);
-
- // Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2);
- // Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2));
- if (abs(x_tmp - x_tmp2) > _RAWERR) return false;
- if (abs(y_tmp - y_tmp2) > _RAWERR) return false;
-
- *x = x_tmp;
- *y = y_tmp;
-
- return true;
- }
-
- /***************************************************************************************
- ** Function name: getTouch
- ** Description: read callibrated position. Return false if not pressed.
- ***************************************************************************************/
- #define Z_THRESHOLD 350 // Touch pressure threshold for validating touches
- uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){
- uint16_t x_tmp, y_tmp;
-
- if (threshold<20) threshold = 10;
- if (_pressTime > millis()) threshold=10;
- uint8_t n = 5;
- uint8_t valid = 0;
- while (n--)
- {
- if (validTouch(&x_tmp, &y_tmp, threshold)) valid++;;
- }
- if (valid<1) { _pressTime = 0; return false; }
-
- _pressTime = millis() + 50;
- convertRawXY(&x_tmp, &y_tmp);
- if (x_tmp >= _width || y_tmp >= _height) return false;
- _pressX = x_tmp;
- _pressY = y_tmp;
- *x = _pressX;
- *y = _pressY;
- return valid;
- }
- /***************************************************************************************
- ** Function name: convertRawXY
- ** Description: convert raw touch x,y values to screen coordinates
- ***************************************************************************************/
- void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y)
- {
- uint16_t x_tmp = *x, y_tmp = *y, xx, yy;
- if(!touchCalibration_rotate){
- xx=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
- yy=(y_tmp-touchCalibration_y0)*_height/touchCalibration_y1;
- if(touchCalibration_invert_x)
- xx = _width - xx;
- if(touchCalibration_invert_y)
- yy = _height - yy;
- } else {
- xx=(y_tmp-touchCalibration_x0)*_width/touchCalibration_x1;
- yy=(x_tmp-touchCalibration_y0)*_height/touchCalibration_y1;
- if(touchCalibration_invert_x)
- xx = _width - xx;
- if(touchCalibration_invert_y)
- yy = _height - yy;
- }
- *x = xx;
- *y = yy;
- }
- /***************************************************************************************
- ** Function name: calibrateTouch
- ** Description: generates calibration parameters for touchscreen.
- ***************************************************************************************/
- void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){
- int16_t values[] = {0,0,0,0,0,0,0,0};
- uint16_t x_tmp, y_tmp;
- for(uint8_t i = 0; i<4; i++){
- fillRect(0, 0, size+1, size+1, color_bg);
- fillRect(0, _height-size-1, size+1, size+1, color_bg);
- fillRect(_width-size-1, 0, size+1, size+1, color_bg);
- fillRect(_width-size-1, _height-size-1, size+1, size+1, color_bg);
- if (i == 5) break; // used to clear the arrows
-
- switch (i) {
- case 0: // up left
- drawLine(0, 0, 0, size, color_fg);
- drawLine(0, 0, size, 0, color_fg);
- drawLine(0, 0, size , size, color_fg);
- break;
- case 1: // bot left
- drawLine(0, _height-size-1, 0, _height-1, color_fg);
- drawLine(0, _height-1, size, _height-1, color_fg);
- drawLine(size, _height-size-1, 0, _height-1 , color_fg);
- break;
- case 2: // up right
- drawLine(_width-size-1, 0, _width-1, 0, color_fg);
- drawLine(_width-size-1, size, _width-1, 0, color_fg);
- drawLine(_width-1, size, _width-1, 0, color_fg);
- break;
- case 3: // bot right
- drawLine(_width-size-1, _height-size-1, _width-1, _height-1, color_fg);
- drawLine(_width-1, _height-1-size, _width-1, _height-1, color_fg);
- drawLine(_width-1-size, _height-1, _width-1, _height-1, color_fg);
- break;
- }
- // user has to get the chance to release
- if(i>0) delay(1000);
- for(uint8_t j= 0; j<8; j++){
- // Use a lower detect threshold as corners tend to be less sensitive
- while(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD/2));
- values[i*2 ] += x_tmp;
- values[i*2+1] += y_tmp;
- }
- values[i*2 ] /= 8;
- values[i*2+1] /= 8;
- }
- // from case 0 to case 1, the y value changed.
- // If the measured delta of the touch x axis is bigger than the delta of the y axis, the touch and TFT axes are switched.
- touchCalibration_rotate = false;
- if(abs(values[0]-values[2]) > abs(values[1]-values[3])){
- touchCalibration_rotate = true;
- touchCalibration_x0 = (values[1] + values[3])/2; // calc min x
- touchCalibration_x1 = (values[5] + values[7])/2; // calc max x
- touchCalibration_y0 = (values[0] + values[4])/2; // calc min y
- touchCalibration_y1 = (values[2] + values[6])/2; // calc max y
- } else {
- touchCalibration_x0 = (values[0] + values[2])/2; // calc min x
- touchCalibration_x1 = (values[4] + values[6])/2; // calc max x
- touchCalibration_y0 = (values[1] + values[5])/2; // calc min y
- touchCalibration_y1 = (values[3] + values[7])/2; // calc max y
- }
- // in addition, the touch screen axis could be in the opposite direction of the TFT axis
- touchCalibration_invert_x = false;
- if(touchCalibration_x0 > touchCalibration_x1){
- values[0]=touchCalibration_x0;
- touchCalibration_x0 = touchCalibration_x1;
- touchCalibration_x1 = values[0];
- touchCalibration_invert_x = true;
- }
- touchCalibration_invert_y = false;
- if(touchCalibration_y0 > touchCalibration_y1){
- values[0]=touchCalibration_y0;
- touchCalibration_y0 = touchCalibration_y1;
- touchCalibration_y1 = values[0];
- touchCalibration_invert_y = true;
- }
- // pre calculate
- touchCalibration_x1 -= touchCalibration_x0;
- touchCalibration_y1 -= touchCalibration_y0;
- if(touchCalibration_x0 == 0) touchCalibration_x0 = 1;
- if(touchCalibration_x1 == 0) touchCalibration_x1 = 1;
- if(touchCalibration_y0 == 0) touchCalibration_y0 = 1;
- if(touchCalibration_y1 == 0) touchCalibration_y1 = 1;
- // export parameters, if pointer valid
- if(parameters != NULL){
- parameters[0] = touchCalibration_x0;
- parameters[1] = touchCalibration_x1;
- parameters[2] = touchCalibration_y0;
- parameters[3] = touchCalibration_y1;
- parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2);
- }
- }
- /***************************************************************************************
- ** Function name: setTouch
- ** Description: imports calibration parameters for touchscreen.
- ***************************************************************************************/
- void TFT_eSPI::setTouch(uint16_t *parameters){
- touchCalibration_x0 = parameters[0];
- touchCalibration_x1 = parameters[1];
- touchCalibration_y0 = parameters[2];
- touchCalibration_y1 = parameters[3];
- if(touchCalibration_x0 == 0) touchCalibration_x0 = 1;
- if(touchCalibration_x1 == 0) touchCalibration_x1 = 1;
- if(touchCalibration_y0 == 0) touchCalibration_y0 = 1;
- if(touchCalibration_y1 == 0) touchCalibration_y1 = 1;
- touchCalibration_rotate = parameters[4] & 0x01;
- touchCalibration_invert_x = parameters[4] & 0x02;
- touchCalibration_invert_y = parameters[4] & 0x04;
- }
|