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

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