Modified version of the DmTftLibrary, optimized for the LPC4088 Experiment Base Board

Dependents:   lpc4088_ebb_dm_calc lpc4088_ebb_dm_bubbles

Fork of DmTftLibrary by Display Module

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
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 
00025 #elif defined (DM_TOOLCHAIN_MBED)
00026 // disp        - which display is used
00027 // spiMode     - How to read SPI-data, Software, Hardware or Auto
00028 DmTouch::DmTouch(Display disp, SpiMode spiMode)
00029 #endif
00030 {
00031   _disp = disp;
00032   switch (disp) {
00033     // Display with 40-pin connector on top of adapter board
00034     case DmTouch::DM_TFT28_103:
00035     case DmTouch::DM_TFT24_104:
00036       _cs = D8;
00037       _irq = D10;
00038       _clk = A1;
00039       _mosi = A0;
00040       _miso = D9;
00041       _width = 240;
00042       _height = 320;
00043       _hardwareSpi = false;
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       break;
00056 
00057     case DmTouch::DM_TFT35_107:
00058     default:
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       break;
00068   }
00069 
00070   if (spiMode == DmTouch::Hardware) {
00071     _hardwareSpi = true;
00072   } else if (spiMode == DmTouch::Software) {
00073     _hardwareSpi = false;
00074   }
00075 
00076 #if defined(DM_TOOLCHAIN_ARDUINO)
00077   if (!useIrq) {
00078     _irq = -1;
00079   }
00080 #elif defined (DM_TOOLCHAIN_MBED)
00081   _irq = -1;
00082 #endif
00083   
00084   setCalibrationMatrix(DmTouchCalibration::getDefaultCalibrationData(disp));
00085 
00086   _samplesPerMeasurement = 3;
00087 }
00088 
00089 void DmTouch::init() {
00090 #if defined (DM_TOOLCHAIN_ARDUINO)
00091   pinMode(_cs, OUTPUT);
00092   _pinCS  = portOutputRegister(digitalPinToPort(_cs));
00093   _bitmaskCS  = digitalPinToBitMask(_cs);
00094 
00095   if (_hardwareSpi) {
00096     SPI.begin();
00097     SPI.setClockDivider(SPI_CLOCK_DIV32);
00098     SPI.setBitOrder(MSBFIRST);
00099     SPI.setDataMode(SPI_MODE0);
00100     _spiSettings = SPCR;
00101   }
00102   else {
00103     pinMode(_clk, OUTPUT);
00104     pinMode(_mosi, OUTPUT);
00105     pinMode(_miso, INPUT);
00106     _pinCLK  = portOutputRegister(digitalPinToPort(_clk));
00107     _bitmaskCLK  = digitalPinToBitMask(_clk);
00108     _pinMOSI  = portOutputRegister(digitalPinToPort(_mosi));
00109     _bitmaskMOSI  = digitalPinToBitMask(_mosi);
00110     _pinMISO = portInputRegister(digitalPinToPort(_miso));
00111     _bitmaskMISO  = digitalPinToBitMask(_miso);
00112   }
00113 #elif defined (DM_TOOLCHAIN_MBED)
00114   _pinCS = new DigitalOut((PinName)_cs);
00115   if (_hardwareSpi) {
00116     sbi(_pinCS, _bitmaskCS);
00117     _spi = new SPI((PinName)_mosi, (PinName)_miso, (PinName)_clk);
00118     _spi->format(8,0);
00119     _spi->frequency(2000000); // Max SPI speed
00120     //cbi(_pinCS, _bitmaskCS);
00121   } else {
00122     _pinCLK = new DigitalOut((PinName)_clk);
00123     _pinMISO = new DigitalIn((PinName)_miso);
00124     _pinMOSI = new DigitalOut((PinName)_mosi);
00125     sbi(_pinCS, _bitmaskCS);
00126     sbi(_pinCLK, _bitmaskCLK);
00127   }
00128 #endif
00129 
00130   if (_irq != -1) { // We will use Touch IRQ
00131     enableIrq();
00132   }
00133 }
00134 
00135 void DmTouch::enableIrq() {
00136 #if defined (DM_TOOLCHAIN_ARDUINO)
00137   pinMode(_irq, INPUT);
00138   _pinIrq = portInputRegister(digitalPinToPort(_irq));
00139   _bitmaskIrq  = digitalPinToBitMask(_irq);
00140 
00141   cbi(_pinCS, _bitmaskCS);
00142   spiWrite(0x80); // Enable PENIRQ
00143   sbi(_pinCS, _bitmaskCS);
00144 #endif    
00145 }
00146 
00147 void DmTouch::spiWrite(uint8_t data) {
00148   if (_hardwareSpi) {
00149 #if defined (DM_TOOLCHAIN_ARDUINO)
00150     SPCR = _spiSettings;   // SPI Control Register
00151     SPDR = data;        // SPI Data Register
00152     while(!(SPSR & _BV(SPIF)));  // SPI Status Register Wait for transmission to finish
00153 #elif defined (DM_TOOLCHAIN_MBED)
00154     _spi->write(data);
00155 #endif
00156   }
00157   else {
00158     uint8_t count=0;
00159     uint8_t temp = data;
00160     //delay(1);
00161     cbi(_pinCLK, _bitmaskCLK);
00162     for(count=0;count<8;count++) {
00163       if(temp&0x80) {
00164         sbi(_pinMOSI, _bitmaskMOSI);
00165       }
00166       else {
00167         cbi(_pinMOSI, _bitmaskMOSI);
00168       }
00169 
00170       temp=temp<<1;
00171 
00172       pulse_low(_pinCLK, _bitmaskCLK);
00173     }
00174   }
00175 }
00176 
00177 uint8_t DmTouch::spiRead() {// Only used for Hardware SPI
00178 #if defined (DM_TOOLCHAIN_ARDUINO)
00179   uint8_t data;
00180   SPCR = _spiSettings;
00181   spiWrite(0x00);
00182   data = SPDR;
00183 
00184   return data;
00185 #elif defined (DM_TOOLCHAIN_MBED)
00186   if (_hardwareSpi) {
00187     return _spi->write(0x00); // dummy byte to read
00188   } else {
00189     uint8_t count=0;
00190     uint8_t temp=0;
00191     cbi(_pinCLK, _bitmaskCLK);
00192     cbi(_pinMOSI, _bitmaskMOSI); // same as using 0x00 as dummy byte
00193     for(count=0;count<8;count++) {
00194 
00195       pulse_low(_pinCLK, _bitmaskCLK);
00196       temp = temp<<1;
00197       temp |= _pinMISO->read();
00198     }
00199     return temp;
00200   }
00201 #endif
00202 }
00203 
00204 uint16_t DmTouch::readData12(uint8_t command) {
00205   uint8_t temp = 0;
00206   uint16_t value = 0;
00207 
00208   spiWrite(command); // Send command
00209 
00210 #if defined (DM_TOOLCHAIN_ARDUINO)
00211   if (_hardwareSpi) {
00212     // We use 7-bits from the first byte and 5-bit from the second byte
00213     temp = spiRead();
00214     value = temp<<8;
00215     temp = spiRead();
00216 
00217     value |= temp;
00218     value >>=3;
00219     value &= 0xFFF;
00220   } else {
00221     pulse_high(_pinCLK, _bitmaskCLK);
00222     unsigned nop;
00223     uint8_t count=0;
00224     for(count=0;count<12;count++) {
00225       value<<=1;
00226       pulse_high(_pinCLK, _bitmaskCLK);
00227       if ( gbi(_pinMISO, _bitmaskMISO) ) {
00228         value++;
00229       }
00230     }
00231   }
00232 #elif defined (DM_TOOLCHAIN_MBED)
00233   // We use 7-bits from the first byte and 5-bit from the second byte
00234   temp = spiRead();
00235   value = temp<<8;
00236   temp = spiRead();
00237   value |= temp;
00238   value >>=3;
00239   value &= 0xFFF;
00240 #endif
00241   return value;
00242 }
00243 
00244 void DmTouch::readRawData(uint16_t &x, uint16_t &y) {
00245   cbi(_pinCS, _bitmaskCS);
00246   x = readData12(0xD0);
00247   y = readData12(0x90);
00248   sbi(_pinCS, _bitmaskCS);
00249 }
00250 
00251 void DmTouch::readTouchData(uint16_t& posX, uint16_t& posY, bool& touching) {  
00252   uint16_t touchX, touchY;
00253   if (!getMiddleXY(touchX,touchY)) {
00254     touching = false;
00255   }
00256 
00257   posX = getDisplayCoordinateX(touchX, touchY);
00258   posY = getDisplayCoordinateY(touchX, touchY);
00259   
00260 #if defined (DM_TOOLCHAIN_ARDUINO)
00261   touching = isTouched();
00262 #elif defined (DM_TOOLCHAIN_MBED)
00263   touching = (posX < _width && posY < _height);
00264 #endif
00265 }
00266 
00267 bool DmTouch::isSampleValid() {
00268   uint16_t sampleX,sampleY;
00269   readRawData(sampleX,sampleY);
00270   if (sampleX > 0 && sampleX < 4095 && sampleY > 0 && sampleY < 4095) {
00271     return true;
00272   } else {
00273     return false;
00274   }
00275 }
00276 
00277 bool DmTouch::isTouched() {
00278 #if defined (DM_TOOLCHAIN_ARDUINO)
00279   if (_irq == -1) {
00280     return isSampleValid();
00281   }
00282 
00283   if ( !gbi(_pinIrq, _bitmaskIrq) ) {
00284     return true;
00285   }
00286 
00287   return false;
00288 #elif defined (DM_TOOLCHAIN_MBED)
00289   return isSampleValid();
00290 #endif
00291 }
00292 
00293 bool DmTouch::getMiddleXY(uint16_t &x, uint16_t &y) {
00294   bool haveAllMeasurements  = true;
00295   uint16_t valuesX[MEASUREMENTS];
00296   uint16_t valuesY[MEASUREMENTS];
00297   uint8_t nbrOfMeasurements = 0;
00298 
00299   for (int i=0; i<MEASUREMENTS; i++) {
00300     getAverageXY(valuesX[i], valuesY[i]);
00301     nbrOfMeasurements++;
00302 #if defined (DM_TOOLCHAIN_ARDUINO)
00303     if (!isTouched()) {
00304       haveAllMeasurements = false;
00305       break;
00306     }
00307 #elif defined (DM_TOOLCHAIN_MBED)
00308     if (valuesX[i] >= 4095 || valuesY[i] >= 4095) {
00309       haveAllMeasurements = false;
00310       break;
00311     }
00312 #endif
00313   }
00314   if (haveAllMeasurements) {
00315     x = calculateMiddleValue(valuesX, nbrOfMeasurements);
00316     y = calculateMiddleValue(valuesY, nbrOfMeasurements);
00317   }
00318 
00319   return haveAllMeasurements;
00320 }
00321 
00322 void DmTouch::getAverageXY(uint16_t &x, uint16_t &y) {
00323   uint32_t sumX = 0;
00324   uint32_t sumY = 0;
00325   uint16_t sampleX,sampleY;
00326   readRawData(sampleX,sampleY);
00327 
00328   for (int i=0; i<_samplesPerMeasurement; i++) {
00329     readRawData(sampleX,sampleY);
00330     sumX += sampleX;
00331     sumY += sampleY;
00332   }
00333 
00334   x = (uint32_t)sumX/_samplesPerMeasurement;
00335   y = (uint32_t)sumY/_samplesPerMeasurement;
00336 }
00337 
00338 // Total number of samples = MEASUREMENTS * _samplesPerMeasurement
00339 void DmTouch::setPrecison(uint8_t samplesPerMeasurement) {
00340   _samplesPerMeasurement = samplesPerMeasurement;
00341 }
00342 
00343 void DmTouch::setCalibrationMatrix(CalibrationMatrix calibrationMatrix) {
00344   _calibrationMatrix = calibrationMatrix;
00345 }
00346 
00347 void DmTouch::waitForTouch() {
00348   while(!isTouched()) {}
00349 }
00350 
00351 void DmTouch::waitForTouchRelease() {
00352   while(isTouched()) {}
00353 }
00354 
00355 uint16_t DmTouch::getDisplayCoordinateX(uint16_t x_touch, uint16_t y_touch) {
00356   uint16_t Xd;
00357   float temp;
00358   temp = (_calibrationMatrix.a * x_touch + _calibrationMatrix.b * y_touch + _calibrationMatrix.c) / rescaleFactor();
00359   Xd = (uint16_t)(temp);
00360   if (Xd > 60000) {
00361     Xd = 0;
00362   }
00363   return Xd;
00364 }
00365 
00366 uint16_t DmTouch::getDisplayCoordinateY(uint16_t x_touch, uint16_t y_touch) {
00367   uint16_t Yd;
00368   float temp;
00369   temp = (_calibrationMatrix.d * x_touch + _calibrationMatrix.e * y_touch + _calibrationMatrix.f) / rescaleFactor();
00370   Yd = (uint16_t)(temp);
00371   if (Yd > 60000) {
00372     Yd = 0;
00373   }
00374   return Yd;
00375 }
00376 
00377 uint16_t DmTouch::calculateMiddleValue(uint16_t values[], uint8_t count) {
00378   uint16_t temp;
00379 
00380   for(uint8_t i=0; i<count-1; i++) {
00381     for(uint8_t j=i+1; j<count; j++) {
00382       if(values[j] < values[i]) {
00383         temp = values[i];
00384         values[i] = values[j];
00385         values[j] = temp;
00386       }
00387     }
00388   }
00389 
00390   if(count%2==0) {
00391     return((values[count/2] + values[count/2 - 1]) / 2.0);
00392   } else {
00393     return values[count/2];
00394   }
00395 }