Driver Library for our displays

Dependents:   dm_bubbles dm_calc dm_paint dm_sdcard_with_adapter ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers DmTouch.cpp Source File

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 }