Skip to content

Commit 889add0

Browse files
committedFeb 26, 2025
Adopted XPT2046_Bitbang instead of XPT2046_Touchscreen.
1 parent 73d9938 commit 889add0

6 files changed

+203
-53
lines changed
 

‎MLX90640.ino

+2-3
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,8 @@
4848
* https://github.com/witnessmenow/ESP32-Cheap-Yellow-Display/discussions/88
4949
* https://github.com/TheNitek/XPT2046_Bitbang_Arduino_Library
5050
*--------------------------------------------------------------------------------*/
51-
#ifdef ARDUINO_ESP32_2432S028R
52-
#include <XPT2046_Touchscreen.h>
53-
#endif
51+
//#include <XPT2046_Touchscreen.h>
52+
#include <XPT2046_Bitbang.h>
5453
#endif
5554

5655
/*--------------------------------------------------------------------------------

‎README.md

+9
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,15 @@ If `USE_PREFERENCES` is set to `true`, you can save the calibration results to f
162162
you need to open the serial monitor with **115200** bps before running the calibration and embed the displayed data into
163163
[`touch.hpp`](https://github.com/embedded-kiddie/MLX90640/blob/main/touch.hpp#L25-L48) after calibration is completed.
164164

165+
## Known Issue
166+
167+
When TFT_eSPI is selected on ESP32-2432S028R, rendering will be slower than LovyanGFX and screenshots can not be saved correctly.
168+
169+
<p align="center">
170+
<img src="images/screenshot-LovyanGFX.png" width="45%" alt="Screenshot by LovyanGFX" title="Screenshot by LovyanGFX" />
171+
<img src="images/screenshot-TFT_eSPI.png" width="45%" alt="Screenshot by TFT_eSPI" title="Screenshot by TFT_eSPI" />
172+
</p>
173+
165174
## Related Project
166175
- [MLX90640Viewer](https://github.com/embedded-kiddie/MLX90640Viewer)
167176
The MLX90640Viewer is a tool that applies heatmaps and visualizes the output of the Melexis MLX90640 32x24 IR array,

‎boards/XPT2046_ScreenPoint.h

+177-44
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
/*----------------------------------------------------------------------
2-
* Touch screen calibration for XPT2046_Touchscreen
1+
/*----------------------------------------------------------------------------
2+
* A wrapper class for the touchscreen libraries that supports
3+
* calibration of the touch panel and rotation of the screen
34
*
45
* This program is based on the following article:
56
* https://bytesnbits.co.uk/arduino-touchscreen-calibration-coding/
6-
*----------------------------------------------------------------------*/
7+
*----------------------------------------------------------------------------*/
78
#ifndef _XPT2046_SCREENPOINT_H_
89
#define _XPT2046_SCREENPOINT_H_
910

@@ -28,12 +29,40 @@
2829
#error use LovyanGFX, TFT_eSPI, Adafruit_GFX or GFX_Library_for_Arduino
2930
#endif
3031

