Skip to content

Commit f5fa2c5

Browse files
committed
added tap detection. Couldn't make latching work
1 parent 110cca4 commit f5fa2c5

File tree

2 files changed

+116
-8
lines changed

2 files changed

+116
-8
lines changed

adafruit_msa301.py

Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@
4848
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MSA301.git"
4949

5050
import struct
51+
5152
from micropython import const
5253
from adafruit_register.i2c_struct import ROUnaryStruct
5354
from adafruit_register.i2c_bit import RWBit
5455
from adafruit_register.i2c_bits import RWBits, ROBits
5556
import adafruit_bus_device.i2c_device as i2cdevice
57+
5658
_MSA301_I2CADDR_DEFAULT = const(0x26)
5759

5860
_MSA301_REG_PARTID = const(0x01)
@@ -64,7 +66,6 @@
6466
_MSA301_REG_OUT_Z_H = const(0x07)
6567
_MSA301_REG_MOTIONINT = const(0x09)
6668
_MSA301_REG_DATAINT = const(0x0A)
67-
_MSA301_REG_CLICKSTATUS = const(0x0B)
6869
_MSA301_REG_RESRANGE = const(0x0F)
6970
_MSA301_REG_ODR = const(0x10)
7071
_MSA301_REG_POWERMODE = const(0x11)
@@ -177,7 +178,20 @@ class Resolution: # pylint: disable=too-few-public-methods
177178
RESOLUTION_10_BIT = 0b10
178179
RESOLUTION_8_BIT = 0b11
179180

180-
class MSA301:
181+
class TapDuration: #pylint: disable=too-few-public-methods,too-many-instance-attributes
182+
"""An enum-like class representing the options for the "double_tap_window" parameter of
183+
`enable_tap_detection`"""
184+
DURATION_50_MS = 0b000 #< 50 millis
185+
DURATION_100_MS = 0b001 #< 100 millis
186+
DURATION_150_MS = 0b010 #< 150 millis
187+
DURATION_200_MS = 0b011 #< 200 millis
188+
DURATION_250_MS = 0b100 #< 250 millis
189+
DURATION_375_MS = 0b101 #< 375 millis
190+
DURATION_500_MS = 0b110 #< 500 millis
191+
DURATION_700_MS = 0b111 #< 50 millis700 millis
192+
193+
194+
class MSA301:#pylint: disable=too-many-instance-attributes
181195
"""Driver for the MSA301 Accelerometer.
182196
183197
:param ~busio.I2C i2c_bus: The I2C bus the MSA is connected to.
@@ -197,23 +211,31 @@ def __init__(self, i2c_bus):
197211
self.bandwidth = BandWidth.WIDTH_250_HZ
198212
self.range = Range.RANGE_4_G
199213
self.resolution = Resolution.RESOLUTION_14_BIT
200-
201-
214+
self._tap_count = 0
202215

203216
_disable_x = RWBit(_MSA301_REG_ODR, 7)
204217
_disable_y = RWBit(_MSA301_REG_ODR, 6)
205218
_disable_z = RWBit(_MSA301_REG_ODR, 5)
206219

207220
_xyz_raw = ROBits(48, _MSA301_REG_OUT_X_L, 0, 6)
208221

209-
power_mode = RWBits(2, _MSA301_REG_POWERMODE, 6)
222+
# tap INT enable and status
223+
_single_tap_int_en = RWBit(_MSA301_REG_INTSET0, 5)
224+
_double_tap_int_en = RWBit(_MSA301_REG_INTSET0, 4)
225+
_motion_int_status = ROUnaryStruct(_MSA301_REG_MOTIONINT, "B")
210226

211-
bandwidth = RWBits(4, _MSA301_REG_POWERMODE, 1)
227+
# tap interrupt knobs
228+
_tap_quiet = RWBit(_MSA301_REG_TAPDUR, 7)
229+
_tap_shock = RWBit(_MSA301_REG_TAPDUR, 6)
230+
_tap_duration = RWBits(3, _MSA301_REG_TAPDUR, 0)
231+
_tap_threshold = RWBits(5, _MSA301_REG_TAPTH, 0)
232+
reg_tapdur = ROUnaryStruct(_MSA301_REG_TAPDUR, "B")
212233

234+
# general settings knobs
235+
power_mode = RWBits(2, _MSA301_REG_POWERMODE, 6)
236+
bandwidth = RWBits(4, _MSA301_REG_POWERMODE, 1)
213237
data_rate = RWBits(4, _MSA301_REG_ODR, 0)
214-
215238
range = RWBits(2, _MSA301_REG_RESRANGE, 0)
216-
217239
resolution = RWBits(2, _MSA301_REG_RESRANGE, 2)
218240

219241
@property
@@ -248,3 +270,74 @@ def acceleration(self):
248270
z_acc = ((z>>2) / scale) * _STANDARD_GRAVITY
249271

250272
return (x_acc, y_acc, z_acc)
273+
274+
def enable_tap_detection(self, *,
275+
tap_count=1,
276+
threshold=25,
277+
long_initial_window=True,
278+
long_quiet_window=True,
279+
double_tap_window=TapDuration.DURATION_250_MS):
280+
"""
281+
Enables tap detection with configurable parameters.
282+
283+
:param int tap_count: 1 to detect only single taps, or 2 to detect only double taps.\
284+
default is 1
285+
286+
:param int threshold: A threshold for the tap detection.\
287+
The higher the value the less sensitive the detection. This changes based on the\
288+
accelerometer range. Default is 25.
289+
290+
:param int long_initial_window: This sets the length of the window of time where a\
291+
spike in acceleration must occour in before being followed by a quiet period.\
292+
`True` (default) sets the value to 70ms, False to 50ms. Default is `True`
293+
294+
:param int long_quiet_window: The length of the "quiet" period after an acceleration\
295+
spike where no more spikes can occour for a tap to be registered.\
296+
`True` (default) sets the value to 30ms, False to 20ms. Default is `True`.
297+
298+
:param int double_tap_window: The length of time after an initial tap is registered\
299+
in which a second tap must be detected to count as a double tap. Setting a lower\
300+
value will require a faster double tap. The value must be a\
301+
``TapDuration``. Default is ``TapDuration.DURATION_250_MS``.
302+
303+
If you wish to set them yourself rather than using the defaults,
304+
you must use keyword arguments::
305+
306+
msa.enable_tap_detection(tap_count=2,
307+
threshold=25,
308+
double_tap_window=TapDuration.DURATION_700_MS)
309+
310+
"""
311+
self._tap_shock = not long_initial_window
312+
self._tap_quiet = long_quiet_window
313+
self._tap_threshold = threshold
314+
self._tap_count = tap_count
315+
316+
if double_tap_window > 7 or double_tap_window < 0:
317+
raise ValueError("double_tap_window must be a TapDuration")
318+
if tap_count == 1:
319+
self._single_tap_int_en = True
320+
elif tap_count == 2:
321+
self._tap_duration = double_tap_window
322+
self._double_tap_int_en = True
323+
else:
324+
raise ValueError("tap must be 1 for single tap, or 2 for double tap")
325+
326+
@property
327+
def tapped(self):
328+
"""`True` if a single or double tap was detected, depending on the value of the\
329+
``tap_count`` argument passed to ``enable_tap_detection``"""
330+
if self._tap_count == 0:
331+
return False
332+
333+
motion_int_status = self._motion_int_status
334+
335+
if motion_int_status == 0: # no interrupts triggered
336+
return False
337+
338+
if self._tap_count == 1 and motion_int_status & 1<<5:
339+
return True
340+
if self._tap_count == 2 and motion_int_status & 1<<4:
341+
return True
342+
343+
return False

examples/tap_example.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import time
2+
import board
3+
import busio
4+
import adafruit_msa301
5+
6+
i2c = busio.I2C(board.SCL, board.SDA)
7+
8+
msa = adafruit_msa301.MSA301(i2c)
9+
10+
msa.enable_tap_detection()
11+
12+
while True:
13+
if msa.tapped:
14+
print("Single Tap!")
15+
time.sleep(0.01)

0 commit comments

Comments
 (0)