Skip to content

Commit b3a1dcd

Browse files
committed
Added support for Cypress touchscreen on Inkplate 6 FLICK.
1 parent b14609d commit b3a1dcd

File tree

3 files changed

+247
-17
lines changed

3 files changed

+247
-17
lines changed

src/boards/Inkplate6FLICKGen2.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,6 @@
3737
#define TOUCHSCREEN_IO_EXPANDER IO_INT_ADDR
3838
#define TOUCHSCREEN_IO_REGS ioRegsInt
3939

40-
static volatile bool _tsFlag = false;
41-
static void IRAM_ATTR tsInt()
42-
{
43-
_tsFlag = true;
44-
}
45-
4640
#define WAVEFORM3BIT \
4741
{{0, 0, 0, 0, 0, 2, 1, 1, 0}, {0, 0, 2, 1, 1, 1, 2, 1, 0}, {0, 2, 2, 2, 1, 1, 2, 1, 0}, \
4842
{0, 0, 2, 2, 2, 1, 2, 1, 0}, {0, 0, 0, 0, 2, 2, 2, 1, 0}, {0, 0, 2, 1, 2, 1, 1, 2, 0}, \

src/include/TouchCypress.cpp

Lines changed: 232 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
// Macro helpers.
2424
#define TS_GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4)
2525

26+
// Interrupt function callback for Touch Interruput event.
27+
static volatile bool _tsFlag = false;
28+
static void IRAM_ATTR tsInt()
29+
{
30+
_tsFlag = true;
31+
}
32+
2633
/**
2734
* @brief touchInArea checks if touch occured in given rectangle area
2835
*
@@ -39,7 +46,47 @@
3946
*/
4047
bool Touch::touchInArea(int16_t x1, int16_t y1, int16_t w, int16_t h)
4148
{
49+
int16_t x2 = x1 + w, y2 = y1 + h;
50+
if (tsAvailable())
51+
{
52+
uint8_t n;
53+
uint16_t x[2], y[2];
54+
uint8_t z[2];
55+
n = tsGetData(x, y, z);
56+
57+
// Ugh...touchscreen expects to get handshake packet after each interrupt event, but this
58+
// is not possible on EPS32 easly (there should be I2C communication inside ISR). This is a
59+
// workaround; get the X and Y position and wait for 100ms. If multiple INT events have been
60+
// detected, code will wait until no more new INT events have been detected.
61+
unsigned long _tsIntTimeout = millis();
62+
while ((millis() - _tsIntTimeout) < 100ULL)
63+
{
64+
if (_tsFlag)
65+
{
66+
_tsIntTimeout = millis();
67+
_tsFlag = false;
68+
tsHandshake();
69+
}
70+
}
71+
72+
if (n && z[0] > 0)
73+
{
74+
touchT = millis();
75+
touchN = n;
76+
memcpy(touchX, x, 2);
77+
memcpy(touchY, y, 2);
78+
}
79+
}
4280

81+
if (millis() - touchT < 100)
82+
{
83+
if (touchN == 1 && BOUND(x1, touchX[0], x2) && BOUND(y1, touchY[0], y2))
84+
return true;
85+
if (touchN == 2 && ((BOUND(x1, touchX[0], x2) && BOUND(y1, touchY[0], y2)) ||
86+
(BOUND(x1, touchX[1], x2) && BOUND(y1, touchY[1], y2))))
87+
return true;
88+
}
89+
return false;
4390
}
4491

4592
/**
@@ -95,6 +142,9 @@ bool Touch::tsInit(uint8_t _pwrState)
95142
pinMode(TS_INT, INPUT);
96143
attachInterrupt(TS_INT, tsInt, FALLING);
97144

145+
// Wait a little bit.
146+
delay(50);
147+
98148
// Clear the interrpt flag.
99149
_tsFlag = false;
100150
}
@@ -126,7 +176,7 @@ void Touch::tsShutdown()
126176
*/
127177
void Touch::tsGetRawData(uint8_t *b)
128178
{
129-
179+
tsReadI2CRegs(CYPRESS_TOUCH_BASE_ADDR, b, 16);
130180
}
131181

132182
/**
@@ -143,9 +193,188 @@ void Touch::tsGetRawData(uint8_t *b)
143193
* @note touch screen doesn't return data for two fingers when fingers
144194
* are align at the y axis, or one above another
145195
*/
146-
uint8_t Touch::tsGetData(uint16_t *xPos, uint16_t *yPos)
196+
uint8_t Touch::tsGetData(uint16_t *xPos, uint16_t *yPos, uint8_t *z)
147197
{
198+
// Struct typedef for touch data report from the touchscreen controller IC.
199+
struct cypressTouchData _touchReport;
200+
201+
// Check for the null-pointer.
202+
if (xPos == NULL || yPos == NULL) return 0;
203+
204+
// Fill the array with zeros.
205+
xPos[0] = 0;
206+
xPos[1] = 0;
207+
yPos[0] = 0;
208+
yPos[1] = 0;
209+
210+
// Copy Z into array only if array address is passed as argument in function.
211+
if (z != NULL)
212+
{
213+
z[0] = 0;
214+
z[1] = 0;
215+
}
216+
217+
// Check the flag for the new data.
218+
if (!_tsFlag) return 0;
219+
220+
// If there is new data, clear the interrupt flag.
221+
_tsFlag = false;
222+
223+
// Read the new data from the touchscreen controller IC.
224+
// Return zero detected fingers if reading has failed.
225+
if (!tsGetTouchData(&_touchReport)) return 0;
226+
227+
// Scale it to fit the screen.
228+
tsScale(&_touchReport, E_INK_WIDTH - 1, E_INK_HEIGHT - 1, false, true, true);
229+
230+
// Copy values into ararys.
231+
for (int i = 0; i < _touchReport.fingers; i++)
232+
{
233+
// Save values into the arrays.
234+
xPos[i] = _touchReport.x[i];
235+
yPos[i] = _touchReport.y[i];
236+
237+
// Copy Z into array only if array address is passed as argument in function.
238+
if (z != NULL)
239+
{
240+
z[i] = _touchReport.z[i];
241+
}
242+
}
243+
244+
// Rotate it if needed.
245+
// Rotation 0 does not need swapping (defalut rotation).
246+
if (getRotation() != 0)
247+
{
248+
// Temp variable for swap.
249+
uint16_t _temp;
148250

251+
// Check for each finger.
252+
for (int i = 0; i < _touchReport.fingers; i++)
253+
{
254+
switch(getRotation())
255+
{
256+
case 1:
257+
// Rotation clockwise (to the right - aka. portrait mode).
258+
_temp = xPos[i];
259+
xPos[i] = map(yPos[i], 0, E_INK_HEIGHT, 0, E_INK_HEIGHT);
260+
yPos[i] = map(_temp, 0, E_INK_WIDTH - 1, E_INK_WIDTH - 1, 0);
261+
break;
262+
case 2:
263+
// Flipped by 180 deg.
264+
xPos[i] = map(xPos[i], 0, E_INK_WIDTH - 1, E_INK_WIDTH - 1, 0);
265+
yPos[i] = map(yPos[i], 0, E_INK_HEIGHT - 1, E_INK_HEIGHT - 1, 0);
266+
break;
267+
case 3:
268+
// Rotation counter-clockwise from default rotation (90 degs to the left).
269+
_temp = xPos[i];
270+
xPos[i] = map(yPos[i], 0, E_INK_HEIGHT - 1, E_INK_HEIGHT - 1, 0);
271+
yPos[i] = map(_temp, 0, E_INK_WIDTH - 1, 0, E_INK_WIDTH - 1);
272+
break;
273+
}
274+
}
275+
}
276+
277+
// Return number of detected fingers on the touchscreen.
278+
return _touchReport.fingers;
279+
}
280+
281+
/**
282+
* @brief Get the new touch event data from the touchscreen controller.
283+
*
284+
* @param struct cypressTouchData _touchData
285+
* Pointer to the structure for the touch report data (such as X, Y and
286+
* Z values of each touch channel, nuber of fingers etc.)
287+
*
288+
* @return bool
289+
* true - Touch data is successfully read and the data is valid.
290+
* false - Touch data read has failed.
291+
*/
292+
bool Touch::tsGetTouchData(struct cypressTouchData *_touchData)
293+
{
294+
// Check for the null-pointer trap.
295+
if (_touchData == NULL) return false;
296+
297+
// Clear struct for touchscreen data.
298+
memset(_touchData, 0, sizeof(cypressTouchData));
299+
300+
// Buffer for the I2C registers.
301+
uint8_t _regs[32];
302+
303+
// Read registers for the touch data (32 bytes of data).
304+
// If read failed for some reason, return false.
305+
if (!tsReadI2CRegs(CYPRESS_TOUCH_BASE_ADDR, _regs, sizeof(_regs))) return false;
306+
307+
// Send a handshake.
308+
tsHandshake();
309+
310+
// Parse the data!
311+
// Data goes as follows:
312+
// [1 byte] Handshake bit - Must be written back with xor on last MSB bit for TSC knows that INT has been read.
313+
// [1 byte] Something? It changes with every new data. Data is always 0x00, 0x40, 0x80, 0xC0)
314+
// [1 byte] Number of fingers detected - Zero, one or two.
315+
// [2 bytes] X value position of the finger that has been detected first.
316+
// [2 bytes] Y value position of the finger that has been detected first.
317+
// [1 byte] Z value or the presusre os the touch on the first finger.
318+
// [1 byte] Type of detection - 0 or 255 finger released
319+
// [2 bytes] X value position of the finger that has been detected second.
320+
// [2 bytes] Y value position of the finger that has been detected second.
321+
// [1 byte] Z value or the presusre os the touch on the second finger.
322+
_touchData->x[0] = _regs[3] << 8 | _regs[4];
323+
_touchData->y[0] = _regs[5] << 8 | _regs[6];
324+
_touchData->z[0] = _regs[7];
325+
_touchData->x[1] = _regs[9] << 8 | _regs[10];
326+
_touchData->y[1] = _regs[11] << 8 | _regs[12];
327+
_touchData->z[1] = _regs[13];
328+
_touchData->detectionType = _regs[8];
329+
_touchData->fingers = _regs[2];
330+
331+
// Everything went ok? Return true.
332+
return true;
333+
}
334+
335+
/**
336+
* @brief Method scales, flips and swaps X and Y cooridinates to ensure X and Y matches the screen.
337+
*
338+
* @param struct cypressTouchData _touchData
339+
* Defined in cypressTouchTypedefs.h. Filled touch data report.
340+
* @param uint16_t _xSize
341+
* Screen size in pixels for X axis.
342+
* @param uint16_t _ySize
343+
* Screen size in pixels for Y axis.
344+
* @param bool _flipX
345+
* Flip the direction of the X axis.
346+
* @param bool _flipY
347+
* Flip the direction of the Y axis.
348+
* @param bool _swapXY
349+
* Swap X and Y cooridinates.
350+
*/
351+
void Touch::tsScale(struct cypressTouchData *_touchData, uint16_t _xSize, uint16_t _ySize, bool _flipX, bool _flipY, bool _swapXY)
352+
{
353+
// Temp. variables for the mapped value.
354+
uint16_t _mappedX = 0;
355+
uint16_t _mappedY = 0;
356+
357+
// Map both touch channels.
358+
for (int i = 0; i < _touchData->fingers; i++)
359+
{
360+
// Check for the flip.
361+
if (_flipX) _touchData->x[i] = CYPRESS_TOUCH_MAX_X - _touchData->x[i];
362+
if (_flipY) _touchData->y[i] = CYPRESS_TOUCH_MAX_Y - _touchData->y[i];
363+
364+
// Check for X and Y swap.
365+
if (_swapXY)
366+
{
367+
uint16_t _temp = _touchData->x[i];
368+
_touchData->x[i] = _touchData->y[i];
369+
_touchData->y[i] = _temp;
370+
}
371+
372+
// Map X value.
373+
_mappedX = map(_touchData->x[i], 0, CYPRESS_TOUCH_MAX_X, 0, _xSize);
374+
375+
// Map Y value.
376+
_mappedX = map(_touchData->y[i], 0, CYPRESS_TOUCH_MAX_Y, 0, _ySize);
377+
}
149378
}
150379

151380
/**
@@ -195,11 +424,7 @@ uint8_t Touch::tsGetPowerState()
195424
*/
196425
bool Touch::tsAvailable()
197426
{
198-
// Check for the handshake.
199-
if (_tsFlag) tsHandshake();
200-
bool _temp = _tsFlag;
201-
_tsFlag = false;
202-
return _temp;
427+
return _tsFlag;
203428
}
204429

205430

src/include/TouchCypress.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,16 @@ class Touch : virtual public Expander
8282
bool tsAvailable();
8383
void tsSetPowerState(uint8_t _s);
8484
uint8_t tsGetPowerState();
85-
uint8_t tsGetData(uint16_t *xPos, uint16_t *yPos);
85+
uint8_t tsGetData(uint16_t *xPos, uint16_t *yPos, uint8_t *z = NULL);
8686

8787
virtual int getRotation() = 0;
8888

8989
void tsGetRawData(uint8_t *b);
9090

91+
// Do a handshake for Touchscreen Controller to acknowledge successfull touch report read.
92+
// Must be public due interrupts.
93+
void tsHandshake();
94+
9195
private:
9296
// Bootloader struct typedef.
9397
struct cyttspBootloaderData _blData;
@@ -98,6 +102,12 @@ class Touch : virtual public Expander
98102
// Method disables or enables power to the Touchscreen.
99103
void tsPower(bool _pwr);
100104

105+
// Get the new touch event data/report.
106+
bool tsGetTouchData(struct cypressTouchData *_touchData);
107+
108+
// Scale touch data report to fit screen (and also rotation).
109+
void tsScale(struct cypressTouchData *_touchData, uint16_t _xSize, uint16_t _ySize, bool _flipX, bool _flipY, bool _swapXY);
110+
101111
// Disable touchscreen.
102112
void tsEnd();
103113

@@ -122,9 +132,6 @@ class Touch : virtual public Expander
122132
// Try to ping Touchscreen controller via I2C (I2C test).
123133
bool tsPing(int _retries = 5);
124134

125-
// Do a handshake for Touchscreen Controller to acknowledge successfull touch report read.
126-
void tsHandshake();
127-
128135
// Low-level I2C stuff.
129136
// Send command to the Touchscreen Controller via I2C.
130137
bool tsSendCommand(uint8_t _cmd);
@@ -135,6 +142,10 @@ class Touch : virtual public Expander
135142
// Write into Touchscreen Controller registers with I2C by using Arduino Wire library.
136143
bool tsWriteI2CRegs(uint8_t _cmd, uint8_t *_buffer, int _len);
137144

145+
// Used in touchInArea method.
146+
uint8_t touchN;
147+
uint16_t touchX[2], touchY[2];
148+
uint32_t touchT = 0;
138149
};
139150

140151
#endif

0 commit comments

Comments
 (0)