Let me provide you with my calibration sketch. Provided 'as is' and without support. (it's been several years since i wrote this)
The idea is that when you use a toothpick and slide to the edge, you will find the correct extreme value
/* TFT Touchscreen Calibrateter
*/
#include <EEPROM.h> // for storage of the settings
#include <Adafruit_GFX.h> // Core graphics library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft; // hard-wired for UNO shields anyway.
#include <TouchScreen.h>
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif
// most mcufriend shields use these pins and Portrait mode:
const uint8_t YP = A1; // must be an analog pin, use "An" notation!
const uint8_t XM = A2; // must be an analog pin, use "An" notation!
const uint8_t YM = 7; // can be a digital pin
const uint8_t XP = 6; // can be a digital pin
uint8_t SwapXY = 1; // depends on the TFT shield
uint16_t TS_LEFT = 930;
uint16_t TS_RT = 175;
uint16_t TS_TOP = 175; // this is actually the usb end at the start of the program
uint16_t TS_BOT = 920;
volatile uint16_t TFT_X_RANGE = 240; // making these variables volatile solves the issue that when changing
volatile uint16_t TFT_Y_RANGE = 320; // their value (or even keeping it the same but writing to them)
// caused an incorrect memory write with black area's on screen.
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 455);
TSPoint tp;
#define MINPRESSURE 5
#define MAXPRESSURE 1000
#define RELEASECYCLES 200
#define EEPROM_OFFSET 448 // set this to a matching value in the program
// depending on the calibrated values, do not use
// the low Eeprom adddresses since the graphics library
// appears to be using them.
#define SWAP(a, b) {uint16_t tmp = a; a = b; b = tmp;}
uint16_t identifier;
uint8_t orientation = 0; //Portrait
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
void setup() {
tft.begin(9600);
tft.reset();
identifier = tft.readID();
tft.begin(identifier);
tft.setRotation(orientation); // we use orientation here to set the TFT rotation
// TS_Rotation(orientation);
ts = TouchScreen(XP, YP, XM, YM, 455); // call the constructor
while (!TitleScreen()) Change_TFTXY_Settings();
CalibrationScreen();
}
void loop() {
}
void CalibrationScreen() {
tft.fillScreen(BLUE);
tft.setTextSize(2);
tft.setTextColor(BLACK);
const char * title = "TFT Calibrater"; // header text
tft.setCursor((TFT_X_RANGE/2) - strlen(title)*6,20);
tft.print(title);
tft.setCursor((TFT_X_RANGE/2) - 54,40);
tft.print(String(TFT_X_RANGE)+" X "+String(TFT_Y_RANGE));
tft.fillRect(TFT_X_RANGE/4,TFT_Y_RANGE/4,TFT_X_RANGE/2,TFT_Y_RANGE/2,RED);
tft.setTextSize(1);
const char * order = "Press the red rectangle";
tft.setCursor((TFT_X_RANGE/2) - strlen(order)*3,TFT_Y_RANGE-50);
tft.print(order);
tft.drawRect(2,2,TFT_X_RANGE-4,TFT_Y_RANGE-4,RED);
WaitReleaseReadPress(true);
tft.fillRect((TFT_X_RANGE/8)*3,(TFT_Y_RANGE/8)*3,TFT_X_RANGE/4,TFT_Y_RANGE/4,YELLOW);
while (!ConfirmRelease());
tft.fillRect((TFT_X_RANGE/8)*3,(TFT_Y_RANGE/8)*3,TFT_X_RANGE/4,TFT_Y_RANGE/4,RED);
uint16_t minx=500,miny=500,maxx=500,maxy=500;
uint8_t minxq=4,minyq=4,maxxq=4,maxyq=4,i=0;
tft.drawRect(2,2,TFT_X_RANGE-4,TFT_Y_RANGE-4,BLUE);
tft.fillRect(0, 0, TFT_X_RANGE, TFT_Y_RANGE/4, BLUE);
tft.fillRect(0, (TFT_Y_RANGE/4)*3 ,TFT_X_RANGE, TFT_Y_RANGE/4, BLUE);
tft.fillRect((TFT_X_RANGE/8),(TFT_Y_RANGE/8),(TFT_X_RANGE/4)*3,(TFT_Y_RANGE/4)*3,RED);
EdgeLookText();
WaitReleaseReadPress(true);
tft.fillScreen(BLUE);
tft.fillRect(TFT_X_RANGE/4,TFT_Y_RANGE/4,TFT_X_RANGE/2,TFT_Y_RANGE/2,RED);
DrawArrow(0);
FillQuad(i,CYAN);
while (i<4) {
tp = ts.getPoint();
ResetPins();
if (tp.z < MINPRESSURE || tp.z > MAXPRESSURE) continue;
tft.setTextColor(YELLOW,BLUE);
tft.setTextSize(2);
tft.setCursor((TFT_X_RANGE/4)+20,(TFT_Y_RANGE/4)*(3-(i/2)*3)+20);
tft.print("tp.x=" + String(tp.x));
tft.setCursor((TFT_X_RANGE/4)+20,(TFT_Y_RANGE/4)*(3-(i/2)*3)+50);
tft.print("tp.y=" + String(tp.y));
tft.setTextSize(1);
if (tp.x>maxx) {
maxx=tp.x;
maxxq=i;
tft.setCursor((TFT_X_RANGE/4)*3+10,40);
tft.print("MaxX="+String(maxx));
}
if (tp.x<minx) {
minx=tp.x;
minxq=i;
tft.setCursor(10,40);
tft.print("MinX="+String(minx));
}
if (tp.y>maxy) {
maxy=tp.y;
maxyq=i;
tft.setCursor((TFT_X_RANGE/4)*3+10,(TFT_Y_RANGE/4)*3+40);
tft.print("MaxY="+String(maxy));
}
if (tp.y<miny) {
miny=tp.y;
minyq=i;
tft.setCursor(10,(TFT_Y_RANGE/4)*3+40);
tft.print("MinY="+String(miny));
}
if (tp.x > 450 && tp.x < 570 && tp.y > 450 && tp.y < 570) { // exit
FillQuad(i,BLUE);
i++;
tft.fillRect((TFT_X_RANGE/8)*3,(TFT_Y_RANGE/8)*3,TFT_X_RANGE/4,TFT_Y_RANGE/4,YELLOW);
while (!ConfirmRelease());
tft.fillRect((TFT_X_RANGE/4),(TFT_Y_RANGE/4),TFT_X_RANGE/2,TFT_Y_RANGE/2,RED);
DrawArrow(i);
FillQuad(i,CYAN);
}
}
tft.fillScreen(YELLOW);
tft.fillRect((TFT_X_RANGE/4),(TFT_Y_RANGE/4),TFT_X_RANGE/2,TFT_Y_RANGE/2,BLUE);
tft.setTextColor(BLACK,YELLOW);
tft.setTextSize(2);
SetCursorInQuad(minxq,0);
tft.print("MinX");
SetCursorInQuad(minxq,2);
tft.print(String(minx));
SetCursorInQuad(maxxq,0);
tft.print("MaxX");
SetCursorInQuad(maxxq,2);
tft.print(String(maxx));
SetCursorInQuad(minyq,0);
tft.print("MinY");
SetCursorInQuad(minyq,2);
tft.print(String(miny));
SetCursorInQuad(maxyq,0);
tft.print("MaxY");
SetCursorInQuad(maxyq,2);
tft.print(String(maxy));
EepromSaveScreen();
WaitReleaseReadPress(true);
StoreInVar(minxq,minx-3);
StoreInVar(maxxq,maxx+3);
StoreInVar(minyq,miny-3);
StoreInVar(maxyq,maxy+3);
StoreValues();
ReadValues();
PrintValues();
}
void StoreInVar(uint8_t side,uint16_t value) {
switch(side) {
case 0:
TS_TOP=value;
break;
case 1:
TS_RT=value;
break;
case 2:
TS_BOT=value;
break;
case 3:
TS_LEFT=value;
break;
}
}
void EepromSaveScreen() {
tft.setTextColor(YELLOW,BLUE);
tft.setTextSize(1);
const char * line1 = "The Values found";
const char * line2 = "Will be stored in";
const char * line3 = "The Eeprom as 16";
const char * line4 = "bit U-integers";
const char * line5 = "Press to continue";
tft.setCursor((TFT_X_RANGE/2) - strlen(line1)*3,((TFT_Y_RANGE/2)-24));
tft.print(line1);
tft.setCursor((TFT_X_RANGE/2) - strlen(line2)*3,((TFT_Y_RANGE/2)-12));
tft.print(line2);
tft.setCursor((TFT_X_RANGE/2) - strlen(line3)*3,((TFT_Y_RANGE/2)));
tft.print(line3);
tft.setCursor((TFT_X_RANGE/2) - strlen(line4)*3,((TFT_Y_RANGE/2)+12));
tft.print(line4);
tft.setCursor((TFT_X_RANGE/2) - strlen(line5)*3,((TFT_Y_RANGE/2)+30));
tft.print(line5);
}
void StoreValues() {
Write16bitEeprom(EEPROM_OFFSET,TFT_X_RANGE);
Write16bitEeprom(EEPROM_OFFSET+2,TFT_Y_RANGE);
Write16bitEeprom(EEPROM_OFFSET+4,TS_TOP);
Write16bitEeprom(EEPROM_OFFSET+6,TS_RT);
Write16bitEeprom(EEPROM_OFFSET+8,TS_BOT);
Write16bitEeprom(EEPROM_OFFSET+10,TS_LEFT);
}
void Write16bitEeprom(uint16_t location, uint16_t uinteg) {
EEPROM.write(location,lowByte(uinteg));
EEPROM.write(location+1,highByte(uinteg));
}
void ReadValues() { //copy the following 2 functions into your program
TFT_X_RANGE=Read16bitEeprom(EEPROM_OFFSET);
TFT_Y_RANGE=Read16bitEeprom(EEPROM_OFFSET+2);
TS_TOP=Read16bitEeprom(EEPROM_OFFSET+4);
TS_RT=Read16bitEeprom(EEPROM_OFFSET+6);
TS_BOT=Read16bitEeprom(EEPROM_OFFSET+8);
TS_LEFT=Read16bitEeprom(EEPROM_OFFSET+10);
}
uint16_t Read16bitEeprom(uint16_t location) {
return( ((uint16_t) EEPROM.read(location+1)<<8) | (uint16_t) EEPROM.read(location));
}
void PrintValues() {
tft.fillScreen(GREEN);
tft.fillRect((TFT_X_RANGE/4),(TFT_Y_RANGE/4),TFT_X_RANGE/2,TFT_Y_RANGE/2,WHITE);
tft.setTextColor(BLACK);
tft.setTextSize(2);
SetCursorInQuad(0,1);
tft.print(String(TS_TOP));
SetCursorInQuad(1,1);
tft.print(String(TS_RT));
SetCursorInQuad(2,1);
tft.print(String(TS_BOT));
SetCursorInQuad(3,1);
tft.print(String(TS_LEFT));
tft.setCursor(TFT_X_RANGE/2-15,TFT_Y_RANGE/2-24);
tft.print(String(TFT_X_RANGE));
tft.setCursor(TFT_X_RANGE/2-3,TFT_Y_RANGE/2-6);
tft.print("X");
tft.setCursor(TFT_X_RANGE/2-15,TFT_Y_RANGE/2+12);
tft.print(String(TFT_Y_RANGE));
}
void SetCursorInQuad(uint8_t quad, uint8_t line) {
switch(quad) {
case 0:
tft.setCursor((TFT_X_RANGE/8)*3+line*7,20+line*15);
break;
case 1:
tft.setCursor((TFT_X_RANGE/4)*3+5+line*7,(TFT_Y_RANGE/8)*3+20+line*15);
break;
case 2:
tft.setCursor((TFT_X_RANGE/8)*3+line*7,(TFT_Y_RANGE/4)*3+20+line*15);
break;
case 3:
tft.setCursor(5+line*7,(TFT_Y_RANGE/8)*3+20+line*15);
break;
}
return;
}
void FillQuad(uint8_t quad,uint16_t color) {
switch (quad) {
case 0:
tft.fillRect(TFT_X_RANGE/4,0,TFT_X_RANGE/2,TFT_Y_RANGE/4,color);
break;
case 1:
tft.fillRect((TFT_X_RANGE/4)*3,TFT_Y_RANGE/4,TFT_X_RANGE/4,TFT_Y_RANGE/2,color);
break;
case 2:
tft.fillRect(TFT_X_RANGE/4,(TFT_Y_RANGE/4)*3,TFT_X_RANGE/2,TFT_Y_RANGE/4,color);
break;
case 3:
tft.fillRect(0,TFT_Y_RANGE/4,TFT_X_RANGE/4,TFT_Y_RANGE/2,color);
}
}
void DrawArrow(uint8_t direct) {
if (direct>3) return;
if (direct%2) { // horizontal
for (uint8_t i=0; i<10; i++) {
if ((i) && (i<9)) tft.drawLine(TFT_X_RANGE/2-(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
TFT_X_RANGE/2+(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i, BLACK);
if (direct/2) { // to left
tft.drawLine(TFT_X_RANGE/2-(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
TFT_X_RANGE/2, TFT_Y_RANGE/2-5+i-(TFT_Y_RANGE/16)*2,BLACK);
tft.drawLine(TFT_X_RANGE/2-(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
TFT_X_RANGE/2, TFT_Y_RANGE/2-5+i+(TFT_Y_RANGE/16)*2,BLACK);
}
else { // to right
tft.drawLine(TFT_X_RANGE/2+(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
TFT_X_RANGE/2, TFT_Y_RANGE/2-5+i-(TFT_Y_RANGE/16)*2,BLACK);
tft.drawLine(TFT_X_RANGE/2+(TFT_X_RANGE/16)*3, TFT_Y_RANGE/2-5+i,
TFT_X_RANGE/2, TFT_Y_RANGE/2-5+i+(TFT_Y_RANGE/16)*2,BLACK);
}
}
}
else { // vertical
for (uint8_t i=0; i<10; i++) {
if ((i) && (i<9)) tft.drawLine(TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2-(TFT_Y_RANGE/16)*3,
TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2+(TFT_Y_RANGE/16)*3, BLACK);
if (!(direct/2)) { // to Bottom
tft.drawLine(TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2-(TFT_Y_RANGE/16)*3,
TFT_X_RANGE/2-5+i-(TFT_X_RANGE/16)*2, TFT_Y_RANGE/2, BLACK);
tft.drawLine(TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2-(TFT_Y_RANGE/16)*3,
TFT_X_RANGE/2-5+i+(TFT_X_RANGE/16)*2, TFT_Y_RANGE/2, BLACK);
}
else { // to Top
tft.drawLine(TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2+(TFT_Y_RANGE/16)*3,
TFT_X_RANGE/2-5+i-(TFT_X_RANGE/16)*2, TFT_Y_RANGE/2, BLACK);
tft.drawLine(TFT_X_RANGE/2-5+i, TFT_Y_RANGE/2+(TFT_Y_RANGE/16)*3,
TFT_X_RANGE/2-5+i+(TFT_X_RANGE/16)*2, TFT_Y_RANGE/2, BLACK);
}
}
}
}
void EdgeLookText() {
tft.setTextColor(BLACK,RED);
tft.setTextSize(1);
const char * line1 = "Look for the edge's";
const char * line2 = "extreme value in the";
const char * line3 = "lightblue area, using";
const char * line4 = "a toothpick, and when";
const char * line5 = "done press the center";
const char * line6 = "of this red square for";
const char * line7 = "the next edge.";
const char * line8 = "Press to continue";
tft.setCursor((TFT_X_RANGE/2) - strlen(line1)*3,((TFT_Y_RANGE/2)-48));
tft.print(line1);
tft.setCursor((TFT_X_RANGE/2) - strlen(line2)*3,((TFT_Y_RANGE/2)-36));
tft.print(line2);
tft.setCursor((TFT_X_RANGE/2) - strlen(line3)*3,((TFT_Y_RANGE/2)-24));
tft.print(line3);
tft.setCursor((TFT_X_RANGE/2) - strlen(line4)*3,((TFT_Y_RANGE/2)-12));
tft.print(line4);
tft.setCursor((TFT_X_RANGE/2) - strlen(line5)*3,((TFT_Y_RANGE/2)));
tft.print(line5);
tft.setCursor((TFT_X_RANGE/2) - strlen(line6)*3,((TFT_Y_RANGE/2)+12));
tft.print(line6);
tft.setCursor((TFT_X_RANGE/2) - strlen(line7)*3,((TFT_Y_RANGE/2)+24));
tft.print(line7);
tft.setCursor((TFT_X_RANGE/2) - strlen(line8)*3,((TFT_Y_RANGE/2)+48));
tft.print(line8);
}
bool TitleScreen() {
tft.fillScreen(WHITE);
tft.setTextSize(2);
tft.setTextColor(BLACK);
const char * title = "TFT Calibrater";
tft.setCursor((TFT_X_RANGE/2) - strlen(title)*6,20);
tft.print(title);
delay(1000);
tft.setTextSize(1);
const char * story1 = "Your screen should be";
const char * story2 = "in Portait mode, where";
const char * story3 = "the USB-end is the top.";
const char * story4 = "And this text should be";
const char * story5 = "centered, left to right,";
const char * story6 = "and top to bottom, with";
const char * story7 = "a frame around it.";
const char * story8 = "If so, press the screen,";
const char * story9 = "if not, press and hold";
const char * story10 = "for 3 seconds";
tft.setCursor((TFT_X_RANGE/2) - strlen(story1)*3,((TFT_Y_RANGE/2)-54));
tft.print(story1);
tft.setCursor((TFT_X_RANGE/2) - strlen(story2)*3,((TFT_Y_RANGE/2)-42));
tft.print(story2);
tft.setCursor((TFT_X_RANGE/2) - strlen(story3)*3,((TFT_Y_RANGE/2)-30));
tft.print(story3);
tft.setCursor((TFT_X_RANGE/2) - strlen(story4)*3,((TFT_Y_RANGE/2)-18));
tft.print(story4);
tft.setCursor((TFT_X_RANGE/2) - strlen(story5)*3,((TFT_Y_RANGE/2)-6));
tft.print(story5);
tft.setCursor((TFT_X_RANGE/2) - strlen(story6)*3,((TFT_Y_RANGE/2)+6));
tft.print(story6);
tft.setCursor((TFT_X_RANGE/2) - strlen(story7)*3,((TFT_Y_RANGE/2)+18));
tft.print(story7);
tft.setCursor((TFT_X_RANGE/2) - strlen(story8)*3,((TFT_Y_RANGE/2)+30));
tft.print(story8);
tft.setCursor((TFT_X_RANGE/2) - strlen(story9)*3,((TFT_Y_RANGE/2)+42));
tft.print(story9);
tft.setCursor((TFT_X_RANGE/2) - strlen(story10)*3,((TFT_Y_RANGE/2)+54));
tft.print(story10);
tft.drawRect(2,2,TFT_X_RANGE-4,TFT_Y_RANGE-4,BLACK);
WaitReleaseReadPress(true);
uint32_t moment=millis();
while (!ConfirmRelease()) if ((millis()-moment)>3000) return false;
return true;
}
void Change_TFTXY_Settings() {
tft.fillScreen(RED);
delay(3000);
}
bool ConfirmRelease() {
uint8_t prs=0;
while (prs<RELEASECYCLES) {
tp = ts.getPoint();
ResetPins();
if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) return false ;
delay(1);
prs++;
}
return true;
}
void WaitReleaseReadPress(bool waitrelease) {
if (waitrelease) {
while (!ConfirmRelease());
}
while (tp.z < MINPRESSURE || tp.z > MAXPRESSURE) {
tp = ts.getPoint();
ResetPins();
}
delay (100);
}
void ResetPins(){
pinMode(XM, OUTPUT); // reset the pins after use.
pinMode(YP, OUTPUT);
pinMode(XP, OUTPUT);
pinMode(YM, OUTPUT);
}