48
48
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_MSA301.git"
49
49
50
50
import struct
51
+
51
52
from micropython import const
52
53
from adafruit_register .i2c_struct import ROUnaryStruct
53
54
from adafruit_register .i2c_bit import RWBit
54
55
from adafruit_register .i2c_bits import RWBits , ROBits
55
56
import adafruit_bus_device .i2c_device as i2cdevice
57
+
56
58
_MSA301_I2CADDR_DEFAULT = const (0x26 )
57
59
58
60
_MSA301_REG_PARTID = const (0x01 )
64
66
_MSA301_REG_OUT_Z_H = const (0x07 )
65
67
_MSA301_REG_MOTIONINT = const (0x09 )
66
68
_MSA301_REG_DATAINT = const (0x0A )
67
- _MSA301_REG_CLICKSTATUS = const (0x0B )
68
69
_MSA301_REG_RESRANGE = const (0x0F )
69
70
_MSA301_REG_ODR = const (0x10 )
70
71
_MSA301_REG_POWERMODE = const (0x11 )
@@ -177,7 +178,20 @@ class Resolution: # pylint: disable=too-few-public-methods
177
178
RESOLUTION_10_BIT = 0b10
178
179
RESOLUTION_8_BIT = 0b11
179
180
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
181
195
"""Driver for the MSA301 Accelerometer.
182
196
183
197
:param ~busio.I2C i2c_bus: The I2C bus the MSA is connected to.
@@ -197,23 +211,31 @@ def __init__(self, i2c_bus):
197
211
self .bandwidth = BandWidth .WIDTH_250_HZ
198
212
self .range = Range .RANGE_4_G
199
213
self .resolution = Resolution .RESOLUTION_14_BIT
200
-
201
-
214
+ self ._tap_count = 0
202
215
203
216
_disable_x = RWBit (_MSA301_REG_ODR , 7 )
204
217
_disable_y = RWBit (_MSA301_REG_ODR , 6 )
205
218
_disable_z = RWBit (_MSA301_REG_ODR , 5 )
206
219
207
220
_xyz_raw = ROBits (48 , _MSA301_REG_OUT_X_L , 0 , 6 )
208
221
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" )
210
226
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" )
212
233
234
+ # general settings knobs
235
+ power_mode = RWBits (2 , _MSA301_REG_POWERMODE , 6 )
236
+ bandwidth = RWBits (4 , _MSA301_REG_POWERMODE , 1 )
213
237
data_rate = RWBits (4 , _MSA301_REG_ODR , 0 )
214
-
215
238
range = RWBits (2 , _MSA301_REG_RESRANGE , 0 )
216
-
217
239
resolution = RWBits (2 , _MSA301_REG_RESRANGE , 2 )
218
240
219
241
@property
@@ -248,3 +270,74 @@ def acceleration(self):
248
270
z_acc = ((z >> 2 ) / scale ) * _STANDARD_GRAVITY
249
271
250
272
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
0 commit comments