/ adafruit_stmpe610.py
adafruit_stmpe610.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2017 Jerry Needell
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  """
 23  `adafruit_stmpe610`
 24  ====================================================
 25  
 26  This is a CircuitPython Driver for the STMPE610 Resistive Touch sensor
 27  
 28  * Author(s): Jerry Needell
 29  """
 30  
 31  # imports
 32  
 33  import time
 34  from micropython import const
 35  
 36  
 37  __version__ = "0.0.0-auto.0"
 38  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_STMPE610.git"
 39  
 40  
 41  _STMPE_ADDR = const(0x41)
 42  _STMPE_VERSION = const(0x0811)
 43  
 44  _STMPE_SYS_CTRL1 = const(0x03)
 45  _STMPE_SYS_CTRL1_RESET = const(0x02)
 46  _STMPE_SYS_CTRL2 = const(0x04)
 47  
 48  _STMPE_TSC_CTRL = const(0x40)
 49  _STMPE_TSC_CTRL_EN = const(0x01)
 50  _STMPE_TSC_CTRL_XYZ = const(0x00)
 51  _STMPE_TSC_CTRL_XY = const(0x02)
 52  
 53  _STMPE_INT_CTRL = const(0x09)
 54  _STMPE_INT_CTRL_POL_HIGH = const(0x04)
 55  _STMPE_INT_CTRL_POL_LOW = const(0x00)
 56  _STMPE_INT_CTRL_EDGE = const(0x02)
 57  _STMPE_INT_CTRL_LEVEL = const(0x00)
 58  _STMPE_INT_CTRL_ENABLE = const(0x01)
 59  _STMPE_INT_CTRL_DISABLE = const(0x00)
 60  
 61  
 62  _STMPE_INT_EN = const(0x0A)
 63  _STMPE_INT_EN_TOUCHDET = const(0x01)
 64  _STMPE_INT_EN_FIFOTH = const(0x02)
 65  _STMPE_INT_EN_FIFOOF = const(0x04)
 66  _STMPE_INT_EN_FIFOFULL = const(0x08)
 67  _STMPE_INT_EN_FIFOEMPTY = const(0x10)
 68  _STMPE_INT_EN_ADC = const(0x40)
 69  _STMPE_INT_EN_GPIO = const(0x80)
 70  
 71  _STMPE_INT_STA = const(0x0B)
 72  _STMPE_INT_STA_TOUCHDET = const(0x01)
 73  
 74  _STMPE_ADC_CTRL1 = const(0x20)
 75  _STMPE_ADC_CTRL1_12BIT = const(0x08)
 76  _STMPE_ADC_CTRL1_10BIT = const(0x00)
 77  
 78  _STMPE_ADC_CTRL2 = const(0x21)
 79  _STMPE_ADC_CTRL2_1_625MHZ = const(0x00)
 80  _STMPE_ADC_CTRL2_3_25MHZ = const(0x01)
 81  _STMPE_ADC_CTRL2_6_5MHZ = const(0x02)
 82  
 83  _STMPE_TSC_CFG = const(0x41)
 84  _STMPE_TSC_CFG_1SAMPLE = const(0x00)
 85  _STMPE_TSC_CFG_2SAMPLE = const(0x40)
 86  _STMPE_TSC_CFG_4SAMPLE = const(0x80)
 87  _STMPE_TSC_CFG_8SAMPLE = const(0xC0)
 88  _STMPE_TSC_CFG_DELAY_10US = const(0x00)
 89  _STMPE_TSC_CFG_DELAY_50US = const(0x08)
 90  _STMPE_TSC_CFG_DELAY_100US = const(0x10)
 91  _STMPE_TSC_CFG_DELAY_500US = const(0x18)
 92  _STMPE_TSC_CFG_DELAY_1MS = const(0x20)
 93  _STMPE_TSC_CFG_DELAY_5MS = const(0x28)
 94  _STMPE_TSC_CFG_DELAY_10MS = const(0x30)
 95  _STMPE_TSC_CFG_DELAY_50MS = const(0x38)
 96  _STMPE_TSC_CFG_SETTLE_10US = const(0x00)
 97  _STMPE_TSC_CFG_SETTLE_100US = const(0x01)
 98  _STMPE_TSC_CFG_SETTLE_500US = const(0x02)
 99  _STMPE_TSC_CFG_SETTLE_1MS = const(0x03)
