Skip to content

Commit

Permalink
Added touchscreen calibration.
Browse files Browse the repository at this point in the history
  • Loading branch information
marcmerlin committed Apr 16, 2017
1 parent 2ee418b commit ac2e2b5
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 18 deletions.
106 changes: 100 additions & 6 deletions IoTuz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ void IoTuz::reset_tft() {

// maxlength is the maximum number of characters that need to be deleted before writing on top
// 55x30 characters
void IoTuz::tftprint(uint16_t x, uint16_t y, uint8_t maxlength, char *text) {
void IoTuz::tftprint(uint8_t x, uint8_t y, uint8_t maxlength, char *text) {
if (maxlength > 0) tft.fillRect(x*6, y*8, maxlength*6, 8, ILI9341_BLACK);
tft.setCursor(x*6, y*8);
tft.println(text);
Expand All @@ -263,14 +263,17 @@ void IoTuz::tftprint(uint16_t x, uint16_t y, uint8_t maxlength, char *text) {
TS_Point IoTuz::get_touch() {
// Clear (i.e. set) CS for TS before talking to it
i2cexp_clear_bits(I2CEXP_TOUCH_CS);
// Calling getpoint calls SPI.beginTransaction with a speed of only 2MHz, so we need tohttps://github.com/marcmerlin/IoTuz
// reset the speed to something faster before talking to the screen again.https://github.com/marcmerlin/IoTuz
// Calling getpoint calls SPI.beginTransaction with a speed of only 2MHz, so we need to
// reset the speed to something faster before talking to the screen again.
TS_Point p = ts.getPoint();
// Then disable it again so that talking SPI to LCD doesn't reach TS
i2cexp_set_bits(I2CEXP_TOUCH_CS);

if (ts_revX) p.x = 4096 - p.x;
if (ts_revY) p.y = 4096 - p.y;

// Tell the caller that the touch is bogus or none happened by setting z to 0.
if (p.z < MINPRESSURE || p.z > MAXPRESSURE) p.z = 0;
if (p.z < minpressure || p.z > maxpressure) p.z = 0;
// I've seen bogus touches where both x and y were 0
if (p.x == 0 && p.y == 0) p.z = 0;

Expand All @@ -292,14 +295,105 @@ void IoTuz::touchcoord2pixelcoord(uint16_t *pixel_x, uint16_t *pixel_y, uint16_t
Serial.print(pixel_z);
//*pixel_x = constrain((*pixel_x-320)/11.25, 0, 319);
//*pixel_y = constrain((*pixel_y-200)/15, 0, 239);
*pixel_x = map(*pixel_x, TS_MINX, TS_MAXX, 0, tftw);
*pixel_y = map(*pixel_y, TS_MINY, TS_MAXY, 0, tfth);
*pixel_x = map(*pixel_x, ts_minX, ts_maxX, 0, tftw);
*pixel_y = map(*pixel_y, ts_minY, ts_maxY, 0, tfth);
Serial.print(" to pixel coordinates ");
Serial.print(*pixel_x);
Serial.print("x");
Serial.println(*pixel_y);
}

void IoTuz::_getMinMaxTS () {
TS_Point p;
uint16_t untouch = 0;

do {
p = get_touch();
sprintf(tft_str, "%d", p.x);
tftprint(18, 15, 4, tft_str);
sprintf(tft_str, "%d", p.y);
tftprint(30, 15, 4, tft_str);

if (p.x < ts_minX) { ts_minX = p.x; untouch = 0; }
if (p.y < ts_minY) { ts_minY = p.y; untouch = 0; }
if (p.x > ts_maxX) { ts_maxX = p.x; untouch = 0; }
if (p.y > ts_maxY) { ts_maxY = p.y; untouch = 0; }

sprintf(tft_str, "%d", ts_minX);
tftprint(21, 16, 4, tft_str);
sprintf(tft_str, "%d", ts_maxX);
tftprint(33, 16, 4, tft_str);
sprintf(tft_str, "%d", ts_minX);
tftprint(21, 17, 4, tft_str);
sprintf(tft_str, "%d", ts_maxX);
tftprint(33, 17, 4, tft_str);

if (!p.z) untouch++;
if (!(untouch % 100)) {
Serial.print("Untouch count: ");
Serial.println(untouch);
}

} while (untouch < 300);
}

void IoTuz::calibrateScreen() {
TS_Point p;

Serial.print("Old calibration data MinX: ");
Serial.print(ts_minX);
Serial.print(", MaxX: ");
Serial.print(ts_maxX);
Serial.print(", MinY: ");
Serial.print(ts_minY);
Serial.print(", MaxY: ");
Serial.print(ts_maxY);
Serial.println();
ts_minX = ts_minY = ts_maxX = ts_maxY = 2048;

tftprint(15, 12, 0, "Touch Screen Calibration");
tftprint(15, 13, 0, "Please Draw the 4 lines");
tftprint(15, 14, 0, " From center to corner ");
tftprint(15, 15, 0, "X: 0000 Y: 0000 ");
tftprint(15, 16, 0, "MinX: 0000, MaxX: 0000");
tftprint(15, 17, 0, "MinY: 0000, MaxY: 0000");

tft.drawLine(32 , 24, 0, 0, ILI9341_BLUE);
// Wait for touch
do { p = get_touch();} while (!p.z);
if (p.x > 2048) {
ts_revX = true;
tftprint(15, 18, 0, "X Reversed");
}
if (p.y > 2048) {
ts_revY = true;
tftprint(26, 18, 0, "Y Reversed");
}

// Now that ts_revXY are set, get_touch will invert returned
// coordinates to make handling easier.
_getMinMaxTS();
tft.drawLine(287 , 24, 319, 0, ILI9341_BLUE);
_getMinMaxTS();
tft.drawLine(32 , 215, 0, 239, ILI9341_BLUE);
_getMinMaxTS();
tft.drawLine(287 , 215, 319, 239, ILI9341_BLUE);
_getMinMaxTS();

Serial.print("New calibration data MinX: ");
Serial.print(ts_minX);
Serial.print(", MaxX: ");
Serial.print(ts_maxX);
Serial.print(", MinY: ");
Serial.print(ts_minY);
Serial.print(", MaxY: ");
Serial.print(ts_maxY);
Serial.println();

tftprint(30, 20, 0, "Done!");
delay(3000);
}

IoTuz::IoTuz()
{
// Any write to I2CEXP should contain those mask bits so allow reads to work later
Expand Down
25 changes: 15 additions & 10 deletions IoTuz.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// This code can work somewhat on the WROVER board, you can comment this out:
//#define WROVER
#define WROVER

// MartyMacGyver/ESP32-Digital-RGB-LED-Drivers is better than the Adafruit
// Neopixel library. It flickers a bit, but if you want it, there you go:
Expand Down Expand Up @@ -134,14 +134,6 @@ BME280: 0x77 (Temp/Humidity/Pressure)
// This is all stored in i2cexp which we initialize to the bits used as input:
#define I2CEXP_IMASK ( I2CEXP_ACCEL_INT + I2CEXP_A_BUT + I2CEXP_B_BUT + I2CEXP_ENC_BUT + I2CEXP_TOUCH_INT )

// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 320
#define TS_MINY 220
#define TS_MAXX 3920
#define TS_MAXY 3820
#define MINPRESSURE 500
#define MAXPRESSURE 3000

// Touch screen select is on port expander line 6, not directly connected, so the library
// cannot toggle it directly. It however requires a CS pin, so I'm giving it 33, a spare IO
// pin so that it doesn't break anything else.
Expand Down Expand Up @@ -202,6 +194,17 @@ class IoTuz {
int8_t joyRelX, joyRelY;
bool joyBtn;

// Some touch screens have reversed coordinates. The original IoTuz did not
// but the compatible replacement screen I got, is reversed.
bool ts_revX = false;
bool ts_revY = false;
// This is calibration data for the raw touch data to the screen coordinates
uint16_t ts_minX=320;
uint16_t ts_minY=220;
uint16_t ts_maxX=3920;
uint16_t ts_maxY=3820;
uint16_t minpressure=500;
uint16_t maxpressure=3000;

// Buffer to store strings going to be printed on tft
char tft_str[64];
Expand All @@ -219,15 +222,17 @@ class IoTuz {
float battery_level();
void screen_bl(bool);
void reset_tft();
void tftprint(uint16_t, uint16_t, uint8_t, char *);
void tftprint(uint8_t, uint8_t, uint8_t, char *);
TS_Point get_touch();
void touchcoord2pixelcoord(uint16_t *, uint16_t *, uint16_t);
void calibrateScreen();
void begin();

private:
uint8_t _i2cexp;
void pcf8574_write_(uint8_t);
ButtState _but(uint8_t);
void _getMinMaxTS();
};


Expand Down
12 changes: 10 additions & 2 deletions examples/fulldemo/fulldemo.ino
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ char* opt_name[NVERT][NHORIZ][3] = {
{ { "Select", "LEDs", "Color"}, { "Rotary", "For Bright", "LED Off"}, { "", "Rotary", "Encoder"}, { "", "Round", "Rects"}, { "Round", "Fill", "Rects"}, },
{ { "", "Text", ""}, { "", "Fill", ""}, { "", "Diagonal", "Lines"}, { "Horizon", "Vert", "Lines"}, { "", "Rectangle", ""}, },
{ { "", "Fill", "Rectangle"}, { "", "Circles", ""}, { "", "Fill", "Circles"}, { "", "Triangles", ""}, { "", "Fill", "Triangles"}, },
{ { "", "Tetris", ""}, { "", "Breakout", ""}, { "", "DemoSauce", ""}, { "", "", ""}, { "", "", ""}, },
{ { "", "Tetris", ""}, { "", "Breakout", ""}, { "", "DemoSauce", ""}, { "", "", ""}, { "Calibrate", "Touch", "Screen"}, },
};
// tft_width, tft_height, calculated in setup after tft init
uint16_t tftw, tfth;
Expand Down Expand Up @@ -75,6 +75,7 @@ typedef enum {
TETRIS = 20,
BREAKOUT = 21,
DEMOSAUCE = 22,
CALIBRATE = 24,
} LCDtest;

void lcd_test(LCDtest choice) {
Expand Down Expand Up @@ -364,13 +365,16 @@ void draw_choices(void) {
tft.setTextColor(ILI9341_GREEN);
} else if (y*NHORIZ+x == 4 || y*NHORIZ+x == 7) {
tft.setTextColor(ILI9341_BLUE);
} else if (y*NHORIZ+x == 24) {
tft.setTextColor(ILI9341_YELLOW);
} else {
tft.setTextColor(ILI9341_WHITE);
}
tft.println(opt_name[y][x][line]);
}
}
}
tft.setTextColor(ILI9341_WHITE);

}

Expand Down Expand Up @@ -399,7 +403,7 @@ void move_current_box(uint8_t x, uint8_t y) {

uint8_t get_selection() {
TS_Point p;
static int8_t x, y = 0;
static int8_t x = 4, y = 4;
static uint32_t lastMove = 0 ;
uint8_t select;
int8_t encoder;
Expand Down Expand Up @@ -891,6 +895,10 @@ void loop() {
}
demosauce_loop();
break;
case CALIBRATE:
iotuz.calibrateScreen();
need_select = true;
return;
default:
if (select >= 8) {
DISABLE_OVERLAY_TEXT = true;
Expand Down

0 comments on commit ac2e2b5

Please sign in to comment.