Touch screen calibration sketch (work in progress)
This commit is contained in:
parent
43473ad407
commit
7db46ae421
|
|
@ -14,6 +14,33 @@
|
|||
// Sizes!
|
||||
enum RA8875sizes { RA8875_480x272, RA8875_800x480 };
|
||||
|
||||
// Touch screen cal structs
|
||||
typedef struct Point
|
||||
{
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} tsPoint_t;
|
||||
|
||||
typedef struct Matrix
|
||||
{
|
||||
int32_t An,
|
||||
Bn,
|
||||
Cn,
|
||||
Dn,
|
||||
En,
|
||||
Fn,
|
||||
Divider ;
|
||||
} tsMatrix_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t xraw; // Touch screen x
|
||||
uint32_t yraw; // Touch screen Y
|
||||
uint16_t xlcd; // LCD co-ordinate X
|
||||
uint16_t ylcd; // LCD co-ordinate Y
|
||||
bool valid; // Whether this is a valid reading or not
|
||||
} tsTouchData_t;
|
||||
|
||||
class Adafruit_RA8875 : public Adafruit_GFX {
|
||||
public:
|
||||
Adafruit_RA8875(uint8_t cs, uint8_t rst);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,343 @@
|
|||
#include <SPI.h>
|
||||
#include "Adafruit_GFX.h"
|
||||
#include "Adafruit_RA8875.h"
|
||||
|
||||
#define RA8875_INT 3
|
||||
#define RA8875_CS 10
|
||||
#define RA8875_RESET 9
|
||||
|
||||
Adafruit_RA8875 tft = Adafruit_RA8875(RA8875_CS, RA8875_RESET);
|
||||
tsPoint_t _tsLCDPoints[3];
|
||||
tsPoint_t _tsTSPoints[3];
|
||||
tsMatrix_t _tsMatrix;
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Calculates the difference between the touch screen and the
|
||||
actual screen co-ordinates, taking into account misalignment
|
||||
and any physical offset of the touch screen.
|
||||
|
||||
@note This is based on the public domain touch screen calibration code
|
||||
written by Carlos E. Vidales (copyright (c) 2001).
|
||||
|
||||
For more information, see the following app notes:
|
||||
|
||||
- AN2173 - Touch Screen Control and Calibration
|
||||
Svyatoslav Paliy, Cypress Microsystems
|
||||
- Calibration in touch-screen systems
|
||||
Wendy Fang and Tony Chang,
|
||||
Analog Applications Journal, 3Q 2007 (Texas Instruments)
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int setCalibrationMatrix( tsPoint_t * displayPtr, tsPoint_t * screenPtr, tsMatrix_t * matrixPtr)
|
||||
{
|
||||
int retValue = 0;
|
||||
|
||||
matrixPtr->Divider = ((screenPtr[0].x - screenPtr[2].x) * (screenPtr[1].y - screenPtr[2].y)) -
|
||||
((screenPtr[1].x - screenPtr[2].x) * (screenPtr[0].y - screenPtr[2].y)) ;
|
||||
|
||||
if( matrixPtr->Divider == 0 )
|
||||
{
|
||||
retValue = -1 ;
|
||||
}
|
||||
else
|
||||
{
|
||||
matrixPtr->An = ((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].y - screenPtr[2].y)) -
|
||||
((displayPtr[1].x - displayPtr[2].x) * (screenPtr[0].y - screenPtr[2].y)) ;
|
||||
|
||||
matrixPtr->Bn = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].x - displayPtr[2].x)) -
|
||||
((displayPtr[0].x - displayPtr[2].x) * (screenPtr[1].x - screenPtr[2].x)) ;
|
||||
|
||||
matrixPtr->Cn = (screenPtr[2].x * displayPtr[1].x - screenPtr[1].x * displayPtr[2].x) * screenPtr[0].y +
|
||||
(screenPtr[0].x * displayPtr[2].x - screenPtr[2].x * displayPtr[0].x) * screenPtr[1].y +
|
||||
(screenPtr[1].x * displayPtr[0].x - screenPtr[0].x * displayPtr[1].x) * screenPtr[2].y ;
|
||||
|
||||
matrixPtr->Dn = ((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].y - screenPtr[2].y)) -
|
||||
((displayPtr[1].y - displayPtr[2].y) * (screenPtr[0].y - screenPtr[2].y)) ;
|
||||
|
||||
matrixPtr->En = ((screenPtr[0].x - screenPtr[2].x) * (displayPtr[1].y - displayPtr[2].y)) -
|
||||
((displayPtr[0].y - displayPtr[2].y) * (screenPtr[1].x - screenPtr[2].x)) ;
|
||||
|
||||
matrixPtr->Fn = (screenPtr[2].x * displayPtr[1].y - screenPtr[1].x * displayPtr[2].y) * screenPtr[0].y +
|
||||
(screenPtr[0].x * displayPtr[2].y - screenPtr[2].x * displayPtr[0].y) * screenPtr[1].y +
|
||||
(screenPtr[1].x * displayPtr[0].y - screenPtr[0].x * displayPtr[1].y) * screenPtr[2].y ;
|
||||
|
||||
// Persist data to EEPROM
|
||||
// eepromWriteS32(CFG_EEPROM_TOUCHSCREEN_CAL_AN, matrixPtr->An);
|
||||
// eepromWriteS32(CFG_EEPROM_TOUCHSCREEN_CAL_BN, matrixPtr->Bn);
|
||||
// eepromWriteS32(CFG_EEPROM_TOUCHSCREEN_CAL_CN, matrixPtr->Cn);
|
||||
// eepromWriteS32(CFG_EEPROM_TOUCHSCREEN_CAL_DN, matrixPtr->Dn);
|
||||
// eepromWriteS32(CFG_EEPROM_TOUCHSCREEN_CAL_EN, matrixPtr->En);
|
||||
// eepromWriteS32(CFG_EEPROM_TOUCHSCREEN_CAL_FN, matrixPtr->Fn);
|
||||
// eepromWriteS32(CFG_EEPROM_TOUCHSCREEN_CAL_DIVIDER, matrixPtr->Divider);
|
||||
// eepromWriteU8(CFG_EEPROM_TOUCHSCREEN_CALIBRATED, 1);
|
||||
}
|
||||
|
||||
return( retValue ) ;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Converts the supplied touch screen location (screenPtr) to
|
||||
a pixel location on the display (displayPtr) using the
|
||||
supplied matrix.
|
||||
|
||||
@param[in] displayPtr Pointer to the tsPoint_t that will hold the
|
||||
compensated co-ordinates after calibration (the
|
||||
actual equivalent pixel location)
|
||||
@param[in] screenPtr Pointer to the tsPonint_t that contains the
|
||||
raw touch screen co-ordinated (pre-cal)
|
||||
@param[in] matrixPtr Pointer to the calibration matrix coefficients
|
||||
used during the calibration process (calculated
|
||||
via the tsCalibrate() helper function)
|
||||
|
||||
@note This is based on the public domain touch screen calibration code
|
||||
written by Carlos E. Vidales (copyright (c) 2001).
|
||||
*/
|
||||
/**************************************************************************/
|
||||
int getDisplayPoint( tsPoint_t * displayPtr, tsPoint_t * screenPtr, tsMatrix_t * matrixPtr )
|
||||
{
|
||||
int retValue = 0 ;
|
||||
|
||||
if( matrixPtr->Divider != 0 )
|
||||
{
|
||||
displayPtr->x = ( (matrixPtr->An * screenPtr->x) +
|
||||
(matrixPtr->Bn * screenPtr->y) +
|
||||
matrixPtr->Cn
|
||||
) / matrixPtr->Divider ;
|
||||
|
||||
displayPtr->y = ( (matrixPtr->Dn * screenPtr->x) +
|
||||
(matrixPtr->En * screenPtr->y) +
|
||||
matrixPtr->Fn
|
||||
) / matrixPtr->Divider ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return( retValue );
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Waits for a touch event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void waitForTouchEvent(tsTouchData_t * touchData)
|
||||
{
|
||||
uint16_t tx, ty;
|
||||
|
||||
/* Clear the touch data object and placeholder variables */
|
||||
memset(touchData, 0, sizeof(touchData));
|
||||
tx = ty = 0;
|
||||
|
||||
/* Clear any previous interrupts to avoid false buffered reads */
|
||||
tft.touchRead(&tx, &ty);
|
||||
delay(1);
|
||||
|
||||
/* Wait around for a new touch event (INT pin goes low) */
|
||||
while (digitalRead(RA8875_INT))
|
||||
{
|
||||
}
|
||||
|
||||
/* Make sure this is really a touch event */
|
||||
if (tft.touched())
|
||||
{
|
||||
tft.touchRead(&tx, &ty);
|
||||
Serial.print("Touch: ");
|
||||
Serial.print(tx); Serial.print(", "); Serial.println(ty);
|
||||
touchData->xraw = tx;
|
||||
touchData->yraw = ty;
|
||||
touchData->valid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
touchData->valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Renders the calibration screen with an appropriately
|
||||
placed test point and waits for a touch event
|
||||
*/
|
||||
/**************************************************************************/
|
||||
tsTouchData_t tsRenderCalibrationScreen(uint16_t x, uint16_t y, uint16_t radius)
|
||||
{
|
||||
tft.fillScreen(RA8875_WHITE);
|
||||
tft.drawCircle(x, y, radius, RA8875_RED);
|
||||
tft.drawCircle(x, y, radius + 2, 0x8410); /* 50% Gray */
|
||||
|
||||
// Wait for a valid touch events
|
||||
tsTouchData_t data;
|
||||
|
||||
bool valid = false;
|
||||
while (!valid)
|
||||
{
|
||||
/* Keep polling until the TS event flag is valid */
|
||||
waitForTouchEvent(&data);
|
||||
valid = data.valid;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@brief Starts the screen calibration process. Each corner will be
|
||||
tested, meaning that each boundary (top, left, right and
|
||||
bottom) will be tested twice and the readings averaged.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void tsCalibrate(void)
|
||||
{
|
||||
tsTouchData_t data;
|
||||
|
||||
/* --------------- Welcome Screen --------------- */
|
||||
Serial.println("Starting the calibration process");
|
||||
data = tsRenderCalibrationScreen(tft.width() / 2, tft.height() / 2, 5);
|
||||
delay(250);
|
||||
|
||||
/* ----------------- First Dot ------------------ */
|
||||
// 10% over and 10% down
|
||||
data = tsRenderCalibrationScreen(tft.width() / 10, tft.height() / 10, 5);
|
||||
_tsLCDPoints[0].x = tft.width() / 10;
|
||||
_tsLCDPoints[0].y = tft.height() / 10;
|
||||
_tsTSPoints[0].x = data.xraw;
|
||||
_tsTSPoints[0].y = data.yraw;
|
||||
Serial.print("Point 1 - LCD");
|
||||
Serial.print(" X: ");
|
||||
Serial.print(_tsLCDPoints[0].x);
|
||||
Serial.print(" Y: ");
|
||||
Serial.print(_tsLCDPoints[0].y);
|
||||
Serial.print(" TS X: ");
|
||||
Serial.print(_tsTSPoints[0].x);
|
||||
Serial.print(" Y: ");
|
||||
Serial.println(_tsTSPoints[0].y);
|
||||
delay(750);
|
||||
|
||||
/* ---------------- Second Dot ------------------ */
|
||||
// 50% over and 90% down
|
||||
data = tsRenderCalibrationScreen(tft.width() / 2, tft.height() - tft.height() / 10, 5);
|
||||
_tsLCDPoints[1].x = tft.width() / 2;
|
||||
_tsLCDPoints[1].y = tft.height() - tft.height() / 10;
|
||||
_tsTSPoints[1].x = data.xraw;
|
||||
_tsTSPoints[1].y = data.yraw;
|
||||
Serial.print("Point 2 - LCD");
|
||||
Serial.print(" X: ");
|
||||
Serial.print(_tsLCDPoints[1].x);
|
||||
Serial.print(" Y: ");
|
||||
Serial.print(_tsLCDPoints[1].y);
|
||||
Serial.print(" TS X: ");
|
||||
Serial.print(_tsTSPoints[1].x);
|
||||
Serial.print(" Y: ");
|
||||
Serial.println(_tsTSPoints[1].y);
|
||||
delay(750);
|
||||
|
||||
/* ---------------- Third Dot ------------------- */
|
||||
// 90% over and 50% down
|
||||
data = tsRenderCalibrationScreen(tft.width() - tft.width() / 10, tft.height() / 2, 5);
|
||||
_tsLCDPoints[2].x = tft.width() - tft.width() / 10;
|
||||
_tsLCDPoints[2].y = tft.height() / 2;
|
||||
_tsTSPoints[2].x = data.xraw;
|
||||
_tsTSPoints[2].y = data.yraw;
|
||||
Serial.print("Point 3 - LCD");
|
||||
Serial.print(" X: ");
|
||||
Serial.print(_tsLCDPoints[2].x);
|
||||
Serial.print(" Y: ");
|
||||
Serial.print(_tsLCDPoints[2].y);
|
||||
Serial.print(" TS X: ");
|
||||
Serial.print(_tsTSPoints[2].x);
|
||||
Serial.print(" Y: ");
|
||||
Serial.println(_tsTSPoints[2].y);
|
||||
delay(750);
|
||||
|
||||
/* Clear the screen */
|
||||
tft.fillScreen(RA8875_WHITE);
|
||||
|
||||
// Do matrix calculations for calibration and store to EEPROM
|
||||
setCalibrationMatrix(&_tsLCDPoints[0], &_tsTSPoints[0], &_tsMatrix);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Hello, RA8875!");
|
||||
|
||||
/* Initialise the display using 'RA8875_480x272' or 'RA8875_800x480' */
|
||||
if (!tft.begin(RA8875_480x272))
|
||||
{
|
||||
Serial.println("RA8875 not found ... check your wires!");
|
||||
while (1);
|
||||
}
|
||||
|
||||
/* Enables the display and sets up the backlight */
|
||||
Serial.println("Found RA8875");
|
||||
tft.displayOn(true);
|
||||
tft.GPIOX(true); // Enable TFT - display enable tied to GPIOX
|
||||
tft.PWM1config(true, RA8875_PWM_CLK_DIV1024); // PWM output for backlight
|
||||
tft.PWM1out(255);
|
||||
|
||||
/* Enable the touch screen */
|
||||
Serial.println("Enabled the touch screen");
|
||||
pinMode(RA8875_INT, INPUT);
|
||||
digitalWrite(RA8875_INT, HIGH);
|
||||
tft.touchEnable(true);
|
||||
|
||||
// Try some GFX acceleration!
|
||||
//tft.drawCircle(100, 100, 50, RA8875_BLACK);
|
||||
//tft.fillCircle(100, 100, 49, RA8875_GREEN);
|
||||
//tft.drawPixel(10,10,RA8875_BLACK);
|
||||
//tft.drawPixel(11,11,RA8875_BLACK);
|
||||
//tft.drawRect(10, 10, 400, 200, RA8875_GREEN);
|
||||
//tft.fillRect(11, 11, 398, 198, RA8875_BLUE);
|
||||
//tft.drawLine(10, 10, 200, 100, RA8875_RED);
|
||||
|
||||
tft.fillScreen(RA8875_WHITE);
|
||||
delay(100);
|
||||
|
||||
/* Start the calibration process */
|
||||
tsCalibrate();
|
||||
|
||||
/* _tsMatrix should now be populated with the correct coefficients! */
|
||||
Serial.println("Waiting for touch events ...");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
|
||||
*/
|
||||
/**************************************************************************/
|
||||
void loop()
|
||||
{
|
||||
tsTouchData_t data = { 0 };
|
||||
waitForTouchEvent(&data);
|
||||
|
||||
/* Calcuate the real X/Y position based on the calibration matrix */
|
||||
tsPoint_t raw = { data.xraw, data.yraw }; /* Raw TS co-ordinates */
|
||||
tsPoint_t calibrated = { 0, 0 }; /* Placeholder for calibrated co-ordinates */
|
||||
|
||||
Serial.print("Raw: ");
|
||||
Serial.print(raw.x);
|
||||
Serial.print(", ");
|
||||
Serial.print(raw.y);
|
||||
Serial.println("");
|
||||
|
||||
getDisplayPoint(&calibrated, &raw, &_tsMatrix );
|
||||
|
||||
Serial.print("Cal: ");
|
||||
Serial.print(calibrated.x);
|
||||
Serial.print(", ");
|
||||
Serial.print(calibrated.y);
|
||||
Serial.println("");
|
||||
|
||||
/* Draw a single pixel at the calibrated point */
|
||||
tft.fillCircle(calibrated.x, calibrated.y, 3, RA8875_BLACK);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue