A library for ADS7843 touch-screens which is interrupt driven, allowing you to register callback handlers for touchStart, touchMove and touchEnd events.
Dependents: TouchScreenCalibrate TouchScreenGUIDemo
TouchScreen.cpp@2:e5ea47fb1ede, 2016-05-08 (annotated)
- Committer:
- duncanFrance
- Date:
- Sun May 08 14:43:16 2016 +0000
- Revision:
- 2:e5ea47fb1ede
- Parent:
- 0:3f0160100cc9
- Child:
- 3:8b5fcf3857ac
Formatting
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
duncanFrance | 0:3f0160100cc9 | 1 | #include "TouchScreen.h" |
duncanFrance | 0:3f0160100cc9 | 2 | |
duncanFrance | 0:3f0160100cc9 | 3 | TouchScreen::TouchScreen(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq) : |
duncanFrance | 0:3f0160100cc9 | 4 | _spi(mosi, miso, sclk), _cs(cs), _intPin(irq), _int(irq), _precision(TOUCHSCREEN_PRECISION_12) |
duncanFrance | 0:3f0160100cc9 | 5 | { |
duncanFrance | 0:3f0160100cc9 | 6 | setLCDGeometry(320,240,TOUCHSCREEN_ORIENTATION_LANDSCAPE); |
duncanFrance | 0:3f0160100cc9 | 7 | setCalibration(540, 3700, 340, 3656); |
duncanFrance | 0:3f0160100cc9 | 8 | |
duncanFrance | 0:3f0160100cc9 | 9 | _movementThresholdSquared = TOUCHSCREEN_MOVEMENT_THRESHOLD * TOUCHSCREEN_MOVEMENT_THRESHOLD; |
duncanFrance | 0:3f0160100cc9 | 10 | _cs = 1; |
duncanFrance | 0:3f0160100cc9 | 11 | _spi.frequency(TOUCHSCREEN_SPI_FREQUENCY) ; |
duncanFrance | 0:3f0160100cc9 | 12 | _spi.format(8,0) ; |
duncanFrance | 0:3f0160100cc9 | 13 | _state = TOUCHSCREEN_STATE_IDLE; |
duncanFrance | 0:3f0160100cc9 | 14 | _int.fall(this, &TouchScreen::_fallInterruptHandler); |
duncanFrance | 0:3f0160100cc9 | 15 | _handlerThread = new Thread(&TouchScreen::_monitor, this); |
duncanFrance | 0:3f0160100cc9 | 16 | } |
duncanFrance | 0:3f0160100cc9 | 17 | |
duncanFrance | 0:3f0160100cc9 | 18 | void TouchScreen::setLCDGeometry(int width, int height, uint8_t orientation) { |
duncanFrance | 0:3f0160100cc9 | 19 | _lcdWidth = width; |
duncanFrance | 0:3f0160100cc9 | 20 | _lcdHeight = height; |
duncanFrance | 0:3f0160100cc9 | 21 | _lcdOrientation = orientation; |
duncanFrance | 0:3f0160100cc9 | 22 | } |
duncanFrance | 0:3f0160100cc9 | 23 | |
duncanFrance | 0:3f0160100cc9 | 24 | void TouchScreen::setCalibration(int xmin, int xmax, int ymin, int ymax) { |
duncanFrance | 0:3f0160100cc9 | 25 | _xmin = xmin; _xmax = xmax; |
duncanFrance | 0:3f0160100cc9 | 26 | _ymin = ymin; _ymax = ymax; |
duncanFrance | 0:3f0160100cc9 | 27 | } |
duncanFrance | 0:3f0160100cc9 | 28 | |
duncanFrance | 0:3f0160100cc9 | 29 | void TouchScreen::setTouchStartHandler(TouchCallbackHandler handler) |
duncanFrance | 0:3f0160100cc9 | 30 | { |
duncanFrance | 0:3f0160100cc9 | 31 | _touchStartHandler = handler; |
duncanFrance | 0:3f0160100cc9 | 32 | } |
duncanFrance | 0:3f0160100cc9 | 33 | |
duncanFrance | 0:3f0160100cc9 | 34 | void TouchScreen::setTouchMoveHandler(TouchCallbackHandler handler) |
duncanFrance | 0:3f0160100cc9 | 35 | { |
duncanFrance | 0:3f0160100cc9 | 36 | _touchMoveHandler = handler; |
duncanFrance | 0:3f0160100cc9 | 37 | } |
duncanFrance | 0:3f0160100cc9 | 38 | |
duncanFrance | 0:3f0160100cc9 | 39 | void TouchScreen::setTouchEndHandler(TouchCallbackHandler handler) |
duncanFrance | 0:3f0160100cc9 | 40 | { |
duncanFrance | 0:3f0160100cc9 | 41 | _touchEndHandler = handler; |
duncanFrance | 0:3f0160100cc9 | 42 | } |
duncanFrance | 0:3f0160100cc9 | 43 | |
duncanFrance | 0:3f0160100cc9 | 44 | void TouchScreen::setMovementTheshold(int thresholdInPixels) { |
duncanFrance | 0:3f0160100cc9 | 45 | _movementThresholdSquared = thresholdInPixels * thresholdInPixels; |
duncanFrance | 0:3f0160100cc9 | 46 | } |
duncanFrance | 0:3f0160100cc9 | 47 | |
duncanFrance | 0:3f0160100cc9 | 48 | TouchPosition TouchScreen::_getPosition() |
duncanFrance | 0:3f0160100cc9 | 49 | { |
duncanFrance | 0:3f0160100cc9 | 50 | int xf, yf, xt, yt; |
duncanFrance | 0:3f0160100cc9 | 51 | int xmin = 65535, ymin = 65535; |
duncanFrance | 0:3f0160100cc9 | 52 | int xmax = 0, ymax = 0; |
duncanFrance | 0:3f0160100cc9 | 53 | |
duncanFrance | 0:3f0160100cc9 | 54 | unsigned int samples; |
duncanFrance | 0:3f0160100cc9 | 55 | |
duncanFrance | 0:3f0160100cc9 | 56 | TouchPosition position; |
duncanFrance | 0:3f0160100cc9 | 57 | |
duncanFrance | 0:3f0160100cc9 | 58 | xf=0; |
duncanFrance | 0:3f0160100cc9 | 59 | yf=0; |
duncanFrance | 0:3f0160100cc9 | 60 | samples=0; |
duncanFrance | 0:3f0160100cc9 | 61 | |
duncanFrance | 0:3f0160100cc9 | 62 | for(int i=0; i<32; i++) { |
duncanFrance | 0:3f0160100cc9 | 63 | xt = _read(TOUCHSCREEN_CMD_GETX + _precision); |
duncanFrance | 0:3f0160100cc9 | 64 | yt = _read(TOUCHSCREEN_CMD_GETY + _precision); |
duncanFrance | 0:3f0160100cc9 | 65 | if(xt>0 && yt>0) { |
duncanFrance | 0:3f0160100cc9 | 66 | xf+=xt; |
duncanFrance | 0:3f0160100cc9 | 67 | yf+=yt; |
duncanFrance | 0:3f0160100cc9 | 68 | samples++; |
duncanFrance | 0:3f0160100cc9 | 69 | if(xt < xmin) xmin = xt; |
duncanFrance | 0:3f0160100cc9 | 70 | if(xmax < xt) xmax = xt; |
duncanFrance | 0:3f0160100cc9 | 71 | if(yt < ymin) ymin = yt; |
duncanFrance | 0:3f0160100cc9 | 72 | if(ymax < yt) ymax = yt; |
duncanFrance | 0:3f0160100cc9 | 73 | } |
duncanFrance | 0:3f0160100cc9 | 74 | } |
duncanFrance | 0:3f0160100cc9 | 75 | // remove the outlier samples |
duncanFrance | 0:3f0160100cc9 | 76 | xf = xf - xmin - xmax; |
duncanFrance | 0:3f0160100cc9 | 77 | yf = yf - ymin - ymax; |
duncanFrance | 0:3f0160100cc9 | 78 | |
duncanFrance | 0:3f0160100cc9 | 79 | |
duncanFrance | 0:3f0160100cc9 | 80 | if(samples > 2) { |
duncanFrance | 0:3f0160100cc9 | 81 | samples -=2; |
duncanFrance | 0:3f0160100cc9 | 82 | xf = xf / samples; |
duncanFrance | 0:3f0160100cc9 | 83 | yf = yf / samples; |
duncanFrance | 0:3f0160100cc9 | 84 | |
duncanFrance | 0:3f0160100cc9 | 85 | // Now adjust and scale to fit screen |
duncanFrance | 0:3f0160100cc9 | 86 | |
duncanFrance | 0:3f0160100cc9 | 87 | if(_lcdOrientation & TOUCHSCREEN_ORIENTATION_PORTRAIT) { |
duncanFrance | 0:3f0160100cc9 | 88 | // swap x and y |
duncanFrance | 0:3f0160100cc9 | 89 | xt = xf; |
duncanFrance | 0:3f0160100cc9 | 90 | xf = yf; |
duncanFrance | 0:3f0160100cc9 | 91 | yf = xt; |
duncanFrance | 0:3f0160100cc9 | 92 | } |
duncanFrance | 0:3f0160100cc9 | 93 | |
duncanFrance | 0:3f0160100cc9 | 94 | position.x = xf; |
duncanFrance | 0:3f0160100cc9 | 95 | position.y = yf; |
duncanFrance | 0:3f0160100cc9 | 96 | position.screenX = ((xf - _xmin) * _lcdWidth) / (_xmax - _xmin); |
duncanFrance | 0:3f0160100cc9 | 97 | position.screenY = ((yf - _ymin) * _lcdHeight) / (_ymax - _ymin); |
duncanFrance | 0:3f0160100cc9 | 98 | |
duncanFrance | 0:3f0160100cc9 | 99 | if(_lcdOrientation & TOUCHSCREEN_ORIENTATION_ROTATED) { |
duncanFrance | 0:3f0160100cc9 | 100 | position.screenX = _lcdWidth - position.screenX; |
duncanFrance | 0:3f0160100cc9 | 101 | position.screenY = _lcdHeight - position.screenY; |
duncanFrance | 0:3f0160100cc9 | 102 | } |
duncanFrance | 0:3f0160100cc9 | 103 | |
duncanFrance | 0:3f0160100cc9 | 104 | position.valid = true; |
duncanFrance | 0:3f0160100cc9 | 105 | |
duncanFrance | 0:3f0160100cc9 | 106 | } else { |
duncanFrance | 0:3f0160100cc9 | 107 | position.valid = false; |
duncanFrance | 0:3f0160100cc9 | 108 | } |
duncanFrance | 0:3f0160100cc9 | 109 | |
duncanFrance | 0:3f0160100cc9 | 110 | return position; |
duncanFrance | 0:3f0160100cc9 | 111 | } |
duncanFrance | 0:3f0160100cc9 | 112 | |
duncanFrance | 0:3f0160100cc9 | 113 | void TouchScreen::_handleTouchStart() |
duncanFrance | 0:3f0160100cc9 | 114 | { |
duncanFrance | 0:3f0160100cc9 | 115 | _lastPosition.valid = false; |
duncanFrance | 0:3f0160100cc9 | 116 | _currentPosition = _getPosition(); |
duncanFrance | 0:3f0160100cc9 | 117 | // Raise an event if we got a valid position |
duncanFrance | 0:3f0160100cc9 | 118 | if(_currentPosition.valid && _touchStartHandler) { |
duncanFrance | 0:3f0160100cc9 | 119 | _touchStartHandler(_currentPosition); |
duncanFrance | 0:3f0160100cc9 | 120 | } |
duncanFrance | 0:3f0160100cc9 | 121 | } |
duncanFrance | 0:3f0160100cc9 | 122 | |
duncanFrance | 0:3f0160100cc9 | 123 | void TouchScreen::_handleTouchEnd() |
duncanFrance | 0:3f0160100cc9 | 124 | { |
duncanFrance | 0:3f0160100cc9 | 125 | // Raise an event if we got a valid position |
duncanFrance | 0:3f0160100cc9 | 126 | if(_currentPosition.valid && _touchEndHandler) { |
duncanFrance | 0:3f0160100cc9 | 127 | _touchEndHandler(_currentPosition); |
duncanFrance | 0:3f0160100cc9 | 128 | } |
duncanFrance | 0:3f0160100cc9 | 129 | } |
duncanFrance | 0:3f0160100cc9 | 130 | |
duncanFrance | 0:3f0160100cc9 | 131 | void TouchScreen::_handleTouchMoved() |
duncanFrance | 0:3f0160100cc9 | 132 | { |
duncanFrance | 0:3f0160100cc9 | 133 | // Update the position |
duncanFrance | 0:3f0160100cc9 | 134 | TouchPosition newPosition = _getPosition(); |
duncanFrance | 0:3f0160100cc9 | 135 | if(!_lastPosition.valid) { |
duncanFrance | 0:3f0160100cc9 | 136 | _lastPosition = newPosition; |
duncanFrance | 0:3f0160100cc9 | 137 | } |
duncanFrance | 0:3f0160100cc9 | 138 | |
duncanFrance | 0:3f0160100cc9 | 139 | if(_touchMoveHandler && _moved(newPosition, _lastPosition)) { |
duncanFrance | 0:3f0160100cc9 | 140 | _lastPosition = _currentPosition; |
duncanFrance | 0:3f0160100cc9 | 141 | _currentPosition = newPosition; |
duncanFrance | 0:3f0160100cc9 | 142 | _touchMoveHandler(_currentPosition); |
duncanFrance | 0:3f0160100cc9 | 143 | } |
duncanFrance | 0:3f0160100cc9 | 144 | } |
duncanFrance | 0:3f0160100cc9 | 145 | |
duncanFrance | 0:3f0160100cc9 | 146 | bool TouchScreen::_moved(TouchPosition a, TouchPosition b) |
duncanFrance | 0:3f0160100cc9 | 147 | { |
duncanFrance | 0:3f0160100cc9 | 148 | bool moved = false; |
duncanFrance | 0:3f0160100cc9 | 149 | |
duncanFrance | 0:3f0160100cc9 | 150 | if(a.valid && b.valid) { |
duncanFrance | 0:3f0160100cc9 | 151 | int dx = a.screenX - b.screenX; |
duncanFrance | 0:3f0160100cc9 | 152 | int dy = a.screenY - b.screenY; |
duncanFrance | 0:3f0160100cc9 | 153 | if((dx*dx + dy*dy) > _movementThresholdSquared) { |
duncanFrance | 0:3f0160100cc9 | 154 | moved = true; |
duncanFrance | 0:3f0160100cc9 | 155 | } |
duncanFrance | 0:3f0160100cc9 | 156 | } |
duncanFrance | 0:3f0160100cc9 | 157 | |
duncanFrance | 0:3f0160100cc9 | 158 | return moved; |
duncanFrance | 0:3f0160100cc9 | 159 | } |
duncanFrance | 0:3f0160100cc9 | 160 | |
duncanFrance | 0:3f0160100cc9 | 161 | void TouchScreen::_fallInterruptHandler() |
duncanFrance | 0:3f0160100cc9 | 162 | { |
duncanFrance | 0:3f0160100cc9 | 163 | __disable_irq(); // is this needed in an ISR? |
duncanFrance | 0:3f0160100cc9 | 164 | |
duncanFrance | 0:3f0160100cc9 | 165 | _int.fall(0); |
duncanFrance | 0:3f0160100cc9 | 166 | _int.rise(this, &TouchScreen::_riseInterruptHandler); |
duncanFrance | 0:3f0160100cc9 | 167 | _ticker.attach_us(this, &TouchScreen::_tickerInterruptHandler, TOUCHSCREEN_DEBOUNCE_MICROS); |
duncanFrance | 0:3f0160100cc9 | 168 | _state = TOUCHSCREEN_STATE_DEBOUNCE; |
duncanFrance | 0:3f0160100cc9 | 169 | |
duncanFrance | 0:3f0160100cc9 | 170 | __enable_irq(); |
duncanFrance | 0:3f0160100cc9 | 171 | |
duncanFrance | 0:3f0160100cc9 | 172 | } |
duncanFrance | 0:3f0160100cc9 | 173 | |
duncanFrance | 0:3f0160100cc9 | 174 | void TouchScreen::_riseInterruptHandler() |
duncanFrance | 0:3f0160100cc9 | 175 | { |
duncanFrance | 0:3f0160100cc9 | 176 | __disable_irq(); |
duncanFrance | 0:3f0160100cc9 | 177 | |
duncanFrance | 0:3f0160100cc9 | 178 | _int.rise(0); |
duncanFrance | 0:3f0160100cc9 | 179 | _int.fall(this, &TouchScreen::_fallInterruptHandler); |
duncanFrance | 0:3f0160100cc9 | 180 | _ticker.attach_us(this, &TouchScreen::_tickerInterruptHandler, TOUCHSCREEN_DEBOUNCE_MICROS); |
duncanFrance | 0:3f0160100cc9 | 181 | _state = TOUCHSCREEN_STATE_DEBOUNCE; |
duncanFrance | 0:3f0160100cc9 | 182 | |
duncanFrance | 0:3f0160100cc9 | 183 | __enable_irq(); |
duncanFrance | 0:3f0160100cc9 | 184 | } |
duncanFrance | 0:3f0160100cc9 | 185 | |
duncanFrance | 0:3f0160100cc9 | 186 | void TouchScreen::_tickerInterruptHandler() |
duncanFrance | 0:3f0160100cc9 | 187 | { |
duncanFrance | 0:3f0160100cc9 | 188 | __disable_irq(); |
duncanFrance | 0:3f0160100cc9 | 189 | switch(_state) { |
duncanFrance | 0:3f0160100cc9 | 190 | /** |
duncanFrance | 0:3f0160100cc9 | 191 | * This state should not be reachable in this ISR |
duncanFrance | 0:3f0160100cc9 | 192 | **/ |
duncanFrance | 0:3f0160100cc9 | 193 | case TOUCHSCREEN_STATE_IDLE: |
duncanFrance | 0:3f0160100cc9 | 194 | // fallthrough to set the pin interrupt handler |
duncanFrance | 0:3f0160100cc9 | 195 | |
duncanFrance | 0:3f0160100cc9 | 196 | /** |
duncanFrance | 0:3f0160100cc9 | 197 | * The debounce timer timed-out, so we have a valid level. |
duncanFrance | 0:3f0160100cc9 | 198 | **/ |
duncanFrance | 0:3f0160100cc9 | 199 | case TOUCHSCREEN_STATE_DEBOUNCE: |
duncanFrance | 0:3f0160100cc9 | 200 | |
duncanFrance | 0:3f0160100cc9 | 201 | _ticker.detach(); |
duncanFrance | 0:3f0160100cc9 | 202 | |
duncanFrance | 0:3f0160100cc9 | 203 | if(_intPin == 1) { |
duncanFrance | 0:3f0160100cc9 | 204 | _int.rise(0); |
duncanFrance | 0:3f0160100cc9 | 205 | _int.fall(this, &TouchScreen::_fallInterruptHandler); |
duncanFrance | 0:3f0160100cc9 | 206 | _state = TOUCHSCREEN_STATE_IDLE; |
duncanFrance | 0:3f0160100cc9 | 207 | |
duncanFrance | 0:3f0160100cc9 | 208 | if(_handlerThread != 0) { |
duncanFrance | 0:3f0160100cc9 | 209 | _handlerThread->signal_set(TOUCHSCREEN_SIGNAL_END); |
duncanFrance | 0:3f0160100cc9 | 210 | } |
duncanFrance | 0:3f0160100cc9 | 211 | } else { |
duncanFrance | 0:3f0160100cc9 | 212 | _int.fall(0); |
duncanFrance | 0:3f0160100cc9 | 213 | _int.rise(this, &TouchScreen::_riseInterruptHandler); |
duncanFrance | 0:3f0160100cc9 | 214 | _state = TOUCHSCREEN_STATE_POLL; |
duncanFrance | 0:3f0160100cc9 | 215 | _ticker.attach_us(this, &TouchScreen::_tickerInterruptHandler, TOUCHSCREEN_POLL_MICROS); |
duncanFrance | 0:3f0160100cc9 | 216 | |
duncanFrance | 0:3f0160100cc9 | 217 | if(_handlerThread != 0) { |
duncanFrance | 0:3f0160100cc9 | 218 | _handlerThread->signal_set(TOUCHSCREEN_SIGNAL_START); |
duncanFrance | 0:3f0160100cc9 | 219 | } |
duncanFrance | 0:3f0160100cc9 | 220 | } |
duncanFrance | 0:3f0160100cc9 | 221 | |
duncanFrance | 0:3f0160100cc9 | 222 | break; |
duncanFrance | 0:3f0160100cc9 | 223 | |
duncanFrance | 0:3f0160100cc9 | 224 | case TOUCHSCREEN_STATE_POLL: |
duncanFrance | 0:3f0160100cc9 | 225 | if(_handlerThread != 0) { |
duncanFrance | 0:3f0160100cc9 | 226 | _handlerThread->signal_set(TOUCHSCREEN_SIGNAL_POLL); |
duncanFrance | 0:3f0160100cc9 | 227 | } |
duncanFrance | 0:3f0160100cc9 | 228 | |
duncanFrance | 0:3f0160100cc9 | 229 | } |
duncanFrance | 0:3f0160100cc9 | 230 | __enable_irq(); |
duncanFrance | 0:3f0160100cc9 | 231 | } |
duncanFrance | 0:3f0160100cc9 | 232 | |
duncanFrance | 0:3f0160100cc9 | 233 | unsigned int TouchScreen::_read(uint8_t cmd) |
duncanFrance | 0:3f0160100cc9 | 234 | { |
duncanFrance | 0:3f0160100cc9 | 235 | unsigned int tmp; |
duncanFrance | 0:3f0160100cc9 | 236 | |
duncanFrance | 2:e5ea47fb1ede | 237 | __disable_irq(); |
duncanFrance | 0:3f0160100cc9 | 238 | _cs = 0; |
duncanFrance | 0:3f0160100cc9 | 239 | wait_us(1); |
duncanFrance | 0:3f0160100cc9 | 240 | _spi.write(cmd); |
duncanFrance | 0:3f0160100cc9 | 241 | wait_us(1); |
duncanFrance | 0:3f0160100cc9 | 242 | // First clock start conversion, so we only get 7-bits on this read |
duncanFrance | 0:3f0160100cc9 | 243 | tmp = _spi.write(0x00) << 5; |
duncanFrance | 0:3f0160100cc9 | 244 | // Remaining 5 bits on this read |
duncanFrance | 0:3f0160100cc9 | 245 | tmp |= _spi.write(0x00) >> 3; |
duncanFrance | 0:3f0160100cc9 | 246 | _cs = 1; |
duncanFrance | 0:3f0160100cc9 | 247 | |
duncanFrance | 0:3f0160100cc9 | 248 | if (_precision == TOUCHSCREEN_PRECISION_8) { |
duncanFrance | 0:3f0160100cc9 | 249 | tmp = tmp & 0x0ff0; // mask off lowest 4 bits since they are meaningless |
duncanFrance | 0:3f0160100cc9 | 250 | } |
duncanFrance | 0:3f0160100cc9 | 251 | tmp &= 0xfff; |
duncanFrance | 2:e5ea47fb1ede | 252 | |
duncanFrance | 2:e5ea47fb1ede | 253 | __enable_irq(); |
duncanFrance | 0:3f0160100cc9 | 254 | return tmp; |
duncanFrance | 0:3f0160100cc9 | 255 | } |