acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
Touch.cpp (13229B)
1 // The following touch screen support code by maxpautsch was merged 1/10/17 2 // https://github.com/maxpautsch 3 4 // Define TOUCH_CS is the user setup file to enable this code 5 6 // A demo is provided in examples Generic folder 7 8 // Additions by Bodmer to double sample, use Z value to improve detection reliability 9 // and to correct rotation handling 10 11 // See license in root directory. 12 13 /*************************************************************************************** 14 ** Function name: begin_touch_read_write - was spi_begin_touch 15 ** Description: Start transaction and select touch controller 16 ***************************************************************************************/ 17 // The touch controller has a low SPI clock rate 18 inline void TFT_eSPI::begin_touch_read_write(void){ 19 DMA_BUSY_CHECK; 20 CS_H; // Just in case it has been left low 21 #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) 22 if (locked) {locked = false; spi.beginTransaction(SPISettings(SPI_TOUCH_FREQUENCY, MSBFIRST, SPI_MODE0));} 23 #else 24 spi.setFrequency(SPI_TOUCH_FREQUENCY); 25 #endif 26 SET_BUS_READ_MODE; 27 T_CS_L; 28 } 29 30 /*************************************************************************************** 31 ** Function name: end_touch_read_write - was spi_end_touch 32 ** Description: End transaction and deselect touch controller 33 ***************************************************************************************/ 34 inline void TFT_eSPI::end_touch_read_write(void){ 35 T_CS_H; 36 #if defined (SPI_HAS_TRANSACTION) && defined (SUPPORT_TRANSACTIONS) 37 if(!inTransaction) {if (!locked) {locked = true; spi.endTransaction();}} 38 #else 39 spi.setFrequency(SPI_FREQUENCY); 40 #endif 41 //SET_BUS_WRITE_MODE; 42 } 43 44 /*************************************************************************************** 45 ** Function name: Legacy - deprecated 46 ** Description: Start/end transaction 47 ***************************************************************************************/ 48 void TFT_eSPI::spi_begin_touch() {begin_touch_read_write();} 49 void TFT_eSPI::spi_end_touch() { end_touch_read_write();} 50 51 /*************************************************************************************** 52 ** Function name: getTouchRaw 53 ** Description: read raw touch position. Always returns true. 54 ***************************************************************************************/ 55 uint8_t TFT_eSPI::getTouchRaw(uint16_t *x, uint16_t *y){ 56 uint16_t tmp; 57 58 begin_touch_read_write(); 59 60 // Start YP sample request for x position, read 4 times and keep last sample 61 spi.transfer(0xd0); // Start new YP conversion 62 spi.transfer(0); // Read first 8 bits 63 spi.transfer(0xd0); // Read last 8 bits and start new YP conversion 64 spi.transfer(0); // Read first 8 bits 65 spi.transfer(0xd0); // Read last 8 bits and start new YP conversion 66 spi.transfer(0); // Read first 8 bits 67 spi.transfer(0xd0); // Read last 8 bits and start new YP conversion 68 69 tmp = spi.transfer(0); // Read first 8 bits 70 tmp = tmp <<5; 71 tmp |= 0x1f & (spi.transfer(0x90)>>3); // Read last 8 bits and start new XP conversion 72 73 *x = tmp; 74 75 // Start XP sample request for y position, read 4 times and keep last sample 76 spi.transfer(0); // Read first 8 bits 77 spi.transfer(0x90); // Read last 8 bits and start new XP conversion 78 spi.transfer(0); // Read first 8 bits 79 spi.transfer(0x90); // Read last 8 bits and start new XP conversion 80 spi.transfer(0); // Read first 8 bits 81 spi.transfer(0x90); // Read last 8 bits and start new XP conversion 82 83 tmp = spi.transfer(0); // Read first 8 bits 84 tmp = tmp <<5; 85 tmp |= 0x1f & (spi.transfer(0)>>3); // Read last 8 bits 86 87 *y = tmp; 88 89 end_touch_read_write(); 90 91 return true; 92 } 93 94 /*************************************************************************************** 95 ** Function name: getTouchRawZ 96 ** Description: read raw pressure on touchpad and return Z value. 97 ***************************************************************************************/ 98 uint16_t TFT_eSPI::getTouchRawZ(void){ 99 100 begin_touch_read_write(); 101 102 // Z sample request 103 int16_t tz = 0xFFF; 104 spi.transfer(0xb0); // Start new Z1 conversion 105 tz += spi.transfer16(0xc0) >> 3; // Read Z1 and start Z2 conversion 106 tz -= spi.transfer16(0x00) >> 3; // Read Z2 107 108 end_touch_read_write(); 109 110 if (tz == 4095) tz = 0; 111 112 return (uint16_t)tz; 113 } 114 115 /*************************************************************************************** 116 ** Function name: validTouch 117 ** Description: read validated position. Return false if not pressed. 118 ***************************************************************************************/ 119 #define _RAWERR 20 // Deadband error allowed in successive position samples 120 uint8_t TFT_eSPI::validTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ 121 uint16_t x_tmp, y_tmp, x_tmp2, y_tmp2; 122 123 // Wait until pressure stops increasing to debounce pressure 124 uint16_t z1 = 1; 125 uint16_t z2 = 0; 126 while (z1 > z2) 127 { 128 z2 = z1; 129 z1 = getTouchRawZ(); 130 delay(1); 131 } 132 133 // Serial.print("Z = ");Serial.println(z1); 134 135 if (z1 <= threshold) return false; 136 137 getTouchRaw(&x_tmp,&y_tmp); 138 139 // Serial.print("Sample 1 x,y = "); Serial.print(x_tmp);Serial.print(",");Serial.print(y_tmp); 140 // Serial.print(", Z = ");Serial.println(z1); 141 142 delay(1); // Small delay to the next sample 143 if (getTouchRawZ() <= threshold) return false; 144 145 delay(2); // Small delay to the next sample 146 getTouchRaw(&x_tmp2,&y_tmp2); 147 148 // Serial.print("Sample 2 x,y = "); Serial.print(x_tmp2);Serial.print(",");Serial.println(y_tmp2); 149 // Serial.print("Sample difference = ");Serial.print(abs(x_tmp - x_tmp2));Serial.print(",");Serial.println(abs(y_tmp - y_tmp2)); 150 151 if (abs(x_tmp - x_tmp2) > _RAWERR) return false; 152 if (abs(y_tmp - y_tmp2) > _RAWERR) return false; 153 154 *x = x_tmp; 155 *y = y_tmp; 156 157 return true; 158 } 159 160 /*************************************************************************************** 161 ** Function name: getTouch 162 ** Description: read callibrated position. Return false if not pressed. 163 ***************************************************************************************/ 164 #define Z_THRESHOLD 350 // Touch pressure threshold for validating touches 165 uint8_t TFT_eSPI::getTouch(uint16_t *x, uint16_t *y, uint16_t threshold){ 166 uint16_t x_tmp, y_tmp; 167 168 if (threshold<20) threshold = 20; 169 if (_pressTime > millis()) threshold=20; 170 171 uint8_t n = 5; 172 uint8_t valid = 0; 173 while (n--) 174 { 175 if (validTouch(&x_tmp, &y_tmp, threshold)) valid++;; 176 } 177 178 if (valid<1) { _pressTime = 0; return false; } 179 180 _pressTime = millis() + 50; 181 182 convertRawXY(&x_tmp, &y_tmp); 183 184 if (x_tmp >= _width || y_tmp >= _height) return false; 185 186 _pressX = x_tmp; 187 _pressY = y_tmp; 188 *x = _pressX; 189 *y = _pressY; 190 return valid; 191 } 192 193 /*************************************************************************************** 194 ** Function name: convertRawXY 195 ** Description: convert raw touch x,y values to screen coordinates 196 ***************************************************************************************/ 197 void TFT_eSPI::convertRawXY(uint16_t *x, uint16_t *y) 198 { 199 uint16_t x_tmp = *x, y_tmp = *y, xx, yy; 200 201 if(!touchCalibration_rotate){ 202 xx=(x_tmp-touchCalibration_x0)*_width/touchCalibration_x1; 203 yy=(y_tmp-touchCalibration_y0)*_height/touchCalibration_y1; 204 if(touchCalibration_invert_x) 205 xx = _width - xx; 206 if(touchCalibration_invert_y) 207 yy = _height - yy; 208 } else { 209 xx=(y_tmp-touchCalibration_x0)*_width/touchCalibration_x1; 210 yy=(x_tmp-touchCalibration_y0)*_height/touchCalibration_y1; 211 if(touchCalibration_invert_x) 212 xx = _width - xx; 213 if(touchCalibration_invert_y) 214 yy = _height - yy; 215 } 216 *x = xx; 217 *y = yy; 218 } 219 220 /*************************************************************************************** 221 ** Function name: calibrateTouch 222 ** Description: generates calibration parameters for touchscreen. 223 ***************************************************************************************/ 224 void TFT_eSPI::calibrateTouch(uint16_t *parameters, uint32_t color_fg, uint32_t color_bg, uint8_t size){ 225 int16_t values[] = {0,0,0,0,0,0,0,0}; 226 uint16_t x_tmp, y_tmp; 227 228 229 230 for(uint8_t i = 0; i<4; i++){ 231 fillRect(0, 0, size+1, size+1, color_bg); 232 fillRect(0, _height-size-1, size+1, size+1, color_bg); 233 fillRect(_width-size-1, 0, size+1, size+1, color_bg); 234 fillRect(_width-size-1, _height-size-1, size+1, size+1, color_bg); 235 236 if (i == 5) break; // used to clear the arrows 237 238 switch (i) { 239 case 0: // up left 240 drawLine(0, 0, 0, size, color_fg); 241 drawLine(0, 0, size, 0, color_fg); 242 drawLine(0, 0, size , size, color_fg); 243 break; 244 case 1: // bot left 245 drawLine(0, _height-size-1, 0, _height-1, color_fg); 246 drawLine(0, _height-1, size, _height-1, color_fg); 247 drawLine(size, _height-size-1, 0, _height-1 , color_fg); 248 break; 249 case 2: // up right 250 drawLine(_width-size-1, 0, _width-1, 0, color_fg); 251 drawLine(_width-size-1, size, _width-1, 0, color_fg); 252 drawLine(_width-1, size, _width-1, 0, color_fg); 253 break; 254 case 3: // bot right 255 drawLine(_width-size-1, _height-size-1, _width-1, _height-1, color_fg); 256 drawLine(_width-1, _height-1-size, _width-1, _height-1, color_fg); 257 drawLine(_width-1-size, _height-1, _width-1, _height-1, color_fg); 258 break; 259 } 260 261 // user has to get the chance to release 262 if(i>0) delay(1000); 263 264 for(uint8_t j= 0; j<8; j++){ 265 // Use a lower detect threshold as corners tend to be less sensitive 266 while(!validTouch(&x_tmp, &y_tmp, Z_THRESHOLD/2)); 267 values[i*2 ] += x_tmp; 268 values[i*2+1] += y_tmp; 269 } 270 values[i*2 ] /= 8; 271 values[i*2+1] /= 8; 272 } 273 274 275 // from case 0 to case 1, the y value changed. 276 // 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. 277 touchCalibration_rotate = false; 278 if(abs(values[0]-values[2]) > abs(values[1]-values[3])){ 279 touchCalibration_rotate = true; 280 touchCalibration_x0 = (values[1] + values[3])/2; // calc min x 281 touchCalibration_x1 = (values[5] + values[7])/2; // calc max x 282 touchCalibration_y0 = (values[0] + values[4])/2; // calc min y 283 touchCalibration_y1 = (values[2] + values[6])/2; // calc max y 284 } else { 285 touchCalibration_x0 = (values[0] + values[2])/2; // calc min x 286 touchCalibration_x1 = (values[4] + values[6])/2; // calc max x 287 touchCalibration_y0 = (values[1] + values[5])/2; // calc min y 288 touchCalibration_y1 = (values[3] + values[7])/2; // calc max y 289 } 290 291 // in addition, the touch screen axis could be in the opposite direction of the TFT axis 292 touchCalibration_invert_x = false; 293 if(touchCalibration_x0 > touchCalibration_x1){ 294 values[0]=touchCalibration_x0; 295 touchCalibration_x0 = touchCalibration_x1; 296 touchCalibration_x1 = values[0]; 297 touchCalibration_invert_x = true; 298 } 299 touchCalibration_invert_y = false; 300 if(touchCalibration_y0 > touchCalibration_y1){ 301 values[0]=touchCalibration_y0; 302 touchCalibration_y0 = touchCalibration_y1; 303 touchCalibration_y1 = values[0]; 304 touchCalibration_invert_y = true; 305 } 306 307 // pre calculate 308 touchCalibration_x1 -= touchCalibration_x0; 309 touchCalibration_y1 -= touchCalibration_y0; 310 311 if(touchCalibration_x0 == 0) touchCalibration_x0 = 1; 312 if(touchCalibration_x1 == 0) touchCalibration_x1 = 1; 313 if(touchCalibration_y0 == 0) touchCalibration_y0 = 1; 314 if(touchCalibration_y1 == 0) touchCalibration_y1 = 1; 315 316 // export parameters, if pointer valid 317 if(parameters != NULL){ 318 parameters[0] = touchCalibration_x0; 319 parameters[1] = touchCalibration_x1; 320 parameters[2] = touchCalibration_y0; 321 parameters[3] = touchCalibration_y1; 322 parameters[4] = touchCalibration_rotate | (touchCalibration_invert_x <<1) | (touchCalibration_invert_y <<2); 323 } 324 } 325 326 327 /*************************************************************************************** 328 ** Function name: setTouch 329 ** Description: imports calibration parameters for touchscreen. 330 ***************************************************************************************/ 331 void TFT_eSPI::setTouch(uint16_t *parameters){ 332 touchCalibration_x0 = parameters[0]; 333 touchCalibration_x1 = parameters[1]; 334 touchCalibration_y0 = parameters[2]; 335 touchCalibration_y1 = parameters[3]; 336 337 if(touchCalibration_x0 == 0) touchCalibration_x0 = 1; 338 if(touchCalibration_x1 == 0) touchCalibration_x1 = 1; 339 if(touchCalibration_y0 == 0) touchCalibration_y0 = 1; 340 if(touchCalibration_y1 == 0) touchCalibration_y1 = 1; 341 342 touchCalibration_rotate = parameters[4] & 0x01; 343 touchCalibration_invert_x = parameters[4] & 0x02; 344 touchCalibration_invert_y = parameters[4] & 0x04; 345 }