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
Diff: TouchScreen.cpp
- Revision:
- 0:3f0160100cc9
- Child:
- 2:e5ea47fb1ede
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/TouchScreen.cpp Sat Mar 19 15:39:36 2016 +0000 @@ -0,0 +1,252 @@ +#include "TouchScreen.h" + +TouchScreen::TouchScreen(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName irq) : + _spi(mosi, miso, sclk), _cs(cs), _intPin(irq), _int(irq), _precision(TOUCHSCREEN_PRECISION_12) +{ + setLCDGeometry(320,240,TOUCHSCREEN_ORIENTATION_LANDSCAPE); + setCalibration(540, 3700, 340, 3656); + + _movementThresholdSquared = TOUCHSCREEN_MOVEMENT_THRESHOLD * TOUCHSCREEN_MOVEMENT_THRESHOLD; + _cs = 1; + _spi.frequency(TOUCHSCREEN_SPI_FREQUENCY) ; + _spi.format(8,0) ; + _state = TOUCHSCREEN_STATE_IDLE; + _int.fall(this, &TouchScreen::_fallInterruptHandler); + _handlerThread = new Thread(&TouchScreen::_monitor, this); +} + +void TouchScreen::setLCDGeometry(int width, int height, uint8_t orientation) { + _lcdWidth = width; + _lcdHeight = height; + _lcdOrientation = orientation; +} + +void TouchScreen::setCalibration(int xmin, int xmax, int ymin, int ymax) { + _xmin = xmin; _xmax = xmax; + _ymin = ymin; _ymax = ymax; +} + +void TouchScreen::setTouchStartHandler(TouchCallbackHandler handler) +{ + _touchStartHandler = handler; +} + +void TouchScreen::setTouchMoveHandler(TouchCallbackHandler handler) +{ + _touchMoveHandler = handler; +} + +void TouchScreen::setTouchEndHandler(TouchCallbackHandler handler) +{ + _touchEndHandler = handler; +} + +void TouchScreen::setMovementTheshold(int thresholdInPixels) { + _movementThresholdSquared = thresholdInPixels * thresholdInPixels; +} + +TouchPosition TouchScreen::_getPosition() +{ + int xf, yf, xt, yt; + int xmin = 65535, ymin = 65535; + int xmax = 0, ymax = 0; + + unsigned int samples; + + TouchPosition position; + + xf=0; + yf=0; + samples=0; + + for(int i=0; i<32; i++) { + xt = _read(TOUCHSCREEN_CMD_GETX + _precision); + yt = _read(TOUCHSCREEN_CMD_GETY + _precision); + if(xt>0 && yt>0) { + xf+=xt; + yf+=yt; + samples++; + if(xt < xmin) xmin = xt; + if(xmax < xt) xmax = xt; + if(yt < ymin) ymin = yt; + if(ymax < yt) ymax = yt; + } + } + // remove the outlier samples + xf = xf - xmin - xmax; + yf = yf - ymin - ymax; + + + if(samples > 2) { + samples -=2; + xf = xf / samples; + yf = yf / samples; + + // Now adjust and scale to fit screen + + if(_lcdOrientation & TOUCHSCREEN_ORIENTATION_PORTRAIT) { + // swap x and y + xt = xf; + xf = yf; + yf = xt; + } + + position.x = xf; + position.y = yf; + position.screenX = ((xf - _xmin) * _lcdWidth) / (_xmax - _xmin); + position.screenY = ((yf - _ymin) * _lcdHeight) / (_ymax - _ymin); + + if(_lcdOrientation & TOUCHSCREEN_ORIENTATION_ROTATED) { + position.screenX = _lcdWidth - position.screenX; + position.screenY = _lcdHeight - position.screenY; + } + + position.valid = true; + + } else { + position.valid = false; + } + + return position; +} + +void TouchScreen::_handleTouchStart() +{ + _lastPosition.valid = false; + _currentPosition = _getPosition(); + // Raise an event if we got a valid position + if(_currentPosition.valid && _touchStartHandler) { + _touchStartHandler(_currentPosition); + } +} + +void TouchScreen::_handleTouchEnd() +{ + // Raise an event if we got a valid position + if(_currentPosition.valid && _touchEndHandler) { + _touchEndHandler(_currentPosition); + } +} + +void TouchScreen::_handleTouchMoved() +{ + // Update the position + TouchPosition newPosition = _getPosition(); + if(!_lastPosition.valid) { + _lastPosition = newPosition; + } + + if(_touchMoveHandler && _moved(newPosition, _lastPosition)) { + _lastPosition = _currentPosition; + _currentPosition = newPosition; + _touchMoveHandler(_currentPosition); + } +} + +bool TouchScreen::_moved(TouchPosition a, TouchPosition b) +{ + bool moved = false; + + if(a.valid && b.valid) { + int dx = a.screenX - b.screenX; + int dy = a.screenY - b.screenY; + if((dx*dx + dy*dy) > _movementThresholdSquared) { + moved = true; + } + } + + return moved; +} + +void TouchScreen::_fallInterruptHandler() +{ + __disable_irq(); // is this needed in an ISR? + + _int.fall(0); + _int.rise(this, &TouchScreen::_riseInterruptHandler); + _ticker.attach_us(this, &TouchScreen::_tickerInterruptHandler, TOUCHSCREEN_DEBOUNCE_MICROS); + _state = TOUCHSCREEN_STATE_DEBOUNCE; + + __enable_irq(); + +} + +void TouchScreen::_riseInterruptHandler() +{ + __disable_irq(); + + _int.rise(0); + _int.fall(this, &TouchScreen::_fallInterruptHandler); + _ticker.attach_us(this, &TouchScreen::_tickerInterruptHandler, TOUCHSCREEN_DEBOUNCE_MICROS); + _state = TOUCHSCREEN_STATE_DEBOUNCE; + + __enable_irq(); +} + +void TouchScreen::_tickerInterruptHandler() +{ + __disable_irq(); + switch(_state) { + /** + * This state should not be reachable in this ISR + **/ + case TOUCHSCREEN_STATE_IDLE: + // fallthrough to set the pin interrupt handler + + /** + * The debounce timer timed-out, so we have a valid level. + **/ + case TOUCHSCREEN_STATE_DEBOUNCE: + + _ticker.detach(); + + if(_intPin == 1) { + _int.rise(0); + _int.fall(this, &TouchScreen::_fallInterruptHandler); + _state = TOUCHSCREEN_STATE_IDLE; + + if(_handlerThread != 0) { + _handlerThread->signal_set(TOUCHSCREEN_SIGNAL_END); + } + } else { + _int.fall(0); + _int.rise(this, &TouchScreen::_riseInterruptHandler); + _state = TOUCHSCREEN_STATE_POLL; + _ticker.attach_us(this, &TouchScreen::_tickerInterruptHandler, TOUCHSCREEN_POLL_MICROS); + + if(_handlerThread != 0) { + _handlerThread->signal_set(TOUCHSCREEN_SIGNAL_START); + } + } + + break; + + case TOUCHSCREEN_STATE_POLL: + if(_handlerThread != 0) { + _handlerThread->signal_set(TOUCHSCREEN_SIGNAL_POLL); + } + + } + __enable_irq(); +} + +unsigned int TouchScreen::_read(uint8_t cmd) +{ + unsigned int tmp; + + _cs = 0; + wait_us(1); + _spi.write(cmd); + wait_us(1); + // First clock start conversion, so we only get 7-bits on this read + tmp = _spi.write(0x00) << 5; + // Remaining 5 bits on this read + tmp |= _spi.write(0x00) >> 3; + _cs = 1; + + if (_precision == TOUCHSCREEN_PRECISION_8) { + tmp = tmp & 0x0ff0; // mask off lowest 4 bits since they are meaningless + } + tmp &= 0xfff; + return tmp; +} \ No newline at end of file