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 }