Driver Library for our displays
Dependents: dm_bubbles dm_calc dm_paint dm_sdcard_with_adapter ... more
DmTouch.cpp
00001 /********************************************************************************************** 00002 Copyright (c) 2014 DisplayModule. All rights reserved. 00003 00004 Redistribution and use of this source code, part of this source code or any compiled binary 00005 based on this source code is permitted as long as the above copyright notice and following 00006 disclaimer is retained. 00007 00008 DISCLAIMER: 00009 THIS SOFTWARE IS SUPPLIED "AS IS" WITHOUT ANY WARRANTIES AND SUPPORT. DISPLAYMODULE ASSUMES 00010 NO RESPONSIBILITY OR LIABILITY FOR THE USE OF THE SOFTWARE. 00011 ********************************************************************************************/ 00012 // Tested with Xpt2046 and RA8875 00013 00014 #include "DmTouch.h" 00015 #include "DmTouchCalibration.h" 00016 00017 #define MEASUREMENTS 10 00018 00019 #if defined(DM_TOOLCHAIN_ARDUINO) 00020 // disp - which display is used 00021 // spiMode - How to read SPI-data, Software, Hardware or Auto 00022 // useIrq - Enable IRQ or disable IRQ 00023 DmTouch::DmTouch(Display disp, SpiMode spiMode, bool useIrq) 00024 #elif defined (DM_TOOLCHAIN_MBED) 00025 // disp - which display is used 00026 // spiMode - How to read SPI-data, Software, Hardware or Auto 00027 DmTouch::DmTouch(Display disp, PinName mosi, PinName miso, PinName clk) 00028 #endif 00029 { 00030 _disp = disp; 00031 switch (disp) { 00032 // Display with 40-pin connector on top of adapter board 00033 case DmTouch::DM_TFT28_103: 00034 case DmTouch::DM_TFT24_104: 00035 _cs = D8; 00036 _irq = D10; 00037 _clk = A1; 00038 _mosi = A0; 00039 _miso = D9; 00040 _width = 240; 00041 _height = 320; 00042 _hardwareSpi = false; 00043 _touch_id = IC_2046; 00044 break; 00045 00046 case DmTouch::DM_TFT28_105: 00047 _cs = D4; 00048 _irq = D2; 00049 _clk = D13; 00050 _mosi = D11; 00051 _miso = D12; 00052 _width = 240; 00053 _height = 320; 00054 _hardwareSpi = true; 00055 _touch_id = IC_2046; 00056 break; 00057 00058 case DmTouch::DM_TFT35_107: 00059 _cs = D4; 00060 _irq = D2; 00061 _clk = D13; 00062 _mosi = D11; 00063 _miso = D12; 00064 _width = 320; 00065 _height = 240; 00066 _hardwareSpi = true; 00067 _touch_id = IC_2046; 00068 break; 00069 00070 case DmTouch::DM_TFT43_108: // or DM_TFT43_110 00071 _cs = D10; 00072 _irq = D2; 00073 _clk = D13; 00074 _mosi = D11; 00075 _miso = D12; 00076 _width = 480; 00077 _height = 272; 00078 _hardwareSpi = true; 00079 _touch_id = IC_8875; 00080 break; 00081 00082 case DmTouch::DM_TFT50_111: // or DM_TFT50_112 00083 _cs = D10; 00084 _irq = D2; 00085 _clk = D13; 00086 _mosi = D11; 00087 _miso = D12; 00088 _width = 800; 00089 _height = 480; 00090 _hardwareSpi = true; 00091 _touch_id = IC_8875; 00092 break; 00093 00094 default: 00095 _cs = D4; 00096 _irq = D2; 00097 _clk = D13; 00098 _mosi = D11; 00099 _miso = D12; 00100 _width = 320; 00101 _height = 240; 00102 _hardwareSpi = true; 00103 _touch_id = IC_2046; 00104 break; 00105 } 00106 00107 setCalibrationMatrix(DmTouchCalibration::getDefaultCalibrationData(disp)); 00108 00109 _samplesPerMeasurement = 3; 00110 } 00111 00112 void DmTouch::init() { 00113 #if defined (DM_TOOLCHAIN_ARDUINO) 00114 pinMode(_cs, OUTPUT); 00115 _pinCS = portOutputRegister(digitalPinToPort(_cs)); 00116 _bitmaskCS = digitalPinToBitMask(_cs); 00117 00118 if (_hardwareSpi) { 00119 SPI.begin(); 00120 SPI.setClockDivider(SPI_CLOCK_DIV32); 00121 SPI.setBitOrder(MSBFIRST); 00122 SPI.setDataMode(SPI_MODE0); 00123 _spiSettings = SPCR; 00124 } 00125 else { 00126 pinMode(_clk, OUTPUT); 00127 pinMode(_mosi, OUTPUT); 00128 pinMode(_miso, INPUT); 00129 _pinCLK = portOutputRegister(digitalPinToPort(_clk)); 00130 _bitmaskCLK = digitalPinToBitMask(_clk); 00131 _pinMOSI = portOutputRegister(digitalPinToPort(_mosi)); 00132 _bitmaskMOSI = digitalPinToBitMask(_mosi); 00133 _pinMISO = portInputRegister(digitalPinToPort(_miso)); 00134 _bitmaskMISO = digitalPinToBitMask(_miso); 00135 } 00136 #elif defined (DM_TOOLCHAIN_MBED) 00137 _pinCS = new DigitalOut(_cs); 00138 if (_hardwareSpi) { 00139 sbi(_pinCS, _bitmaskCS); 00140 _spi = new SPI((PinName)_mosi, (PinName)_miso, (PinName)_clk); 00141 _spi->format(8,0); 00142 _spi->frequency(2000000); // Max SPI speed 00143 } else { 00144 _pinCLK = new DigitalOut(_clk); 00145 _pinMISO = new DigitalIn(_miso); 00146 _pinMOSI = new DigitalOut(_mosi); 00147 sbi(_pinCLK, _bitmaskCLK); 00148 } 00149 #endif 00150 00151 if (_irq != NC) { // We will use Touch IRQ 00152 enableIrq(); 00153 } 00154 } 00155 00156 void DmTouch::enableIrq() { 00157 #if defined (DM_TOOLCHAIN_ARDUINO) 00158 pinMode(_irq, INPUT); 00159 _pinIrq = portInputRegister(digitalPinToPort(_irq)); 00160 _bitmaskIrq = digitalPinToBitMask(_irq); 00161 00162 cbi(_pinCS, _bitmaskCS); 00163 spiWrite(0x80); // Enable PENIRQ 00164 sbi(_pinCS, _bitmaskCS); 00165 #elif defined (DM_TOOLCHAIN_MBED) 00166 _pinIrq = new DigitalIn((PinName)_irq); 00167 _pinIrq->mode(PullUp); 00168 #endif 00169 if(_touch_id == IC_8875) { 00170 // enable touch panel 00171 cbi(_pinCS, _bitmaskCS); 00172 spiWrite(0x80); 00173 spiWrite(0x70); 00174 sbi(_pinCS, _bitmaskCS); 00175 00176 cbi(_pinCS, _bitmaskCS); 00177 spiWrite(0x00); 00178 spiWrite(0xB3); 00179 sbi(_pinCS, _bitmaskCS); 00180 00181 // set auto mode 00182 cbi(_pinCS, _bitmaskCS); 00183 spiWrite(0x80); 00184 spiWrite(0x71); 00185 sbi(_pinCS, _bitmaskCS); 00186 00187 cbi(_pinCS, _bitmaskCS); 00188 spiWrite(0x00); 00189 spiWrite(0x04); 00190 sbi(_pinCS, _bitmaskCS); 00191 00192 // enable touch panel interrupt 00193 cbi(_pinCS, _bitmaskCS); 00194 spiWrite(0x80); 00195 spiWrite(0xF0); 00196 sbi(_pinCS, _bitmaskCS); 00197 00198 cbi(_pinCS, _bitmaskCS); 00199 uint8_t temp; 00200 spiWrite(0x40); 00201 temp = spiRead(); 00202 sbi(_pinCS, _bitmaskCS); 00203 00204 cbi(_pinCS, _bitmaskCS); 00205 spiWrite(0x80); 00206 spiWrite(0xF0); 00207 sbi(_pinCS, _bitmaskCS); 00208 00209 cbi(_pinCS, _bitmaskCS); 00210 spiWrite(0x00); 00211 spiWrite(temp | 0x04); 00212 sbi(_pinCS, _bitmaskCS); 00213 00214 // Clear TP INT Status 00215 cbi(_pinCS, _bitmaskCS); 00216 spiWrite(0x80); 00217 spiWrite(0xF1); 00218 sbi(_pinCS, _bitmaskCS); 00219 00220 cbi(_pinCS, _bitmaskCS); 00221 spiWrite(0x00); 00222 spiWrite(0x04); 00223 sbi(_pinCS, _bitmaskCS); 00224 } 00225 else{ 00226 cbi(_pinCS, _bitmaskCS); 00227 spiWrite(0x80); // Enable PENIRQ 00228 sbi(_pinCS, _bitmaskCS); 00229 } 00230 } 00231 00232 void DmTouch::spiWrite(uint8_t data) { 00233 if (_hardwareSpi) { 00234 #if defined (DM_TOOLCHAIN_ARDUINO) 00235 SPCR = _spiSettings; // SPI Control Register 00236 SPDR = data; // SPI Data Register 00237 while(!(SPSR & _BV(SPIF))); // SPI Status Register Wait for transmission to finish 00238 #elif defined (DM_TOOLCHAIN_MBED) 00239 _spi->write(data); 00240 #endif 00241 } 00242 else { 00243 uint8_t count=0; 00244 uint8_t temp = data; 00245 delay(1); 00246 cbi(_pinCLK, _bitmaskCLK); 00247 for(count=0;count<8;count++) { 00248 if(temp&0x80) { 00249 sbi(_pinMOSI, _bitmaskMOSI); 00250 } 00251 else { 00252 cbi(_pinMOSI, _bitmaskMOSI); 00253 } 00254 00255 temp=temp<<1; 00256 00257 slow_pulse_low(_pinCLK, _bitmaskCLK); 00258 } 00259 } 00260 } 00261 00262 uint8_t DmTouch::spiRead() {// Only used for Hardware SPI 00263 #if defined (DM_TOOLCHAIN_ARDUINO) 00264 uint8_t data; 00265 SPCR = _spiSettings; 00266 spiWrite(0x00); 00267 data = SPDR; 00268 00269 return data; 00270 #elif defined (DM_TOOLCHAIN_MBED) 00271 if (_hardwareSpi) { 00272 return _spi->write(0x00); // dummy byte to read 00273 } else { 00274 uint8_t count=0; 00275 uint8_t temp=0; 00276 cbi(_pinCLK, _bitmaskCLK); 00277 cbi(_pinMOSI, _bitmaskMOSI); // same as using 0x00 as dummy byte 00278 for(count=0;count<8;count++) { 00279 00280 pulse_low(_pinCLK, _bitmaskCLK); 00281 temp = temp<<1; 00282 temp |= _pinMISO->read(); 00283 } 00284 return temp; 00285 } 00286 #endif 00287 } 00288 00289 uint16_t DmTouch::readData12(uint8_t command) { 00290 uint8_t temp = 0; 00291 uint16_t value = 0; 00292 00293 spiWrite(command); // Send command 00294 00295 #if defined (DM_TOOLCHAIN_ARDUINO) 00296 if (_hardwareSpi) { 00297 // We use 7-bits from the first byte and 5-bit from the second byte 00298 temp = spiRead(); 00299 value = temp<<8; 00300 temp = spiRead(); 00301 00302 value |= temp; 00303 value >>=3; 00304 value &= 0xFFF; 00305 } else { 00306 pulse_high(_pinCLK, _bitmaskCLK); 00307 unsigned nop; 00308 uint8_t count=0; 00309 for(count=0;count<12;count++) { 00310 value<<=1; 00311 pulse_high(_pinCLK, _bitmaskCLK); 00312 if ( gbi(_pinMISO, _bitmaskMISO) ) { 00313 value++; 00314 } 00315 } 00316 } 00317 #elif defined (DM_TOOLCHAIN_MBED) 00318 // We use 7-bits from the first byte and 5-bit from the second byte 00319 temp = spiRead(); 00320 value = temp<<8; 00321 temp = spiRead(); 00322 value |= temp; 00323 value >>=3; 00324 value &= 0xFFF; 00325 #endif 00326 return value; 00327 } 00328 00329 void DmTouch::readRawData(uint16_t &x, uint16_t &y) { 00330 if(_touch_id == IC_8875){ 00331 uint16_t tx, ty; 00332 uint8_t temp; 00333 00334 cbi(_pinCS, _bitmaskCS); 00335 spiWrite(0x80); 00336 spiWrite(0x72); 00337 sbi(_pinCS, _bitmaskCS); 00338 00339 cbi(_pinCS, _bitmaskCS); 00340 spiWrite(0x40); 00341 tx = spiRead(); 00342 sbi(_pinCS, _bitmaskCS); 00343 00344 cbi(_pinCS, _bitmaskCS); 00345 spiWrite(0x80); 00346 spiWrite(0x73); 00347 sbi(_pinCS, _bitmaskCS); 00348 00349 cbi(_pinCS, _bitmaskCS); 00350 spiWrite(0x40); 00351 ty = spiRead(); 00352 sbi(_pinCS, _bitmaskCS); 00353 00354 cbi(_pinCS, _bitmaskCS); 00355 spiWrite(0x80); 00356 spiWrite(0x74); 00357 sbi(_pinCS, _bitmaskCS); 00358 00359 cbi(_pinCS, _bitmaskCS); 00360 spiWrite(0x40); 00361 temp = spiRead(); 00362 sbi(_pinCS, _bitmaskCS); 00363 00364 tx <<= 2; 00365 ty <<= 2; 00366 tx |= temp & 0x03; // get the bottom x bits 00367 ty |= (temp >> 2) & 0x03; // get the bottom y bits 00368 00369 x = tx; 00370 y = ty; 00371 00372 // Clear TP INT Status 00373 cbi(_pinCS, _bitmaskCS); 00374 spiWrite(0x80); 00375 spiWrite(0xF1); 00376 sbi(_pinCS, _bitmaskCS); 00377 00378 cbi(_pinCS, _bitmaskCS); 00379 spiWrite(0x00); 00380 spiWrite(0x04); 00381 sbi(_pinCS, _bitmaskCS); 00382 } 00383 else{ 00384 cbi(_pinCS, _bitmaskCS); 00385 x = readData12(0xD0); 00386 y = readData12(0x90); 00387 sbi(_pinCS, _bitmaskCS); 00388 } 00389 } 00390 00391 void DmTouch::readTouchData(uint16_t& posX, uint16_t& posY, bool& touching) { 00392 uint16_t touchX, touchY; 00393 getMiddleXY(touchX,touchY); 00394 00395 posX = getDisplayCoordinateX(touchX, touchY); 00396 posY = getDisplayCoordinateY(touchX, touchY); 00397 #if defined (DM_TOOLCHAIN_ARDUINO) 00398 touching = isTouched(); 00399 #elif defined (DM_TOOLCHAIN_MBED) 00400 if(_touch_id == IC_8875) { 00401 touching = isTouched() && (posX < _width && posY < _height); 00402 } 00403 else{ 00404 touching = (posX < _width && posY < _height); 00405 } 00406 #endif 00407 } 00408 00409 bool DmTouch::isSampleValid() { 00410 uint16_t sampleX,sampleY; 00411 readRawData(sampleX,sampleY); 00412 if (sampleX > 0 && sampleX < 4095 && sampleY > 0 && sampleY < 4095) { 00413 return true; 00414 } else { 00415 return false; 00416 } 00417 } 00418 00419 bool DmTouch::isTouched() { 00420 #if defined (DM_TOOLCHAIN_ARDUINO) 00421 if (_irq == -1) { 00422 return isSampleValid(); 00423 } 00424 00425 if ( !gbi(_pinIrq, _bitmaskIrq) ) { 00426 if(_touch_id == IC_8875){ 00427 // Clear TP INT Status 00428 cbi(_pinCS, _bitmaskCS); 00429 spiWrite(0x80); 00430 spiWrite(0xF1); 00431 sbi(_pinCS, _bitmaskCS); 00432 00433 cbi(_pinCS, _bitmaskCS); 00434 spiWrite(0x00); 00435 spiWrite(0x04); 00436 sbi(_pinCS, _bitmaskCS); 00437 } 00438 return true; 00439 } 00440 00441 return false; 00442 #elif defined (DM_TOOLCHAIN_MBED) 00443 if(_touch_id == IC_8875) { 00444 delay(1); 00445 if (!_pinIrq->read()) { 00446 // Clear TP INT Status 00447 cbi(_pinCS, _bitmaskCS); 00448 spiWrite(0x80); 00449 spiWrite(0xF1); 00450 sbi(_pinCS, _bitmaskCS); 00451 00452 cbi(_pinCS, _bitmaskCS); 00453 spiWrite(0x00); 00454 spiWrite(0x04); 00455 sbi(_pinCS, _bitmaskCS); 00456 return true; 00457 } else { 00458 return false; 00459 } 00460 } 00461 return isSampleValid(); 00462 #endif 00463 } 00464 00465 bool DmTouch::getMiddleXY(uint16_t &x, uint16_t &y) { 00466 bool haveAllMeasurements = true; 00467 uint16_t valuesX[MEASUREMENTS]; 00468 uint16_t valuesY[MEASUREMENTS]; 00469 uint8_t nbrOfMeasurements = 0; 00470 00471 for (int i=0; i<MEASUREMENTS; i++) { 00472 getAverageXY(valuesX[i], valuesY[i]); 00473 nbrOfMeasurements++; 00474 if(_touch_id != IC_8875) { 00475 if (!isTouched()) { 00476 haveAllMeasurements = false; 00477 break; 00478 } 00479 } 00480 } 00481 if (haveAllMeasurements) { 00482 x = calculateMiddleValue(valuesX, nbrOfMeasurements); 00483 y = calculateMiddleValue(valuesY, nbrOfMeasurements); 00484 } 00485 00486 return haveAllMeasurements; 00487 } 00488 00489 void DmTouch::getAverageXY(uint16_t &x, uint16_t &y) { 00490 uint32_t sumX = 0; 00491 uint32_t sumY = 0; 00492 uint16_t sampleX,sampleY; 00493 readRawData(sampleX,sampleY); 00494 00495 for (int i=0; i<_samplesPerMeasurement; i++) { 00496 readRawData(sampleX,sampleY); 00497 sumX += sampleX; 00498 sumY += sampleY; 00499 } 00500 00501 x = (uint32_t)sumX/_samplesPerMeasurement; 00502 y = (uint32_t)sumY/_samplesPerMeasurement; 00503 } 00504 00505 // Total number of samples = MEASUREMENTS * _samplesPerMeasurement 00506 void DmTouch::setPrecison(uint8_t samplesPerMeasurement) { 00507 _samplesPerMeasurement = samplesPerMeasurement; 00508 } 00509 00510 void DmTouch::setCalibrationMatrix(CalibrationMatrix calibrationMatrix) { 00511 _calibrationMatrix = calibrationMatrix; 00512 } 00513 00514 void DmTouch::waitForTouch() { 00515 while(!isTouched()) {} 00516 } 00517 00518 void DmTouch::waitForTouchRelease() { 00519 while(isTouched()) {} 00520 } 00521 00522 uint16_t DmTouch::getDisplayCoordinateX(uint16_t x_touch, uint16_t y_touch) { 00523 uint16_t Xd; 00524 float temp; 00525 temp = (_calibrationMatrix.a * x_touch + _calibrationMatrix.b * y_touch + _calibrationMatrix.c) / rescaleFactor(); 00526 Xd = (uint16_t)(temp); 00527 if (Xd > 60000) { 00528 Xd = 0; 00529 } 00530 return Xd; 00531 } 00532 00533 uint16_t DmTouch::getDisplayCoordinateY(uint16_t x_touch, uint16_t y_touch) { 00534 uint16_t Yd; 00535 float temp; 00536 temp = (_calibrationMatrix.d * x_touch + _calibrationMatrix.e * y_touch + _calibrationMatrix.f) / rescaleFactor(); 00537 Yd = (uint16_t)(temp); 00538 if (Yd > 60000) { 00539 Yd = 0; 00540 } 00541 return Yd; 00542 } 00543 00544 uint16_t DmTouch::calculateMiddleValue(uint16_t values[], uint8_t count) { 00545 uint16_t temp; 00546 00547 for(uint8_t i=0; i<count-1; i++) { 00548 for(uint8_t j=i+1; j<count; j++) { 00549 if(values[j] < values[i]) { 00550 temp = values[i]; 00551 values[i] = values[j]; 00552 values[j] = temp; 00553 } 00554 } 00555 } 00556 00557 if(count%2==0) { 00558 return((values[count/2] + values[count/2 - 1]) / 2.0); 00559 } else { 00560 return values[count/2]; 00561 } 00562 }
Generated on Wed Jul 13 2022 04:21:40 by 1.7.2