100  _STMPE_TSC_CFG_SETTLE_5MS = const(0x04)
101  _STMPE_TSC_CFG_SETTLE_10MS = const(0x05)
102  _STMPE_TSC_CFG_SETTLE_50MS = const(0x06)
103  _STMPE_TSC_CFG_SETTLE_100MS = const(0x07)
104  
105  _STMPE_FIFO_TH = const(0x4A)
106  
107  _STMPE_FIFO_SIZE = const(0x4C)
108  
109  _STMPE_FIFO_STA = const(0x4B)
110  _STMPE_FIFO_STA_RESET = const(0x01)
111  _STMPE_FIFO_STA_OFLOW = const(0x80)
112  _STMPE_FIFO_STA_FULL = const(0x40)
113  _STMPE_FIFO_STA_EMPTY = const(0x20)
114  _STMPE_FIFO_STA_THTRIG = const(0x10)
115  
116  _STMPE_TSC_I_DRIVE = const(0x58)
117  _STMPE_TSC_I_DRIVE_20MA = const(0x00)
118  _STMPE_TSC_I_DRIVE_50MA = const(0x01)
119  
120  _STMPE_TSC_DATA_X = const(0x4D)
121  _STMPE_TSC_DATA_Y = const(0x4F)
122  _STMPE_TSC_FRACTION_Z = const(0x56)
123  
124  _STMPE_GPIO_SET_PIN = const(0x10)
125  _STMPE_GPIO_CLR_PIN = const(0x11)
126  _STMPE_GPIO_DIR = const(0x13)
127  _STMPE_GPIO_ALT_FUNCT = const(0x17)
128  
129  
130  class Adafruit_STMPE610:
131      """
132      A driver for the STMPE610 Resistive Touch sensor.
133      """
134  
135      def __init__(self):
136          """Reset the controller"""
137          self._write_register_byte(_STMPE_SYS_CTRL1, _STMPE_SYS_CTRL1_RESET)
138          time.sleep(0.001)
139  
140          self._write_register_byte(_STMPE_SYS_CTRL2, 0x0)  # turn on clocks!
141          self._write_register_byte(
142              _STMPE_TSC_CTRL, _STMPE_TSC_CTRL_XYZ | _STMPE_TSC_CTRL_EN
143          )  # XYZ and enable!
144          self._write_register_byte(_STMPE_INT_EN, _STMPE_INT_EN_TOUCHDET)
145          self._write_register_byte(
146              _STMPE_ADC_CTRL1, _STMPE_ADC_CTRL1_10BIT | (0x6 << 4)
147          )  # 96 clocks per conversion
148          self._write_register_byte(_STMPE_ADC_CTRL2, _STMPE_ADC_CTRL2_6_5MHZ)
149          self._write_register_byte(
150              _STMPE_TSC_CFG,
151              _STMPE_TSC_CFG_4SAMPLE
152              | _STMPE_TSC_CFG_DELAY_1MS
153              | _STMPE_TSC_CFG_SETTLE_5MS,
154          )
155          self._write_register_byte(_STMPE_TSC_FRACTION_Z, 0x6)
156          self._write_register_byte(_STMPE_FIFO_TH, 1)
157          self._write_register_byte(_STMPE_FIFO_STA, _STMPE_FIFO_STA_RESET)
158          self._write_register_byte(_STMPE_FIFO_STA, 0)  # unreset
159          self._write_register_byte(_STMPE_TSC_I_DRIVE, _STMPE_TSC_I_DRIVE_50MA)
160          self._write_register_byte(_STMPE_INT_STA, 0xFF)  # reset all ints
161          self._write_register_byte(
162              _STMPE_INT_CTRL, _STMPE_INT_CTRL_POL_HIGH | _STMPE_INT_CTRL_ENABLE
163          )
164  
165      def read_data(self):
166          """Request next stored reading - return tuple containing  (x,y,pressure) """
167          d_1 = self._read_byte(0xD7)
168          d_2 = self._read_byte(0xD7)
169          d_3 = self._read_byte(0xD7)
170          d_4 = self._read_byte(0xD7)
171          x_loc = d_1 << 4 | d_2 >> 4
172          y_loc = (d_2 & 0xF) << 8 | d_3
173          pressure = d_4
174          # reset all ints  (not sure what this does)
175          if self.buffer_empty:
176              self._write_register_byte(_STMPE_INT_STA, 0xFF)
177          return (x_loc, y_loc, pressure)
178  
179      def _read_byte(self, register):
180          """Read a byte register value and return it"""
181          return self._read_register(register, 1)[0]
182  
183      def _read_register(self, register, length):
184          # Read an arbitrarily long register (specified by length number of
185          # bytes) and return a bytearray of the retrieved data.
186          # Subclasses MUST implement this!
187          raise NotImplementedError
188  
189      def _write_register_byte(self, register, value):
190          # Write a single byte register at the specified register address.
191          # Subclasses MUST implement this!
192          raise NotImplementedError
193  
194      @property
195      def touches(self):
196          """
197          Returns a list of touchpoint dicts, with 'x' and 'y' containing the
198          touch coordinates, and 'pressure'
199          """
200          touchpoints = []
201          while (len(touchpoints) < 4) and not self.buffer_empty:
202              (x_loc, y_loc, pressure) = self.read_data()
203              point = {"x": x_loc, "y": y_loc, "pressure": pressure}
204              touchpoints.append(point)
205          return touchpoints
206  
207      @property
208      def get_version(self):
209          "Read the version number from the sensosr"
210          v_1 = self._read_byte(0)
211          v_2 = self._read_byte(1)
212          version = v_1 << 8 | v_2
213          # print("version ",hex(version))
214          return version
215  
216      @property
217      def touched(self):
218          "Report if any touches have been detectd"
219          touch = self._read_byte(_STMPE_TSC_CTRL) & 0x80
220          return touch == 0x80
221  
222      @property
223      def buffer_size(self):
224          "The amount of touch data in the buffer"
225          return self._read_byte(_STMPE_FIFO_SIZE)
226  
227      @property
228      def buffer_empty(self):
229          "Buffer empty status"
230          empty = self._read_byte(_STMPE_FIFO_STA) & _STMPE_FIFO_STA_EMPTY
231          return empty != 0
232  
233      @property
234      def get_point(self):
235          "Read one touch from the buffer"
236          (x_loc, y_loc, pressure) = self.read_data()
237          point = {"x": x_loc, "y": y_loc, "pressure": pressure}
238          return point
239  
240  
241  class Adafruit_STMPE610_I2C(Adafruit_STMPE610):
242      """
243      I2C driver for the STMPE610 Resistive Touch sensor.
244      """
245  
246      def __init__(self, i2c, address=_STMPE_ADDR):
247          """
248          Check the STMPE610 was founnd
249          Default address is 0x41 but another address can be passed in as an argument
250          """
251          import adafruit_bus_device.i2c_device as i2cdev  # pylint: disable=import-outside-toplevel
252  
253          self._i2c = i2cdev.I2CDevice(i2c, address)
254          # Check device version.
255          version = self.get_version
256          if _STMPE_VERSION != version:
257              raise RuntimeError("Failed to find STMPE610! Chip Version 0x%x" % version)
258          super().__init__()
259  
260      def _read_register(self, register, length):
261          """Low level register reading over I2C, returns a list of values"""
262          with self._i2c as i2c:
263              i2c.write(bytearray([register & 0xFF]))
264              result = bytearray(length)
265              i2c.readinto(result)
266              # print("$%02X => %s" % (register, [hex(i) for i in result]))
267              return result
268  
269      def _write_register_byte(self, register, value):
270          """Low level register writing over I2C, writes one 8-bit value"""
271          with self._i2c as i2c:
272              i2c.write(bytes([register & 0xFF, value & 0xFF]))
273              # print("$%02X <= 0x%02X" % (register, value))
274  
275  
276  class Adafruit_STMPE610_SPI(Adafruit_STMPE610):
277      """
278      SPI driver for the STMPE610 Resistive Touch sensor.
279      """
280  
281      def __init__(self, spi, cs, baudrate=1000000):
282          """
283          Check the STMPE610 was found,Default clock rate 1000000 - can be changed with 'baudrate'
284          """
285          import adafruit_bus_device.spi_device as spidev  # pylint: disable=import-outside-toplevel
286  
287          self._spi = spidev.SPIDevice(spi, cs, baudrate=baudrate)
288          # Check device version.
289          version = self.get_version
290          if _STMPE_VERSION != version:
291              # if it fails try SPI MODE 1  -- that is what Arduino does
292              self._spi = spidev.SPIDevice(
293                  spi, cs, baudrate=baudrate, polarity=0, phase=1
294              )
295              version = self.get_version
296              if _STMPE_VERSION != version:
297                  raise RuntimeError(
298                      "Failed to find STMPE610! Chip Version 0x%x" % version
299                  )
300          super().__init__()
301  
302      # pylint: disable=no-member
303      # Disable should be reconsidered when refactor can be tested.
304      def _read_register(self, register, length):
305          """Low level register reading over SPI, returns a list of values"""
306          register = (register | 0x80) & 0xFF  # Read single, bit 7 high.
307          with self._spi as spi:
308              spi.write(bytearray([register]))
309              result = bytearray(length)
310              spi.readinto(result)
311              #            print("$%02X => %s" % (register, [hex(i) for i in result]))
312              return result
313  
314      def _write_register_byte(self, register, value):
315          """Low level register writing over SPI, writes one 8-bit value"""
316          register &= 0x7F  # Write, bit 7 low.
317          with self._spi as spi:
318              spi.write(bytes([register, value & 0xFF]))