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
- Committer:
- duncanFrance
- Date:
- 2016-05-17
- Revision:
- 3:8b5fcf3857ac
- Parent:
- 2:e5ea47fb1ede
File content as of revision 3:8b5fcf3857ac:
#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.attach(handler); } void TouchScreen::setTouchMoveHandler(TouchCallbackHandler handler) { _touchMoveHandler.attach(handler); } void TouchScreen::setTouchEndHandler(TouchCallbackHandler handler) { _touchEndHandler.attach(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.call(_currentPosition); } } void TouchScreen::_handleTouchEnd() { // Raise an event if we got a valid position if(_currentPosition.valid && _touchEndHandler) { _touchEndHandler.call(_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.call(_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; __disable_irq(); _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; __enable_irq(); return tmp; }