32+
#if defined (_XPT2046_Touchscreen_h_)
33+
/*************************************************/
34+
/**** Inherits from XPT2046_Touchscreen class ****/
35+
/*************************************************/
36+
#define PARENT_CLASS XPT2046_Touchscreen
37+
#define SCREEN_POINT TS_Point
38+
#define SP_RAW_X(p) p.x
39+
#define SP_RAW_Y(p) p.y
40+
#define SP_RAW_Z(p) p.z
41+
42+
#define Z_THRESHOLD 600
43+
#endif // _XPT2046_Touchscreen_h_
44+
45+
#if defined (XPT2046_Bitbang_h)
46+
/*************************************************/
47+
/****** Inherits from XPT2046_Bitbang class ******/
48+
/*************************************************/
49+
#define PARENT_CLASS XPT2046_Bitbang
50+
#define SCREEN_POINT TouchPoint
51+
#define SP_RAW_X(p) p.xRaw
52+
#define SP_RAW_Y(p) p.yRaw
53+
#define SP_RAW_Z(p) p.zRaw
54+
55+
#define N_SAMPLES 4
56+
#define N_THRESHOLD 3
57+
#define Z_THRESHOLD 600
58+
#endif // XPT2046_Bitbang_h
59+
3160
/*----------------------------------------------------------------------
32-
* Defining the class that inherits from XPT2046_Touchscreen class
61+
* Defining the class that inherits from XPT2046 libraries
3362
*----------------------------------------------------------------------*/
34-
class XPT2046_ScreenPoint : public XPT2046_Touchscreen {
63+
class XPT2046_ScreenPoint : public PARENT_CLASS {
3564
// Inheriting constructor from the parent class
36-
using XPT2046_Touchscreen::XPT2046_Touchscreen;
65+
using PARENT_CLASS::PARENT_CLASS;
3766

3867
private:
3968
bool calibrated = false;
@@ -42,13 +71,17 @@ class XPT2046_ScreenPoint : public XPT2046_Touchscreen {
4271
float xCalM = 0.0, yCalM = 0.0; // gradients
4372
float xCalC = 0.0, yCalC = 0.0; // y axis crossing points
4473

74+
#if defined (_XPT2046_Touchscreen_h_)
75+
/*************************************************/
76+
/**** Inherits from XPT2046_Touchscreen class ****/
77+
/*************************************************/
4578
public:
4679
void setRotation(uint8_t r) {
47-
XPT2046_Touchscreen::setRotation(rotation = r % 4);
80+
PARENT_CLASS::setRotation(rotation = r % 4);
4881
}
4982

5083
void begin(SPIClass &spi, uint16_t w, uint16_t h, uint8_t r = 0) {
51-
XPT2046_Touchscreen::begin(spi);
84+
PARENT_CLASS::begin(spi);
5285
setRotation(r);
5386
width = w;
5487
height = h;
@@ -57,6 +90,102 @@ class XPT2046_ScreenPoint : public XPT2046_Touchscreen {
5790
void begin(uint16_t w, uint16_t h, uint8_t r = 0) {
5891
begin(SPI, w, h, r);
5992
}
93+
#endif // _XPT2046_Touchscreen_h_
94+
95+
#if defined (XPT2046_Bitbang_h)
96+
/*************************************************/
97+
/****** Inherits from XPT2046_Bitbang class ******/
98+
/*************************************************/
99+
100+
// Smirnov-Grubbs criterion
101+
static SCREEN_POINT filter(SCREEN_POINT *p) {
102+
uint16_t xRaw, yRaw, zRaw;
103+
104+
xRaw = yRaw = zRaw = 0;
105+
for (int i = 0; i < N_SAMPLES; ++i) {
106+
xRaw += SP_RAW_X(p[i]);
107+
yRaw += SP_RAW_Y(p[i]);
108+
zRaw += SP_RAW_Z(p[i]);
109+
}
110+
111+
xRaw /= N_SAMPLES;
112+
yRaw /= N_SAMPLES;
113+
zRaw /= N_SAMPLES;
114+
115+
uint16_t n, x, y, z;
116+
n = x = y = z = 0;
117+
for (int i = 0; i < N_SAMPLES; i++) {
118+
if (abs(xRaw - SP_RAW_X(p[i])) <= N_THRESHOLD && abs(yRaw - SP_RAW_Y(p[i])) <= N_THRESHOLD) {
119+
x += SP_RAW_X(p[i]);
120+
y += SP_RAW_Y(p[i]);
121+
z += SP_RAW_Z(p[i]);
122+
n++;
123+
}
124+
}
125+
126+
if (n > 0) {
127+
x /= n;
128+
y /= n;
129+
z /= n;
130+
}
131+
132+
return SCREEN_POINT {0, 0, x, y, z};
133+
}
134+
135+
public:
136+
void setRotation(uint8_t r) {
137+
rotation = r % 4;
138+
}
139+
140+
void begin(uint16_t w, uint16_t h, uint8_t r = 0) {
141+
PARENT_CLASS::begin();
142+
setRotation(r);
143+
width = w;
144+
height = h;
145+
}
146+
147+
void begin(void) {
148+
begin();
149+
}
150+
151+
bool touched(void) {
152+
SCREEN_POINT p = PARENT_CLASS::getTouch();
153+
return (SP_RAW_Z(p) >= Z_THRESHOLD);
154+
}
155+
156+
SCREEN_POINT getPoint(void) {
157+
SCREEN_POINT p[N_SAMPLES], q, r;
158+
159+
for (int i = 0; i < N_SAMPLES; i++) {
160+
p[i] = PARENT_CLASS::getTouch();
161+
}
162+
163+
// Filter outliers
164+
q = filter(p);
165+
166+
switch (rotation) {
167+
case 0:
168+
SP_RAW_X(r) = 4095 - SP_RAW_Y(q);
169+
SP_RAW_Y(r) = SP_RAW_X(q);
170+
break;
171+
case 1:
172+
SP_RAW_X(r) = SP_RAW_X(q);
173+
SP_RAW_Y(r) = SP_RAW_Y(q);
174+
break;
175+
case 2:
176+
SP_RAW_X(r) = SP_RAW_Y(q);
177+
SP_RAW_Y(r) = 4095 - SP_RAW_X(q);
178+
break;
179+
default: // 3
180+
SP_RAW_X(r) = 4095 - SP_RAW_X(q);
181+
SP_RAW_Y(r) = 4095 - SP_RAW_Y(q);
182+
break;
183+
}
184+
SP_RAW_Z(r) = SP_RAW_Z(q);
185+
r.x = r.y = 0;
186+
return r;
187+
}
188+
#endif // XPT2046_Bitbang_h
60189

61190
bool setTouch(const uint16_t *cal) {
62191
if (cal[4] == rotation) {
@@ -82,37 +211,34 @@ class XPT2046_ScreenPoint : public XPT2046_Touchscreen {
82211
return calibrated;
83212
}
84213

85-
bool getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = 600) {
86-
if (touched()) {
87-
TS_Point p = getPoint();
88-
89-
if (p.z >= threshold) {
90-
if (calibrated) {
91-
int16_t xCoord = round((p.x * xCalM) + xCalC);
92-
int16_t yCoord = round((p.y * yCalM) + yCalC);
93-
94-
if (xCoord < 0) xCoord = 0; else
95-
if (xCoord >= width ) xCoord = width - 1;
96-
if (yCoord < 0) yCoord = 0; else
97-
if (yCoord >= height) yCoord = height - 1;
98-
99-
*x = xCoord;
100-
*y = yCoord;
101-
} else {
102-
// https://randomnerdtutorials.com/lvgl-cheap-yellow-display-esp32-2432s028r/
103-
static const struct {
104-
uint16_t xmin, xmax, ymin, ymax;
105-
} cal[4] = {
106-
{240, 3800, 200, 3700},
107-
{200, 3700, 240, 3800},
108-
{260, 3850, 300, 3950},
109-
{300, 3950, 260, 3850}
110-
};
111-
*x = map(p.x, cal[rotation].xmin, cal[rotation].xmax, 0, width );
112-
*y = map(p.y, cal[rotation].ymin, cal[rotation].ymax, 0, height);
113-
}
114-
return true;
214+
bool getTouch(uint16_t *x, uint16_t *y, uint16_t threshold = Z_THRESHOLD) {
215+
SCREEN_POINT gp = getPoint();
216+
if (SP_RAW_Z(gp) >= threshold) {
217+
if (calibrated) {
218+
int16_t xCoord = round((SP_RAW_X(gp) * xCalM) + xCalC);
219+
int16_t yCoord = round((SP_RAW_Y(gp) * yCalM) + yCalC);
220+
221+
if (xCoord < 0) xCoord = 0; else
222+
if (xCoord >= width ) xCoord = width - 1;
223+
if (yCoord < 0) yCoord = 0; else
224+
if (yCoord >= height) yCoord = height - 1;
225+
226+
*x = xCoord;
227+
*y = yCoord;
228+
} else {
229+
// https://randomnerdtutorials.com/lvgl-cheap-yellow-display-esp32-2432s028r/
230+
static const struct {
231+
uint16_t xmin, xmax, ymin, ymax;
232+
} cal[4] = {
233+
{240, 3800, 200, 3700},
234+
{200, 3700, 240, 3800},
235+
{260, 3850, 300, 3950},
236+
{300, 3950, 260, 3850}
237+
};
238+
*x = map(SP_RAW_X(gp), cal[rotation].xmin, cal[rotation].xmax, 0, width );
239+
*y = map(SP_RAW_Y(gp), cal[rotation].ymin, cal[rotation].ymax, 0, height);
115240
}
241+
return true;
116242
}
117243
return false;
118244
}
@@ -138,9 +264,13 @@ class XPT2046_ScreenPoint : public XPT2046_Touchscreen {
138264
while (!touched());
139265
delay(50); // wait for touch being stable
140266

141-
TS_Point p = getPoint();
142-
cal[0] = p.x;
143-
cal[1] = p.y;
267+
SCREEN_POINT p;
268+
do {
269+
p = getPoint();
270+
} while (SP_RAW_Z(p) < Z_THRESHOLD);
271+
272+
cal[0] = SP_RAW_X(p);
273+
cal[1] = SP_RAW_Y(p);
144274
tft->drawFastHLine(10, 20, 20, color_bg);
145275
tft->drawFastVLine(20, 10, 20, color_bg);
146276

@@ -153,9 +283,12 @@ class XPT2046_ScreenPoint : public XPT2046_Touchscreen {
153283
while (!touched());
154284
delay(50); // wait for touch being stable
155285

156-
p = getPoint();
157-
cal[2] = p.x;
158-
cal[3] = p.y;
286+
do {
287+
p = getPoint();
288+
} while (SP_RAW_Z(p) < Z_THRESHOLD);
289+
290+
cal[2] = SP_RAW_X(p);
291+
cal[3] = SP_RAW_Y(p);
159292
tft->drawFastHLine(width - 30, height - 20, 20, color_bg);
160293
tft->drawFastVLine(width - 20, height - 30, 20, color_bg);
161294

‎images/screenshot-LovyanGFX.png

8.45 KB
Loading

‎images/screenshot-TFT_eSPI.png

60.4 KB
Loading

‎touch.hpp

+15-6
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ TouchConfig_t tch_cnf = {
3232
// LovyanGFX
3333
.cal = { 0, 0, 0, 0, 0, 0, 0, 0 },
3434

35-
#elif defined (_XPT2046_Touchscreen_h_)
35+
#elif defined (_XPT2046_SCREENPOINT_H_)
3636

3737
// XPT2046_Touchscreen
3838
.cal = { 0, 0, 0, 0, 0, },
@@ -107,6 +107,11 @@ static SPIClass sp_spi = SPIClass(TOUCH_SPI_BUS);
107107
static XPT2046_ScreenPoint sp(TOUCH_CS, TOUCH_IRQ);
108108
#endif
109109

110+
#if defined (XPT2046_Bitbang_h)
111+
#include "boards/XPT2046_ScreenPoint.h"
112+
static XPT2046_ScreenPoint sp(TOUCH_MOSI, TOUCH_MISO, TOUCH_CLK, TOUCH_CS);
113+
#endif
114+
110115
/*--------------------------------------------------------------------------------
111116
* Setup touch manager
112117
*--------------------------------------------------------------------------------*/
@@ -117,6 +122,10 @@ bool touch_setup(void) {
117122
sp.begin(sp_spi, lcd_width, lcd_height, SCREEN_ROTATION);
118123
#endif
119124

125+
#if defined (XPT2046_Bitbang_h)
126+
sp.begin(lcd_width, lcd_height, SCREEN_ROTATION);
127+
#endif
128+
120129
#if USE_PREFERENCES
121130
// Load calibration parameters from FLASH
122131
if (touch_load(&tch_cnf) == false) {
@@ -135,7 +144,7 @@ bool touch_setup(void) {
135144
GFX_EXEC(setTouchCalibrate(tch_cnf.cal));
136145
return true;
137146

138-
#elif defined (_XPT2046_Touchscreen_h_)
147+
#elif defined (_XPT2046_SCREENPOINT_H_)
139148

140149
sp.setTouch(static_cast<const uint16_t*>(tch_cnf.cal));
141150
return true;
@@ -160,15 +169,15 @@ bool touch_event(Touch_t &touch) {
160169
static uint8_t count;
161170
Event_t event = EVENT_NONE;
162171

163-
#if defined (_XPT2046_Touchscreen_h_)
172+
#if defined (_XPT2046_SCREENPOINT_H_)
164173

165174
bool stat = sp.getTouch(&x, &y);
166175

167176
#else // LovyanGFX || TFT_eSPI
168177

169178
bool stat = GFX_EXEC(getTouch(&x, &y));
170179

171-
#endif // _XPT2046_Touchscreen_h_
180+
#endif // _XPT2046_SCREENPOINT_H_
172181

173182
// when state changes, check again after a certain period of time
174183
uint32_t dt = time - prev_time;
@@ -243,7 +252,7 @@ void touch_calibrate(TouchConfig_t *config) {
243252
Serial.begin(115200);
244253
}
245254

246-
#if defined (_XPT2046_Touchscreen_h_)
255+
#if defined (_XPT2046_SCREENPOINT_H_)
247256

248257
extern TFT_eSPI tft;
249258
sp.calibrateTouch(config->cal, &tft, TFT_WHITE, TFT_BLACK);
@@ -306,7 +315,7 @@ void touch_calibrate(TouchConfig_t *config) {
306315
#define RO_MODE true
307316
#define INIT_KEY "initialized"
308317

309-
#if defined (_XPT2046_Touchscreen_h_)
318+
#if defined (_XPT2046_SCREENPOINT_H_)
310319
#define PREF_KEY "XPT2046"
311320
#elif defined (LOVYANGFX_HPP_)
312321
#define PREF_KEY "LovyanGFX"

0 commit comments

Comments
 (0)
Please sign in to comment.