From 5ba3e3e1219eb4e77e37aa8c8b1597dc021160ea Mon Sep 17 00:00:00 2001 From: RoaCode <176423185+RoaCode@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:20:27 -0400 Subject: [PATCH 1/3] Added range and data_ready interrupt parameters --- .pre-commit-config.yaml | 2 +- adafruit_adxl37x.py | 131 +++++++++++++++++++++++++++++++-- examples/adxl37x_data_ready.py | 24 ++++++ 3 files changed, 149 insertions(+), 8 deletions(-) create mode 100644 examples/adxl37x_data_ready.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 70ade69..874bf5f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/pycqa/pylint - rev: v2.17.4 + rev: v3.2.6 hooks: - id: pylint name: pylint (library code) diff --git a/adafruit_adxl37x.py b/adafruit_adxl37x.py index 3c20f2a..b1c613c 100644 --- a/adafruit_adxl37x.py +++ b/adafruit_adxl37x.py @@ -33,7 +33,7 @@ import adafruit_adxl34x try: - from typing import Tuple, Optional + from typing import Tuple, Optional, Dict # This is only needed for typing import busio @@ -48,20 +48,66 @@ _ADXL347_MULTIPLIER: float = 0.049 # 49mg per lsb _STANDARD_GRAVITY: float = 9.80665 # earth standard gravity +_REG_DEVID: int = const(0x00) # Device ID +_REG_THRESH_TAP: int = const(0x1D) # Tap threshold +_REG_OFSX: int = const(0x1E) # X-axis offset +_REG_OFSY: int = const(0x1F) # Y-axis offset +_REG_OFSZ: int = const(0x20) # Z-axis offset +_REG_DUR: int = const(0x21) # Tap duration +_REG_LATENT: int = const(0x22) # Tap latency +_REG_WINDOW: int = const(0x23) # Tap window +_REG_THRESH_ACT: int = const(0x24) # Activity threshold +_REG_THRESH_INACT: int = const(0x25) # Inactivity threshold +_REG_TIME_INACT: int = const(0x26) # Inactivity time +_REG_ACT_INACT_CTL: int = const(0x27) # Axis enable control for [in]activity detection +_REG_THRESH_FF: int = const(0x28) # Free-fall threshold +_REG_TIME_FF: int = const(0x29) # Free-fall time +_REG_TAP_AXES: int = const(0x2A) # Axis control for single/double tap +_REG_ACT_TAP_STATUS: int = const(0x2B) # Source for single/double tap +_REG_BW_RATE: int = const(0x2C) # Data rate and power mode control +_REG_POWER_CTL: int = const(0x2D) # Power-saving features control +_REG_INT_ENABLE: int = const(0x2E) # Interrupt enable control +_REG_INT_MAP: int = const(0x2F) # Interrupt mapping control +_REG_INT_SOURCE: int = const(0x30) # Source of interrupts +_REG_DATA_FORMAT: int = const(0x31) # Data format control _REG_DATAX0: int = const(0x32) # X-axis data 0 _REG_DATAX1: int = const(0x33) # X-axis data 1 _REG_DATAY0: int = const(0x34) # Y-axis data 0 _REG_DATAY1: int = const(0x35) # Y-axis data 1 _REG_DATAZ0: int = const(0x36) # Z-axis data 0 _REG_DATAZ1: int = const(0x37) # Z-axis data 1 +_REG_FIFO_CTL: int = const(0x38) # FIFO control +_REG_FIFO_STATUS: int = const(0x39) # FIFO status +_INT_DATA_READY: int = const(0b10000000) # DATA_READY bit +_INT_SINGLE_TAP: int = const(0b01000000) # SINGLE_TAP bit +_INT_DOUBLE_TAP: int = const(0b00100000) # DOUBLE_TAP bit +_INT_ACT: int = const(0b00010000) # ACT bit +_INT_INACT: int = const(0b00001000) # INACT bit + + +# _INT_FREE_FALL: int = const(0b00000100) # FREE_FALL bit, unused in ADXL375 class DataRate(adafruit_adxl34x.DataRate): # pylint: disable=too-few-public-methods """Stub class for data rate.""" -class Range(adafruit_adxl34x.Range): # pylint: disable=too-few-public-methods - """Stub class for range.""" +class Range: # pylint: disable=too-few-public-methods + """An enum-like class representing the possible measurement ranges in +/- G. + + Possible values are: + + - ``Range.RANGE_200_G`` + - ``Range.RANGE_100_G`` + - ``Range.RANGE_50_G`` + - ``Range.RANGE_25_G`` + + """ + + RANGE_200_G: int = const(0b11) # +/- 200g + RANGE_100_G: int = const(0b10) # +/- 100g + RANGE_50_G: int = const(0b01) # +/- 50g + RANGE_25_G: int = const(0b00) # +/- 25g (default value) class ADXL375(adafruit_adxl34x.ADXL345): @@ -114,10 +160,81 @@ def acceleration(self) -> Tuple[int, int, int]: @property def range(self) -> int: - """Range is fixed. Updating the range is not implemented.""" - raise NotImplementedError("Range not implemented. ADXL375 is fixed at 200G.") + """The measurement range of the sensor.""" + range_register = self._read_register_unpacked(_REG_DATA_FORMAT) + return range_register & 0x03 @range.setter def range(self, val: int) -> None: - """Range is fixed. Updating the range is not implemented.""" - raise NotImplementedError("Range not implemented. ADXL375 is fixed at 200G.") + # read the current value of the data format register + format_register = self._read_register_unpacked(_REG_DATA_FORMAT) + + # update the range + format_register |= val + + # Make sure that the FULL-RES bit is enabled for range scaling + format_register |= 0x08 + + # write the updated values + self._write_register_byte(_REG_DATA_FORMAT, format_register) + + @property + def events(self) -> Dict[str, bool]: + """ + :attr:`events` will return a dictionary with a key for each + event type that has been enabled. + The possible keys are: + + +------------+----------------------------------------------------------------------------+ + | Key | Description | + +============+============================================================================+ + | ``tap`` | True if a tap was detected recently. Whether it's looking for a single | + | | or double tap is determined by the tap param of `enable_tap_detection` | + +------------+----------------------------------------------------------------------------+ + | ``motion`` | True if the sensor has seen acceleration above the threshold | + | | set with `enable_motion_detection`. | + +------------+----------------------------------------------------------------------------+ + |``data_ready``| True if the sensor has data to be read. Can be used for more precise | + | | timing if reading many samples | + +------------+----------------------------------------------------------------------------+ + + + """ + + interrupt_source_register = self._read_clear_interrupt_source() + + self._event_status.clear() + + for event_type, value in self._enabled_interrupts.items(): + if event_type == "motion": + self._event_status[event_type] = ( + interrupt_source_register & _INT_ACT > 0 + ) + if event_type == "tap": + if value == 1: + self._event_status[event_type] = ( + interrupt_source_register & _INT_SINGLE_TAP > 0 + ) + else: + self._event_status[event_type] = ( + interrupt_source_register & _INT_DOUBLE_TAP > 0 + ) + if event_type == "data_ready": + self._event_status[event_type] = ( + interrupt_source_register & _INT_DATA_READY > 0 + ) + + return self._event_status + + def enable_data_ready_interrupt(self): + """ + Enable Data Ready interrupt for precise data timing + """ + active_interrupts = self._read_register_unpacked(_REG_INT_ENABLE) + + self._write_register_byte(_REG_INT_ENABLE, 0x0) # disable interrupts for setup + + # add DATA_READY to the active interrupts and set them to re-enable + active_interrupts |= _INT_DATA_READY + self._write_register_byte(_REG_INT_ENABLE, active_interrupts) + self._enabled_interrupts["data_ready"] = True diff --git a/examples/adxl37x_data_ready.py b/examples/adxl37x_data_ready.py new file mode 100644 index 0000000..8043030 --- /dev/null +++ b/examples/adxl37x_data_ready.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2022 Kattni Rembor for Adafruit Industries +# SPDX-License-Identifier: MIT + +import board +import digitalio +import adafruit_adxl37x + +i2c = board.STEMMA_I2C() # uses board.SCL and board.SDA +accelerometer = adafruit_adxl37x.ADXL375(i2c) + +interrupt = digitalio.DigitalInOut(board.GP3) # Set interrupt dio pin + +print("Accelerometer starting...") +accelerometer.data_rate = ( + accelerometer.DataRate.RATE_800_HZ +) # Set Data Rate of accelerometer +accelerometer.range = adafruit_adxl37x.Range.RANGE_200_G # Set Full Data Range 200g +accelerometer.enable_data_ready_interrupt() # Enable Data Ready Interrupt + +while True: + if interrupt.value: + # ADXL375 interrupt pin stays HIGH until data is read, so simply reading the logic state + # is sufficient instead of having to catch the rising edge. + print("%f %f %f m/s^2" % accelerometer.acceleration) From c010d78cdb32372c8c79ce9ddb413d0f6c240c07 Mon Sep 17 00:00:00 2001 From: RoaCode <176423185+RoaCode@users.noreply.github.com> Date: Thu, 12 Sep 2024 16:21:22 -0400 Subject: [PATCH 2/3] Added white space around double-ticks in events comment --- adafruit_adxl37x.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adafruit_adxl37x.py b/adafruit_adxl37x.py index b1c613c..7fe81ac 100644 --- a/adafruit_adxl37x.py +++ b/adafruit_adxl37x.py @@ -181,7 +181,7 @@ def range(self, val: int) -> None: @property def events(self) -> Dict[str, bool]: """ - :attr:`events` will return a dictionary with a key for each + :attr: `events` will return a dictionary with a key for each event type that has been enabled. The possible keys are: @@ -194,8 +194,8 @@ def events(self) -> Dict[str, bool]: | ``motion`` | True if the sensor has seen acceleration above the threshold | | | set with `enable_motion_detection`. | +------------+----------------------------------------------------------------------------+ - |``data_ready``| True if the sensor has data to be read. Can be used for more precise | - | | timing if reading many samples | + | ``data_ready`` | True if the sensor has data to be read. Can be used for more precise | + | | timing if reading many samples | +------------+----------------------------------------------------------------------------+ From 38506f1c5dce8b174ab1614b8aa5d0ab39052684 Mon Sep 17 00:00:00 2001 From: RoaCode <176423185+RoaCode@users.noreply.github.com> Date: Fri, 13 Sep 2024 10:41:05 -0400 Subject: [PATCH 3/3] Added disable_data_ready_interrupt and improved docs Added matching interrupt disable function for data_ready and added sphinx references for documentation. --- adafruit_adxl37x.py | 14 +++++++++++--- docs/conf.py | 4 ++++ docs/examples.rst | 9 +++++++++ docs/index.rst | 5 ++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/adafruit_adxl37x.py b/adafruit_adxl37x.py index 7fe81ac..e624796 100644 --- a/adafruit_adxl37x.py +++ b/adafruit_adxl37x.py @@ -189,13 +189,14 @@ def events(self) -> Dict[str, bool]: | Key | Description | +============+============================================================================+ | ``tap`` | True if a tap was detected recently. Whether it's looking for a single | - | | or double tap is determined by the tap param of `enable_tap_detection` | + | | or double tap is determined by the tap param of | + | | :meth:`adafruit_adxl34x.enable_tap_detection` | +------------+----------------------------------------------------------------------------+ | ``motion`` | True if the sensor has seen acceleration above the threshold | - | | set with `enable_motion_detection`. | + | | set with :meth:`adafruit_adxl34x.enable_motion_detection` | +------------+----------------------------------------------------------------------------+ | ``data_ready`` | True if the sensor has data to be read. Can be used for more precise | - | | timing if reading many samples | + | | timing if reading many samples. Set with `enable_data_ready_interrupt` | +------------+----------------------------------------------------------------------------+ @@ -238,3 +239,10 @@ def enable_data_ready_interrupt(self): active_interrupts |= _INT_DATA_READY self._write_register_byte(_REG_INT_ENABLE, active_interrupts) self._enabled_interrupts["data_ready"] = True + + def disable_data_ready_interrupt(self) -> None: + """Disable Data Ready interrupt""" + active_interrupts = self._read_register_unpacked(_REG_INT_ENABLE) + active_interrupts &= ~_INT_DATA_READY + self._write_register_byte(_REG_INT_ENABLE, active_interrupts) + self._enabled_interrupts.pop("data_ready") diff --git a/docs/conf.py b/docs/conf.py index 681c3e8..9be4c1c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -34,6 +34,10 @@ "python": ("https://docs.python.org/3", None), "BusDevice": ("https://docs.circuitpython.org/projects/busdevice/en/latest/", None), "CircuitPython": ("https://docs.circuitpython.org/en/latest/", None), + "adafruit_adxl34x": ( + "https://docs.circuitpython.org/projects/adxl34x/en/latest/", + None, + ), } # Show the docstring from both the class and its __init__() method. diff --git a/docs/examples.rst b/docs/examples.rst index 2ca5fa8..aa20fd9 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -6,3 +6,12 @@ Ensure your device works with this simple test. .. literalinclude:: ../examples/adxl37x_simpletest.py :caption: examples/adxl37x_simpletest.py :linenos: + +Data Ready Interrupt +--------------------- + +Use the Data Ready interrupt for precise data timing. + +.. literalinclude:: ../examples/adxl37x_data_ready.py + :caption: examples/adxl37x_data_ready.py + :linenos: diff --git a/docs/index.rst b/docs/index.rst index 5a3f345..8e2d79b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -25,11 +25,14 @@ Table of Contents :caption: Tutorials Adafruit ADXL375 + Adafruit ADXL345 - Triple-Axis Accelerometer (+-2g/4g/8g/16g) w/ I2C/SPI Learning Guide .. toctree:: :caption: Related Products - ADXL375 - High G Accelerometer with I2C - STEMMA QT + ADXL345 - Triple-Axis Accelerometer (+-2g/4g/8g/16g) w/ I2C/SPI + ADXL375 - High G Accelerometer with I2C - STEMMA QT + .. toctree:: :caption: Other Links