Skip to content

Commit 2ed0fbb

Browse files
committed
improved touch2046
1 parent de16c0f commit 2ed0fbb

File tree

3 files changed

+179
-88
lines changed

3 files changed

+179
-88
lines changed

src/modm/driver/touch/touch2046.hpp

Lines changed: 111 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// coding: utf-8
22
/*
33
* Copyright (c) 2021, Raphael Lehmann
4+
* Copyright (c) 2021, Thomas Sommer
45
*
56
* This file is part of the modm project.
67
*
@@ -19,58 +20,112 @@
1920

2021
#include <array>
2122
#include <tuple>
23+
#include <modm/ui/graphic/display.hpp>
24+
#include <modm/ui/shape/point.hpp>
2225

2326
namespace modm
2427
{
2528

2629
/// \ingroup modm_driver_touch2046
2730
struct touch2046 {
28-
enum class Orientation {
29-
Normal,
30-
//...
31+
enum class Control : uint8_t
32+
{
33+
START = Bit7, // 1: Marks the control byte
34+
35+
A2 = Bit6, // see enum class ChDiff / ChSingleEnd
36+
A1 = Bit5,
37+
A0 = Bit4,
38+
39+
MODE = Bit3, // see enum class Mode
40+
REF = Bit2, // see enum class Reference
41+
42+
PD1 = Bit1, // see enum class PowerDown
43+
PD0 = Bit0,
44+
};
45+
MODM_FLAGS8(Control);
46+
47+
// Valid when Control::MODE is 0
48+
enum class ChDiff : uint8_t
49+
{
50+
Z1 = int(Control::A0) | int(Control::A1),
51+
Z2 = int(Control::A2),
52+
X = int(Control::A0) | int(Control::A2),
53+
Y = int(Control::A0)
54+
};
55+
typedef Configuration<Control_t, ChDiff, 0b111'0000> ChDiff_t;
56+
57+
// Valid when Control::MODE is 1
58+
enum class ChSingleEnd : uint8_t
59+
{
60+
TEMP0 = 0,
61+
Y = int(Control::A0),
62+
VBAT = int(Control::A1),
63+
Z1 = int(Control::A0) | int(Control::A1),
64+
Z2 = int(Control::A2),
65+
X = int(Control::A0) | int(Control::A2),
66+
AUX = int(Control::A0) | int(Control::A1),
67+
TEMP1 = int(Control::A0) | int(Control::A1) | int(Control::A2)
68+
};
69+
typedef Configuration<Control_t, ChSingleEnd, 0b111'0000> ChSingleEnd_t;
70+
71+
enum class Mode : uint8_t
72+
{
73+
Res_12Bit = 0,
74+
Res_8Bit = int(Control::MODE)
75+
};
76+
typedef Configuration<Control_t, Mode, 0b1, 3> Mode_t;
77+
78+
enum class Reference : uint8_t
79+
{
80+
Differential = 0,
81+
SingleEnded = int(Control::REF)
82+
};
83+
typedef Configuration<Control_t, Reference, 0b1, 2> Reference_t;
84+
85+
enum class PowerDown : uint8_t
86+
{
87+
Auto = 0,
88+
RefOff_AdcOn = int(Control::PD0),
89+
RefOn_AdcOff = int(Control::PD1),
90+
AlwaysOn = int(Control::PD0) | int(Control::PD1)
3191
};
92+
typedef Configuration<Control_t, PowerDown, 0b11, 0> PowerDown_t;
93+
3294

3395
/**
3496
* Calibration values are used to calculate touch point
3597
* from raw values.
3698
*
37-
* \ref FactorX and \ref FactorY scaled by 1000000 to avoid float
38-
* arithmetic. E.g. to get a factor of 0.75 \ref FactorX has to be
39-
* set to 750'000.
40-
*
4199
* isTouched() = bool(Z > ThresholdZ)
42100
*
43101
* X = (rawX * FactorX / 1000000) + OffsetX
44102
* limited to [0, MaxX]
45103
* Y = (rawY * FactorY / 1000000) + OffsetY
46104
* limited to [0, MaxY]
47-
*
48-
* Orientation (rotation, mirror) are applied after the
49-
* above operations.
50105
*/
106+
51107
struct Calibration
52108
{
109+
int32_t FactorX = 24;
53110
int16_t OffsetX = 0;
111+
int32_t FactorY = 24;
54112
int16_t OffsetY = 0;
55-
int32_t FactorX = 1'000'000;
56-
int32_t FactorY = 1'000'000;
57-
uint16_t MaxX = 240;
58-
uint16_t MaxY = 320;
59-
uint16_t ThresholdZ = 1500;
60-
Orientation orientation = Orientation::Normal;
113+
uint16_t ThresholdZ = 1000;
61114
};
62115
};
63116

64117
/**
65118
* \ingroup modm_driver_touch2046
66-
* \author Raphael Lehmann
119+
* \author Raphael Lehmann, Thomas Sommer
67120
*
68121
* Datasheet TSC2046: https://www.ti.com/lit/ds/symlink/tsc2046.pdf
69122
*/
70-
template < class SpiMaster, class Cs>
123+
template < class SpiMaster, class Cs, Resolution R>
71124
class Touch2046 : public touch2046, public modm::SpiDevice< SpiMaster >, protected modm::NestedResumable<3>
72125
{
73126
public:
127+
using Orientation = modm::graphic::Orientation;
128+
74129
/**
75130
* Set calibration data
76131
*
@@ -81,14 +136,6 @@ class Touch2046 : public touch2046, public modm::SpiDevice< SpiMaster >, protect
81136
cal = calibration;
82137
}
83138

84-
/**
85-
* Get raw X, Y and Z values
86-
*
87-
* \return Position and intensity of touch point. Full int16_t range.
88-
*/
89-
modm::ResumableResult<std::tuple<uint16_t,uint16_t,uint16_t>>
90-
getRawValues();
91-
92139
/**
93140
* Is screen touched?
94141
*
@@ -98,36 +145,57 @@ class Touch2046 : public touch2046, public modm::SpiDevice< SpiMaster >, protect
98145
isTouched();
99146

100147
/**
101-
* Get touch position
148+
* Get touch position as tuple
102149
*
103150
* \return Position (X, Y) of touch point.
104151
*/
105152
modm::ResumableResult<std::tuple<uint16_t,uint16_t>>
106153
getTouchPosition();
107154

155+
/**
156+
* Get touch position as modm::shape::Point
157+
*
158+
* \return Point of touch point.
159+
*/
160+
modm::ResumableResult<modm::shape::Point>
161+
getTouchPoint();
162+
163+
void setOrientation(Orientation orientation)
164+
{ this->orientation = orientation; }
165+
166+
Orientation getOrientation() const
167+
{ return orientation; }
168+
108169
private:
109-
static constexpr uint8_t MeasureZ1 = 0xB1;
110-
static constexpr uint8_t MeasureZ2 = 0xC1;
111-
static constexpr uint8_t MeasureX = 0xD1;
112-
static constexpr uint8_t MeasureY = 0x91;
113-
static constexpr uint8_t Powerdown = 0b1111'1100;
114-
static constexpr std::array<uint8_t, 17> bufferWrite = {
115-
MeasureZ1, 0x00,
116-
MeasureZ2, 0x00,
117-
MeasureY, 0x00,
118-
MeasureX, 0x00,
119-
MeasureY, 0x00,
120-
MeasureX, 0x00,
121-
MeasureY, 0x00,
122-
(MeasureX & Powerdown), 0x00,
123-
0x00};
124-
std::array<uint16_t, 9> bufferRead = {};
170+
modm::ResumableResult<void>
171+
updateZ();
172+
173+
modm::ResumableResult<void>
174+
updateXY();
175+
176+
static constexpr Control_t Measure = Control::START | Mode_t(Mode::Res_12Bit)
177+
| Reference_t(Reference::Differential) | PowerDown_t(PowerDown::RefOff_AdcOn);
178+
179+
static constexpr std::array<uint16_t, 8> bufferWrite = {
180+
(Measure | ChDiff_t(ChDiff::Z1)).value,
181+
((Measure | ChDiff_t(ChDiff::Z2)) & ~PowerDown_t::mask()).value,
182+
(Measure | ChDiff_t(ChDiff::X)).value,
183+
(Measure | ChDiff_t(ChDiff::Y)).value,
184+
(Measure | ChDiff_t(ChDiff::X)).value,
185+
(Measure | ChDiff_t(ChDiff::Y)).value,
186+
(Measure | ChDiff_t(ChDiff::X)).value,
187+
((Measure | ChDiff_t(ChDiff::Y)) & ~PowerDown_t::mask()).value
188+
};
189+
std::array<uint16_t, 7> bufferRead = {};
125190

191+
public:
126192
uint16_t x = 0;
127193
uint16_t y = 0;
128194
uint16_t z = 0;
129195

130196
Calibration cal;
197+
198+
Orientation orientation = Orientation::Portrait90;
131199
};
132200

133201
} // modm namespace
Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// coding: utf-8
22
/*
33
* Copyright (c) 2021, Raphael Lehmann
4+
* Copyright (c) 2021, Thomas Sommer
45
*
56
* This file is part of the modm project.
67
*
@@ -10,70 +11,91 @@
1011
*/
1112
// ----------------------------------------------------------------------------
1213

13-
#ifndef MODM_TOUCH2046_HPP
14-
#error "Don't include this file directly, use 'touch2046.hpp' instead!"
15-
#endif
14+
#pragma once
15+
#include "touch2046.hpp"
1616

17+
#include <modm/math/utils/endianness.hpp>
1718

18-
template < class SpiMaster, class Cs >
19-
modm::ResumableResult<std::tuple<uint16_t,uint16_t,uint16_t>>
20-
modm::Touch2046<SpiMaster, Cs>::getRawValues()
19+
template<class SpiMaster, class Cs, Resolution R>
20+
modm::ResumableResult<void>
21+
modm::Touch2046<SpiMaster, Cs, R>::updateZ()
2122
{
2223
RF_BEGIN();
2324

2425
RF_WAIT_UNTIL(this->acquireMaster());
2526
Cs::reset();
2627

27-
RF_CALL(SpiMaster::transfer(
28-
bufferWrite.data(),
29-
reinterpret_cast<uint8_t*>(bufferRead.data()) + 1,
30-
17));
28+
RF_CALL(SpiMaster::template transfer<16>(&bufferWrite[0], &bufferRead[0], 3));
3129

32-
z = 4095 + (modm::fromBigEndian(bufferRead[1]) >> 3)
33-
- (modm::fromBigEndian(bufferRead[2]) >> 3);
30+
z = 4095 + (bufferRead[1] >> 3) - (bufferRead[2] >> 3);
3431

35-
y = (modm::fromBigEndian(bufferRead[3]) >> 3)
36-
+ (modm::fromBigEndian(bufferRead[5]) >> 3)
37-
+ (modm::fromBigEndian(bufferRead[7]) >> 3);
32+
if (this->releaseMaster())
33+
Cs::set();
34+
35+
RF_END_RETURN();
36+
}
37+
38+
template<class SpiMaster, class Cs, Resolution R>
39+
modm::ResumableResult<void>
40+
modm::Touch2046<SpiMaster, Cs, R>::updateXY()
41+
{
42+
RF_BEGIN();
43+
44+
RF_WAIT_UNTIL(this->acquireMaster());
45+
Cs::reset();
3846

39-
x = (modm::fromBigEndian(bufferRead[4]) >> 3)
40-
+ (modm::fromBigEndian(bufferRead[6]) >> 3)
41-
+ (modm::fromBigEndian(bufferRead[8]) >> 3);
47+
RF_CALL(SpiMaster::template transfer<16>(&bufferWrite[2], &bufferRead[0], bufferRead.size()));
4248

43-
if (this->releaseMaster()) {
49+
if (this->releaseMaster())
4450
Cs::set();
45-
}
4651

47-
RF_END_RETURN(std::make_tuple(x, y, z));
52+
x = (bufferRead[1] >> 3) + (bufferRead[3] >> 3) + (bufferRead[5] >> 3);
53+
y = (bufferRead[2] >> 3) + (bufferRead[4] >> 3) + (bufferRead[6] >> 3);
54+
55+
static constexpr int scale_shift = 10;
56+
x = std::clamp<int16_t>((((uint32_t)(x * cal.FactorX) >> scale_shift) + cal.OffsetX), 0, R.x);
57+
y = std::clamp<int16_t>((((uint32_t)(y * cal.FactorY) >> scale_shift) + cal.OffsetY), 0, R.y);
58+
59+
RF_END_RETURN();
4860
}
4961

50-
template < class SpiMaster, class Cs >
62+
template<class SpiMaster, class Cs, Resolution R>
5163
modm::ResumableResult<bool>
52-
modm::Touch2046<SpiMaster, Cs>::isTouched()
64+
modm::Touch2046<SpiMaster, Cs, R>::isTouched()
5365
{
5466
RF_BEGIN();
55-
std::tie(std::ignore, std::ignore, z) = RF_CALL(getRawValues());
67+
RF_CALL(updateZ());
5668
RF_END_RETURN(z > cal.ThresholdZ);
5769
}
5870

59-
template < class SpiMaster, class Cs >
60-
modm::ResumableResult<std::tuple<uint16_t,uint16_t>>
61-
modm::Touch2046<SpiMaster, Cs>::getTouchPosition()
71+
template<class SpiMaster, class Cs, Resolution R>
72+
modm::ResumableResult<modm::shape::Point>
73+
modm::Touch2046<SpiMaster, Cs, R>::getTouchPoint()
6274
{
6375
RF_BEGIN();
76+
RF_CALL(updateXY());
6477

65-
std::tie(x, y, std::ignore) = RF_CALL(getRawValues());
66-
67-
x = std::min<uint16_t>(
68-
((static_cast<int32_t>(x * cal.FactorX) / 1'000'000)
69-
+ cal.OffsetX),
70-
cal.MaxX);
71-
y = std::min<uint16_t>(
72-
((static_cast<int32_t>(y * cal.FactorY) / 1'000'000)
73-
+ cal.OffsetY),
74-
cal.MaxY);
78+
switch(orientation) {
79+
case Orientation::Landscape0: RF_RETURN(Point(R.y - y, R.x - x));
80+
case Orientation::Portrait90: RF_RETURN(Point(x, R.y - y));
81+
case Orientation::Landscape180: RF_RETURN(Point(y, x));
82+
case Orientation::Portrait270: RF_RETURN(Point(R.x - x, y));
83+
}
7584

76-
// todo: orientation processing
85+
RF_END();
86+
}
7787

78-
RF_END_RETURN(std::make_tuple(x, y));
88+
template<class SpiMaster, class Cs, Resolution R>
89+
modm::ResumableResult<std::tuple<uint16_t, uint16_t>>
90+
modm::Touch2046<SpiMaster, Cs, R>::getTouchPosition()
91+
{
92+
RF_BEGIN();
93+
RF_CALL(updateXY());
94+
// TODO evaluate orientation & modm::graphic::OrientationFlags::TopDown
95+
if (orientation & modm::graphic::OrientationFlags::Portrait) {
96+
RF_RETURN(std::make_tuple(x, y));
97+
} else {
98+
RF_RETURN(std::make_tuple(y, x));
99+
}
100+
RF_END();
79101
}

0 commit comments

Comments
 (0)