Skip to content

Commit

Permalink
improved touch2046
Browse files Browse the repository at this point in the history
  • Loading branch information
TomSaw committed Sep 14, 2021
1 parent de16c0f commit 8f6dcfa
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 83 deletions.
127 changes: 91 additions & 36 deletions src/modm/driver/touch/touch2046.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// coding: utf-8
/*
* Copyright (c) 2021, Raphael Lehmann
* Copyright (c) 2021, Thomas Sommer
*
* This file is part of the modm project.
*
Expand All @@ -19,16 +20,70 @@

#include <array>
#include <tuple>
#include <modm/ui/graphic/display.hpp>
#include <modm/ui/shape/point.hpp>

namespace modm
{

/// \ingroup modm_driver_touch2046
struct touch2046 {
enum class Orientation {
Normal,
//...
enum class Control : uint8_t
{
START = Bit7, // 1: Marks the control byte

A2 = Bit6, // see enum class ChDiff / ChSingleEnd
A1 = Bit5,
A0 = Bit4,

MODE = Bit3, // see enum class Mode
REF = Bit2, // see enum class Reference

PD1 = Bit1, // see enum class PowerDown
PD0 = Bit0,
};
MODM_FLAGS8(Control);

// Valid when Control::MODE is 0
enum class ChDiff : uint8_t
{
Z1 = int(Control::A0) | int(Control::A1),
Z2 = int(Control::A2),
X = int(Control::A0) | int(Control::A2),
Y = int(Control::A0)
};
typedef Configuration<Control_t, ChDiff, 0b111'0000> ChDiff_t;

// Valid when Control::MODE is 1
enum class ChSingleEnd : uint8_t
{
// TODO see Datasheet P10 Table 1
};
typedef Configuration<Control_t, ChSingleEnd, 0b111'0000> ChSingleEnd_t;

enum class Mode : uint8_t
{
Res_12Bit = 0,
Res_8Bit = int(Control::MODE)
};
typedef Configuration<Control_t, Mode, 0b1, 3> Mode_t;

enum class Reference : uint8_t
{
Differential = 0,
SingleEnded = int(Control::REF)
};
typedef Configuration<Control_t, Reference, 0b1, 2> Reference_t;

enum class PowerDown : uint8_t
{
Auto = 0,
RefOff_AdcOn = int(Control::PD0),
RefOn_AdcOff = int(Control::PD1),
AlwaysOn = int(Control::PD0) | int(Control::PD1)
};
typedef Configuration<Control_t, PowerDown, 0b11, 0> PowerDown_t;


/**
* Calibration values are used to calculate touch point
Expand All @@ -44,33 +99,30 @@ struct touch2046 {
* limited to [0, MaxX]
* Y = (rawY * FactorY / 1000000) + OffsetY
* limited to [0, MaxY]
*
* Orientation (rotation, mirror) are applied after the
* above operations.
*/

struct Calibration
{
int16_t OffsetX = 0;
int16_t OffsetY = 0;
int32_t FactorX = 1'000'000;
int32_t FactorY = 1'000'000;
uint16_t MaxX = 240;
uint16_t MaxY = 320;
uint16_t ThresholdZ = 1500;
Orientation orientation = Orientation::Normal;
};
};

/**
* \ingroup modm_driver_touch2046
* \author Raphael Lehmann
* \author Raphael Lehmann, Thomas Sommer
*
* Datasheet TSC2046: https://www.ti.com/lit/ds/symlink/tsc2046.pdf
*/
template < class SpiMaster, class Cs>
template < class SpiMaster, class Cs, Resolution R>
class Touch2046 : public touch2046, public modm::SpiDevice< SpiMaster >, protected modm::NestedResumable<3>
{
public:
using Orientation = modm::graphic::Orientation;

/**
* Set calibration data
*
Expand All @@ -81,14 +133,6 @@ class Touch2046 : public touch2046, public modm::SpiDevice< SpiMaster >, protect
cal = calibration;
}

/**
* Get raw X, Y and Z values
*
* \return Position and intensity of touch point. Full int16_t range.
*/
modm::ResumableResult<std::tuple<uint16_t,uint16_t,uint16_t>>
getRawValues();

/**
* Is screen touched?
*
Expand All @@ -98,36 +142,47 @@ class Touch2046 : public touch2046, public modm::SpiDevice< SpiMaster >, protect
isTouched();

/**
* Get touch position
* Get touch position as tuple
*
* \return Position (X, Y) of touch point.
*/
modm::ResumableResult<std::tuple<uint16_t,uint16_t>>
getTouchPosition();

/**
* Get touch position as modm::shape::Point
*
* \return Point of touch point.
*/
modm::ResumableResult<modm::shape::Point>
getTouchPoint();

void setOrientation(Orientation orientation)
{ this->orientation = orientation; }

Orientation getOrientation() const
{ return orientation; }

private:
static constexpr uint8_t MeasureZ1 = 0xB1;
static constexpr uint8_t MeasureZ2 = 0xC1;
static constexpr uint8_t MeasureX = 0xD1;
static constexpr uint8_t MeasureY = 0x91;
static constexpr uint8_t Powerdown = 0b1111'1100;
static constexpr std::array<uint8_t, 17> bufferWrite = {
MeasureZ1, 0x00,
MeasureZ2, 0x00,
MeasureY, 0x00,
MeasureX, 0x00,
MeasureY, 0x00,
MeasureX, 0x00,
MeasureY, 0x00,
(MeasureX & Powerdown), 0x00,
0x00};
std::array<uint16_t, 9> bufferRead = {};
modm::ResumableResult<void>
updateZ();

modm::ResumableResult<void>
updateXY();

static constexpr Control_t Measure = Control::START | Mode_t(Mode::Res_12Bit)
| Reference_t(Reference::Differential) | PowerDown_t(PowerDown::RefOff_AdcOn);

std::array<uint16_t, 6> bufferWrite = {};
std::array<uint16_t, 6> bufferRead = {};

uint16_t x = 0;
uint16_t y = 0;
uint16_t z = 0;

Calibration cal;

Orientation orientation = Orientation::Portrait90;
};

} // modm namespace
Expand Down
112 changes: 71 additions & 41 deletions src/modm/driver/touch/touch2046_impl.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// coding: utf-8
/*
* Copyright (c) 2021, Raphael Lehmann
* Copyright (c) 2021, Thomas Sommer
*
* This file is part of the modm project.
*
Expand All @@ -10,70 +11,99 @@
*/
// ----------------------------------------------------------------------------

#ifndef MODM_TOUCH2046_HPP
#error "Don't include this file directly, use 'touch2046.hpp' instead!"
#endif
#pragma once
#include "touch2046.hpp"

#include <modm/math/utils/endianness.hpp>

template < class SpiMaster, class Cs >
modm::ResumableResult<std::tuple<uint16_t,uint16_t,uint16_t>>
modm::Touch2046<SpiMaster, Cs>::getRawValues()
template<class SpiMaster, class Cs, Resolution R>
modm::ResumableResult<void>
modm::Touch2046<SpiMaster, Cs, R>::updateZ()
{
RF_BEGIN();

bufferWrite[0] = (Measure | ChDiff_t(ChDiff::Z1)).value;
bufferWrite[1] = (Measure | ChDiff_t(ChDiff::Z2)).value;
bufferWrite[2] = 0; // not required but cleaner on ossziloscope

RF_WAIT_UNTIL(this->acquireMaster());
Cs::reset();

RF_CALL(SpiMaster::transfer(
bufferWrite.data(),
reinterpret_cast<uint8_t*>(bufferRead.data()) + 1,
17));
RF_CALL(SpiMaster::template transfer<16>(bufferWrite.data(), bufferRead.data(), 3));

z = 4095 + (bufferRead[1] >> 3) - (bufferRead[2] >> 3);

if (this->releaseMaster())
Cs::set();

z = 4095 + (modm::fromBigEndian(bufferRead[1]) >> 3)
- (modm::fromBigEndian(bufferRead[2]) >> 3);
RF_END_RETURN();
}

y = (modm::fromBigEndian(bufferRead[3]) >> 3)
+ (modm::fromBigEndian(bufferRead[5]) >> 3)
+ (modm::fromBigEndian(bufferRead[7]) >> 3);
template<class SpiMaster, class Cs, Resolution R>
modm::ResumableResult<void>
modm::Touch2046<SpiMaster, Cs, R>::updateXY()
{
RF_BEGIN();

bufferWrite[0] = (Measure | ChDiff_t(ChDiff::X)).value;
bufferWrite[1] = (Measure | ChDiff_t(ChDiff::Y)).value;
bufferWrite[2] = (Measure | ChDiff_t(ChDiff::X)).value;
bufferWrite[3] = (Measure | ChDiff_t(ChDiff::Y)).value;
bufferWrite[4] = (Measure | ChDiff_t(ChDiff::X)).value;
bufferWrite[5] = ((Measure | ChDiff_t(ChDiff::Y)) & ~PowerDown_t::mask()).value;

RF_WAIT_UNTIL(this->acquireMaster());
Cs::reset();

x = (modm::fromBigEndian(bufferRead[4]) >> 3)
+ (modm::fromBigEndian(bufferRead[6]) >> 3)
+ (modm::fromBigEndian(bufferRead[8]) >> 3);
RF_CALL(SpiMaster::template transfer<16>(bufferWrite.data(), bufferRead.data(), 6));

if (this->releaseMaster()) {
if (this->releaseMaster())
Cs::set();
}

RF_END_RETURN(std::make_tuple(x, y, z));
x = (bufferRead[1] >> 3) + (bufferRead[3] >> 3) + (bufferRead[5] >> 3);
y = (bufferRead[2] >> 3) + (bufferRead[4] >> 3) + (bufferRead[6] >> 3);

x = std::min<uint16_t>((((uint32_t)(x * cal.FactorX) / 1'000'000) + cal.OffsetX), R.x);
y = std::min<uint16_t>((((uint32_t)(y * cal.FactorY) / 1'000'000) + cal.OffsetY), R.y);

RF_END_RETURN();
}

template < class SpiMaster, class Cs >
template<class SpiMaster, class Cs, Resolution R>
modm::ResumableResult<bool>
modm::Touch2046<SpiMaster, Cs>::isTouched()
modm::Touch2046<SpiMaster, Cs, R>::isTouched()
{
RF_BEGIN();
std::tie(std::ignore, std::ignore, z) = RF_CALL(getRawValues());
RF_CALL(updateZ());
RF_END_RETURN(z > cal.ThresholdZ);
}

template < class SpiMaster, class Cs >
modm::ResumableResult<std::tuple<uint16_t,uint16_t>>
modm::Touch2046<SpiMaster, Cs>::getTouchPosition()
template<class SpiMaster, class Cs, Resolution R>
modm::ResumableResult<modm::shape::Point>
modm::Touch2046<SpiMaster, Cs, R>::getTouchPoint()
{
RF_BEGIN();
RF_CALL(updateXY());
// TODO evaluate orientation & modm::graphic::OrientationFlags::TopDown
if (orientation & modm::graphic::OrientationFlags::Portrait) {
RF_RETURN(modm::shape::Point(x, y));
} else {
RF_RETURN(modm::shape::Point(y, x));
}
RF_END();
}

std::tie(x, y, std::ignore) = RF_CALL(getRawValues());

x = std::min<uint16_t>(
((static_cast<int32_t>(x * cal.FactorX) / 1'000'000)
+ cal.OffsetX),
cal.MaxX);
y = std::min<uint16_t>(
((static_cast<int32_t>(y * cal.FactorY) / 1'000'000)
+ cal.OffsetY),
cal.MaxY);

// todo: orientation processing

RF_END_RETURN(std::make_tuple(x, y));
template<class SpiMaster, class Cs, Resolution R>
modm::ResumableResult<std::tuple<uint16_t, uint16_t>>
modm::Touch2046<SpiMaster, Cs, R>::getTouchPosition()
{
RF_BEGIN();
RF_CALL(updateXY());
// TODO evaluate orientation & modm::graphic::OrientationFlags::TopDown
if (orientation & modm::graphic::OrientationFlags::Portrait) {
RF_RETURN(std::make_tuple(x, y));
} else {
RF_RETURN(std::make_tuple(y, x));
}
RF_END();
}
13 changes: 7 additions & 6 deletions src/modm/ui/graphic/display.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class Display : virtual public Canvas<R>
public:
C color;

Orientation getOrientation() const
{ return orientation; }

int16_t
getWidth() const override
{ return (orientation & OrientationFlags::Portrait) ? R.y : R.x; }
Expand All @@ -67,15 +70,12 @@ class Display : virtual public Canvas<R>
getSize() const override
{ return (orientation & OrientationFlags::Portrait) ? R.swapped() : R; }

Orientation getOrientation() const
{ return orientation; }

protected:
Display(C color) : color(color) {};

Orientation orientation = Orientation::Landscape0;

// Static variables for Resumable Functions required for any Display-type
// Static variables for Resumable Functions
shape::Section clipping;
};

Expand All @@ -86,14 +86,15 @@ class Display<C, R, false> : virtual public Canvas<R>
public:
C color;

Orientation
getOrientation() const { return orientation; }
Orientation getOrientation() const
{ return orientation; }

protected:
Display(C color) : color(color) {};

Orientation orientation = Orientation::Landscape0;

// Static variables for Resumable Functions
shape::Section clipping;
};

Expand Down

0 comments on commit 8f6dcfa

Please sign in to comment.