diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..aaf18d2 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.7.5 diff --git a/LICENSE b/LICENSE index 6b323f4..b630ac0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2019 Bryan Siepert for Adafruit Industries +Copyright (c) 2020 Bryan Siepert for Adafruit Industries Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.rst b/README.rst index a2178f7..71a091d 100644 --- a/README.rst +++ b/README.rst @@ -9,11 +9,11 @@ Introduction :target: https://discord.gg/nBQh6qu :alt: Discord -.. image:: https://github.com/adafruit/Adafruit_CircuitPython_ICM20649/workflows/Build%20CI/badge.svg - :target: https://github.com/adafruit/Adafruit_CircuitPython_ICM20649/actions +.. image:: https://github.com/adafruit/Adafruit_CircuitPython_ICM20X/workflows/Build%20CI/badge.svg + :target: https://github.com/adafruit/Adafruit_CircuitPython_ICM20X/actions :alt: Build Status -Library for the ST ICM-20649 Wide-Range 6-DoF Accelerometer and Gyro +Library for the ST ICM-20X Wide-Range 6-DoF Accelerometer and Gyro Family Dependencies @@ -32,17 +32,17 @@ Installing from PyPI ===================== On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from -PyPI `_. To install for current user: +PyPI `_. To install for current user: .. code-block:: shell - pip3 install adafruit-circuitpython-icm20649 + pip3 install adafruit-circuitpython-icm20x To install system-wide (this may be required in some cases): .. code-block:: shell - sudo pip3 install adafruit-circuitpython-icm20649 + sudo pip3 install adafruit-circuitpython-icm20x To install in a virtual environment in your current project: @@ -51,23 +51,45 @@ To install in a virtual environment in your current project: mkdir project-name && cd project-name python3 -m venv .env source .env/bin/activate - pip3 install adafruit-circuitpython-icm20649 + pip3 install adafruit-circuitpython-icm20x Usage Example ============= -.. code-block: python3 +For use with the ICM20649: + +.. code-block:: python3 + + import time + import board + import busio + import adafruit_icm20x + + i2c = busio.I2C(board.SCL, board.SDA) + icm = adafruit_icm20x.ICM20649(i2c) + + while True: + print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % (icm.acceleration)) + print("Gyro X:%.2f, Y: %.2f, Z: %.2f rads/s" % (icm.gyro)) + print("") + time.sleep(0.5) + +For use with the ICM20948: + +.. code-block:: python3 + import time import board import busio - import adafruit_icm20649 + import adafruit_icm20x i2c = busio.I2C(board.SCL, board.SDA) - icm = adafruit_icm20649.ICM20649(i2c) + icm = adafruit_icm20x.ICM20948(i2c) while True: - print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2"%(icm.acceleration)) - print("Gyro X:%.2f, Y: %.2f, Z: %.2f degrees/s"%(icm.gyro)) + print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % (icm.acceleration)) + print("Gyro X:%.2f, Y: %.2f, Z: %.2f rads/s" % (icm.gyro)) + print("Magnetometer X:%.2f, Y: %.2f, Z: %.2f uT" % (icm.magnetic)) print("") time.sleep(0.5) @@ -75,7 +97,7 @@ Contributing ============ Contributions are welcome! Please read our `Code of Conduct -`_ +`_ before contributing to help this project stay welcoming. Documentation diff --git a/adafruit_icm20649.py b/adafruit_icm20649.py deleted file mode 100644 index 36f6ebd..0000000 --- a/adafruit_icm20649.py +++ /dev/null @@ -1,345 +0,0 @@ -# The MIT License (MIT) -# -# Copyright (c) 2019 Bryan Siepert for Adafruit Industries -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -""" -`adafruit_icm20649` -================================================================================ - -Library for the ST ICM20649 Wide-Range 6-DoF Accelerometer and Gyro - -* Author(s): Bryan Siepert - -Implementation Notes --------------------- - -**Hardware:** - -* Adafruit's ICM20649 Breakout: https://adafruit.com/product/4464 - -**Software and Dependencies:** - -* Adafruit CircuitPython firmware for the supported boards: - https://circuitpython.org/downloads - - -* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice -* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register -""" - -__version__ = "0.0.0-auto.0" -__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ICM20649.git" -# Common imports; remove if unused or pylint will complain -from time import sleep -import adafruit_bus_device.i2c_device as i2c_device - -from adafruit_register.i2c_struct import UnaryStruct, ROUnaryStruct, Struct -from adafruit_register.i2c_bit import RWBit -from adafruit_register.i2c_bits import RWBits - -# pylint: disable=bad-whitespace -_ICM20649_DEFAULT_ADDRESS = 0x68 # icm20649 default i2c address -_ICM20649_DEVICE_ID = 0xE1 # Correct context of WHO_AM_I register - -# Bank 0 -_ICM20649_WHO_AM_I = 0x00 # device_id register -_ICM20649_REG_BANK_SEL = 0x7F # register bank selection register -_ICM20649_PWR_MGMT_1 = 0x06 # primary power management register -_ICM20649_ACCEL_XOUT_H = 0x2D # first byte of accel data -_ICM20649_GYRO_XOUT_H = 0x33 # first byte of accel data - -# Bank 2 -_ICM20649_GYRO_SMPLRT_DIV = 0x00 -_ICM20649_GYRO_CONFIG_1 = 0x01 -_ICM20649_ACCEL_SMPLRT_DIV_1 = 0x10 -_ICM20649_ACCEL_SMPLRT_DIV_2 = 0x11 -_ICM20649_ACCEL_CONFIG_1 = 0x14 - - -G_TO_ACCEL = 9.80665 -# pylint: enable=bad-whitespace -class CV: - """struct helper""" - - @classmethod - def add_values(cls, value_tuples): - """Add CV values to the class""" - cls.string = {} - cls.lsb = {} - - for value_tuple in value_tuples: - name, value, string, lsb = value_tuple - setattr(cls, name, value) - cls.string[value] = string - cls.lsb[value] = lsb - - @classmethod - def is_valid(cls, value): - """Validate that a given value is a member""" - return value in cls.string - - -class AccelRange(CV): - """Options for ``accelerometer_range``""" - - pass # pylint: disable=unnecessary-pass - - -AccelRange.add_values( - ( - ("RANGE_4G", 0, 4, 8192), - ("RANGE_8G", 1, 8, 4096.0), - ("RANGE_16G", 2, 16, 2048), - ("RANGE_30G", 3, 30, 1024), - ) -) - - -class GyroRange(CV): - """Options for ``gyro_data_range``""" - - pass # pylint: disable=unnecessary-pass - - -GyroRange.add_values( - ( - ("RANGE_500_DPS", 0, 500, 65.5), - ("RANGE_1000_DPS", 1, 1000, 32.8), - ("RANGE_2000_DPS", 2, 2000, 16.4), - ("RANGE_4000_DPS", 3, 4000, 8.2), - ) -) - - -class ICM20649: # pylint:disable=too-many-instance-attributes - """Library for the ST ICM-20649 Wide-Range 6-DoF Accelerometer and Gyro. - - :param ~busio.I2C i2c_bus: The I2C bus the ICM20649 is connected to. - :param address: The I2C slave address of the sensor - - """ - - # Bank 0 - _device_id = ROUnaryStruct(_ICM20649_WHO_AM_I, "hhh") - _raw_gyro_data = Struct(_ICM20649_GYRO_XOUT_H, ">hhh") - - # Bank 2 - _gyro_range = RWBits(2, _ICM20649_GYRO_CONFIG_1, 1) - _accel_dlpf_enable = RWBits(1, _ICM20649_ACCEL_CONFIG_1, 0) - _accel_range = RWBits(2, _ICM20649_ACCEL_CONFIG_1, 1) - _accel_dlpf_config = RWBits(3, _ICM20649_ACCEL_CONFIG_1, 3) - - # this value is a 12-bit register spread across two bytes, big-endian first - _accel_rate_divisor = UnaryStruct(_ICM20649_ACCEL_SMPLRT_DIV_1, ">H") - - _gyro_rate_divisor = UnaryStruct(_ICM20649_GYRO_SMPLRT_DIV, ">B") - - def __init__(self, i2c_bus, address=_ICM20649_DEFAULT_ADDRESS): - self.i2c_device = i2c_device.I2CDevice(i2c_bus, address) - if self._device_id != _ICM20649_DEVICE_ID: - raise RuntimeError("Failed to find ICM20649 - check your wiring!") - self.reset() - - self._bank = 0 - self._sleep = False - - self._bank = 2 - self._accel_range = AccelRange.RANGE_8G # pylint: disable=no-member - self._cached_accel_range = self._accel_range - - # TODO: CV-ify - self._accel_dlpf_config = 3 - - # 1.125 kHz/(1+ACCEL_SMPLRT_DIV[11:0]), - # 1125Hz/(1+20) = 53.57Hz - self._accel_rate_divisor = 20 - - # writeByte(ICM20649_ADDR,GYRO_CONFIG_1, gyroConfig); - self._gyro_range = GyroRange.RANGE_500_DPS # pylint: disable=no-member - sleep(0.100) - self._cached_gyro_range = self._gyro_range - - # //ORD = 1100Hz/(1+10) = 100Hz - self._gyro_rate_divisor = 0x0A - - # //reset to register bank 0 - self._bank = 0 - - def reset(self): - """Resets the internal registers and restores the default settings""" - self._reset = True - while self._reset: - sleep(0.001) - - @property - def acceleration(self): - """The x, y, z acceleration values returned in a 3-tuple and are in m / s ^ 2.""" - raw_accel_data = self._raw_accel_data - - x = self._scale_xl_data(raw_accel_data[0]) - y = self._scale_xl_data(raw_accel_data[1]) - z = self._scale_xl_data(raw_accel_data[2]) - - return (x, y, z) - - @property - def gyro(self): - """The x, y, z angular velocity values returned in a 3-tuple and are in degrees / second""" - raw_gyro_data = self._raw_gyro_data - x = self._scale_gyro_data(raw_gyro_data[0]) - y = self._scale_gyro_data(raw_gyro_data[1]) - z = self._scale_gyro_data(raw_gyro_data[2]) - - return (x, y, z) - - def _scale_xl_data(self, raw_measurement): - return raw_measurement / AccelRange.lsb[self._cached_accel_range] * G_TO_ACCEL - - def _scale_gyro_data(self, raw_measurement): - return raw_measurement / GyroRange.lsb[self._cached_gyro_range] - - @property - def accelerometer_range(self): - """Adjusts the range of values that the sensor can measure, from +/- 4G to +/-30G - Note that larger ranges will be less accurate. Must be an `AccelRange`""" - return self._cached_accel_range - - @accelerometer_range.setter - def accelerometer_range(self, value): # pylint: disable=no-member - if not AccelRange.is_valid(value): - raise AttributeError("range must be an `AccelRange`") - self._bank = 2 - self._accel_range = value - self._cached_accel_range = value - self._bank = 0 - - @property - def gyro_range(self): - """Adjusts the range of values that the sensor can measure, from 500 Degrees/second to 4000 - degrees/s. Note that larger ranges will be less accurate. Must be a `GyroRange`""" - return self._cached_gyro_range - - @gyro_range.setter - def gyro_range(self, value): - if not GyroRange.is_valid(value): - raise AttributeError("range must be a `GyroRange`") - - self._bank = 2 - self._gyro_range = value - self._cached_gyro_range = value - self._bank = 0 - sleep(0.100) # needed to let new range settle - - @property - def accelerometer_data_rate_divisor(self): - """The divisor for the rate at which accelerometer measurements are taken in Hz - - Note: The data rates are set indirectly by setting a rate divisor according to the - following formula: ``accelerometer_data_rate = 1125/(1+divisor)`` - - This function sets the raw rate divisor. -""" - self._bank = 2 - raw_rate_divisor = self._accel_rate_divisor - self._bank = 0 - # rate_hz = 1125/(1+raw_rate_divisor) - return raw_rate_divisor - - @accelerometer_data_rate_divisor.setter - def accelerometer_data_rate_divisor(self, value): - # check that value <= 4095 - self._bank = 2 - self._accel_rate_divisor = value - self._bank = 0 - - @property - def gyro_data_rate_divisor(self): - """The divisor for the rate at which gyro measurements are taken in Hz - - Note: The data rates are set indirectly by setting a rate divisor according to the - following formula: ``gyro_data_rate = 1100/(1+divisor)`` - - This function sets the raw rate divisor. - """ - - self._bank = 2 - raw_rate_divisor = self._gyro_rate_divisor - self._bank = 0 - # rate_hz = 1100/(1+raw_rate_divisor) - return raw_rate_divisor - - @gyro_data_rate_divisor.setter - def gyro_data_rate_divisor(self, value): - # check that value <= 255 - self._bank = 2 - self._gyro_rate_divisor = value - self._bank = 0 - - def _accel_rate_calc(self, divisor): # pylint:disable=no-self-use - return 1125 / (1 + divisor) - - def _gyro_rate_calc(self, divisor): # pylint:disable=no-self-use - return 1100 / (1 + divisor) - - @property - def accelerometer_data_rate(self): - """The rate at which accelerometer measurements are taken in Hz - - Note: The data rates are set indirectly by setting a rate divisor according to the - following formula: ``accelerometer_data_rate = 1125/(1+divisor)`` - - This function does the math to find the divisor from a given rate but it will not be - exactly as specified. - """ - return self._accel_rate_calc(self.accelerometer_data_rate_divisor) - - @accelerometer_data_rate.setter - def accelerometer_data_rate(self, value): - if value < self._accel_rate_calc(4095) or value > self._accel_rate_calc(0): - raise AttributeError( - "Accelerometer data rate must be between 0.27 and 1125.0" - ) - self.accelerometer_data_rate_divisor = value - - @property - def gyro_data_rate(self): - """The rate at which gyro measurements are taken in Hz - - Note: The data rates are set indirectly by setting a rate divisor according to the - following formula: ``gyro_data_rate = 1100/(1+divisor)`` - - This function does the math to find the divisor from a given rate but it will not - be exactly as specified. - """ - return self._gyro_rate_calc(self.gyro_data_rate_divisor) - - @gyro_data_rate.setter - def gyro_data_rate(self, value): - if value < self._gyro_rate_calc(4095) or value > self._gyro_rate_calc(0): - raise AttributeError("Gyro data rate must be between 4.30 and 1100.0") - - divisor = round(((1125.0 - value) / value)) - self.gyro_data_rate_divisor = divisor diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py new file mode 100644 index 0000000..e595b41 --- /dev/null +++ b/adafruit_icm20x.py @@ -0,0 +1,761 @@ +# The MIT License (MIT) +# +# Copyright (c) 2020 Bryan Siepert for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +`adafruit_icm20x` +================================================================================ + +Library for the ST ICM20X Motion Sensor Family + +* Author(s): Bryan Siepert + +Implementation Notes +-------------------- + +**Hardware:** + +* Adafruit's ICM20649 Breakout: https://adafruit.com/product/4464 +* Adafruit's ICM20948 Breakout: https://adafruit.com/product/4554 + +**Software and Dependencies:** + +* Adafruit CircuitPython firmware for the supported boards: + https://circuitpython.org/downloads + + +* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice +* Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register +""" + +__version__ = "0.0.0-auto.0" +__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ICM20X.git" +# Common imports; remove if unused or pylint will complain +from time import sleep +import adafruit_bus_device.i2c_device as i2c_device + +from adafruit_register.i2c_struct import UnaryStruct, ROUnaryStruct, Struct +from adafruit_register.i2c_bit import RWBit, ROBit +from adafruit_register.i2c_bits import RWBits + +# pylint: disable=bad-whitespace +_ICM20649_DEFAULT_ADDRESS = 0x68 # icm20649 default i2c address +_ICM20948_DEFAULT_ADDRESS = 0x69 # icm20649 default i2c address +_ICM20649_DEVICE_ID = 0xE1 # Correct content of WHO_AM_I register +_ICM20948_DEVICE_ID = 0xEA # Correct content of WHO_AM_I register + +# Functions using these bank-specific registers are responsible for ensuring +# that the correct bank is set +# Bank 0 +_ICM20X_WHO_AM_I = 0x00 # device_id register +_ICM20X_REG_BANK_SEL = 0x7F # register bank selection register +_ICM20X_PWR_MGMT_1 = 0x06 # primary power management register +_ICM20X_ACCEL_XOUT_H = 0x2D # first byte of accel data +_ICM20X_GYRO_XOUT_H = 0x33 # first byte of accel data +_ICM20X_I2C_MST_STATUS = 0x17 # I2C Master Status bits +_ICM20948_EXT_SLV_SENS_DATA_00 = 0x3B + +_ICM20X_USER_CTRL = 0x03 # User Control Reg. Includes I2C Master +_ICM20X_LP_CONFIG = 0x05 # Low Power config +_ICM20X_REG_INT_PIN_CFG = 0xF # Interrupt config register +_ICM20X_REG_INT_ENABLE_0 = 0x10 # Interrupt enable register 0 +_ICM20X_REG_INT_ENABLE_1 = 0x11 # Interrupt enable register 1 + +# Bank 2 +_ICM20X_GYRO_SMPLRT_DIV = 0x00 +_ICM20X_GYRO_CONFIG_1 = 0x01 +_ICM20X_ACCEL_SMPLRT_DIV_1 = 0x10 +_ICM20X_ACCEL_SMPLRT_DIV_2 = 0x11 +_ICM20X_ACCEL_CONFIG_1 = 0x14 + + +# Bank 3 + +_ICM20X_I2C_MST_ODR_CONFIG = 0x0 # Sets ODR for I2C master bus +_ICM20X_I2C_MST_CTRL = 0x1 # I2C master bus config +_ICM20X_I2C_MST_DELAY_CTRL = 0x2 # I2C master bus config +_ICM20X_I2C_SLV0_ADDR = 0x3 # Sets I2C address for I2C master bus slave 0 +_ICM20X_I2C_SLV0_REG = 0x4 # Sets register address for I2C master bus slave 0 +_ICM20X_I2C_SLV0_CTRL = 0x5 # Controls for I2C master bus slave 0 +_ICM20X_I2C_SLV0_DO = 0x6 # Sets I2C master bus slave 0 data out + +_ICM20X_I2C_SLV4_ADDR = 0x13 # Sets I2C address for I2C master bus slave 4 +_ICM20X_I2C_SLV4_REG = 0x14 # Sets register address for I2C master bus slave 4 +_ICM20X_I2C_SLV4_CTRL = 0x15 # Controls for I2C master bus slave 4 +_ICM20X_I2C_SLV4_DO = 0x16 # Sets I2C master bus slave 4 data out +_ICM20X_I2C_SLV4_DI = 0x17 # Sets I2C master bus slave 4 data in + +_ICM20X_UT_PER_LSB = 0.15 # mag data LSB value (fixed) +_ICM20X_RAD_PER_DEG = 0.017453293 # Degrees/s to rad/s multiplier + +G_TO_ACCEL = 9.80665 +# pylint: enable=bad-whitespace +class CV: + """struct helper""" + + @classmethod + def add_values(cls, value_tuples): + """Add CV values to the class""" + cls.string = {} + cls.lsb = {} + + for value_tuple in value_tuples: + name, value, string, lsb = value_tuple + setattr(cls, name, value) + cls.string[value] = string + cls.lsb[value] = lsb + + @classmethod + def is_valid(cls, value): + """Validate that a given value is a member""" + return value in cls.string + + +class AccelRange(CV): + """Options for ``accelerometer_range``""" + + pass # pylint: disable=unnecessary-pass + + +class GyroRange(CV): + """Options for ``gyro_data_range``""" + + pass # pylint: disable=unnecessary-pass + + +class GyroDLPFFreq(CV): + """Options for ``gyro_dlpf_cutoff``""" + + pass # pylint: disable=unnecessary-pass + + +class AccelDLPFFreq(CV): + """Options for ``accel_dlpf_cutoff``""" + + pass # pylint: disable=unnecessary-pass + + +class ICM20X: # pylint:disable=too-many-instance-attributes + """Library for the ST ICM-20X Wide-Range 6-DoF Accelerometer and Gyro Family + + + :param ~busio.I2C i2c_bus: The I2C bus the ICM20X is connected to. + :param address: The I2C slave address of the sensor + + """ + + # Bank 0 + _device_id = ROUnaryStruct(_ICM20X_WHO_AM_I, ">B") + _bank_reg = UnaryStruct(_ICM20X_REG_BANK_SEL, ">B") + _reset = RWBit(_ICM20X_PWR_MGMT_1, 7) + _sleep_reg = RWBit(_ICM20X_PWR_MGMT_1, 6) + _low_power_en = RWBit(_ICM20X_PWR_MGMT_1, 5) + _clock_source = RWBits(3, _ICM20X_PWR_MGMT_1, 0) + + _raw_accel_data = Struct(_ICM20X_ACCEL_XOUT_H, ">hhh") # ds says LE :| + _raw_gyro_data = Struct(_ICM20X_GYRO_XOUT_H, ">hhh") + + _lp_config_reg = UnaryStruct(_ICM20X_LP_CONFIG, ">B") + + _i2c_master_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) + _accel_cycle_en = RWBit(_ICM20X_LP_CONFIG, 5) + _gyro_cycle_en = RWBit(_ICM20X_LP_CONFIG, 4) + + # Bank 2 + _gyro_dlpf_enable = RWBits(1, _ICM20X_GYRO_CONFIG_1, 0) + _gyro_range = RWBits(2, _ICM20X_GYRO_CONFIG_1, 1) + _gyro_dlpf_config = RWBits(3, _ICM20X_GYRO_CONFIG_1, 3) + + _accel_dlpf_enable = RWBits(1, _ICM20X_ACCEL_CONFIG_1, 0) + _accel_range = RWBits(2, _ICM20X_ACCEL_CONFIG_1, 1) + _accel_dlpf_config = RWBits(3, _ICM20X_ACCEL_CONFIG_1, 3) + + # this value is a 12-bit register spread across two bytes, big-endian first + _accel_rate_divisor = UnaryStruct(_ICM20X_ACCEL_SMPLRT_DIV_1, ">H") + _gyro_rate_divisor = UnaryStruct(_ICM20X_GYRO_SMPLRT_DIV, ">B") + AccelDLPFFreq.add_values( + ( + ( + "DISABLED", + -1, + "Disabled", + None, + ), # magical value that we will use do disable + ("FREQ_246_0HZ_3DB", 1, 246.0, None), + ("FREQ_111_4HZ_3DB", 2, 111.4, None), + ("FREQ_50_4HZ_3DB", 3, 50.4, None), + ("FREQ_23_9HZ_3DB", 4, 23.9, None), + ("FREQ_11_5HZ_3DB", 5, 11.5, None), + ("FREQ_5_7HZ_3DB", 6, 5.7, None), + ("FREQ_473HZ_3DB", 7, 473, None), + ) + ) + GyroDLPFFreq.add_values( + ( + ( + "DISABLED", + -1, + "Disabled", + None, + ), # magical value that we will use do disable + ("FREQ_196_6HZ_3DB", 0, 196.6, None), + ("FREQ_151_8HZ_3DB", 1, 151.8, None), + ("FREQ_119_5HZ_3DB", 2, 119.5, None), + ("FREQ_51_2HZ_3DB", 3, 51.2, None), + ("FREQ_23_9HZ_3DB", 4, 23.9, None), + ("FREQ_11_6HZ_3DB", 5, 11.6, None), + ("FREQ_5_7HZ_3DB", 6, 5.7, None), + ("FREQ_361_4HZ_3DB", 7, 361.4, None), + ) + ) + + @property + def _bank(self): + return self._bank_reg >> 4 + + @_bank.setter + def _bank(self, value): + self._bank_reg = value << 4 + + def __init__(self, i2c_bus, address): + + self.i2c_device = i2c_device.I2CDevice(i2c_bus, address) + self._bank = 0 + if not self._device_id in [_ICM20649_DEVICE_ID, _ICM20948_DEVICE_ID]: + raise RuntimeError("Failed to find an ICM20X sensor - check your wiring!") + self.reset() + self.initialize() + + def initialize(self): + """Configure the sensors with the default settings. For use after calling `reset()`""" + + self._sleep = False + self.accelerometer_range = AccelRange.RANGE_8G # pylint: disable=no-member + self.gyro_range = GyroRange.RANGE_500_DPS # pylint: disable=no-member + + self.accelerometer_data_rate_divisor = 20 # ~53.57Hz + self.gyro_data_rate_divisor = 10 # ~100Hz + + def reset(self): + """Resets the internal registers and restores the default settings""" + self._bank = 0 + + sleep(0.005) + self._reset = True + sleep(0.005) + while self._reset: + sleep(0.005) + + @property + def _sleep(self): + self._bank = 0 + sleep(0.005) + self._sleep_reg = False + sleep(0.005) + + @_sleep.setter + def _sleep(self, sleep_enabled): + self._bank = 0 + sleep(0.005) + self._sleep_reg = sleep_enabled + sleep(0.005) + + @property + def acceleration(self): + """The x, y, z acceleration values returned in a 3-tuple and are in m / s ^ 2.""" + self._bank = 0 + raw_accel_data = self._raw_accel_data + sleep(0.005) + + x = self._scale_xl_data(raw_accel_data[0]) + y = self._scale_xl_data(raw_accel_data[1]) + z = self._scale_xl_data(raw_accel_data[2]) + + return (x, y, z) + + @property + def gyro(self): + """The x, y, z angular velocity values returned in a 3-tuple and are in degrees / second""" + self._bank = 0 + raw_gyro_data = self._raw_gyro_data + x = self._scale_gyro_data(raw_gyro_data[0]) + y = self._scale_gyro_data(raw_gyro_data[1]) + z = self._scale_gyro_data(raw_gyro_data[2]) + + return (x, y, z) + + def _scale_xl_data(self, raw_measurement): + sleep(0.005) + return raw_measurement / AccelRange.lsb[self._cached_accel_range] * G_TO_ACCEL + + def _scale_gyro_data(self, raw_measurement): + return ( + raw_measurement / GyroRange.lsb[self._cached_gyro_range] + ) * _ICM20X_RAD_PER_DEG + + @property + def accelerometer_range(self): + """Adjusts the range of values that the sensor can measure, from +/- 4G to +/-30G + Note that larger ranges will be less accurate. Must be an `AccelRange`""" + return self._cached_accel_range + + @accelerometer_range.setter + def accelerometer_range(self, value): # pylint: disable=no-member + if not AccelRange.is_valid(value): + raise AttributeError("range must be an `AccelRange`") + self._bank = 2 + sleep(0.005) + self._accel_range = value + sleep(0.005) + self._cached_accel_range = value + self._bank = 0 + + @property + def gyro_range(self): + """Adjusts the range of values that the sensor can measure, from 500 Degrees/second to 4000 + degrees/s. Note that larger ranges will be less accurate. Must be a `GyroRange`""" + return self._cached_gyro_range + + @gyro_range.setter + def gyro_range(self, value): + if not GyroRange.is_valid(value): + raise AttributeError("range must be a `GyroRange`") + + self._bank = 2 + sleep(0.005) + self._gyro_range = value + sleep(0.005) + self._cached_gyro_range = value + self._bank = 0 + sleep(0.100) # needed to let new range settle + + @property + def accelerometer_data_rate_divisor(self): + """The divisor for the rate at which accelerometer measurements are taken in Hz + + Note: The data rates are set indirectly by setting a rate divisor according to the + following formula: ``accelerometer_data_rate = 1125/(1+divisor)`` + + This function sets the raw rate divisor. + """ + self._bank = 2 + raw_rate_divisor = self._accel_rate_divisor + sleep(0.005) + self._bank = 0 + # rate_hz = 1125/(1+raw_rate_divisor) + return raw_rate_divisor + + @accelerometer_data_rate_divisor.setter + def accelerometer_data_rate_divisor(self, value): + # check that value <= 4095 + self._bank = 2 + sleep(0.005) + self._accel_rate_divisor = value + sleep(0.005) + + @property + def gyro_data_rate_divisor(self): + """The divisor for the rate at which gyro measurements are taken in Hz + + Note: The data rates are set indirectly by setting a rate divisor according to the + following formula: ``gyro_data_rate = 1100/(1+divisor)`` + + This function sets the raw rate divisor. + """ + + self._bank = 2 + raw_rate_divisor = self._gyro_rate_divisor + sleep(0.005) + self._bank = 0 + # rate_hz = 1100/(1+raw_rate_divisor) + return raw_rate_divisor + + @gyro_data_rate_divisor.setter + def gyro_data_rate_divisor(self, value): + # check that value <= 255 + self._bank = 2 + sleep(0.005) + self._gyro_rate_divisor = value + sleep(0.005) + + def _accel_rate_calc(self, divisor): # pylint:disable=no-self-use + return 1125 / (1 + divisor) + + def _gyro_rate_calc(self, divisor): # pylint:disable=no-self-use + return 1100 / (1 + divisor) + + @property + def accelerometer_data_rate(self): + """The rate at which accelerometer measurements are taken in Hz + + Note: The data rates are set indirectly by setting a rate divisor according to the + following formula: ``accelerometer_data_rate = 1125/(1+divisor)`` + + This function does the math to find the divisor from a given rate but it will not be + exactly as specified. + """ + return self._accel_rate_calc(self.accelerometer_data_rate_divisor) + + @accelerometer_data_rate.setter + def accelerometer_data_rate(self, value): + if value < self._accel_rate_calc(4095) or value > self._accel_rate_calc(0): + raise AttributeError( + "Accelerometer data rate must be between 0.27 and 1125.0" + ) + self.accelerometer_data_rate_divisor = value + + @property + def gyro_data_rate(self): + """The rate at which gyro measurements are taken in Hz + + Note: The data rates are set indirectly by setting a rate divisor according to the + following formula: ``gyro_data_rate = 1100/(1+divisor)`` + This function does the math to find the divisor from a given rate but it will not + be exactly as specified. + """ + return self._gyro_rate_calc(self.gyro_data_rate_divisor) + + @gyro_data_rate.setter + def gyro_data_rate(self, value): + if value < self._gyro_rate_calc(4095) or value > self._gyro_rate_calc(0): + raise AttributeError("Gyro data rate must be between 4.30 and 1100.0") + + divisor = round(((1125.0 - value) / value)) + self.gyro_data_rate_divisor = divisor + + @property + def accel_dlpf_cutoff(self): + """The cutoff frequency for the accelerometer's digital low pass filter. Signals + above the given frequency will be filtered out. Must be an ``AccelDLPFCutoff``. + Use AccelDLPFCutoff.DISABLED to disable the filter + + **Note** readings immediately following setting a cutoff frequency will be + inaccurate due to the filter "warming up" """ + self._bank = 2 + return self._accel_dlpf_config + + @accel_dlpf_cutoff.setter + def accel_dlpf_cutoff(self, cutoff_frequency): + if not AccelDLPFFreq.is_valid(cutoff_frequency): + raise AttributeError("accel_dlpf_cutoff must be an `AccelDLPFFreq`") + self._bank = 2 + # check for shutdown + if cutoff_frequency is AccelDLPFFreq.DISABLED: # pylint: disable=no-member + self._accel_dlpf_enable = False + return + self._accel_dlpf_enable = True + self._accel_dlpf_config = cutoff_frequency + + @property + def gyro_dlpf_cutoff(self): + """The cutoff frequency for the gyro's digital low pass filter. Signals above the + given frequency will be filtered out. Must be a ``GyroDLPFFreq``. Use + GyroDLPFCutoff.DISABLED to disable the filter + + **Note** readings immediately following setting a cutoff frequency will be + inaccurate due to the filter "warming up" """ + self._bank = 2 + return self._gyro_dlpf_config + + @gyro_dlpf_cutoff.setter + def gyro_dlpf_cutoff(self, cutoff_frequency): + if not GyroDLPFFreq.is_valid(cutoff_frequency): + raise AttributeError("gyro_dlpf_cutoff must be a `GyroDLPFFreq`") + self._bank = 2 + # check for shutdown + if cutoff_frequency is GyroDLPFFreq.DISABLED: # pylint: disable=no-member + self._gyro_dlpf_enable = False + return + self._gyro_dlpf_enable = True + self._gyro_dlpf_config = cutoff_frequency + + @property + def _low_power(self): + self._bank = 0 + return self._low_power_en + + @_low_power.setter + def _low_power(self, enabled): + self._bank = 0 + self._low_power_en = enabled + + +class ICM20649(ICM20X): + """Library for the ST ICM-20649 Wide-Range 6-DoF Accelerometer and Gyro. + + :param ~busio.I2C i2c_bus: The I2C bus the ICM20649 is connected to. + :param address: The I2C slave address of the sensor + + """ + + def __init__(self, i2c_bus, address=_ICM20649_DEFAULT_ADDRESS): + + AccelRange.add_values( + ( + ("RANGE_4G", 0, 4, 8192), + ("RANGE_8G", 1, 8, 4096.0), + ("RANGE_16G", 2, 16, 2048), + ("RANGE_30G", 3, 30, 1024), + ) + ) + + GyroRange.add_values( + ( + ("RANGE_500_DPS", 0, 500, 65.5), + ("RANGE_1000_DPS", 1, 1000, 32.8), + ("RANGE_2000_DPS", 2, 2000, 16.4), + ("RANGE_4000_DPS", 3, 4000, 8.2), + ) + ) + super().__init__(i2c_bus, address) + + +# https://www.y-ic.es/datasheet/78/SMDSW.020-2OZ.pdf page 19 +_AK09916_WIA1 = 0x00 +_AK09916_WIA2 = 0x01 +_AK09916_ST1 = 0x10 +_AK09916_HXL = 0x11 +_AK09916_HXH = 0x12 +_AK09916_HYL = 0x13 +_AK09916_HYH = 0x14 +_AK09916_HZL = 0x15 +_AK09916_HZH = 0x16 +_AK09916_ST2 = 0x18 +_AK09916_CNTL2 = 0x31 +_AK09916_CNTL3 = 0x32 + + +class MagDataRate(CV): + """Options for ``magnetometer_data_rate``""" + + pass # pylint: disable=unnecessary-pass + + +class ICM20948(ICM20X): # pylint:disable=too-many-instance-attributes + """Library for the ST ICM-20948 Wide-Range 6-DoF Accelerometer and Gyro. + + :param ~busio.I2C i2c_bus: The I2C bus the ICM20948 is connected to. + :param address: The I2C slave address of the sensor + """ + + _slave_finished = ROBit(_ICM20X_I2C_MST_STATUS, 6) + + # mag data is LE + _raw_mag_data = Struct(_ICM20948_EXT_SLV_SENS_DATA_00, "B") + _i2c_master_enable = RWBit(_ICM20X_USER_CTRL, 5) # TODO: use this in sw reset + _i2c_master_reset = RWBit(_ICM20X_USER_CTRL, 1) + + _slave0_addr = UnaryStruct(_ICM20X_I2C_SLV0_ADDR, ">B") + _slave0_reg = UnaryStruct(_ICM20X_I2C_SLV0_REG, ">B") + _slave0_ctrl = UnaryStruct(_ICM20X_I2C_SLV0_CTRL, ">B") + _slave0_do = UnaryStruct(_ICM20X_I2C_SLV0_DO, ">B") + + _slave4_addr = UnaryStruct(_ICM20X_I2C_SLV4_ADDR, ">B") + _slave4_reg = UnaryStruct(_ICM20X_I2C_SLV4_REG, ">B") + _slave4_ctrl = UnaryStruct(_ICM20X_I2C_SLV4_CTRL, ">B") + _slave4_do = UnaryStruct(_ICM20X_I2C_SLV4_DO, ">B") + _slave4_di = UnaryStruct(_ICM20X_I2C_SLV4_DI, ">B") + + def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): + AccelRange.add_values( + ( + ("RANGE_2G", 0, 2, 16384), + ("RANGE_4G", 1, 4, 8192), + ("RANGE_8G", 2, 8, 4096.0), + ("RANGE_16G", 3, 16, 2048), + ) + ) + GyroRange.add_values( + ( + ("RANGE_250_DPS", 0, 250, 131.0), + ("RANGE_500_DPS", 1, 500, 65.5), + ("RANGE_1000_DPS", 2, 1000, 32.8), + ("RANGE_2000_DPS", 3, 2000, 16.4), + ) + ) + + # https://www.y-ic.es/datasheet/78/SMDSW.020-2OZ.pdf page 9 + MagDataRate.add_values( + ( + ("SHUTDOWN", 0x0, "Shutdown", None), + ("SINGLE", 0x1, "Single", None), + ("RATE_10HZ", 0x2, 10, None), + ("RATE_20HZ", 0x4, 20, None), + ("RATE_50HZ", 0x6, 50, None), + ("RATE_100HZ", 0x8, 100, None), + ) + ) + super().__init__(i2c_bus, address) + self._magnetometer_init() + + # A million thanks to the SparkFun folks for their library that I pillaged to write this method! + # See their Python library here: + # https://github.com/sparkfun/Qwiic_9DoF_IMU_ICM20948_Py + @property + def _mag_configured(self): + success = False + for _i in range(5): + success = self._mag_id() is not None + + if success: + return True + self._reset_i2c_master() + # i2c master stuck, try resetting + return False + + def _reset_i2c_master(self): + self._bank = 0 + self._i2c_master_reset = True + + def _magnetometer_enable(self): + + self._bank = 0 + sleep(0.100) + self._bypass_i2c_master = False + sleep(0.005) + + # no repeated start, i2c master clock = 345.60kHz + self._bank = 3 + sleep(0.100) + self._i2c_master_control = 0x17 + sleep(0.100) + + self._bank = 0 + sleep(0.100) + self._i2c_master_enable = True + sleep(0.020) + + def _magnetometer_init(self): + self._magnetometer_enable() + self.magnetometer_data_rate = ( + MagDataRate.RATE_100HZ # pylint: disable=no-member + ) + + if not self._mag_configured: + return False + + self._setup_mag_readout() + + return True + + # set up slave0 for reading into the bank 0 data registers + def _setup_mag_readout(self): + self._bank = 3 + self._slave0_addr = 0x8C + sleep(0.005) + self._slave0_reg = 0x11 + sleep(0.005) + self._slave0_ctrl = 0x89 # enable + sleep(0.005) + + def _mag_id(self): + return self._read_mag_register(0x01) + + @property + def magnetic(self): + """The current magnetic field strengths onthe X, Y, and Z axes in uT (micro-teslas)""" + + self._bank = 0 + full_data = self._raw_mag_data + sleep(0.005) + + x = full_data[0] * _ICM20X_UT_PER_LSB + y = full_data[1] * _ICM20X_UT_PER_LSB + z = full_data[2] * _ICM20X_UT_PER_LSB + + return (x, y, z) + + @property + def magnetometer_data_rate(self): + """The rate at which the magenetometer takes measurements to update its output registers""" + # read mag DR register + self._read_mag_register(_AK09916_CNTL2) + + @magnetometer_data_rate.setter + def magnetometer_data_rate(self, mag_rate): + # From https://www.y-ic.es/datasheet/78/SMDSW.020-2OZ.pdf page 9 + + # "When user wants to change operation mode, transit to Power-down mode first and then + # transit to other modes. After Power-down mode is set, at least 100 microsectons (Twait) + # is needed before setting another mode" + if not MagDataRate.is_valid(mag_rate): + raise AttributeError("range must be an `MagDataRate`") + self._write_mag_register( + _AK09916_CNTL2, MagDataRate.SHUTDOWN # pylint: disable=no-member + ) + sleep(0.001) + self._write_mag_register(_AK09916_CNTL2, mag_rate) + + def _read_mag_register(self, register_addr, slave_addr=0x0C): + self._bank = 3 + + slave_addr |= 0x80 # set top bit for read + + self._slave4_addr = slave_addr + sleep(0.005) + self._slave4_reg = register_addr + sleep(0.005) + self._slave4_ctrl = ( + 0x80 # enable, don't raise interrupt, write register value, no delay + ) + sleep(0.005) + self._bank = 0 + + finished = False + for _i in range(100): + finished = self._slave_finished + if finished: # bueno! + break + sleep(0.010) + + if not finished: + return None + + self._bank = 3 + mag_register_data = self._slave4_di + sleep(0.005) + return mag_register_data + + def _write_mag_register(self, register_addr, value, slave_addr=0x0C): + self._bank = 3 + + self._slave4_addr = slave_addr + sleep(0.005) + self._slave4_reg = register_addr + sleep(0.005) + self._slave4_do = value + sleep(0.005) + self._slave4_ctrl = ( + 0x80 # enable, don't raise interrupt, write register value, no delay + ) + sleep(0.005) + self._bank = 0 + + finished = False + for _i in range(100): + finished = self._slave_finished + if finished: # bueno! + break + sleep(0.010) + + return finished diff --git a/docs/api.rst b/docs/api.rst index b0970b5..69a0acf 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -4,5 +4,5 @@ .. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py) .. use this format as the module name: "adafruit_foo.foo" -.. automodule:: adafruit_icm20649 +.. automodule:: adafruit_icm20x :members: diff --git a/docs/conf.py b/docs/conf.py index fb60b54..49d69b6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,8 +46,8 @@ master_doc = "index" # General information about the project. -project = "Adafruit ICM20649 Library" -copyright = "2019 Bryan Siepert" +project = "Adafruit ICM20X Library" +copyright = "2020 Bryan Siepert" author = "Bryan Siepert" # The version info for the project you're documenting, acts as replacement for @@ -147,8 +147,8 @@ latex_documents = [ ( master_doc, - "AdafruitICM20649Library.tex", - "AdafruitICM20649 Library Documentation", + "AdafruitICM20XLibrary.tex", + "AdafruitICM20X Library Documentation", author, "manual", ), @@ -161,8 +161,8 @@ man_pages = [ ( master_doc, - "AdafruitICM20649library", - "Adafruit ICM20649 Library Documentation", + "AdafruitICM20Xlibrary", + "Adafruit ICM20X Library Documentation", [author], 1, ) @@ -176,10 +176,10 @@ texinfo_documents = [ ( master_doc, - "AdafruitICM20649Library", - "Adafruit ICM20649 Library Documentation", + "AdafruitICM20XLibrary", + "Adafruit ICM20X Library Documentation", author, - "AdafruitICM20649Library", + "AdafruitICM20XLibrary", "One line description of project.", "Miscellaneous", ), diff --git a/docs/examples.rst b/docs/examples.rst index 3b9bebd..76f6011 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -1,8 +1,12 @@ Simple test ------------ -Ensure your device works with this simple test. +Ensure your device works with one of these simple tests. .. literalinclude:: ../examples/icm20649_simpletest.py :caption: examples/icm20649_simpletest.py :linenos: + +.. literalinclude:: ../examples/icm20948_simpletest.py + :caption: examples/icm20948_simpletest.py + :linenos: diff --git a/docs/index.rst b/docs/index.rst index 1afdd92..7001a29 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -32,7 +32,7 @@ Table of Contents .. toctree:: :caption: Other Links - Download + Download CircuitPython Reference Documentation CircuitPython Support Forum Discord Chat diff --git a/examples/icm20649_full_test.py b/examples/icm20649_full_test.py index ef7ad22..a2f0336 100644 --- a/examples/icm20649_full_test.py +++ b/examples/icm20649_full_test.py @@ -1,7 +1,7 @@ import time import board import busio -from adafruit_icm20649 import ICM20649, AccelRange, GyroRange +from adafruit_icm20x import ICM20649, AccelRange, GyroRange def printNewMax(value, current_max, axis): @@ -17,7 +17,7 @@ def printNewMax(value, current_max, axis): ism = ICM20649(i2c) ism.accelerometer_range = AccelRange.RANGE_30G -print("Accelerometer range set to: %d G" % AccelRange.string[ism.accelerometer_range]) +print("Accelerometer range set to: %d g" % AccelRange.string[ism.accelerometer_range]) ism.gyro_range = GyroRange.RANGE_500_DPS print("Gyro range set to: %d DPS" % GyroRange.string[ism.gyro_range]) diff --git a/examples/icm20649_simpletest.py b/examples/icm20649_simpletest.py index 66e92e5..1197544 100644 --- a/examples/icm20649_simpletest.py +++ b/examples/icm20649_simpletest.py @@ -1,13 +1,13 @@ import time import board import busio -import adafruit_icm20649 +import adafruit_icm20x i2c = busio.I2C(board.SCL, board.SDA) -icm = adafruit_icm20649.ICM20649(i2c) +icm = adafruit_icm20x.ICM20649(i2c) while True: print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % (icm.acceleration)) - print("Gyro X:%.2f, Y: %.2f, Z: %.2f degrees/s" % (icm.gyro)) + print("Gyro X:%.2f, Y: %.2f, Z: %.2f rads/s" % (icm.gyro)) print("") time.sleep(0.5) diff --git a/examples/icm20948_accel_data_rate_test.py b/examples/icm20948_accel_data_rate_test.py new file mode 100644 index 0000000..93bf6ea --- /dev/null +++ b/examples/icm20948_accel_data_rate_test.py @@ -0,0 +1,24 @@ +import time +import board +import busio +from adafruit_icm20x import ICM20948 + +cycles = 200 +i2c = busio.I2C(board.SCL, board.SDA) +icm = ICM20948(i2c) + +# Cycle between two data rates +# Best viewed in the Mu serial plotter where you can see how +# the data rate affects the resolution of the data +while True: + icm.accelerometer_data_rate_divisor = 0 # minimum + print("Data Rate:", icm.accelerometer_data_rate) + time.sleep(2) + for i in range(cycles): + print(icm.acceleration) + + icm.accelerometer_data_rate_divisor = 4095 # maximum + print("Data Rate:", icm.accelerometer_data_rate) + time.sleep(2) + for i in range(cycles): + print(icm.acceleration) diff --git a/examples/icm20948_gyro_data_rate_test.py b/examples/icm20948_gyro_data_rate_test.py new file mode 100644 index 0000000..cc62d29 --- /dev/null +++ b/examples/icm20948_gyro_data_rate_test.py @@ -0,0 +1,24 @@ +import time +import board +import busio +from adafruit_icm20x import ICM20948 + +cycles = 200 +i2c = busio.I2C(board.SCL, board.SDA) +icm = ICM20948(i2c) + +# Cycle between two data rates +# Best viewed in the Mu serial plotter where you can see how +# the data rate affects the resolution of the data +while True: + icm.gyro_data_rate_divisor = 0 # minimum + print("Data Rate:", icm.gyro_data_rate) + time.sleep(2) + for i in range(cycles): + print(icm.gyro) + + icm.gyro_data_rate_divisor = 255 # maximum + print("Data Rate:", icm.gyro_data_rate) + time.sleep(2) + for i in range(cycles): + print(icm.gyro) diff --git a/examples/icm20948_mag_data_rate_test.py b/examples/icm20948_mag_data_rate_test.py new file mode 100644 index 0000000..63ba2a6 --- /dev/null +++ b/examples/icm20948_mag_data_rate_test.py @@ -0,0 +1,22 @@ +# pylint: disable=no-member +import time +import board +import busio +from adafruit_icm20x import MagDataRate, ICM20948 + +cycles = 200 +i2c = busio.I2C(board.SCL, board.SDA) +icm = ICM20948(i2c) + +# Cycle between two data rates +# Best viewed in the Mu serial plotter where you can see how +# the data rate affects the resolution of the data +while True: + icm.magnetometer_data_rate = MagDataRate.RATE_100HZ + for i in range(cycles): + print(icm.magnetic) + time.sleep(0.3) + icm.magnetometer_data_rate = MagDataRate.RATE_10HZ + for i in range(cycles): + print(icm.magnetic) + time.sleep(0.3) diff --git a/examples/icm20948_simpletest.py b/examples/icm20948_simpletest.py new file mode 100644 index 0000000..8c1adf7 --- /dev/null +++ b/examples/icm20948_simpletest.py @@ -0,0 +1,14 @@ +import time +import board +import busio +import adafruit_icm20x + +i2c = busio.I2C(board.SCL, board.SDA) +icm = adafruit_icm20x.ICM20948(i2c) + +while True: + print("Acceleration: X:%.2f, Y: %.2f, Z: %.2f m/s^2" % (icm.acceleration)) + print("Gyro X:%.2f, Y: %.2f, Z: %.2f rads/s" % (icm.gyro)) + print("Magnetometer X:%.2f, Y: %.2f, Z: %.2f uT" % (icm.magnetic)) + print("") + time.sleep(0.5) diff --git a/setup.py b/setup.py index 0a294e6..f0ead50 100644 --- a/setup.py +++ b/setup.py @@ -18,14 +18,14 @@ long_description = f.read() setup( - name="adafruit-circuitpython-icm20649", + name="adafruit-circuitpython-icm20x", use_scm_version=True, setup_requires=["setuptools_scm"], - description="Library for the ST ICM-20649 Wide-Range 6-DoF Accelerometer and Gyro", + description="Library for the ST ICM-20X Wide-Range 6-DoF Accelerometer and Gyro Family", long_description=long_description, long_description_content_type="text/x-rst", # The project's main homepage. - url="https://github.com/adafruit/Adafruit_CircuitPython_ICM20649", + url="https://github.com/adafruit/Adafruit_CircuitPython_ICM20X", # Author details author="Adafruit Industries", author_email="circuitpython@adafruit.com", @@ -48,11 +48,11 @@ "Programming Language :: Python :: 3.5", ], # What does your project relate to? - keywords="adafruit blinka circuitpython micropython icm20649 gyro accelerometer high-G " + keywords="adafruit blinka circuitpython micropython icm20649 icm20948 icm20x gyro accelerometer high-G " "6-axis wide range", # You can just specify the packages manually here if your project is # simple. Or you can use find_packages(). # TODO: IF LIBRARY FILES ARE A PACKAGE FOLDER, # CHANGE `py_modules=['...']` TO `packages=['...']` - py_modules=["adafruit_icm20649"], + py_modules=["adafruit_icm20x"], )