From a3319a17d04aead3f8a9ede867e78c8174e9aede Mon Sep 17 00:00:00 2001 From: jerryneedell Date: Tue, 8 Mar 2022 17:40:12 -0500 Subject: [PATCH 1/2] add licences to example --- adafruit_lsm6ds/__init__.py | 98 ++++++++++++++++++++++++-- adafruit_lsm6ds/lsm6dsox.py | 6 +- examples/lsm6ds_lsm6dsox_mlc_test.py | 37 ++++++++++ examples/lsm6ds_lsm6dsox_simpletest.py | 2 +- 4 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 examples/lsm6ds_lsm6dsox_mlc_test.py diff --git a/adafruit_lsm6ds/__init__.py b/adafruit_lsm6ds/__init__.py index 1ea20cc..85284c8 100644 --- a/adafruit_lsm6ds/__init__.py +++ b/adafruit_lsm6ds/__init__.py @@ -55,6 +55,7 @@ __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_LSM6DS.git" +import struct from time import sleep from math import radians from micropython import const @@ -62,7 +63,7 @@ from adafruit_register.i2c_struct import ROUnaryStruct, Struct from adafruit_register.i2c_bits import RWBits -from adafruit_register.i2c_bit import RWBit +from adafruit_register.i2c_bit import RWBit, ROBit try: from typing import Tuple, Optional @@ -139,6 +140,7 @@ class AccelHPF(CV): LSM6DS_CHIP_ID = const(0x6C) +_LSM6DS_MLC_INT1 = const(0x0D) _LSM6DS_WHOAMI = const(0xF) _LSM6DS_CTRL1_XL = const(0x10) _LSM6DS_CTRL2_G = const(0x11) @@ -146,15 +148,26 @@ class AccelHPF(CV): _LSM6DS_CTRL8_XL = const(0x17) _LSM6DS_CTRL9_XL = const(0x18) _LSM6DS_CTRL10_C = const(0x19) +_LSM6DS_ALL_INT_SRC = const(0x1A) _LSM6DS_OUT_TEMP_L = const(0x20) _LSM6DS_OUTX_L_G = const(0x22) _LSM6DS_OUTX_L_A = const(0x28) +_LSM6DS_MLC_STATUS = const(0x38) _LSM6DS_STEP_COUNTER = const(0x4B) +_LSM6DS_TAP_CFG0 = const(0x56) _LSM6DS_TAP_CFG = const(0x58) - +_LSM6DS_MLC0_SRC = const(0x70) _MILLI_G_TO_ACCEL = 0.00980665 +_LSM6DS_EMB_FUNC_EN_A = const(0x04) +_LSM6DS_EMB_FUNC_EN_B = const(0x05) +_LSM6DS_FUNC_CFG_ACCESS = const(0x01) +_LSM6DS_FUNC_CFG_BANK_USER = const(0) +_LSM6DS_FUNC_CFG_BANK_HUB = const(1) +_LSM6DS_FUNC_CFG_BANK_EMBED = const(2) + + class LSM6DS: # pylint: disable=too-many-instance-attributes """Driver for the LSM6DSOX 6-axis accelerometer and gyroscope. @@ -171,7 +184,10 @@ class LSM6DS: # pylint: disable=too-many-instance-attributes _raw_accel_data = Struct(_LSM6DS_OUTX_L_A, " None: + def __init__( + self, i2c_bus: I2C, address: int = LSM6DS_DEFAULT_ADDRESS, ucf: str = None + ) -> None: self._cached_accel_range = None self._cached_gyro_range = None @@ -215,6 +240,10 @@ def __init__(self, i2c_bus: I2C, address: int = LSM6DS_DEFAULT_ADDRESS) -> None: self.accelerometer_range = AccelRange.RANGE_4G # pylint: disable=no-member self.gyro_range = GyroRange.RANGE_250_DPS # pylint: disable=no-member + # Load and configure MLC if UCF file is provided + print(ucf) + if ucf is not None: + self.load_mlc(ucf) def reset(self) -> None: "Resets the sensor's configuration into an initial state" @@ -376,3 +405,64 @@ def temperature(self) -> float: return (temp - 2 ** 13) * 0.0625 return temp * 0.0625 + + def set_embedded_functions(self, enable, emb_ab=None): + """DocString Here""" + self._mem_bank = 1 + if enable: + self._emb_func_en_a = emb_ab[0] + self._emb_func_en_b = emb_ab[1] + else: + emb_a = self._emb_func_en_a + emb_b = self._emb_func_en_b + print(emb_a) + print(emb_b) + self._emb_func_en_a = (emb_a[0] & 0xC7,) + self._emb_func_en_b = (emb_b[0] & 0xE6,) + emb_ab = (emb_a, emb_b) + + self._mem_bank = 0 + return emb_ab + + def load_mlc(self, ucf): + """DOCString Here""" + buf = bytearray(2) + with self.i2c_device as i2c: + # Load MLC config from file + with open(ucf, "r") as ucf_file: + for line in ucf_file: + if line.startswith("Ac"): + command = [int(v, 16) for v in line.strip().split(" ")[1:3]] + print(line) + buf[0] = command[0] + buf[1] = command[1] + i2c.write(buf) + + emb_ab = self.set_embedded_functions(False) + + # Disable I3C interface + self._i3c_disable = 1 + + # Enable Block Data Update + self._block_data_enable = 1 + + # Route signals on interrupt pin 1 + self._mem_bank = 1 + self._route_int1 &= 1 + self._mem_bank = 1 + + # Configure interrupt pin mode + self._tap_latch = 1 + self._tap_clear = 1 + + self.set_embedded_functions(True, emb_ab) + + def read_mlc_output(self): + """DOCString here""" + buf = None + if self._mlc_status: + # junk = self._all_int + self._mem_bank = 1 + buf = self._mlc0_src + self._mem_bank = 0 + return buf diff --git a/adafruit_lsm6ds/lsm6dsox.py b/adafruit_lsm6ds/lsm6dsox.py index 3f5baa5..215b5e6 100644 --- a/adafruit_lsm6ds/lsm6dsox.py +++ b/adafruit_lsm6ds/lsm6dsox.py @@ -50,6 +50,8 @@ class LSM6DSOX(LSM6DS): # pylint: disable=too-many-instance-attributes CHIP_ID = LSM6DS_CHIP_ID - def __init__(self, i2c_bus: I2C, address: int = LSM6DS_DEFAULT_ADDRESS) -> None: - super().__init__(i2c_bus, address) + def __init__( + self, i2c_bus: I2C, address: int = LSM6DS_DEFAULT_ADDRESS, ucf: str = None + ) -> None: + super().__init__(i2c_bus, address, ucf) self._i3c_disable = True diff --git a/examples/lsm6ds_lsm6dsox_mlc_test.py b/examples/lsm6ds_lsm6dsox_mlc_test.py new file mode 100644 index 0000000..f2569aa --- /dev/null +++ b/examples/lsm6ds_lsm6dsox_mlc_test.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: Copyright (c) 2020 Bryan Siepert for Adafruit Industries +# +# SPDX-License-Identifier: MIT +# LSM6DSOX IMU MLC (Machine Learning Core) Example. +# Download the raw UCF file, copy to storage and reset. + +# NOTE: The pre-trained models (UCF files) for the examples can be found here: +# https://github.com/STMicroelectronics/STMems_Machine_Learning_Core/tree/master/application_examples/lsm6dsox + +import board +from adafruit_lsm6ds.lsm6dsox import LSM6DSOX +from adafruit_lsm6ds import Rate, AccelRange, GyroRange + +i2c = board.STEMMA_I2C() # uses board.SCL and board.SDA + + +# Vibration detection example +UCF_FILE = "lsm6dsox_vibration_monitoring.ucf" +UCF_LABELS = {0: "no vibration", 1: "low vibration", 2: "high vibration"} +# NOTE: Selected data rate and scale must match the MLC data rate and scale. +lsm = LSM6DSOX(i2c, ucf=UCF_FILE) +lsm.gyro_range = GyroRange.RANGE_2000_DPS +lsm.accelerometer_range = AccelRange.RANGE_4G +lsm.accelerometer_data_rate = Rate.RATE_26_HZ +lsm.gyro_data_rate = Rate.RATE_26_HZ +# Head gestures example +# UCF_FILE = "lsm6dsox_head_gestures.ucf" +# UCF_LABELS = {0:"Nod", 1:"Shake", 2:"Stationary", 3:"Swing", 4:"Walk"} +# NOTE: Selected data rate and scale must match the MLC data rate and scale. +# lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=250, accel_scale=2, ucf=UCF_FILE) + +print("MLC configured...") + +while True: + buf = lsm.read_mlc_output() + if buf is not None: + print(UCF_LABELS[buf[0]]) diff --git a/examples/lsm6ds_lsm6dsox_simpletest.py b/examples/lsm6ds_lsm6dsox_simpletest.py index db887dd..203f6f5 100644 --- a/examples/lsm6ds_lsm6dsox_simpletest.py +++ b/examples/lsm6ds_lsm6dsox_simpletest.py @@ -5,7 +5,7 @@ import board from adafruit_lsm6ds.lsm6dsox import LSM6DSOX -i2c = board.I2C() # uses board.SCL and board.SDA +i2c = board.STEMMA_I2C() # uses board.SCL and board.SDA sensor = LSM6DSOX(i2c) while True: From 039c91a0eb1598dbd517d775a32558f495029e05 Mon Sep 17 00:00:00 2001 From: jerryneedell Date: Wed, 9 Mar 2022 14:10:10 -0500 Subject: [PATCH 2/2] clean up - black --- adafruit_lsm6ds/__init__.py | 24 ++++++++++-------------- examples/lsm6ds_lsm6dsox_mlc_test.py | 24 +++++++++++++++++++++++- examples/lsm6ds_lsm6dsox_simpletest.py | 2 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/adafruit_lsm6ds/__init__.py b/adafruit_lsm6ds/__init__.py index 85284c8..9bd7159 100644 --- a/adafruit_lsm6ds/__init__.py +++ b/adafruit_lsm6ds/__init__.py @@ -186,8 +186,7 @@ class LSM6DS: # pylint: disable=too-many-instance-attributes _raw_temp_data = Struct(_LSM6DS_OUT_TEMP_L, " float: return temp * 0.0625 - def set_embedded_functions(self, enable, emb_ab=None): - """DocString Here""" + def _set_embedded_functions(self, enable, emb_ab=None): + """Enable/disable embedded functions - returns prior settings when disabled""" self._mem_bank = 1 if enable: self._emb_func_en_a = emb_ab[0] @@ -415,8 +413,6 @@ def set_embedded_functions(self, enable, emb_ab=None): else: emb_a = self._emb_func_en_a emb_b = self._emb_func_en_b - print(emb_a) - print(emb_b) self._emb_func_en_a = (emb_a[0] & 0xC7,) self._emb_func_en_b = (emb_b[0] & 0xE6,) emb_ab = (emb_a, emb_b) @@ -425,7 +421,7 @@ def set_embedded_functions(self, enable, emb_ab=None): return emb_ab def load_mlc(self, ucf): - """DOCString Here""" + """Load MLC configuration file into sensor""" buf = bytearray(2) with self.i2c_device as i2c: # Load MLC config from file @@ -433,12 +429,12 @@ def load_mlc(self, ucf): for line in ucf_file: if line.startswith("Ac"): command = [int(v, 16) for v in line.strip().split(" ")[1:3]] - print(line) buf[0] = command[0] buf[1] = command[1] i2c.write(buf) - emb_ab = self.set_embedded_functions(False) + # Disable embudded function -- save current settings + emb_ab = self._set_embedded_functions(False) # Disable I3C interface self._i3c_disable = 1 @@ -449,19 +445,19 @@ def load_mlc(self, ucf): # Route signals on interrupt pin 1 self._mem_bank = 1 self._route_int1 &= 1 - self._mem_bank = 1 + self._mem_bank = 0 # Configure interrupt pin mode self._tap_latch = 1 self._tap_clear = 1 - self.set_embedded_functions(True, emb_ab) + # Enabble Embedded Functions using previously stored settings + self._set_embedded_functions(True, emb_ab) def read_mlc_output(self): - """DOCString here""" + """Read MLC results""" buf = None if self._mlc_status: - # junk = self._all_int self._mem_bank = 1 buf = self._mlc0_src self._mem_bank = 0 diff --git a/examples/lsm6ds_lsm6dsox_mlc_test.py b/examples/lsm6ds_lsm6dsox_mlc_test.py index f2569aa..16c8d30 100644 --- a/examples/lsm6ds_lsm6dsox_mlc_test.py +++ b/examples/lsm6ds_lsm6dsox_mlc_test.py @@ -7,6 +7,7 @@ # NOTE: The pre-trained models (UCF files) for the examples can be found here: # https://github.com/STMicroelectronics/STMems_Machine_Learning_Core/tree/master/application_examples/lsm6dsox +import time import board from adafruit_lsm6ds.lsm6dsox import LSM6DSOX from adafruit_lsm6ds import Rate, AccelRange, GyroRange @@ -23,11 +24,28 @@ lsm.accelerometer_range = AccelRange.RANGE_4G lsm.accelerometer_data_rate = Rate.RATE_26_HZ lsm.gyro_data_rate = Rate.RATE_26_HZ + + # Head gestures example # UCF_FILE = "lsm6dsox_head_gestures.ucf" # UCF_LABELS = {0:"Nod", 1:"Shake", 2:"Stationary", 3:"Swing", 4:"Walk"} # NOTE: Selected data rate and scale must match the MLC data rate and scale. -# lsm = LSM6DSOX(i2c, gyro_odr=26, accel_odr=26, gyro_scale=250, accel_scale=2, ucf=UCF_FILE) +# lsm = LSM6DSOX(i2c, ucf=UCF_FILE) +# lsm.gyro_range = GyroRange.RANGE_250_DPS +# lsm.accelerometer_range = AccelRange.RANGE_2G +# lsm.accelerometer_data_rate = Rate.RATE_26_HZ +# lsm.gyro_data_rate = Rate.RATE_26_HZ + +# 6 DOF Position example +# UCF_FILE = "lsm6dsox_six_d_position.ucf" +# UCF_LABELS = {0:"None", 1:"X-UP", 2:"X-DOWN", 3:"Y-UP", 4:"Y-DOWN", 5:"Z-UP", 6:"Z-DOWN"} +# NOTE: Selected data rate and scale must match the MLC data rate and scale. +# lsm = LSM6DSOX(i2c, ucf=UCF_FILE) +# lsm.gyro_range = GyroRange.RANGE_250_DPS +# lsm.accelerometer_range = AccelRange.RANGE_2G +# lsm.accelerometer_data_rate = Rate.RATE_26_HZ +# lsm.gyro_data_rate = Rate.RATE_26_HZ + print("MLC configured...") @@ -35,3 +53,7 @@ buf = lsm.read_mlc_output() if buf is not None: print(UCF_LABELS[buf[0]]) + # delay to allow interrupt flag to clear + # interrupt stays high for one sample interval + # (38.4 ms @ 26 Hz ot 19.2 ms @ 52Hz) + time.sleep(0.05) diff --git a/examples/lsm6ds_lsm6dsox_simpletest.py b/examples/lsm6ds_lsm6dsox_simpletest.py index 203f6f5..db887dd 100644 --- a/examples/lsm6ds_lsm6dsox_simpletest.py +++ b/examples/lsm6ds_lsm6dsox_simpletest.py @@ -5,7 +5,7 @@ import board from adafruit_lsm6ds.lsm6dsox import LSM6DSOX -i2c = board.STEMMA_I2C() # uses board.SCL and board.SDA +i2c = board.I2C() # uses board.SCL and board.SDA sensor = LSM6DSOX(i2c) while True: