
Using touch screen features of LCD screen.
Dependencies: DmTouch_UniGraphic UniGraphic mbed
Fork of DisplayModule24_demo by
Revision 9:8917e707fe8e, committed 2016-01-20
- Comitter:
- JLarkin
- Date:
- Wed Jan 20 07:21:30 2016 +0000
- Parent:
- 8:9484e01decd9
- Child:
- 10:ca16a309a737
- Commit message:
- Revised DmTouch to work with UniGraphics, multiple screen orientations, and flexible mbed pins.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DmTouch.cpp Wed Jan 20 07:21:30 2016 +0000 @@ -0,0 +1,551 @@ +/********************************************************************************************** + Copyright (c) 2014 DisplayModule. All rights reserved. + + Redistribution and use of this source code, part of this source code or any compiled binary + based on this source code is permitted as long as the above copyright notice and following + disclaimer is retained. + + DISCLAIMER: + THIS SOFTWARE IS SUPPLIED "AS IS" WITHOUT ANY WARRANTIES AND SUPPORT. DISPLAYMODULE ASSUMES + NO RESPONSIBILITY OR LIABILITY FOR THE USE OF THE SOFTWARE. + ********************************************************************************************/ +// Tested with Xpt2046 and RA8875 + +/* Modified by John M. Larkin, Whitworth University, to remove Arduino code */ + +#include "DmTouch.h" +//#include "DmTouchCalibration.h" + +#define MEASUREMENTS 10 + +// disp - which display is used +// spiMode - How to read SPI-data, Software, Hardware or Auto +// (JML) Modify to include cs and irq as input parameters +// (JML) Modify so doesn't assume Arduino shield +// (JML) Using with mbed so assume hardware SPI available +DmTouch::DmTouch(Display disp, PinName mosi, PinName miso, PinName clk, PinName cs, PinName irq) +{ + _disp = disp; + _cs = cs; + _irq = irq; + _clk = clk; + _mosi = mosi; + _miso = miso; + _hardwareSpi = true; + switch (disp) { + // Display with 40-pin connector on top of adapter board + case DmTouch::DM_TFT28_103: + case DmTouch::DM_TFT24_104: + _width = 240; + _height = 320; + _touch_id = IC_2046; + break; + + case DmTouch::DM_TFT28_105: + _cs = D4; + _irq = D2; + _clk = D13; + _mosi = D11; + _miso = D12; + _width = 240; + _height = 320; + _hardwareSpi = true; + _touch_id = IC_2046; + break; + + case DmTouch::DM_TFT35_107: + _cs = D4; + _irq = D2; + _clk = D13; + _mosi = D11; + _miso = D12; + _width = 320; + _height = 240; + _hardwareSpi = true; + _touch_id = IC_2046; + break; + + case DmTouch::DM_TFT43_108: // or DM_TFT43_110 + _cs = D10; + _irq = D2; + _clk = D13; + _mosi = D11; + _miso = D12; + _width = 480; + _height = 272; + _hardwareSpi = true; + _touch_id = IC_8875; + break; + + case DmTouch::DM_TFT50_111: // or DM_TFT50_112 + _cs = D10; + _irq = D2; + _clk = D13; + _mosi = D11; + _miso = D12; + _width = 800; + _height = 480; + _hardwareSpi = true; + _touch_id = IC_8875; + break; + + default: + _cs = D4; + _irq = D2; + _clk = D13; + _mosi = D11; + _miso = D12; + _width = 320; + _height = 240; + _hardwareSpi = true; + _touch_id = IC_2046; + break; + } + + //setCalibrationMatrix(DmTouchCalibration::getDefaultCalibrationData(disp)); + setCalibrationMatrix(DmTouch::getDefaultCalibrationData(disp)); // Use new local version + + _samplesPerMeasurement = 3; +} + +void DmTouch::init() { + _pinCS = new DigitalOut(_cs); + if (_hardwareSpi) { + sbi(_pinCS, _bitmaskCS); + _spi = new SPI((PinName)_mosi, (PinName)_miso, (PinName)_clk); + _spi->format(8,0); + _spi->frequency(2000000); // Max SPI speed + } else { + _pinCLK = new DigitalOut(_clk); + _pinMISO = new DigitalIn(_miso); + _pinMOSI = new DigitalOut(_mosi); + sbi(_pinCLK, _bitmaskCLK); + } + + if (_irq != NC) { // We will use Touch IRQ + enableIrq(); + } +} + +void DmTouch::enableIrq() { + _pinIrq = new DigitalIn((PinName)_irq); + _pinIrq->mode(PullUp); + if(_touch_id == IC_8875) { + // enable touch panel + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0x70); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x00); + spiWrite(0xB3); + sbi(_pinCS, _bitmaskCS); + + // set auto mode + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0x71); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x00); + spiWrite(0x04); + sbi(_pinCS, _bitmaskCS); + + // enable touch panel interrupt + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0xF0); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + uint8_t temp; + spiWrite(0x40); + temp = spiRead(); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0xF0); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x00); + spiWrite(temp | 0x04); + sbi(_pinCS, _bitmaskCS); + + // Clear TP INT Status + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0xF1); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x00); + spiWrite(0x04); + sbi(_pinCS, _bitmaskCS); + } + else{ + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); // Enable PENIRQ + sbi(_pinCS, _bitmaskCS); + } +} + +void DmTouch::spiWrite(uint8_t data) { + if (_hardwareSpi) { + _spi->write(data); + } + else { + uint8_t count=0; + uint8_t temp = data; + delay(1); + cbi(_pinCLK, _bitmaskCLK); + for(count=0;count<8;count++) { + if(temp&0x80) { + sbi(_pinMOSI, _bitmaskMOSI); + } + else { + cbi(_pinMOSI, _bitmaskMOSI); + } + + temp=temp<<1; + + slow_pulse_low(_pinCLK, _bitmaskCLK); + } + } +} + +uint8_t DmTouch::spiRead() {// Only used for Hardware SPI + if (_hardwareSpi) { + return _spi->write(0x00); // dummy byte to read + } else { + uint8_t count=0; + uint8_t temp=0; + cbi(_pinCLK, _bitmaskCLK); + cbi(_pinMOSI, _bitmaskMOSI); // same as using 0x00 as dummy byte + for(count=0;count<8;count++) { + + pulse_low(_pinCLK, _bitmaskCLK); + temp = temp<<1; + temp |= _pinMISO->read(); + } + return temp; + } +} + +uint16_t DmTouch::readData12(uint8_t command) { + uint8_t temp = 0; + uint16_t value = 0; + + spiWrite(command); // Send command + // We use 7-bits from the first byte and 5-bit from the second byte + temp = spiRead(); + value = temp<<8; + temp = spiRead(); + value |= temp; + value >>=3; + value &= 0xFFF; + return value; +} + +void DmTouch::readRawData(uint16_t &x, uint16_t &y) { + if(_touch_id == IC_8875){ + uint16_t tx, ty; + uint8_t temp; + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0x72); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x40); + tx = spiRead(); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0x73); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x40); + ty = spiRead(); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0x74); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x40); + temp = spiRead(); + sbi(_pinCS, _bitmaskCS); + + tx <<= 2; + ty <<= 2; + tx |= temp & 0x03; // get the bottom x bits + ty |= (temp >> 2) & 0x03; // get the bottom y bits + + x = tx; + y = ty; + + // Clear TP INT Status + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0xF1); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x00); + spiWrite(0x04); + sbi(_pinCS, _bitmaskCS); + } + else{ + cbi(_pinCS, _bitmaskCS); + x = readData12(0xD0); + y = readData12(0x90); + sbi(_pinCS, _bitmaskCS); + } +} + +void DmTouch::readTouchData(uint16_t& posX, uint16_t& posY, bool& touching) { + uint16_t touchX, touchY; + getMiddleXY(touchX,touchY); + uint16_t screenX, screenY; + + posX = getDisplayCoordinateX(touchX, touchY); + posY = getDisplayCoordinateY(touchX, touchY); + if(_touch_id == IC_8875) { + touching = isTouched() && (posX < _width && posY < _height); + } + else{ + touching = (posX < _width && posY < _height); + } + // Now account for screen orientation and return in "screen coordinates" + switch(_orient) { + case 0: + screenX = posX; + screenY = posY; + break; + case 1: + screenX = posY; + screenY = _width-posX; + break; + case 2: + screenX = _width - posX; + screenY = _height - posY; + break; + case 3: + screenX = _height - posY; + screenY = posX; + break; + default: + screenX = posX; + screenY = posY; + } + posX = screenX; + posY = screenY; +} + +bool DmTouch::isSampleValid() { + uint16_t sampleX,sampleY; + readRawData(sampleX,sampleY); + if (sampleX > 0 && sampleX < 4095 && sampleY > 0 && sampleY < 4095) { + return true; + } else { + return false; + } +} + +bool DmTouch::isTouched() { + if(_touch_id == IC_8875) { + delay(1); + if (!_pinIrq->read()) { + // Clear TP INT Status + cbi(_pinCS, _bitmaskCS); + spiWrite(0x80); + spiWrite(0xF1); + sbi(_pinCS, _bitmaskCS); + + cbi(_pinCS, _bitmaskCS); + spiWrite(0x00); + spiWrite(0x04); + sbi(_pinCS, _bitmaskCS); + return true; + } else { + return false; + } + } + return isSampleValid(); +} + +bool DmTouch::getMiddleXY(uint16_t &x, uint16_t &y) { + bool haveAllMeasurements = true; + uint16_t valuesX[MEASUREMENTS]; + uint16_t valuesY[MEASUREMENTS]; + uint8_t nbrOfMeasurements = 0; + + for (int i=0; i<MEASUREMENTS; i++) { + getAverageXY(valuesX[i], valuesY[i]); + nbrOfMeasurements++; + if(_touch_id != IC_8875) { + if (!isTouched()) { + haveAllMeasurements = false; + break; + } + } + } + if (haveAllMeasurements) { + x = calculateMiddleValue(valuesX, nbrOfMeasurements); + y = calculateMiddleValue(valuesY, nbrOfMeasurements); + } + + return haveAllMeasurements; +} + +void DmTouch::getAverageXY(uint16_t &x, uint16_t &y) { + uint32_t sumX = 0; + uint32_t sumY = 0; + uint16_t sampleX,sampleY; + readRawData(sampleX,sampleY); + + for (int i=0; i<_samplesPerMeasurement; i++) { + readRawData(sampleX,sampleY); + sumX += sampleX; + sumY += sampleY; + } + + x = (uint32_t)sumX/_samplesPerMeasurement; + y = (uint32_t)sumY/_samplesPerMeasurement; +} + +// Total number of samples = MEASUREMENTS * _samplesPerMeasurement +void DmTouch::setPrecison(uint8_t samplesPerMeasurement) { + _samplesPerMeasurement = samplesPerMeasurement; +} + +void DmTouch::setCalibrationMatrix(CalibrationMatrix calibrationMatrix) { + _calibrationMatrix = calibrationMatrix; +} + +void DmTouch::waitForTouch() { + while(!isTouched()) {} +} + +void DmTouch::waitForTouchRelease() { + while(isTouched()) {} +} + +uint16_t DmTouch::getDisplayCoordinateX(uint16_t x_touch, uint16_t y_touch) { + uint16_t Xd; + float temp; + temp = (_calibrationMatrix.a * x_touch + _calibrationMatrix.b * y_touch + _calibrationMatrix.c) / rescaleFactor(); + Xd = (uint16_t)(temp); + if (Xd > 60000) { + Xd = 0; + } + return Xd; +} + +uint16_t DmTouch::getDisplayCoordinateY(uint16_t x_touch, uint16_t y_touch) { + uint16_t Yd; + float temp; + temp = (_calibrationMatrix.d * x_touch + _calibrationMatrix.e * y_touch + _calibrationMatrix.f) / rescaleFactor(); + Yd = (uint16_t)(temp); + if (Yd > 60000) { + Yd = 0; + } + return Yd; +} + +uint16_t DmTouch::calculateMiddleValue(uint16_t values[], uint8_t count) { + uint16_t temp; + + for(uint8_t i=0; i<count-1; i++) { + for(uint8_t j=i+1; j<count; j++) { + if(values[j] < values[i]) { + temp = values[i]; + values[i] = values[j]; + values[j] = temp; + } + } + } + + if(count%2==0) { + return((values[count/2] + values[count/2 - 1]) / 2.0); + } else { + return values[count/2]; + } +} + +// (JML) Add a function to set screen orientation to match UniGraphics display feature +void DmTouch::setOrientation(char orient) { + _orient = orient%4; +} + + +/* Moved the default function to DmTouch rather than DmTouchCalibration as interim measure +*/ +CalibrationMatrix DmTouch::getDefaultCalibrationData(DmTouch::Display disp) { + CalibrationMatrix calibrationMatrix = {0}; + switch (disp) { + case DmTouch::DM_TFT28_103: + calibrationMatrix.a = 67548; // 63787; + calibrationMatrix.b = -625; // -138; + calibrationMatrix.c = -16854644;//-15921157; + calibrationMatrix.d = 362; // -244; + calibrationMatrix.e = 89504; // 89313; + calibrationMatrix.f = -14380636;//-10726623; + break; + + case DmTouch::DM_TFT24_104: + calibrationMatrix.a = -71855; + calibrationMatrix.b = 2147; + calibrationMatrix.c = 259719524; + calibrationMatrix.d = -1339; + calibrationMatrix.e = -91012; + calibrationMatrix.f = 354268832; + break; + + case DmTouch::DM_TFT28_105: + calibrationMatrix.a = 65521; + calibrationMatrix.b = -253; + calibrationMatrix.c = -11813673; + calibrationMatrix.d = -439; + calibrationMatrix.e = 89201; + calibrationMatrix.f = -10450920; + break; + + case DmTouch::DM_TFT35_107: + calibrationMatrix.a = 91302; // 85984; + calibrationMatrix.b = 817; // 451; + calibrationMatrix.c = -26296117;//-16494041; + calibrationMatrix.d = -1877; // 2308; + calibrationMatrix.e = 73762; // 65173; + calibrationMatrix.f = -26384255;//-19179080; + break; + case DmTouch::DM_TFT43_108: // or DM_TFT43_110 + calibrationMatrix.a = 541307; + calibrationMatrix.b = -4288; + calibrationMatrix.c = -36678732; + calibrationMatrix.d = 2730; + calibrationMatrix.e = 321714; + calibrationMatrix.f = -31439472; + break; + case DmTouch::DM_TFT50_111: // or DM_TFT50_112 + calibrationMatrix.a = 875894; + calibrationMatrix.b = 1655; + calibrationMatrix.c = -53695309; + calibrationMatrix.d = -993; + calibrationMatrix.e = 544421; + calibrationMatrix.f = -41496753; + break; + default: + break; + } + return calibrationMatrix; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DmTouch.h Wed Jan 20 07:21:30 2016 +0000 @@ -0,0 +1,104 @@ +/********************************************************************************************** + Copyright (c) 2014 DisplayModule. All rights reserved. + + Redistribution and use of this source code, part of this source code or any compiled binary + based on this source code is permitted as long as the above copyright notice and following + disclaimer is retained. + + DISCLAIMER: + THIS SOFTWARE IS SUPPLIED "AS IS" WITHOUT ANY WARRANTIES AND SUPPORT. DISPLAYMODULE ASSUMES + NO RESPONSIBILITY OR LIABILITY FOR THE USE OF THE SOFTWARE. + ********************************************************************************************/ + +#ifndef DM_TOUCH_h +#define DM_TOUCH_h + +#include "mbed.h" +//#include "dm_platform.h" // What is needed from dm_platform.h? + +#define sbi(reg, _bitmask) (*(reg) = 1) +#define cbi(reg, _bitmask) (*(reg) = 0) +#define delay(ms) wait_ms(ms) +#define pulse_high(reg, _bitmask) do { *(reg) = 1; *(reg) = 0; } while(0) +#define pulse_low(reg, _bitmask) do { *(reg) = 0; *(reg) = 1; } while(0) +#define slow_pulse_high(reg, _bitmask) do {\ + *(reg) = 1; \ + slow_pulse_delay(); \ + *(reg) = 0; \ + slow_pulse_delay(); \ +} while(0) +#define slow_pulse_low(reg, _bitmask) do {\ + *(reg) = 0; \ + slow_pulse_delay(); \ + *(reg) = 1; \ + slow_pulse_delay(); \ +} while(0) +#define slow_pulse_delay() + +typedef struct calibrationMatrix { + int a, b, c, d, e, f; +} CalibrationMatrix; + +class DmTouch +{ +public: + enum Display { + DM_TFT28_103 = 103, + DM_TFT24_104 = 104, + DM_TFT28_105 = 105, + DM_TFT35_107 = 107, + DM_TFT43_108 = 108, + DM_TFT50_111 = 111 + }; + + enum SpiMode { + Auto, + Software, + Hardware + }; + + enum TouchId{ + IC_8875 = 0x8875, + IC_2046 = 0x2046 + }; + + DmTouch(Display disp, PinName mosi, PinName miso, PinName clk, PinName cs, PinName irq); // Add cs and irq to input parameters + void init(); + void readTouchData(uint16_t& posX, uint16_t& posY, bool& touching); + bool isTouched(); + bool getMiddleXY(uint16_t &x, uint16_t &y); // Raw Touch Data, used for calibration + void setCalibrationMatrix(CalibrationMatrix calibrationMatrix); + void setPrecison(uint8_t samplesPerMeasurement); + void waitForTouch(); + void waitForTouchRelease(); + uint32_t rescaleFactor() { return 1000000; }; + Display getDisplay() { return _disp; }; + static CalibrationMatrix getDefaultCalibrationData(Display disp); // (JML) Added to this class because avoid DmTouchCalibration initially + void setOrientation(char orient); // Set screen orientation mode + +private: + void spiWrite(uint8_t data); + uint8_t spiRead(); + uint16_t readData12(uint8_t command); + void enableIrq(); + void readRawData(uint16_t &x, uint16_t &y); + void getAverageXY(uint16_t &x, uint16_t &y); + uint16_t getDisplayCoordinateX(uint16_t x_touch, uint16_t y_touch); + uint16_t getDisplayCoordinateY(uint16_t x_touch, uint16_t y_touch); + uint16_t calculateMiddleValue(uint16_t values[], uint8_t count); + bool isSampleValid(); + + Display _disp; + uint16_t _width, _height; + bool _hardwareSpi; + uint8_t _samplesPerMeasurement; + CalibrationMatrix _calibrationMatrix; + uint16_t _touch_id; + char _orient; // Adjust to changes in screen orientation + + PinName _cs, _clk, _mosi, _miso, _irq; + DigitalOut *_pinDC, *_pinCS, *_pinCLK, *_pinMOSI, *_led; + DigitalIn *_pinMISO, *_pinIrq; + SPI *_spi; +}; +#endif \ No newline at end of file
--- a/main.cpp Thu Jan 14 19:32:42 2016 +0000 +++ b/main.cpp Wed Jan 20 07:21:30 2016 +0000 @@ -2,6 +2,8 @@ #include "mbed.h" #include "string" #include "ILI932x.h" +#include "DmTouch.h" + #include "Arial12x12.h" #include "Arial24x23.h" @@ -30,19 +32,37 @@ p1 GND (L1) p40 Vin (L2) + p40 LED Backlight (L19) */ PinName dataBus[]= {p30, p29, p28, p27, p26, p25, p24, p23}; ILI932x myLCD(BUS_8, dataBus, p15, p17, p16, p14, p20, "myLCD", 240, 320); // Bus 8 bit, bus pin array, CS, RST, DC, WR, RD, name, xpixels, ypixels -char orient=3; +/* Additional connections to add touch response + + mbed pin display pin + -------- ----------- + p5 T_MOSI (R11) + p6 T_MISO (R13) + p7 T_CLK (R9) + p8 T_CS (R10) + p9 T_IRQ (R14) +*/ +DmTouch touch(DmTouch::DM_TFT24_104, p5, p6, p7, p8, p9); + +char orient=0; int x,y; +uint16_t tx, ty; +Timer t; int main() { + bool down, lastDown; + touch.init(); + t.start(); myLCD.set_orientation(orient); myLCD.set_font((unsigned char*) Arial24x23); - myLCD.background(Blue); // set background to red - myLCD.foreground(White); // set chars to black + myLCD.background(Blue); // set background to Blue + myLCD.foreground(White); // set chars to White myLCD.cls(); // clear the screen myLCD.locate(10,30); myLCD.printf("UniGraphics Demo\r\n"); @@ -110,6 +130,53 @@ } wait(3); + // Touch screen demo + myLCD.background(Blue); // set background to Blue + myLCD.foreground(White); // set chars to White + myLCD.cls(); // clear the screen + myLCD.locate(10,30); + myLCD.set_font((unsigned char*) Arial24x23); + myLCD.printf("DmTouch Demo\r\n"); + myLCD.set_font((unsigned char*) Arial12x12); + myLCD.locate(10,70); + myLCD.printf("Coming soon...\r\nTouch screen and coordinates will display\r\n"); + myLCD.printf("Moves to next portion of demo after 30 seconds\r\n"); + wait(2); + myLCD.background(Black); // set background to Black + myLCD.foreground(White); // set chars to White + myLCD.cls(); // clear the screen + + touch.setOrientation(orient); + down = false; + lastDown = false; + tx = (uint16_t)0; + ty = (uint16_t)0; + myLCD.locate(20,20); + myLCD.printf("x:"); + myLCD.locate(100, 20); + myLCD.printf("y:"); + + t.reset(); + while (t.read()<30) { + touch.readTouchData(tx, ty, down); + if (down) { + myLCD.locate(40, 20); + myLCD.printf("%5i", tx); + myLCD.locate(120, 20); + myLCD.printf("%5i", ty); + myLCD.fillcircle(tx, ty, 2, Red); + } else if (lastDown) { + // no longer pressed, clean text + myLCD.locate(40, 20); + myLCD.printf(" ", tx); + myLCD.locate(120, 20); + myLCD.printf(" ", ty); + } + wait(0.040); + lastDown = down; + } + + // scroll test, only for TFT myLCD.cls(); myLCD.set_font((unsigned char*) Arial24x23);