periph 1.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- periph/__init__.py +1 -0
- periph/chips/accelerometer/adxl345.py +524 -0
- periph/chips/accelerometer/adxl362.py +704 -0
- periph/chips/adc_dac/ad7705.py +476 -0
- periph/chips/adc_dac/ad7706.py +495 -0
- periph/chips/adc_dac/hx710a.py +187 -0
- periph/chips/adc_dac/hx710b.py +189 -0
- periph/chips/adc_dac/hx711.py +170 -0
- periph/chips/adc_dac/mcp4725.py +167 -0
- periph/chips/adc_dac/mcp4728.py +317 -0
- periph/chips/adc_dac/pcf8591.py +199 -0
- periph/chips/comms/mcp2515.py +651 -0
- periph/chips/comms/rda5807m.py +420 -0
- periph/chips/comms/rfm9x.py +594 -0
- periph/chips/display/pcf8576.py +223 -0
- periph/chips/environmental/aht21.py +150 -0
- periph/chips/environmental/bme280.py +384 -0
- periph/chips/environmental/bme680.py +501 -0
- periph/chips/gas/ens160.py +273 -0
- periph/chips/gnss/neo6.py +439 -0
- periph/chips/gyroscope/l3g4200d.py +448 -0
- periph/chips/gyroscope/l3gd20h.py +337 -0
- periph/chips/humidity/dht11.py +123 -0
- periph/chips/imu/mpu6050.py +251 -0
- periph/chips/imu/mpu9250.py +378 -0
- periph/chips/imu/mpu9255.py +434 -0
- periph/chips/io_expander/mcp23017.py +494 -0
- periph/chips/io_expander/pcf8574.py +401 -0
- periph/chips/io_expander/pcf8575.py +420 -0
- periph/chips/io_expander/tpic6b595.py +271 -0
- periph/chips/led/_color.py +23 -0
- periph/chips/led/_neopixel_rgb_base.py +175 -0
- periph/chips/led/_neopixel_rgbw_base.py +193 -0
- periph/chips/led/apa102.py +200 -0
- periph/chips/led/sk6812rgbw.py +52 -0
- periph/chips/led/ws2812b.py +46 -0
- periph/chips/led/ws2814.py +52 -0
- periph/chips/light/apds9960.py +496 -0
- periph/chips/light/apds_9930.py +364 -0
- periph/chips/magnetometer/as5600.py +290 -0
- periph/chips/magnetometer/hmc5883l.py +210 -0
- periph/chips/memory/_24aa02uid.py +175 -0
- periph/chips/motor/drv8830.py +236 -0
- periph/chips/other/mpr121.py +465 -0
- periph/chips/power/ade7953.py +1196 -0
- periph/chips/power/ina219.py +195 -0
- periph/chips/power/ina226.py +217 -0
- periph/chips/power/ina3221.py +359 -0
- periph/chips/pressure/bmp085.py +234 -0
- periph/chips/pressure/bmp180.py +234 -0
- periph/chips/pressure/bmp280.py +292 -0
- periph/chips/pressure/bmp384.py +471 -0
- periph/chips/pressure/bmp581.py +561 -0
- periph/chips/pressure/lps22df.py +394 -0
- periph/chips/pressure/lps28dfw.py +337 -0
- periph/chips/pressure/lps33hw.py +385 -0
- periph/chips/rfid/mfrc522.py +818 -0
- periph/chips/rtc/ds3231.py +522 -0
- periph/chips/rtc/pcf8523.py +549 -0
- periph/chips/temperature/mcp9808.py +453 -0
- periph/chips/temperature/tmp117.py +461 -0
- periph/chips/tof/_vl53_base.py +174 -0
- periph/chips/tof/vl53l0x.py +816 -0
- periph/chips/tof/vl53l1x.py +815 -0
- periph/connection/__init__.py +31 -0
- periph/connection/base.py +103 -0
- periph/connection/dhtxx_auto.py +52 -0
- periph/connection/dhtxx_circuitpython.py +138 -0
- periph/connection/dhtxx_linux.py +230 -0
- periph/connection/dhtxx_micropython.py +133 -0
- periph/connection/dhtxx_mock.py +34 -0
- periph/connection/hx711_auto.py +66 -0
- periph/connection/hx711_circuitpython.py +114 -0
- periph/connection/hx711_linux.py +121 -0
- periph/connection/hx711_micropython.py +113 -0
- periph/connection/hx711_mock.py +43 -0
- periph/connection/i2c_auto.py +54 -0
- periph/connection/i2c_circuitpython.py +84 -0
- periph/connection/i2c_linux.py +81 -0
- periph/connection/i2c_micropython.py +65 -0
- periph/connection/i2c_mock.py +57 -0
- periph/connection/input_pin.py +259 -0
- periph/connection/neo6_mock.py +36 -0
- periph/connection/neopixel_auto.py +75 -0
- periph/connection/neopixel_circuitpython.py +44 -0
- periph/connection/neopixel_linux.py +47 -0
- periph/connection/neopixel_micropython.py +38 -0
- periph/connection/output_pin.py +81 -0
- periph/connection/sipo_circuitpython.py +119 -0
- periph/connection/sipo_linux.py +149 -0
- periph/connection/sipo_micropython.py +104 -0
- periph/connection/smbus_auto.py +68 -0
- periph/connection/smbus_circuitpython.py +118 -0
- periph/connection/smbus_linux.py +119 -0
- periph/connection/smbus_micropython.py +100 -0
- periph/connection/spi_auto.py +79 -0
- periph/connection/spi_circuitpython.py +97 -0
- periph/connection/spi_linux.py +66 -0
- periph/connection/spi_micropython.py +64 -0
- periph/connection/spi_mock.py +96 -0
- periph/connection/uart_auto.py +76 -0
- periph/connection/uart_circuitpython.py +81 -0
- periph/connection/uart_linux.py +120 -0
- periph/connection/uart_micropython.py +81 -0
- periph-1.2.1.dist-info/METADATA +113 -0
- periph-1.2.1.dist-info/RECORD +108 -0
- periph-1.2.1.dist-info/WHEEL +5 -0
- periph-1.2.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
"""ADXL362 — 3-axis MEMS accelerometer (Analog Devices), SPI only.
|
|
2
|
+
|
|
3
|
+
The ADXL362 is an ultralow power 3-axis accelerometer with 12-bit output
|
|
4
|
+
resolution, a 512-sample FIFO, on-chip temperature sensor, autonomous
|
|
5
|
+
activity/inactivity (motion) detection with two independent interrupt pins,
|
|
6
|
+
and a wake-up mode that consumes ~270 nA. Unlike the ADXL345, it is
|
|
7
|
+
SPI-only; there is no I²C mode.
|
|
8
|
+
|
|
9
|
+
SPI command structure:
|
|
10
|
+
WRITE register 0x0A + addr + data...
|
|
11
|
+
READ register 0x0B + addr + data...
|
|
12
|
+
READ FIFO 0x0D + data...
|
|
13
|
+
|
|
14
|
+
Register addresses are 6 bits (0x00–0x3F). Burst (multi-byte) transfers
|
|
15
|
+
auto-increment the register pointer; the increment halts at the invalid
|
|
16
|
+
address 0x3F rather than wrapping. FIFO reads have no address byte and
|
|
17
|
+
may be burst-read continuously at the SPI clock rate.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
connection: Configured SPI connection pointing at the device.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# SPI command bytes (per spec § Transport Configuration / SPI).
|
|
25
|
+
_CMD_WRITE_REG = 0x0A
|
|
26
|
+
_CMD_READ_REG = 0x0B
|
|
27
|
+
_CMD_READ_FIFO = 0x0D
|
|
28
|
+
|
|
29
|
+
# Soft-reset key (ASCII 'R').
|
|
30
|
+
_SOFT_RESET_KEY = 0x52
|
|
31
|
+
|
|
32
|
+
# Per-range sensitivity (g/LSB), typical values from the datasheet. The
|
|
33
|
+
# ±8 g value is intentionally non-linear (4.255 mg/LSB, not 4× the ±2 g
|
|
34
|
+
# scale of 1 mg/LSB) per the datasheet's per-range table.
|
|
35
|
+
_SENSITIVITY_G_PER_LSB = (0.001, 0.002, 0.004255)
|
|
36
|
+
|
|
37
|
+
# Temperature conversion: bias=350 LSB at 25 °C, sensitivity=0.065 °C/LSB.
|
|
38
|
+
_TEMP_BIAS_LSB = 350
|
|
39
|
+
_TEMP_BIAS_C = 25.0
|
|
40
|
+
_TEMP_SCALE_C = 0.065
|
|
41
|
+
|
|
42
|
+
# ODR codes (FILTER_CTL bits 2:0). '111' (400 Hz) collapses with 0x05–0x07.
|
|
43
|
+
_ODR_CODES = (
|
|
44
|
+
(0x00, 12.5),
|
|
45
|
+
(0x01, 25.0),
|
|
46
|
+
(0x02, 50.0),
|
|
47
|
+
(0x03, 100.0),
|
|
48
|
+
(0x04, 200.0),
|
|
49
|
+
(0x05, 400.0),
|
|
50
|
+
(0x06, 400.0),
|
|
51
|
+
(0x07, 400.0),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Range codes (FILTER_CTL bits 7:6). '1X' both map to ±8 g.
|
|
55
|
+
_RANGE_CODES = (
|
|
56
|
+
(0x00, 2),
|
|
57
|
+
(0x40, 4),
|
|
58
|
+
(0x80, 8),
|
|
59
|
+
(0xC0, 8),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _delay_ms(ms):
|
|
64
|
+
"""Sleep ``ms`` milliseconds, portable across MicroPython and CPython."""
|
|
65
|
+
import time
|
|
66
|
+
if hasattr(time, 'sleep_ms'):
|
|
67
|
+
time.sleep_ms(int(ms))
|
|
68
|
+
else:
|
|
69
|
+
time.sleep(ms / 1000.0)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _sign_extend_12(v):
|
|
73
|
+
"""Sign-extend a 12-bit two's-complement value to a signed Python int."""
|
|
74
|
+
v &= 0x0FFF
|
|
75
|
+
if v & 0x0800:
|
|
76
|
+
v -= 0x1000
|
|
77
|
+
return v
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _sensitivity_for_range_bits(bits):
|
|
81
|
+
"""Return the typical sensitivity (g/LSB) for the RANGE field (bits 7:6)."""
|
|
82
|
+
bits &= 0xC0
|
|
83
|
+
if bits == 0x00:
|
|
84
|
+
return _SENSITIVITY_G_PER_LSB[0]
|
|
85
|
+
if bits == 0x40:
|
|
86
|
+
return _SENSITIVITY_G_PER_LSB[1]
|
|
87
|
+
return _SENSITIVITY_G_PER_LSB[2]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ADXL362Minimal:
|
|
91
|
+
"""ADXL362 minimal interface — read X, Y, Z acceleration in *g*.
|
|
92
|
+
|
|
93
|
+
Performs the chip's full power-up sequence: verifies DEVID_AD=0xAD,
|
|
94
|
+
DEVID_MST=0x1D, and PARTID=0xF2 (the latter is 362 in octal); writes
|
|
95
|
+
the reset FILTER_CTL (RANGE=±2 g, HALF_BW=1, ODR=100 Hz); and switches
|
|
96
|
+
POWER_CTL into measurement mode.
|
|
97
|
+
|
|
98
|
+
Default configuration (baked in at construction):
|
|
99
|
+
- ±2 g measurement range
|
|
100
|
+
- 100 Hz output data rate, ODR/4 antialiasing bandwidth
|
|
101
|
+
- Normal noise mode (LOW_NOISE=00)
|
|
102
|
+
- Continuous measurement mode (POWER_CTL.MEASURE=10)
|
|
103
|
+
- FIFO disabled
|
|
104
|
+
- No interrupts mapped; INT1/INT2 high-impedance
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
connection: Configured SPI connection pointing at the device.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
# Register map (6-bit addresses).
|
|
111
|
+
_REG_DEVID_AD = 0x00
|
|
112
|
+
_REG_DEVID_MST = 0x01
|
|
113
|
+
_REG_PARTID = 0x02
|
|
114
|
+
_REG_XDATA = 0x08
|
|
115
|
+
_REG_YDATA = 0x09
|
|
116
|
+
_REG_ZDATA = 0x0A
|
|
117
|
+
_REG_STATUS = 0x0B
|
|
118
|
+
_REG_FIFO_ENTRIES_L = 0x0C
|
|
119
|
+
_REG_FIFO_ENTRIES_H = 0x0D
|
|
120
|
+
_REG_XDATA_L = 0x0E
|
|
121
|
+
_REG_XDATA_H = 0x0F
|
|
122
|
+
_REG_YDATA_L = 0x10
|
|
123
|
+
_REG_YDATA_H = 0x11
|
|
124
|
+
_REG_ZDATA_L = 0x12
|
|
125
|
+
_REG_ZDATA_H = 0x13
|
|
126
|
+
_REG_TEMP_L = 0x14
|
|
127
|
+
_REG_TEMP_H = 0x15
|
|
128
|
+
_REG_SOFT_RESET = 0x1F
|
|
129
|
+
_REG_THRESH_ACT_L = 0x20
|
|
130
|
+
_REG_THRESH_ACT_H = 0x21
|
|
131
|
+
_REG_TIME_ACT = 0x22
|
|
132
|
+
_REG_THRESH_INACT_L = 0x23
|
|
133
|
+
_REG_THRESH_INACT_H = 0x24
|
|
134
|
+
_REG_TIME_INACT_L = 0x25
|
|
135
|
+
_REG_TIME_INACT_H = 0x26
|
|
136
|
+
_REG_ACT_INACT_CTL = 0x27
|
|
137
|
+
_REG_FIFO_CONTROL = 0x28
|
|
138
|
+
_REG_FIFO_SAMPLES = 0x29
|
|
139
|
+
_REG_INTMAP1 = 0x2A
|
|
140
|
+
_REG_INTMAP2 = 0x2B
|
|
141
|
+
_REG_FILTER_CTL = 0x2C
|
|
142
|
+
_REG_POWER_CTL = 0x2D
|
|
143
|
+
_REG_SELF_TEST = 0x2E
|
|
144
|
+
|
|
145
|
+
# Reset defaults.
|
|
146
|
+
_DEVID_AD_VALUE = 0xAD
|
|
147
|
+
_DEVID_MST_VALUE = 0x1D
|
|
148
|
+
_PARTID_VALUE = 0xF2
|
|
149
|
+
|
|
150
|
+
# FILTER_CTL reset value: RANGE=±2 g, HALF_BW=1, ODR=100 Hz.
|
|
151
|
+
_FILTER_CTL_DEFAULT = 0x13
|
|
152
|
+
# POWER_CTL measurement-mode value: MEASURE=10, all else 0.
|
|
153
|
+
_POWER_CTL_MEASURE = 0x02
|
|
154
|
+
|
|
155
|
+
# Status bits (1<<position).
|
|
156
|
+
_STATUS_DATA_READY = 0x01
|
|
157
|
+
_STATUS_FIFO_READY = 0x02
|
|
158
|
+
_STATUS_FIFO_WATERMARK = 0x04
|
|
159
|
+
_STATUS_FIFO_OVERRUN = 0x08
|
|
160
|
+
_STATUS_ACT = 0x10
|
|
161
|
+
_STATUS_INACT = 0x20
|
|
162
|
+
_STATUS_AWAKE = 0x40
|
|
163
|
+
_STATUS_ERR_USER_REGS = 0x80
|
|
164
|
+
|
|
165
|
+
def __init__(self, connection):
|
|
166
|
+
self._connection = connection
|
|
167
|
+
self._range_bits = 0x00 # ±2 g default
|
|
168
|
+
self._odr_hz = 100.0
|
|
169
|
+
self.init()
|
|
170
|
+
|
|
171
|
+
def init(self):
|
|
172
|
+
"""Run the chip's full power-up sequence.
|
|
173
|
+
|
|
174
|
+
Verifies the triple device-ID read, writes FILTER_CTL and
|
|
175
|
+
POWER_CTL to known-good values, and waits the ODR turnaround
|
|
176
|
+
before returning so the caller can immediately read data.
|
|
177
|
+
"""
|
|
178
|
+
# Power-up to standby turn-on time (datasheet: ≤5 ms typical at 100 Hz).
|
|
179
|
+
_delay_ms(5)
|
|
180
|
+
|
|
181
|
+
# Burst-read DEVID_AD, DEVID_MST, PARTID and verify the triple.
|
|
182
|
+
ids = self._read_burst(self._REG_DEVID_AD, 3)
|
|
183
|
+
if ids[0] != self._DEVID_AD_VALUE:
|
|
184
|
+
raise ValueError('ADXL362 DEVID_AD: expected 0x{:02X}, got 0x{:02X}'.format(
|
|
185
|
+
self._DEVID_AD_VALUE, ids[0]))
|
|
186
|
+
if ids[1] != self._DEVID_MST_VALUE:
|
|
187
|
+
raise ValueError('ADXL362 DEVID_MST: expected 0x{:02X}, got 0x{:02X}'.format(
|
|
188
|
+
self._DEVID_MST_VALUE, ids[1]))
|
|
189
|
+
if ids[2] != self._PARTID_VALUE:
|
|
190
|
+
raise ValueError('ADXL362 PARTID: expected 0x{:02X}, got 0x{:02X}'.format(
|
|
191
|
+
self._PARTID_VALUE, ids[2]))
|
|
192
|
+
|
|
193
|
+
self._write_reg(self._REG_FILTER_CTL, self._FILTER_CTL_DEFAULT)
|
|
194
|
+
self._write_reg(self._REG_POWER_CTL, self._POWER_CTL_MEASURE)
|
|
195
|
+
|
|
196
|
+
# Measurement-mode-instruction-to-valid-data: 4/ODR (40 ms at 100 Hz).
|
|
197
|
+
_delay_ms(40)
|
|
198
|
+
|
|
199
|
+
def _read_burst(self, reg, n):
|
|
200
|
+
"""Read n bytes starting at ``reg`` with auto-incrementing pointer."""
|
|
201
|
+
cmd = bytes([_CMD_READ_REG, reg & 0x3F])
|
|
202
|
+
return self._connection.write_read(cmd, n)
|
|
203
|
+
|
|
204
|
+
def _read_fifo(self, n):
|
|
205
|
+
"""Read n bytes from the FIFO (no address byte)."""
|
|
206
|
+
return self._connection.write_read(bytes([_CMD_READ_FIFO]), n)
|
|
207
|
+
|
|
208
|
+
def _write_reg(self, reg, value):
|
|
209
|
+
"""Write a single register."""
|
|
210
|
+
self._connection.write(bytes([_CMD_WRITE_REG, reg & 0x3F, value & 0xFF]))
|
|
211
|
+
|
|
212
|
+
def _read_reg(self, reg):
|
|
213
|
+
"""Read a single register."""
|
|
214
|
+
return self._read_burst(reg, 1)[0]
|
|
215
|
+
|
|
216
|
+
def _read_fifo_entries(self):
|
|
217
|
+
"""Return the 10-bit FIFO entry count (0–512)."""
|
|
218
|
+
lo = self._read_reg(self._REG_FIFO_ENTRIES_L)
|
|
219
|
+
hi = self._read_reg(self._REG_FIFO_ENTRIES_H)
|
|
220
|
+
return (lo | ((hi & 0x03) << 8))
|
|
221
|
+
|
|
222
|
+
def _threshold_raw(self, threshold_g):
|
|
223
|
+
"""Convert an acceleration threshold in *g* to a 10-bit raw value."""
|
|
224
|
+
sens = _sensitivity_for_range_bits(self._range_bits)
|
|
225
|
+
raw = int(round(threshold_g / sens))
|
|
226
|
+
if raw < 0:
|
|
227
|
+
raw = 0
|
|
228
|
+
if raw > 0x3FF:
|
|
229
|
+
raw = 0x3FF
|
|
230
|
+
return raw
|
|
231
|
+
|
|
232
|
+
def _time_inact_raw(self, samples):
|
|
233
|
+
"""Convert a 16-bit sample count to two FIFO_INACT register bytes."""
|
|
234
|
+
if samples < 0:
|
|
235
|
+
samples = 0
|
|
236
|
+
if samples > 0xFFFF:
|
|
237
|
+
samples = 0xFFFF
|
|
238
|
+
return samples & 0xFF, (samples >> 8) & 0xFF
|
|
239
|
+
|
|
240
|
+
def read(self):
|
|
241
|
+
"""Read 3-axis linear acceleration.
|
|
242
|
+
|
|
243
|
+
Burst-reads the 12-bit XDATA_L/H, YDATA_L/H, ZDATA_L/H register
|
|
244
|
+
sextet so the three samples are guaranteed to come from a single
|
|
245
|
+
measurement.
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
tuple: (x, y, z) acceleration in *g*.
|
|
249
|
+
"""
|
|
250
|
+
raw = self._read_burst(self._REG_XDATA_L, 6)
|
|
251
|
+
rx = _sign_extend_12((raw[1] & 0x0F) << 8 | raw[0])
|
|
252
|
+
ry = _sign_extend_12((raw[3] & 0x0F) << 8 | raw[2])
|
|
253
|
+
rz = _sign_extend_12((raw[5] & 0x0F) << 8 | raw[4])
|
|
254
|
+
sens = _sensitivity_for_range_bits(self._range_bits)
|
|
255
|
+
return (rx * sens, ry * sens, rz * sens)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class ADXL362Full(ADXL362Minimal):
|
|
259
|
+
"""ADXL362 full interface — extends ADXL362Minimal with the full chip API.
|
|
260
|
+
|
|
261
|
+
Adds:
|
|
262
|
+
- Device-ID triple read (DEVID_AD/DEVID_MST/PARTID/REVID).
|
|
263
|
+
- Soft-reset (writes 0x52 to SOFT_RESET).
|
|
264
|
+
- Range, ODR, antialiasing, and noise-mode configuration.
|
|
265
|
+
- Wake-up mode (270 nA) and external clock / external sample sync.
|
|
266
|
+
- 8-bit low-resolution read (XDATA/YDATA/ZDATA).
|
|
267
|
+
- On-chip temperature sensor.
|
|
268
|
+
- STATUS accessors (awake, data_ready, FIFO flags).
|
|
269
|
+
- 512-sample FIFO (disabled / oldest-saved / stream / triggered,
|
|
270
|
+
optional temperature interleaving, 9-bit watermark).
|
|
271
|
+
- Activity / inactivity thresholds and timers (referenced or
|
|
272
|
+
absolute, default/linked/loop modes).
|
|
273
|
+
- Per-pin (INT1/INT2) source mapping and active-high/active-low
|
|
274
|
+
polarity.
|
|
275
|
+
- Self-test.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
connection: Configured SPI connection pointing at the device.
|
|
279
|
+
"""
|
|
280
|
+
|
|
281
|
+
# Interrupt source constants (used by set_interrupt).
|
|
282
|
+
SOURCE_DATA_READY = 0
|
|
283
|
+
SOURCE_FIFO_READY = 1
|
|
284
|
+
SOURCE_FIFO_WATERMARK = 2
|
|
285
|
+
SOURCE_FIFO_OVERRUN = 3
|
|
286
|
+
SOURCE_ACT = 4
|
|
287
|
+
SOURCE_INACT = 5
|
|
288
|
+
SOURCE_AWAKE = 6
|
|
289
|
+
|
|
290
|
+
# Noise mode constants (POWER_CTL.LOW_NOISE[5:4]).
|
|
291
|
+
NOISE_NORMAL = 0
|
|
292
|
+
NOISE_LOW = 1
|
|
293
|
+
NOISE_ULTRALOW = 2
|
|
294
|
+
|
|
295
|
+
# Link/loop mode constants (ACT_INACT_CTL.LINKLOOP[5:4]).
|
|
296
|
+
LINKLOOP_DEFAULT = 0
|
|
297
|
+
LINKLOOP_LINKED = 1
|
|
298
|
+
LINKLOOP_LOOP = 3
|
|
299
|
+
|
|
300
|
+
# FIFO mode constants (FIFO_CONTROL.FIFO_MODE[1:0]).
|
|
301
|
+
FIFO_DISABLED = 0
|
|
302
|
+
FIFO_OLDEST_SAVED = 1
|
|
303
|
+
FIFO_STREAM = 2
|
|
304
|
+
FIFO_TRIGGERED = 3
|
|
305
|
+
|
|
306
|
+
# FIFO entry-axis constants (top 2 bits of each 16-bit FIFO entry).
|
|
307
|
+
AXIS_X = 0
|
|
308
|
+
AXIS_Y = 1
|
|
309
|
+
AXIS_Z = 2
|
|
310
|
+
AXIS_TEMP = 3
|
|
311
|
+
|
|
312
|
+
# INTMAPx bit layout (mirrors the chip register, single source per bit).
|
|
313
|
+
_INTMAP_DATA_READY = 0x01
|
|
314
|
+
_INTMAP_FIFO_READY = 0x02
|
|
315
|
+
_INTMAP_FIFO_WATERMARK = 0x04
|
|
316
|
+
_INTMAP_FIFO_OVERRUN = 0x08
|
|
317
|
+
_INTMAP_ACT = 0x10
|
|
318
|
+
_INTMAP_INACT = 0x20
|
|
319
|
+
_INTMAP_AWAKE = 0x40
|
|
320
|
+
_INTMAP_INT_LOW = 0x80
|
|
321
|
+
|
|
322
|
+
# ACT_INACT_CTL bit layout.
|
|
323
|
+
_AIC_ACT_EN = 0x01
|
|
324
|
+
_AIC_ACT_REF = 0x02
|
|
325
|
+
_AIC_INACT_EN = 0x04
|
|
326
|
+
_AIC_INACT_REF = 0x08
|
|
327
|
+
_AIC_LINKLOOP_MASK = 0x30
|
|
328
|
+
|
|
329
|
+
# FILTER_CTL bit layout.
|
|
330
|
+
_FILTER_ODR_MASK = 0x07
|
|
331
|
+
_FILTER_EXT_SAMPLE = 0x08
|
|
332
|
+
_FILTER_HALF_BW = 0x10
|
|
333
|
+
_FILTER_RANGE_MASK = 0xC0
|
|
334
|
+
|
|
335
|
+
# POWER_CTL bit layout.
|
|
336
|
+
_POWER_MEASURE_MASK = 0x03
|
|
337
|
+
_POWER_AUTOSLEEP = 0x04
|
|
338
|
+
_POWER_WAKEUP = 0x08
|
|
339
|
+
_POWER_LOW_NOISE_MASK = 0x30
|
|
340
|
+
_POWER_EXT_CLK = 0x40
|
|
341
|
+
|
|
342
|
+
def __init__(self, connection):
|
|
343
|
+
super().__init__(connection)
|
|
344
|
+
|
|
345
|
+
def device_id(self):
|
|
346
|
+
"""Return raw device-ID bytes.
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
tuple: (DEVID_AD, DEVID_MST, PARTID, REVID).
|
|
350
|
+
"""
|
|
351
|
+
ids = self._read_burst(self._REG_DEVID_AD, 4)
|
|
352
|
+
return (ids[0], ids[1], ids[2], ids[3])
|
|
353
|
+
|
|
354
|
+
def soft_reset(self):
|
|
355
|
+
"""Soft-reset the chip.
|
|
356
|
+
|
|
357
|
+
Writes 0x52 (ASCII 'R') to SOFT_RESET and waits the documented
|
|
358
|
+
0.5 ms latency. All registers return to reset defaults; caller
|
|
359
|
+
must re-run init() before continuing.
|
|
360
|
+
"""
|
|
361
|
+
self._write_reg(self._REG_SOFT_RESET, _SOFT_RESET_KEY)
|
|
362
|
+
_delay_ms(1) # ≥0.5 ms per datasheet
|
|
363
|
+
# Reset clears cached state but doesn't reset cached Python state.
|
|
364
|
+
self._range_bits = 0x00
|
|
365
|
+
self._odr_hz = 100.0
|
|
366
|
+
|
|
367
|
+
def set_range(self, range_g):
|
|
368
|
+
"""Set the measurement range.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
range_g: 2, 4, or 8 (g).
|
|
372
|
+
"""
|
|
373
|
+
code = {2: 0x00, 4: 0x40, 8: 0x80}.get(range_g)
|
|
374
|
+
if code is None:
|
|
375
|
+
raise ValueError('range_g must be one of 2, 4, 8')
|
|
376
|
+
f = self._read_reg(self._REG_FILTER_CTL)
|
|
377
|
+
f = (f & ~self._FILTER_RANGE_MASK) | (code & self._FILTER_RANGE_MASK)
|
|
378
|
+
self._write_reg(self._REG_FILTER_CTL, f)
|
|
379
|
+
self._range_bits = code
|
|
380
|
+
# Spec datasheet says no separate delay is required, but the ODR
|
|
381
|
+
# turnaround is observed in continuous mode; wait 1/ODR for safety.
|
|
382
|
+
if self._odr_hz > 0:
|
|
383
|
+
_delay_ms(1000.0 / self._odr_hz + 1)
|
|
384
|
+
|
|
385
|
+
def set_odr(self, odr_hz):
|
|
386
|
+
"""Set the output data rate to the nearest supported value (12.5–400 Hz).
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
odr_hz: Requested ODR in Hz; clamped to the nearest of
|
|
390
|
+
12.5, 25, 50, 100, 200, or 400 Hz.
|
|
391
|
+
"""
|
|
392
|
+
best_code = _ODR_CODES[0][0]
|
|
393
|
+
best_rate = _ODR_CODES[0][1]
|
|
394
|
+
best_diff = abs(best_rate - odr_hz)
|
|
395
|
+
for code, actual in _ODR_CODES:
|
|
396
|
+
d = abs(actual - odr_hz)
|
|
397
|
+
if d < best_diff:
|
|
398
|
+
best_code, best_rate, best_diff = code, actual, d
|
|
399
|
+
f = self._read_reg(self._REG_FILTER_CTL)
|
|
400
|
+
f = (f & ~self._FILTER_ODR_MASK) | (best_code & self._FILTER_ODR_MASK)
|
|
401
|
+
self._write_reg(self._REG_FILTER_CTL, f)
|
|
402
|
+
self._odr_hz = best_rate
|
|
403
|
+
|
|
404
|
+
def set_half_bandwidth(self, enabled):
|
|
405
|
+
"""Set FILTER_CTL.HALF_BW (antialiasing bandwidth = ODR/4 or ODR/2)."""
|
|
406
|
+
f = self._read_reg(self._REG_FILTER_CTL)
|
|
407
|
+
if enabled:
|
|
408
|
+
f |= self._FILTER_HALF_BW
|
|
409
|
+
else:
|
|
410
|
+
f &= ~self._FILTER_HALF_BW
|
|
411
|
+
self._write_reg(self._REG_FILTER_CTL, f)
|
|
412
|
+
|
|
413
|
+
def set_noise_mode(self, mode):
|
|
414
|
+
"""Set POWER_CTL.LOW_NOISE (0=normal, 1=low, 2=ultralow noise)."""
|
|
415
|
+
if mode not in (self.NOISE_NORMAL, self.NOISE_LOW, self.NOISE_ULTRALOW):
|
|
416
|
+
raise ValueError('mode must be NOISE_NORMAL, NOISE_LOW, or NOISE_ULTRALOW')
|
|
417
|
+
p = self._read_reg(self._REG_POWER_CTL)
|
|
418
|
+
p = (p & ~self._POWER_LOW_NOISE_MASK) | ((mode << 4) & self._POWER_LOW_NOISE_MASK)
|
|
419
|
+
self._write_reg(self._REG_POWER_CTL, p)
|
|
420
|
+
|
|
421
|
+
def set_wakeup_mode(self, enabled):
|
|
422
|
+
"""Enter wake-up mode (270 nA); ignored unless loop mode is engaged."""
|
|
423
|
+
p = self._read_reg(self._REG_POWER_CTL)
|
|
424
|
+
if enabled:
|
|
425
|
+
p |= self._POWER_WAKEUP
|
|
426
|
+
else:
|
|
427
|
+
p &= ~self._POWER_WAKEUP
|
|
428
|
+
self._write_reg(self._REG_POWER_CTL, p)
|
|
429
|
+
|
|
430
|
+
def set_autosleep(self, enabled):
|
|
431
|
+
"""Set POWER_CTL.AUTOSLEEP; effective only in linked/loop mode."""
|
|
432
|
+
p = self._read_reg(self._REG_POWER_CTL)
|
|
433
|
+
if enabled:
|
|
434
|
+
p |= self._POWER_AUTOSLEEP
|
|
435
|
+
else:
|
|
436
|
+
p &= ~self._POWER_AUTOSLEEP
|
|
437
|
+
self._write_reg(self._REG_POWER_CTL, p)
|
|
438
|
+
|
|
439
|
+
def set_external_clock(self, enabled):
|
|
440
|
+
"""Set POWER_CTL.EXT_CLK; INT1 is repurposed as clock input."""
|
|
441
|
+
p = self._read_reg(self._REG_POWER_CTL)
|
|
442
|
+
if enabled:
|
|
443
|
+
p |= self._POWER_EXT_CLK
|
|
444
|
+
else:
|
|
445
|
+
p &= ~self._POWER_EXT_CLK
|
|
446
|
+
self._write_reg(self._REG_POWER_CTL, p)
|
|
447
|
+
|
|
448
|
+
def set_external_sample_trigger(self, enabled):
|
|
449
|
+
"""Set FILTER_CTL.EXT_SAMPLE; INT2 is repurposed as sync trigger input."""
|
|
450
|
+
f = self._read_reg(self._REG_FILTER_CTL)
|
|
451
|
+
if enabled:
|
|
452
|
+
f |= self._FILTER_EXT_SAMPLE
|
|
453
|
+
else:
|
|
454
|
+
f &= ~self._FILTER_EXT_SAMPLE
|
|
455
|
+
self._write_reg(self._REG_FILTER_CTL, f)
|
|
456
|
+
|
|
457
|
+
def read_8bit(self):
|
|
458
|
+
"""Read 3-axis acceleration using the 8-bit XDATA/YDATA/ZDATA registers.
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
tuple: (x, y, z) acceleration in *g*, ~16-LSB resolution.
|
|
462
|
+
"""
|
|
463
|
+
raw = self._read_burst(self._REG_XDATA, 3)
|
|
464
|
+
# XDATA/YDATA/ZDATA are signed 8-bit two's complement; an LSB here
|
|
465
|
+
# represents 16 codes of the 12-bit scale.
|
|
466
|
+
def s8(v):
|
|
467
|
+
v &= 0xFF
|
|
468
|
+
return v - 0x100 if v & 0x80 else v
|
|
469
|
+
sens = _sensitivity_for_range_bits(self._range_bits) * 16
|
|
470
|
+
return (s8(raw[0]) * sens, s8(raw[1]) * sens, s8(raw[2]) * sens)
|
|
471
|
+
|
|
472
|
+
def temperature(self):
|
|
473
|
+
"""Read the on-chip temperature sensor.
|
|
474
|
+
|
|
475
|
+
Uses the typical bias (350 LSB @ 25 °C) and sensitivity
|
|
476
|
+
(0.065 °C/LSB) from the datasheet; not part-calibrated.
|
|
477
|
+
|
|
478
|
+
Returns:
|
|
479
|
+
float: Temperature in °C.
|
|
480
|
+
"""
|
|
481
|
+
raw = self._read_burst(self._REG_TEMP_L, 2)
|
|
482
|
+
raw12 = _sign_extend_12((raw[1] & 0x0F) << 8 | raw[0])
|
|
483
|
+
return _TEMP_BIAS_C + (raw12 - _TEMP_BIAS_LSB) * _TEMP_SCALE_C
|
|
484
|
+
|
|
485
|
+
def status(self):
|
|
486
|
+
"""Return the raw STATUS register byte."""
|
|
487
|
+
return self._read_reg(self._REG_STATUS)
|
|
488
|
+
|
|
489
|
+
def awake(self):
|
|
490
|
+
"""Return STATUS.AWAKE."""
|
|
491
|
+
return bool(self.status() & self._STATUS_AWAKE)
|
|
492
|
+
|
|
493
|
+
def data_ready(self):
|
|
494
|
+
"""Return STATUS.DATA_READY (cleared by data-register or FIFO read)."""
|
|
495
|
+
return bool(self.status() & self._STATUS_DATA_READY)
|
|
496
|
+
|
|
497
|
+
def fifo_entries(self):
|
|
498
|
+
"""Return the 10-bit FIFO entry count (0–512)."""
|
|
499
|
+
return self._read_fifo_entries()
|
|
500
|
+
|
|
501
|
+
def configure_fifo(self, mode, store_temp=False, watermark=128):
|
|
502
|
+
"""Configure the FIFO mode, optional temperature storage, and watermark.
|
|
503
|
+
|
|
504
|
+
Args:
|
|
505
|
+
mode: One of FIFO_DISABLED (0), FIFO_OLDEST_SAVED (1),
|
|
506
|
+
FIFO_STREAM (2), FIFO_TRIGGERED (3).
|
|
507
|
+
store_temp: True to interleave temperature samples in the FIFO.
|
|
508
|
+
watermark: 9-bit watermark value (0–511).
|
|
509
|
+
"""
|
|
510
|
+
if mode not in (self.FIFO_DISABLED, self.FIFO_OLDEST_SAVED,
|
|
511
|
+
self.FIFO_STREAM, self.FIFO_TRIGGERED):
|
|
512
|
+
raise ValueError('mode must be 0/1/2/3 (DISABLED/OLDEST_SAVED/STREAM/TRIGGERED)')
|
|
513
|
+
if watermark < 0 or watermark > 0x1FF:
|
|
514
|
+
raise ValueError('watermark must be 0–511')
|
|
515
|
+
fc = (mode & 0x03) | ((watermark >> 8) << 3) | (0x04 if store_temp else 0x00)
|
|
516
|
+
self._write_reg(self._REG_FIFO_CONTROL, fc)
|
|
517
|
+
self._write_reg(self._REG_FIFO_SAMPLES, watermark & 0xFF)
|
|
518
|
+
|
|
519
|
+
def read_fifo(self):
|
|
520
|
+
"""Read all available FIFO entries.
|
|
521
|
+
|
|
522
|
+
Each 16-bit entry's top two bits encode the axis (0=X, 1=Y,
|
|
523
|
+
2=Z, 3=temperature); the low 12 bits are signed axis/temperature
|
|
524
|
+
data, scaled with the current range.
|
|
525
|
+
|
|
526
|
+
Returns:
|
|
527
|
+
list[tuple[int, float]]: ``[(axis, value), ...]`` where axis
|
|
528
|
+
is one of AXIS_X/AXIS_Y/AXIS_Z/AXIS_TEMP and value is in
|
|
529
|
+
*g* (axes 0–2) or °C (axis 3).
|
|
530
|
+
"""
|
|
531
|
+
n = self._read_fifo_entries()
|
|
532
|
+
if n == 0:
|
|
533
|
+
return []
|
|
534
|
+
# Always read an even byte count — each FIFO entry is 16 bits.
|
|
535
|
+
raw = self._read_fifo(n * 2)
|
|
536
|
+
sens = _sensitivity_for_range_bits(self._range_bits)
|
|
537
|
+
out = []
|
|
538
|
+
for i in range(n):
|
|
539
|
+
lo = raw[2 * i]
|
|
540
|
+
hi = raw[2 * i + 1]
|
|
541
|
+
raw16 = (hi << 8) | lo
|
|
542
|
+
axis = (raw16 >> 14) & 0x03
|
|
543
|
+
raw12 = _sign_extend_12(raw16 & 0x0FFF)
|
|
544
|
+
if axis == self.AXIS_TEMP:
|
|
545
|
+
value = _TEMP_BIAS_C + (raw12 - _TEMP_BIAS_LSB) * _TEMP_SCALE_C
|
|
546
|
+
else:
|
|
547
|
+
value = raw12 * sens
|
|
548
|
+
out.append((axis, value))
|
|
549
|
+
return out
|
|
550
|
+
|
|
551
|
+
def set_activity_threshold(self, threshold_g, referenced=False):
|
|
552
|
+
"""Set the activity threshold in *g*.
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
threshold_g: Acceleration magnitude that triggers activity
|
|
556
|
+
detection, in *g*. Clamped to 10-bit range relative to
|
|
557
|
+
the current measurement range.
|
|
558
|
+
referenced: True for referenced (relative-to-orientation-at-
|
|
559
|
+
engagement) detection; False for absolute.
|
|
560
|
+
"""
|
|
561
|
+
raw = self._threshold_raw(threshold_g)
|
|
562
|
+
self._write_reg(self._REG_THRESH_ACT_L, raw & 0xFF)
|
|
563
|
+
self._write_reg(self._REG_THRESH_ACT_H, (raw >> 8) & 0x03)
|
|
564
|
+
aic = self._read_reg(self._REG_ACT_INACT_CTL)
|
|
565
|
+
if referenced:
|
|
566
|
+
aic |= self._AIC_ACT_REF
|
|
567
|
+
else:
|
|
568
|
+
aic &= ~self._AIC_ACT_REF
|
|
569
|
+
self._write_reg(self._REG_ACT_INACT_CTL, aic)
|
|
570
|
+
|
|
571
|
+
def set_activity_time(self, samples):
|
|
572
|
+
"""Set the activity-time filter (0–255 samples).
|
|
573
|
+
|
|
574
|
+
Args:
|
|
575
|
+
samples: Number of consecutive over-threshold samples
|
|
576
|
+
required to assert activity (0–255). Ignored in wake-up
|
|
577
|
+
mode, which is single-sample.
|
|
578
|
+
"""
|
|
579
|
+
if samples < 0 or samples > 0xFF:
|
|
580
|
+
raise ValueError('samples must be 0–255')
|
|
581
|
+
self._write_reg(self._REG_TIME_ACT, samples & 0xFF)
|
|
582
|
+
|
|
583
|
+
def set_inactivity_threshold(self, threshold_g, referenced=False):
|
|
584
|
+
"""Set the inactivity threshold in *g*.
|
|
585
|
+
|
|
586
|
+
Args:
|
|
587
|
+
threshold_g: Acceleration magnitude below which inactivity
|
|
588
|
+
is asserted, in *g*. Clamped to 10-bit range.
|
|
589
|
+
referenced: True for referenced (relative-to-orientation-at-
|
|
590
|
+
engagement) detection; False for absolute.
|
|
591
|
+
"""
|
|
592
|
+
raw = self._threshold_raw(threshold_g)
|
|
593
|
+
self._write_reg(self._REG_THRESH_INACT_L, raw & 0xFF)
|
|
594
|
+
self._write_reg(self._REG_THRESH_INACT_H, (raw >> 8) & 0x03)
|
|
595
|
+
aic = self._read_reg(self._REG_ACT_INACT_CTL)
|
|
596
|
+
if referenced:
|
|
597
|
+
aic |= self._AIC_INACT_REF
|
|
598
|
+
else:
|
|
599
|
+
aic &= ~self._AIC_INACT_REF
|
|
600
|
+
self._write_reg(self._REG_ACT_INACT_CTL, aic)
|
|
601
|
+
|
|
602
|
+
def set_inactivity_time(self, samples):
|
|
603
|
+
"""Set the inactivity-time filter (0–65535 samples).
|
|
604
|
+
|
|
605
|
+
Args:
|
|
606
|
+
samples: Number of consecutive under-threshold samples
|
|
607
|
+
required to assert inactivity (0–65535).
|
|
608
|
+
"""
|
|
609
|
+
if samples < 0 or samples > 0xFFFF:
|
|
610
|
+
raise ValueError('samples must be 0–65535')
|
|
611
|
+
lo, hi = self._time_inact_raw(samples)
|
|
612
|
+
self._write_reg(self._REG_TIME_INACT_L, lo)
|
|
613
|
+
self._write_reg(self._REG_TIME_INACT_H, hi)
|
|
614
|
+
|
|
615
|
+
def enable_activity_detection(self, enabled):
|
|
616
|
+
"""Set ACT_INACT_CTL.ACT_EN."""
|
|
617
|
+
aic = self._read_reg(self._REG_ACT_INACT_CTL)
|
|
618
|
+
if enabled:
|
|
619
|
+
aic |= self._AIC_ACT_EN
|
|
620
|
+
else:
|
|
621
|
+
aic &= ~self._AIC_ACT_EN
|
|
622
|
+
self._write_reg(self._REG_ACT_INACT_CTL, aic)
|
|
623
|
+
|
|
624
|
+
def enable_inactivity_detection(self, enabled):
|
|
625
|
+
"""Set ACT_INACT_CTL.INACT_EN."""
|
|
626
|
+
aic = self._read_reg(self._REG_ACT_INACT_CTL)
|
|
627
|
+
if enabled:
|
|
628
|
+
aic |= self._AIC_INACT_EN
|
|
629
|
+
else:
|
|
630
|
+
aic &= ~self._AIC_INACT_EN
|
|
631
|
+
self._write_reg(self._REG_ACT_INACT_CTL, aic)
|
|
632
|
+
|
|
633
|
+
def set_link_loop_mode(self, mode):
|
|
634
|
+
"""Set ACT_INACT_CTL.LINKLOOP[5:4].
|
|
635
|
+
|
|
636
|
+
Args:
|
|
637
|
+
mode: LINKLOOP_DEFAULT (0), LINKLOOP_LINKED (1), or
|
|
638
|
+
LINKLOOP_LOOP (3).
|
|
639
|
+
"""
|
|
640
|
+
if mode not in (self.LINKLOOP_DEFAULT, self.LINKLOOP_LINKED, self.LINKLOOP_LOOP):
|
|
641
|
+
raise ValueError('mode must be LINKLOOP_DEFAULT/LINKED/LOOP')
|
|
642
|
+
aic = self._read_reg(self._REG_ACT_INACT_CTL)
|
|
643
|
+
aic = (aic & ~self._AIC_LINKLOOP_MASK) | ((mode << 4) & self._AIC_LINKLOOP_MASK)
|
|
644
|
+
self._write_reg(self._REG_ACT_INACT_CTL, aic)
|
|
645
|
+
|
|
646
|
+
def _intmap_bit(self, source):
|
|
647
|
+
return {
|
|
648
|
+
self.SOURCE_DATA_READY: self._INTMAP_DATA_READY,
|
|
649
|
+
self.SOURCE_FIFO_READY: self._INTMAP_FIFO_READY,
|
|
650
|
+
self.SOURCE_FIFO_WATERMARK: self._INTMAP_FIFO_WATERMARK,
|
|
651
|
+
self.SOURCE_FIFO_OVERRUN: self._INTMAP_FIFO_OVERRUN,
|
|
652
|
+
self.SOURCE_ACT: self._INTMAP_ACT,
|
|
653
|
+
self.SOURCE_INACT: self._INTMAP_INACT,
|
|
654
|
+
self.SOURCE_AWAKE: self._INTMAP_AWAKE,
|
|
655
|
+
}[source]
|
|
656
|
+
|
|
657
|
+
def set_interrupt(self, pin, source, enabled):
|
|
658
|
+
"""Set or clear one interrupt source on the named INT pin.
|
|
659
|
+
|
|
660
|
+
Args:
|
|
661
|
+
pin: 1 or 2.
|
|
662
|
+
source: One of SOURCE_DATA_READY/SOURCE_FIFO_READY/...
|
|
663
|
+
enabled: True to map, False to clear.
|
|
664
|
+
"""
|
|
665
|
+
if pin not in (1, 2):
|
|
666
|
+
raise ValueError('pin must be 1 or 2')
|
|
667
|
+
reg = self._REG_INTMAP1 if pin == 1 else self._REG_INTMAP2
|
|
668
|
+
cur = self._read_reg(reg)
|
|
669
|
+
bit = self._intmap_bit(source)
|
|
670
|
+
if enabled:
|
|
671
|
+
cur |= bit
|
|
672
|
+
else:
|
|
673
|
+
cur &= ~bit
|
|
674
|
+
self._write_reg(reg, cur)
|
|
675
|
+
|
|
676
|
+
def set_interrupt_polarity(self, pin, active_low):
|
|
677
|
+
"""Set the active-low polarity for one INT pin.
|
|
678
|
+
|
|
679
|
+
Args:
|
|
680
|
+
pin: 1 or 2.
|
|
681
|
+
active_low: True for active-low, False for active-high.
|
|
682
|
+
"""
|
|
683
|
+
if pin not in (1, 2):
|
|
684
|
+
raise ValueError('pin must be 1 or 2')
|
|
685
|
+
reg = self._REG_INTMAP1 if pin == 1 else self._REG_INTMAP2
|
|
686
|
+
cur = self._read_reg(reg)
|
|
687
|
+
if active_low:
|
|
688
|
+
cur |= self._INTMAP_INT_LOW
|
|
689
|
+
else:
|
|
690
|
+
cur &= ~self._INTMAP_INT_LOW
|
|
691
|
+
self._write_reg(reg, cur)
|
|
692
|
+
|
|
693
|
+
def self_test(self, enabled):
|
|
694
|
+
"""Enable or disable the electrostatic self-test force on all axes."""
|
|
695
|
+
st = self._read_reg(self._REG_SELF_TEST)
|
|
696
|
+
if enabled:
|
|
697
|
+
st |= 0x01
|
|
698
|
+
else:
|
|
699
|
+
st &= ~0x01
|
|
700
|
+
self._write_reg(self._REG_SELF_TEST, st)
|
|
701
|
+
if enabled:
|
|
702
|
+
# Spec: wait 4/ODR after asserting or deasserting SELF_TEST.ST
|
|
703
|
+
if self._odr_hz > 0:
|
|
704
|
+
_delay_ms(4000.0 / self._odr_hz + 1)
|