From 522e57c487815ca41a9914561f381966083e6f0a Mon Sep 17 00:00:00 2001 From: siddacious Date: Fri, 6 Mar 2020 13:56:09 -0800 Subject: [PATCH 01/26] starting refactor --- adafruit_icm20649.py => adafruit_icm20x.py | 55 +++++++++++++++------- 1 file changed, 37 insertions(+), 18 deletions(-) rename adafruit_icm20649.py => adafruit_icm20x.py (85%) diff --git a/adafruit_icm20649.py b/adafruit_icm20x.py similarity index 85% rename from adafruit_icm20649.py rename to adafruit_icm20x.py index 36f6ebd..b81f367 100644 --- a/adafruit_icm20649.py +++ b/adafruit_icm20x.py @@ -54,16 +54,26 @@ 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 +#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 + # 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 +_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 +_ICM20649_I2C_MST_STATUS = 0x17 # I2C Master Status bits + +_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 _ICM20649_GYRO_SMPLRT_DIV = 0x00 @@ -72,6 +82,22 @@ _ICM20649_ACCEL_SMPLRT_DIV_2 = 0x11 _ICM20649_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) G_TO_ACCEL = 9.80665 # pylint: enable=bad-whitespace @@ -118,17 +144,7 @@ class GyroRange(CV): 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 +class ICM20X: #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. @@ -343,3 +359,6 @@ def gyro_data_rate(self, value): divisor = round(((1125.0 - value) / value)) self.gyro_data_rate_divisor = divisor + +class ICM20649(ICM20X): + pass \ No newline at end of file From 07262d0243de6a23ef8d2b6bb4fb3e297f4fe6b1 Mon Sep 17 00:00:00 2001 From: siddacious Date: Fri, 6 Mar 2020 15:09:43 -0800 Subject: [PATCH 02/26] both sensor working, ranges are wrong --- adafruit_icm20x.py | 24 +++++++++++++++++++----- examples/icm20649_simpletest.py | 4 ++-- examples/icm20948_simpletest.py | 13 +++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 examples/icm20948_simpletest.py diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index b81f367..b492d69 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -20,10 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. """ -`adafruit_icm20649` +`adafruit_icm20x` ================================================================================ -Library for the ST ICM20649 Wide-Range 6-DoF Accelerometer and Gyro +Library for the ST ICM20X Motion Sensor Family * Author(s): Bryan Siepert @@ -33,6 +33,7 @@ **Hardware:** * Adafruit's ICM20649 Breakout: https://adafruit.com/product/4464 +* Adafruit's ICM20948 Breakout: https://adafruit.com/product/4554 **Software and Dependencies:** @@ -175,8 +176,8 @@ class ICM20X: #pylint:disable=too-many-instance-attributes 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!") + 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._bank = 0 @@ -361,4 +362,17 @@ def gyro_data_rate(self, value): self.gyro_data_rate_divisor = divisor class ICM20649(ICM20X): - pass \ No newline at end of file + """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 + + """ + + +class ICM20948(ICM20X): + """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 + """ diff --git a/examples/icm20649_simpletest.py b/examples/icm20649_simpletest.py index 66e92e5..f555ec6 100644 --- a/examples/icm20649_simpletest.py +++ b/examples/icm20649_simpletest.py @@ -1,10 +1,10 @@ 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)) diff --git a/examples/icm20948_simpletest.py b/examples/icm20948_simpletest.py new file mode 100644 index 0000000..4514128 --- /dev/null +++ b/examples/icm20948_simpletest.py @@ -0,0 +1,13 @@ +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 degrees/s"%(icm.gyro)) + print("") + time.sleep(0.5) From b1ca88e8412d789117da300e188a9b18252f9b5e Mon Sep 17 00:00:00 2001 From: siddacious Date: Fri, 6 Mar 2020 16:22:35 -0800 Subject: [PATCH 03/26] ranges scaling correctly --- adafruit_icm20x.py | 63 +++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index b492d69..3b9f3f5 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -126,24 +126,10 @@ def is_valid(cls, value): 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 - class ICM20X: #pylint:disable=too-many-instance-attributes """Library for the ST ICM-20649 Wide-Range 6-DoF Accelerometer and Gyro. @@ -174,8 +160,10 @@ class ICM20X: #pylint:disable=too-many-instance-attributes _gyro_rate_divisor = UnaryStruct(_ICM20649_GYRO_SMPLRT_DIV, ">B") - def __init__(self, i2c_bus, address=_ICM20649_DEFAULT_ADDRESS): + 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() @@ -189,6 +177,7 @@ def __init__(self, i2c_bus, address=_ICM20649_DEFAULT_ADDRESS): # TODO: CV-ify self._accel_dlpf_config = 3 +<<<<<<< HEAD # 1.125 kHz/(1+ACCEL_SMPLRT_DIV[11:0]), # 1125Hz/(1+20) = 53.57Hz @@ -196,14 +185,15 @@ def __init__(self, i2c_bus, address=_ICM20649_DEFAULT_ADDRESS): # writeByte(ICM20649_ADDR,GYRO_CONFIG_1, gyroConfig); self._gyro_range = GyroRange.RANGE_500_DPS # pylint: disable=no-member +======= + self._accel_rate_divisor = 20 + + self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member +>>>>>>> ranges scaling correctly 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 + self._gyro_rate_divisor = 10 def reset(self): """Resets the internal registers and restores the default settings""" @@ -214,6 +204,7 @@ def reset(self): @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 x = self._scale_xl_data(raw_accel_data[0]) @@ -225,6 +216,7 @@ def acceleration(self): @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]) @@ -368,6 +360,22 @@ class ICM20649(ICM20X): :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) class ICM20948(ICM20X): @@ -376,3 +384,18 @@ class ICM20948(ICM20X): :param ~busio.I2C i2c_bus: The I2C bus the ICM20948 is connected to. :param address: The I2C slave address of the sensor """ + def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): + print("948, mos defs") + 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) + )) + super().__init__(i2c_bus, address) From b8d1e907d9fdbbdcd11d512f778ec2f9bb0f4b9f Mon Sep 17 00:00:00 2001 From: siddacious Date: Fri, 6 Mar 2020 19:20:55 -0800 Subject: [PATCH 04/26] almost there on mag, missing some bytes --- adafruit_icm20x.py | 159 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 16 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 3b9f3f5..755ca8c 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -52,7 +52,7 @@ 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_bit import RWBit, ROBit from adafruit_register.i2c_bits import RWBits #pylint: disable=bad-whitespace @@ -122,15 +122,16 @@ def is_valid(cls, value): """Validate that a given value is a member""" return value in cls.string +<<<<<<< HEAD +======= +>>>>>>> almost there on mag, missing some bytes class AccelRange(CV): """Options for ``accelerometer_range``""" - class GyroRange(CV): """Options for ``gyro_data_range``""" - class ICM20X: #pylint:disable=too-many-instance-attributes """Library for the ST ICM-20649 Wide-Range 6-DoF Accelerometer and Gyro. @@ -141,7 +142,7 @@ class ICM20X: #pylint:disable=too-many-instance-attributes # Bank 0 _device_id = ROUnaryStruct(_ICM20649_WHO_AM_I, "H") - _gyro_rate_divisor = UnaryStruct(_ICM20649_GYRO_SMPLRT_DIV, ">B") - + @property + def _bank(self): + return self._bank_reg + @_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) @@ -177,19 +182,9 @@ def __init__(self, i2c_bus, address): # TODO: CV-ify self._accel_dlpf_config = 3 -<<<<<<< HEAD - - # 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 -======= self._accel_rate_divisor = 20 self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member ->>>>>>> ranges scaling correctly sleep(0.100) self._cached_gyro_range = self._gyro_range @@ -197,6 +192,8 @@ def __init__(self, i2c_bus, address): def reset(self): """Resets the internal registers and restores the default settings""" + self._bank = 0 + self._reset = True while self._reset: sleep(0.001) @@ -399,3 +396,133 @@ def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): ('RANGE_2000_DPS', 3, 2000, 16.4) )) super().__init__(i2c_bus, address) + #self._magnetometer_init() + @property + def magnetic(self): + """The current magnetic field strengths onthe X, Y, and Z axes in uT (micro-teslas)""" + return (0, 0, 0) + +# 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 + + _bypass_i2c_master = RWBit(_ICM20X_REG_INT_PIN_CFG, 1) + _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) + _i2c_master_control = UnaryStruct(_ICM20X_I2C_MST_CTRL, ">B") + _i2c_master_enable = RWBit(_ICM20X_USER_CTRL, 5) + _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_ctrl = UnaryStruct(_ICM20X_I2C_SLV4_CTRL, ">B") + _slave4_do = UnaryStruct(_ICM20X_I2C_SLV4_DO, ">B") + _slave4_di = UnaryStruct(_ICM20X_I2C_SLV4_DI, ">B") + _slave4_finished = ROBit(_ICM20649_I2C_MST_STATUS, 6) + # _i2c_master_enable = RWBit(_ICM20X_I2C_MST_CTRL, ) + def _magnetometer_init(self): + # set all the other enabling bits for the master bus + # wake up the mag by setting its data rate? + # set up reads by configuring slave0 + + self._bank = 0 + self._i2c_master_duty_cycle_en = True + self._bypass_i2c_master = False + self._bank = 3 + # no repeated start, i2c master clock = 345.60kHz + self._i2c_master_control = 0x17 + + self._bank = 0 + self._i2c_master_enable = True + + + # mag_chip_id = self._read_mag_register(0x01) + # print("MAG ID: ", mag_chip_id) + + print("Resetting I2C master") + self._reset_i2c_master() + + print("Trying to soft reset the mag") + self._soft_reset_mag() + + print("Setting mag data rate") + self._write_mag_register(0x31, 0x08) + + print("Setting up Slave 0 for reading from mag") + self._bank = 3 + self._slave0_addr = 0x8C + self._slave0_reg = 0x10 + self._slave0_ctrl = 0x89 # enable + + + def _read_mag_register(self, register_addr, slave_addr=0x0C): + slave_addr |= 0x80 # set top bit for read + + self._slave4_addr = slave_addr + self._slave4_reg = register_addr + self._slave4_ctrl = 0x80 # enable + self._bank = 0 + while not self._slave4_finished: + sleep(0.010) + self._bank = 3 + return self._slave4_do + + def _write_mag_register(self, register_addr, value, slave_addr=0x0C): + + self._slave4_addr = slave_addr + self._slave4_reg = register_addr + self._slave4_di = value + self._slave4_ctrl = 0x80 # enable + self._bank = 0 + while not self._slave4_finished: + sleep(0.010) + + + def _reset_i2c_master(self): + self._bank = 0 + self._i2c_master_reset = True + while self._i2c_master_reset: + sleep(0.010) + + def _soft_reset_mag(self): + + self._write_mag_register(0x32, 0x01) + while self._read_mag_register(0x32): + sleep(0.010) + + +# bool Adafruit_ICM20948::_write_ext_reg(uint8_t slv_addr, uint8_t reg_addr, uint8_t value, uint8_t num_tries) { + +# uint8_t buffer[2]; +# _setBank(3); +# uint8_t tries = 0; +# // set the I2C address on the external bus +# buffer[0] = ICM20948_I2C_SLV4_ADDR; +# buffer[1] = slv_addr; +# if (!i2c_dev->write(buffer, 2)) { +# return false; +# } +# // specify which register we're writing to +# buffer[0] = ICM20948_I2C_SLV4_REG; +# buffer[1] = reg_addr; +# if (!i2c_dev->write(buffer, 2)) { +# return false; +# } +# // set the data to write +# buffer[0] = ICM20948_I2C_SLV4_DO; +# buffer[1] = value; +# if (!i2c_dev->write(buffer, 2)) { +# return false; +# } +# // start writing +# buffer[0] = ICM20948_I2C_SLV4_CTRL; +# buffer[1] = 0x80; +# if (!i2c_dev->write(buffer, 2)) { +# return false; +# } \ No newline at end of file From ef70411334b493416b50f420d7d94a85882426e4 Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 9 Mar 2020 18:59:29 -0700 Subject: [PATCH 05/26] working! --- adafruit_icm20x.py | 149 ++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 63 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 755ca8c..d1c9640 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -69,6 +69,7 @@ _ICM20649_ACCEL_XOUT_H = 0x2D # first byte of accel data _ICM20649_GYRO_XOUT_H = 0x33 # first byte of accel data _ICM20649_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 @@ -81,7 +82,12 @@ _ICM20649_GYRO_CONFIG_1 = 0x01 _ICM20649_ACCEL_SMPLRT_DIV_1 = 0x10 _ICM20649_ACCEL_SMPLRT_DIV_2 = 0x11 +<<<<<<< HEAD _ICM20649_ACCEL_CONFIG_1 = 0x14 +======= +_ICM20649_ACCEL_CONFIG_1 = 0x14 +# _ICM20649_ACCEL_CONFIG_2 = 0x15 +>>>>>>> working! # Bank 3 _ICM20X_I2C_MST_ODR_CONFIG = 0x0 # Sets ODR for I2C master bus @@ -150,8 +156,13 @@ class ICM20X: #pylint:disable=too-many-instance-attributes _raw_accel_data = Struct(_ICM20649_ACCEL_XOUT_H, ">hhh") _raw_gyro_data = Struct(_ICM20649_GYRO_XOUT_H, ">hhh") + _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) + + # Bank 2 _gyro_range = RWBits(2, _ICM20649_GYRO_CONFIG_1, 1) + _accel_config = Struct(_ICM20649_ACCEL_CONFIG_1, ">B") + _gyro_config1 = Struct(_ICM20649_GYRO_CONFIG_1, ">B") _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) @@ -176,19 +187,38 @@ def __init__(self, i2c_bus, address): 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 - self._accel_rate_divisor = 20 + self._i2c_master_duty_cycle_en = True - self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member + # WRITE 0b00111001 to ACCEL_CONFIG + # WRITE 0b00111001 to GYRO_CONFIG_1 + # WRITE 0b00111000 to ACCEL_CONFIG + # WRITE 0b00111000 to GYRO_CONFIG_1 + self._bank = 2 + # WRITE 0b00000001 to ACCEL_CONFIG + print("accel") + print("copying 1") + self._accel_config = [0b00000001] + self._gyro_config1 =[0b00000001] + print("copying 2") + self._accel_config = [0b00111001] + self._gyro_config1 = [0b00111001] + print("copying 3") + self._accel_config = [0b00111000] + self._gyro_config1 = [0b00111000] + print("done copying, onto set range") + + #self._accel_range = AccelRange.RANGE_8G #pylint: disable=no-member + self._cached_accel_range = 0 + + #TODO: CV-ify + #self._accel_dlpf_config = 3 + #self._accel_rate_divisor = 20 + + #self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member sleep(0.100) - self._cached_gyro_range = self._gyro_range + self._cached_gyro_range = 0 - self._gyro_rate_divisor = 10 + #self._gyro_rate_divisor = 10 def reset(self): """Resets the internal registers and restores the default settings""" @@ -267,7 +297,7 @@ def accelerometer_data_rate_divisor(self): 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 @@ -395,18 +425,40 @@ def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): ('RANGE_1000_DPS', 2, 1000, 32.8), ('RANGE_2000_DPS', 3, 2000, 16.4) )) + print("\tCALLING BASE INIT") super().__init__(i2c_bus, address) - #self._magnetometer_init() + print("\tMAG INIT") + self._magnetometer_init() @property def magnetic(self): """The current magnetic field strengths onthe X, Y, and Z axes in uT (micro-teslas)""" - return (0, 0, 0) -# 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 + self._bank = 0 + full_data = self._all_data + + + x = full_data[8] * 0.15 + y = full_data[9] * 0.15 + z = full_data[10] * 0.15 + + # x = full_data[13:15] * 0.15 + # y = full_data[15:17] * 0.15 + # z = full_data[17:19] * 0.15 + + return(x, y, z) + + # 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 + + _slave_finished = ROBit(_ICM20649_I2C_MST_STATUS, 6) + + _raw_mag_data = Struct(_ICM20948_EXT_SLV_SENS_DATA_00, ">hhhh") + + + _all_data = Struct(_ICM20649_ACCEL_XOUT_H, ">hhhhhhhhhhh") _bypass_i2c_master = RWBit(_ICM20X_REG_INT_PIN_CFG, 1) _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) _i2c_master_control = UnaryStruct(_ICM20X_I2C_MST_CTRL, ">B") @@ -424,7 +476,6 @@ def magnetic(self): _slave4_ctrl = UnaryStruct(_ICM20X_I2C_SLV4_CTRL, ">B") _slave4_do = UnaryStruct(_ICM20X_I2C_SLV4_DO, ">B") _slave4_di = UnaryStruct(_ICM20X_I2C_SLV4_DI, ">B") - _slave4_finished = ROBit(_ICM20649_I2C_MST_STATUS, 6) # _i2c_master_enable = RWBit(_ICM20X_I2C_MST_CTRL, ) def _magnetometer_init(self): # set all the other enabling bits for the master bus @@ -432,7 +483,7 @@ def _magnetometer_init(self): # set up reads by configuring slave0 self._bank = 0 - self._i2c_master_duty_cycle_en = True + self._bypass_i2c_master = False self._bank = 3 # no repeated start, i2c master clock = 345.60kHz @@ -445,42 +496,45 @@ def _magnetometer_init(self): # mag_chip_id = self._read_mag_register(0x01) # print("MAG ID: ", mag_chip_id) - print("Resetting I2C master") - self._reset_i2c_master() - - print("Trying to soft reset the mag") - self._soft_reset_mag() - + # print("Resetting I2C master") + # self._reset_i2c_master() + # sleep(1) + # print("Trying to soft reset the mag") + # self._soft_reset_mag() + # sleep(1) print("Setting mag data rate") self._write_mag_register(0x31, 0x08) - + # print("checking setup") + # rate = self._read_mag_register(0x31) print("Setting up Slave 0 for reading from mag") self._bank = 3 self._slave0_addr = 0x8C self._slave0_reg = 0x10 self._slave0_ctrl = 0x89 # enable - 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 self._slave4_reg = register_addr self._slave4_ctrl = 0x80 # enable self._bank = 0 - while not self._slave4_finished: + while not self._slave_finished: sleep(0.010) self._bank = 3 - return self._slave4_do + return self._slave4_di def _write_mag_register(self, register_addr, value, slave_addr=0x0C): + self._bank = 3 self._slave4_addr = slave_addr self._slave4_reg = register_addr - self._slave4_di = value + self._slave4_do = value self._slave4_ctrl = 0x80 # enable self._bank = 0 - while not self._slave4_finished: + while not self._slave_finished: sleep(0.010) @@ -494,35 +548,4 @@ def _soft_reset_mag(self): self._write_mag_register(0x32, 0x01) while self._read_mag_register(0x32): - sleep(0.010) - - -# bool Adafruit_ICM20948::_write_ext_reg(uint8_t slv_addr, uint8_t reg_addr, uint8_t value, uint8_t num_tries) { - -# uint8_t buffer[2]; -# _setBank(3); -# uint8_t tries = 0; -# // set the I2C address on the external bus -# buffer[0] = ICM20948_I2C_SLV4_ADDR; -# buffer[1] = slv_addr; -# if (!i2c_dev->write(buffer, 2)) { -# return false; -# } -# // specify which register we're writing to -# buffer[0] = ICM20948_I2C_SLV4_REG; -# buffer[1] = reg_addr; -# if (!i2c_dev->write(buffer, 2)) { -# return false; -# } -# // set the data to write -# buffer[0] = ICM20948_I2C_SLV4_DO; -# buffer[1] = value; -# if (!i2c_dev->write(buffer, 2)) { -# return false; -# } -# // start writing -# buffer[0] = ICM20948_I2C_SLV4_CTRL; -# buffer[1] = 0x80; -# if (!i2c_dev->write(buffer, 2)) { -# return false; -# } \ No newline at end of file + sleep(0.010) \ No newline at end of file From 26ea8365ec75d4e6104cca74de3ed44984198f33 Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 9 Mar 2020 19:59:50 -0700 Subject: [PATCH 06/26] working tempermentally --- adafruit_icm20x.py | 136 ++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 75 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index d1c9640..63753d8 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -105,6 +105,7 @@ _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 @@ -220,6 +221,25 @@ def __init__(self, i2c_bus, address): #self._gyro_rate_divisor = 10 + ################## + + # 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 + + # sleep(0.100) + # #TODO: CV-ify + # self._bank = 2 + # self._accel_dlpf_config = 3 + + + + # # //reset to register bank 0 + # self._bank = 0 + ################################ + def reset(self): """Resets the internal registers and restores the default settings""" self._bank = 0 @@ -255,7 +275,7 @@ 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] + return (raw_measurement / GyroRange.lsb[self._cached_gyro_range]) * _ICM20X_RAD_PER_DEG @property def accelerometer_range(self): @@ -411,54 +431,11 @@ class ICM20948(ICM20X): :param ~busio.I2C i2c_bus: The I2C bus the ICM20948 is connected to. :param address: The I2C slave address of the sensor """ - def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): - print("948, mos defs") - 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) - )) - print("\tCALLING BASE INIT") - super().__init__(i2c_bus, address) - print("\tMAG INIT") - self._magnetometer_init() - @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._all_data - - - x = full_data[8] * 0.15 - y = full_data[9] * 0.15 - z = full_data[10] * 0.15 - - # x = full_data[13:15] * 0.15 - # y = full_data[15:17] * 0.15 - # z = full_data[17:19] * 0.15 - - return(x, y, z) - - - # 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 _slave_finished = ROBit(_ICM20649_I2C_MST_STATUS, 6) - _raw_mag_data = Struct(_ICM20948_EXT_SLV_SENS_DATA_00, ">hhhh") - + _raw_mag_data = Struct(_ICM20948_EXT_SLV_SENS_DATA_00, "hhhhhhhhhhh") _bypass_i2c_master = RWBit(_ICM20X_REG_INT_PIN_CFG, 1) _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) _i2c_master_control = UnaryStruct(_ICM20X_I2C_MST_CTRL, ">B") @@ -476,42 +453,56 @@ def magnetic(self): _slave4_ctrl = UnaryStruct(_ICM20X_I2C_SLV4_CTRL, ">B") _slave4_do = UnaryStruct(_ICM20X_I2C_SLV4_DO, ">B") _slave4_di = UnaryStruct(_ICM20X_I2C_SLV4_DI, ">B") - # _i2c_master_enable = RWBit(_ICM20X_I2C_MST_CTRL, ) + + 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) + )) + super().__init__(i2c_bus, address) + self._magnetometer_init() def _magnetometer_init(self): - # set all the other enabling bits for the master bus - # wake up the mag by setting its data rate? - # set up reads by configuring slave0 self._bank = 0 - self._bypass_i2c_master = False - self._bank = 3 + # no repeated start, i2c master clock = 345.60kHz + self._bank = 3 self._i2c_master_control = 0x17 self._bank = 0 self._i2c_master_enable = True - - # mag_chip_id = self._read_mag_register(0x01) - # print("MAG ID: ", mag_chip_id) - - # print("Resetting I2C master") - # self._reset_i2c_master() - # sleep(1) - # print("Trying to soft reset the mag") - # self._soft_reset_mag() - # sleep(1) - print("Setting mag data rate") + # set the magnetometer data rate self._write_mag_register(0x31, 0x08) - # print("checking setup") - # rate = self._read_mag_register(0x31) - print("Setting up Slave 0 for reading from mag") + + # set up slave0 for reading into the bank 0 data registers self._bank = 3 self._slave0_addr = 0x8C - self._slave0_reg = 0x10 + self._slave0_reg = 0x11 self._slave0_ctrl = 0x89 # enable + @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 + + x = full_data[0] * 0.15 + y = full_data[1] * 0.15 + z = full_data[2] * 0.15 + + return(x, y, z) + def _read_mag_register(self, register_addr, slave_addr=0x0C): self._bank = 3 @@ -538,14 +529,9 @@ def _write_mag_register(self, register_addr, value, slave_addr=0x0C): sleep(0.010) - def _reset_i2c_master(self): - self._bank = 0 - self._i2c_master_reset = True - while self._i2c_master_reset: - sleep(0.010) - def _soft_reset_mag(self): - self._write_mag_register(0x32, 0x01) - while self._read_mag_register(0x32): - sleep(0.010) \ No newline at end of file + + + + From d99533bca7921e057c57908591ad921cfca57f0b Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 19 May 2020 13:00:23 -0700 Subject: [PATCH 07/26] fixing timing issues, formatting --- .python-version | 1 + adafruit_icm20x.py | 228 +++++++++++++++++++++----------- examples/icm20649_full_test.py | 2 +- examples/icm20649_simpletest.py | 4 +- examples/icm20948_simpletest.py | 7 +- 5 files changed, 160 insertions(+), 82 deletions(-) create mode 100644 .python-version 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/adafruit_icm20x.py b/adafruit_icm20x.py index 63753d8..dcf1465 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -55,27 +55,27 @@ 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 +# 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 # 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 -_ICM20649_I2C_MST_STATUS = 0x17 # I2C Master Status bits +_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 +_ICM20649_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 +_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 _ICM20649_GYRO_SMPLRT_DIV = 0x00 @@ -83,13 +83,18 @@ _ICM20649_ACCEL_SMPLRT_DIV_1 = 0x10 _ICM20649_ACCEL_SMPLRT_DIV_2 = 0x11 <<<<<<< HEAD +<<<<<<< HEAD _ICM20649_ACCEL_CONFIG_1 = 0x14 ======= _ICM20649_ACCEL_CONFIG_1 = 0x14 +======= +_ICM20649_ACCEL_CONFIG_1 = 0x14 +>>>>>>> fixing timing issues, formatting # _ICM20649_ACCEL_CONFIG_2 = 0x15 >>>>>>> working! # Bank 3 +<<<<<<< HEAD _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 @@ -106,6 +111,24 @@ _ICM20X_UT_PER_LSB = 0.15 # mag data LSB value (fixed) _ICM20X_RAD_PER_DEG = 0.017453293 # Degrees/s to rad/s multiplier +======= +_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 +>>>>>>> fixing timing issues, formatting G_TO_ACCEL = 9.80665 # pylint: enable=bad-whitespace @@ -130,16 +153,28 @@ def is_valid(cls, value): return value in cls.string <<<<<<< HEAD +<<<<<<< HEAD ======= >>>>>>> almost there on mag, missing some bytes +class AccelRange(CV): + """Options for ``accelerometer_range``""" +======= + class AccelRange(CV): """Options for ``accelerometer_range``""" + pass # pylint: disable=unnecessary-pass + +>>>>>>> fixing timing issues, formatting + class GyroRange(CV): """Options for ``gyro_data_range``""" -class ICM20X: #pylint:disable=too-many-instance-attributes + pass # pylint: disable=unnecessary-pass + + +class ICM20X: # 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. @@ -159,7 +194,6 @@ class ICM20X: #pylint:disable=too-many-instance-attributes _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) - # Bank 2 _gyro_range = RWBits(2, _ICM20649_GYRO_CONFIG_1, 1) _accel_config = Struct(_ICM20649_ACCEL_CONFIG_1, ">B") @@ -171,12 +205,15 @@ class ICM20X: #pylint:disable=too-many-instance-attributes # 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") + @property def _bank(self): return self._bank_reg + @_bank.setter def _bank(self, value): - self._bank_reg = value <<4 + self._bank_reg = value << 4 + def __init__(self, i2c_bus, address): self.i2c_device = i2c_device.I2CDevice(i2c_bus, address) @@ -187,8 +224,10 @@ def __init__(self, i2c_bus, address): self._bank = 0 self._sleep = False + sleep(0.005) self._i2c_master_duty_cycle_en = True + sleep(0.005) # WRITE 0b00111001 to ACCEL_CONFIG # WRITE 0b00111001 to GYRO_CONFIG_1 @@ -196,30 +235,26 @@ def __init__(self, i2c_bus, address): # WRITE 0b00111000 to GYRO_CONFIG_1 self._bank = 2 # WRITE 0b00000001 to ACCEL_CONFIG - print("accel") - print("copying 1") + self._accel_config = [0b00000001] - self._gyro_config1 =[0b00000001] - print("copying 2") + self._gyro_config1 = [0b00000001] self._accel_config = [0b00111001] self._gyro_config1 = [0b00111001] - print("copying 3") self._accel_config = [0b00111000] self._gyro_config1 = [0b00111000] - print("done copying, onto set range") - #self._accel_range = AccelRange.RANGE_8G #pylint: disable=no-member + self._accel_range = AccelRange.RANGE_8G # pylint: disable=no-member self._cached_accel_range = 0 - #TODO: CV-ify - #self._accel_dlpf_config = 3 - #self._accel_rate_divisor = 20 + # TODO: CV-ify + # self._accel_dlpf_config = 3 + # self._accel_rate_divisor = 20 - #self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member + # self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member sleep(0.100) self._cached_gyro_range = 0 - #self._gyro_rate_divisor = 10 + # self._gyro_rate_divisor = 10 ################## @@ -234,8 +269,6 @@ def __init__(self, i2c_bus, address): # self._bank = 2 # self._accel_dlpf_config = 3 - - # # //reset to register bank 0 # self._bank = 0 ################################ @@ -244,15 +277,18 @@ 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.001) + 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]) @@ -275,7 +311,9 @@ 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]) * _ICM20X_RAD_PER_DEG + return ( + raw_measurement / GyroRange.lsb[self._cached_gyro_range] + ) * _ICM20X_RAD_PER_DEG @property def accelerometer_range(self): @@ -289,6 +327,7 @@ def accelerometer_range(self, value): # pylint: disable=no-member raise AttributeError("range must be an `AccelRange`") self._bank = 2 self._accel_range = value + sleep(0.005) self._cached_accel_range = value self._bank = 0 @@ -305,6 +344,7 @@ def gyro_range(self, value): self._bank = 2 self._gyro_range = value + sleep(0.005) self._cached_gyro_range = value self._bank = 0 sleep(0.100) # needed to let new range settle @@ -320,6 +360,7 @@ def accelerometer_data_rate_divisor(self): """ 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 @@ -329,6 +370,7 @@ def accelerometer_data_rate_divisor(self, value): # check that value <= 4095 self._bank = 2 self._accel_rate_divisor = value + sleep(0.005) self._bank = 0 @property @@ -343,6 +385,7 @@ def gyro_data_rate_divisor(self): 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 @@ -352,6 +395,7 @@ def gyro_data_rate_divisor(self, value): # check that value <= 255 self._bank = 2 self._gyro_rate_divisor = value + sleep(0.005) self._bank = 0 def _accel_rate_calc(self, divisor): # pylint:disable=no-self-use @@ -400,6 +444,7 @@ def gyro_data_rate(self, value): divisor = round(((1125.0 - value) / value)) self.gyro_data_rate_divisor = divisor + class ICM20649(ICM20X): """Library for the ST ICM-20649 Wide-Range 6-DoF Accelerometer and Gyro. @@ -407,21 +452,26 @@ class ICM20649(ICM20X): :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) - )) + 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) @@ -455,40 +505,62 @@ class ICM20948(ICM20X): _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) - )) + 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), + ) + ) super().__init__(i2c_bus, address) self._magnetometer_init() + def _magnetometer_init(self): self._bank = 0 self._bypass_i2c_master = False + sleep(0.005) + # print("I2C Master bypassed:", self._bypass_i2c_master) + # sleep(0.005) # no repeated start, i2c master clock = 345.60kHz self._bank = 3 self._i2c_master_control = 0x17 + sleep(0.005) + # print("i2c master control:", bin(self._i2c_master_control)) + # sleep(0.005) self._bank = 0 self._i2c_master_enable = True + sleep(0.020) + # print("i2c master enable:", bin(self._i2c_master_enable)) + # sleep(0.005) + # https://www.y-ic.es/datasheet/78/SMDSW.020-2OZ.pdf page 9 # set the magnetometer data rate + # 0x1 = 10hz Continuous measurement mode 1 + # 0x2 = 20hz Continuous measurement mode 2 + # 0x4 = 50hz Continuous measurement mode 3 + # 0x8 = 100hz Continuous measurement mode 4 self._write_mag_register(0x31, 0x08) # set up slave0 for reading into the bank 0 data registers self._bank = 3 self._slave0_addr = 0x8C + sleep(0.005) self._slave0_reg = 0x11 - self._slave0_ctrl = 0x89 # enable + sleep(0.005) + self._slave0_ctrl = 0x89 # enable + sleep(0.005) @property def magnetic(self): @@ -496,42 +568,46 @@ def magnetic(self): self._bank = 0 full_data = self._raw_mag_data + sleep(0.005) - x = full_data[0] * 0.15 - y = full_data[1] * 0.15 - z = full_data[2] * 0.15 + 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) + return (x, y, z) def _read_mag_register(self, register_addr, slave_addr=0x0C): self._bank = 3 - slave_addr |= 0x80 # set top bit for read + slave_addr |= 0x80 # set top bit for read self._slave4_addr = slave_addr + sleep(0.005) self._slave4_reg = register_addr - self._slave4_ctrl = 0x80 # enable + sleep(0.005) + self._slave4_ctrl = 0x80 # enable + sleep(0.005) self._bank = 0 while not self._slave_finished: sleep(0.010) self._bank = 3 - return self._slave4_di + 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 - self._slave4_ctrl = 0x80 # enable + sleep(0.005) + self._slave4_ctrl = 0x80 # enable + sleep(0.005) self._bank = 0 + # wait for write to mag register to finish") while not self._slave_finished: + print(".", end="") sleep(0.010) - - - - - - - - diff --git a/examples/icm20649_full_test.py b/examples/icm20649_full_test.py index ef7ad22..4be225a 100644 --- a/examples/icm20649_full_test.py +++ b/examples/icm20649_full_test.py @@ -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 f555ec6..1197544 100644 --- a/examples/icm20649_simpletest.py +++ b/examples/icm20649_simpletest.py @@ -4,10 +4,10 @@ import adafruit_icm20x i2c = busio.I2C(board.SCL, board.SDA) -icm = adafruit_icm20x.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_simpletest.py b/examples/icm20948_simpletest.py index 4514128..8c1adf7 100644 --- a/examples/icm20948_simpletest.py +++ b/examples/icm20948_simpletest.py @@ -4,10 +4,11 @@ import adafruit_icm20x i2c = busio.I2C(board.SCL, board.SDA) -icm = adafruit_icm20x.ICM20948(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) From a1c65cad36348107ff3b3454ce7300f0ca8095bd Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 19 May 2020 14:12:37 -0700 Subject: [PATCH 08/26] fixing docs build --- README.rst | 28 ++++++++++++++++++++++++---- docs/api.rst | 2 +- examples/icm20649_full_test.py | 2 +- setup.py | 2 +- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index a2178f7..727e083 100644 --- a/README.rst +++ b/README.rst @@ -56,18 +56,38 @@ To install in a virtual environment in your current project: Usage Example ============= +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) 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/examples/icm20649_full_test.py b/examples/icm20649_full_test.py index 4be225a..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): diff --git a/setup.py b/setup.py index 0a294e6..399f8b9 100644 --- a/setup.py +++ b/setup.py @@ -54,5 +54,5 @@ # 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"], ) From de783127afbf1e5c8ea49c30fb05bd6980bf8351 Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 25 May 2020 13:32:22 -0700 Subject: [PATCH 09/26] fixed scaling issues created by debugging code --- adafruit_icm20x.py | 79 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index dcf1465..7bdccb0 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -223,46 +223,42 @@ def __init__(self, i2c_bus, address): self.reset() self._bank = 0 + sleep(0.005) self._sleep = False sleep(0.005) self._i2c_master_duty_cycle_en = True sleep(0.005) - # WRITE 0b00111001 to ACCEL_CONFIG - # WRITE 0b00111001 to GYRO_CONFIG_1 - # WRITE 0b00111000 to ACCEL_CONFIG - # WRITE 0b00111000 to GYRO_CONFIG_1 self._bank = 2 # WRITE 0b00000001 to ACCEL_CONFIG - self._accel_config = [0b00000001] - self._gyro_config1 = [0b00000001] - self._accel_config = [0b00111001] - self._gyro_config1 = [0b00111001] - self._accel_config = [0b00111000] - self._gyro_config1 = [0b00111000] + # sleep(0.005) + # self._accel_config = [0b00111000] + # sleep(0.005) + # self._gyro_config1 = [0b00111000] + # sleep(0.005) - self._accel_range = AccelRange.RANGE_8G # pylint: disable=no-member - self._cached_accel_range = 0 + # self.accel_range = AccelRange.RANGE_8G # pylint: disable=no-member + # self._cached_accel_range = 0 # TODO: CV-ify # self._accel_dlpf_config = 3 # self._accel_rate_divisor = 20 # self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member - sleep(0.100) - self._cached_gyro_range = 0 + # sleep(0.100) + # self._cached_gyro_range = 0 # self._gyro_rate_divisor = 10 ################## - # self.accelerometer_range = AccelRange.RANGE_8G #pylint: disable=no-member - # self.gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member + 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 + self.accelerometer_data_rate_divisor = 20 # ~53.57Hz + self.gyro_data_rate_divisor = 10 # ~100Hz # sleep(0.100) # #TODO: CV-ify @@ -273,6 +269,52 @@ def __init__(self, i2c_bus, address): # self._bank = 0 ################################ + # def _swreset(self): + + # self._i2c_master_duty_cycle_en = True + + # # set all registers to init/power up values + # _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 + # _ICM20649_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 + # _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 + # # _ICM20649_ACCEL_CONFIG_2 = 0x15 + + # # 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 + # pass + def reset(self): """Resets the internal registers and restores the default settings""" self._bank = 0 @@ -308,6 +350,7 @@ def gyro(self): 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): From e78cc5ff4455b97006686c511ef7cb10a5f8d643 Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 25 May 2020 16:22:08 -0700 Subject: [PATCH 10/26] working, cleaned up --- adafruit_icm20x.py | 133 +++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 89 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 7bdccb0..80e0765 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -192,7 +192,7 @@ class ICM20X: # pylint:disable=too-many-instance-attributes _raw_accel_data = Struct(_ICM20649_ACCEL_XOUT_H, ">hhh") _raw_gyro_data = Struct(_ICM20649_GYRO_XOUT_H, ">hhh") - _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) + # _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) # Bank 2 _gyro_range = RWBits(2, _ICM20649_GYRO_CONFIG_1, 1) @@ -208,7 +208,7 @@ class ICM20X: # pylint:disable=too-many-instance-attributes @property def _bank(self): - return self._bank_reg + return self._bank_reg >> 4 @_bank.setter def _bank(self, value): @@ -221,99 +221,24 @@ def __init__(self, i2c_bus, address): 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): + # TODO: method-ify self._bank = 0 sleep(0.005) self._sleep = False sleep(0.005) - - self._i2c_master_duty_cycle_en = True + # TODO: method-ify + # self._i2c_master_duty_cycle_en = True #WHY? sleep(0.005) - self._bank = 2 - # WRITE 0b00000001 to ACCEL_CONFIG - - # sleep(0.005) - # self._accel_config = [0b00111000] - # sleep(0.005) - # self._gyro_config1 = [0b00111000] - # sleep(0.005) - - # self.accel_range = AccelRange.RANGE_8G # pylint: disable=no-member - # self._cached_accel_range = 0 - - # TODO: CV-ify - # self._accel_dlpf_config = 3 - # self._accel_rate_divisor = 20 - - # self._gyro_range = GyroRange.RANGE_500_DPS #pylint: disable=no-member - # sleep(0.100) - # self._cached_gyro_range = 0 - - # self._gyro_rate_divisor = 10 - - ################## - 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 - # sleep(0.100) - # #TODO: CV-ify - # self._bank = 2 - # self._accel_dlpf_config = 3 - - # # //reset to register bank 0 - # self._bank = 0 - ################################ - - # def _swreset(self): - - # self._i2c_master_duty_cycle_en = True - - # # set all registers to init/power up values - # _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 - # _ICM20649_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 - # _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 - # # _ICM20649_ACCEL_CONFIG_2 = 0x15 - - # # 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 - # pass def reset(self): """Resets the internal registers and restores the default settings""" @@ -369,6 +294,7 @@ 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 @@ -386,6 +312,7 @@ def gyro_range(self, 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 @@ -412,10 +339,10 @@ def accelerometer_data_rate_divisor(self): 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) - self._bank = 0 - +\ @property def gyro_data_rate_divisor(self): """The divisor for the rate at which gyro measurements are taken in Hz @@ -437,10 +364,10 @@ def gyro_data_rate_divisor(self): 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) - self._bank = 0 - +\ def _accel_rate_calc(self, divisor): # pylint:disable=no-self-use return 1125 / (1 + divisor) @@ -532,8 +459,12 @@ class ICM20948(ICM20X): _bypass_i2c_master = RWBit(_ICM20X_REG_INT_PIN_CFG, 1) _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) _i2c_master_control = UnaryStruct(_ICM20X_I2C_MST_CTRL, ">B") - _i2c_master_enable = RWBit(_ICM20X_USER_CTRL, 5) - _i2c_master_reset = RWBit(_ICM20X_USER_CTRL, 1) + + _i2c_master_enable = RWBit(_ICM20X_USER_CTRL, 5) # TODO: use this in sw reset + # _i2c_slave_reset = RWBit(_ICM20X_USER_CTRL, 4) + # _dmp_reset = RWBit(_ICM20X_USER_CTRL, 3) + # _sram_reset = RWBit(_ICM20X_USER_CTRL, 2) + # _i2c_master_reset = RWBit(_ICM20X_USER_CTRL, 1) _slave0_addr = UnaryStruct(_ICM20X_I2C_SLV0_ADDR, ">B") _slave0_reg = UnaryStruct(_ICM20X_I2C_SLV0_REG, ">B") @@ -570,21 +501,43 @@ def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): def _magnetometer_init(self): self._bank = 0 + sleep(0.100) self._bypass_i2c_master = False sleep(0.005) # print("I2C Master bypassed:", self._bypass_i2c_master) # sleep(0.005) + + # TODO: Determine why this does not work sometimes # no repeated start, i2c master clock = 345.60kHz self._bank = 3 + sleep(0.100) self._i2c_master_control = 0x17 - sleep(0.005) + sleep(0.100) # print("i2c master control:", bin(self._i2c_master_control)) # sleep(0.005) + """ + write>0x7F>-0x30$ | write>0x7F>-0x30$ + write>0x01>-0x17$ | write>0x01>-0x17$ + write>0x01$ | write>0x01$ + read>-0x17$ | read>-0x00$ ********* + """ + # TODO: Determine why this does not work sometimes self._bank = 0 + sleep(0.100) self._i2c_master_enable = True sleep(0.020) + """ + write>0x7F>-0x00$ | write>0x7F>-0x00$ + write>0x03$ | write>0x03$ + read>-0x00$ | read>-0x00$ + write>0x03>-0x20$ | write>0x03>-0x20$ + write>0x7F$ | write>0x7F$ + read>-0x00$ | read>-0x00$ + write>0x03$ | write>0x03$ + read>-0x20$ | read>-0x00$ ********** + """ # print("i2c master enable:", bin(self._i2c_master_enable)) # sleep(0.005) @@ -594,6 +547,8 @@ def _magnetometer_init(self): # 0x2 = 20hz Continuous measurement mode 2 # 0x4 = 50hz Continuous measurement mode 3 # 0x8 = 100hz Continuous measurement mode 4 + # TODO: Investigate why the above I2C master setup sometimes fails, causing this to endlessly loop + # waiting for the I2C write to the magnetometer to finish self._write_mag_register(0x31, 0x08) # set up slave0 for reading into the bank 0 data registers From c18c3dda68cb323bf4236ab8f060f5932279132e Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 25 May 2020 16:26:42 -0700 Subject: [PATCH 11/26] black'd and linted --- adafruit_icm20x.py | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 80e0765..0997390 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -224,6 +224,7 @@ def __init__(self, i2c_bus, address): self.initialize() def initialize(self): + """Configure the sensors with the default settings. For use after calling `reset()`""" # TODO: method-ify self._bank = 0 sleep(0.005) @@ -239,7 +240,6 @@ def initialize(self): 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 @@ -342,7 +342,7 @@ def accelerometer_data_rate_divisor(self, value): 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 @@ -367,7 +367,7 @@ def gyro_data_rate_divisor(self, value): 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) @@ -460,7 +460,7 @@ class ICM20948(ICM20X): _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) _i2c_master_control = UnaryStruct(_ICM20X_I2C_MST_CTRL, ">B") - _i2c_master_enable = RWBit(_ICM20X_USER_CTRL, 5) # TODO: use this in sw reset + _i2c_master_enable = RWBit(_ICM20X_USER_CTRL, 5) # TODO: use this in sw reset # _i2c_slave_reset = RWBit(_ICM20X_USER_CTRL, 4) # _dmp_reset = RWBit(_ICM20X_USER_CTRL, 3) # _sram_reset = RWBit(_ICM20X_USER_CTRL, 2) @@ -507,7 +507,6 @@ def _magnetometer_init(self): # print("I2C Master bypassed:", self._bypass_i2c_master) # sleep(0.005) - # TODO: Determine why this does not work sometimes # no repeated start, i2c master clock = 345.60kHz self._bank = 3 @@ -516,30 +515,26 @@ def _magnetometer_init(self): sleep(0.100) # print("i2c master control:", bin(self._i2c_master_control)) # sleep(0.005) - """ - write>0x7F>-0x30$ | write>0x7F>-0x30$ - write>0x01>-0x17$ | write>0x01>-0x17$ - write>0x01$ | write>0x01$ - read>-0x17$ | read>-0x00$ ********* - """ + # trace: + # write>0x7F>-0x30$ | write>0x7F>-0x30$ + # write>0x01>-0x17$ | write>0x01>-0x17$ + # write>0x01$ | write>0x01$ + # read>-0x17$ | read>-0x00$ ********* # TODO: Determine why this does not work sometimes self._bank = 0 sleep(0.100) self._i2c_master_enable = True sleep(0.020) - """ - write>0x7F>-0x00$ | write>0x7F>-0x00$ - write>0x03$ | write>0x03$ - read>-0x00$ | read>-0x00$ - write>0x03>-0x20$ | write>0x03>-0x20$ - write>0x7F$ | write>0x7F$ - read>-0x00$ | read>-0x00$ - write>0x03$ | write>0x03$ - read>-0x20$ | read>-0x00$ ********** - """ - # print("i2c master enable:", bin(self._i2c_master_enable)) - # sleep(0.005) + # trace + # write>0x7F>-0x00$ | write>0x7F>-0x00$ + # write>0x03$ | write>0x03$ + # read>-0x00$ | read>-0x00$ + # write>0x03>-0x20$ | write>0x03>-0x20$ + # write>0x7F$ | write>0x7F$ + # read>-0x00$ | read>-0x00$ + # write>0x03$ | write>0x03$ + # read>-0x20$ | read>-0x00$ ********** # https://www.y-ic.es/datasheet/78/SMDSW.020-2OZ.pdf page 9 # set the magnetometer data rate @@ -547,8 +542,8 @@ def _magnetometer_init(self): # 0x2 = 20hz Continuous measurement mode 2 # 0x4 = 50hz Continuous measurement mode 3 # 0x8 = 100hz Continuous measurement mode 4 - # TODO: Investigate why the above I2C master setup sometimes fails, causing this to endlessly loop - # waiting for the I2C write to the magnetometer to finish + # TODO: Investigate why the above I2C master setup sometimes fails, causing + # this to endlessly loop waiting for the I2C write to the magnetometer to finish self._write_mag_register(0x31, 0x08) # set up slave0 for reading into the bank 0 data registers From ace6db7f5a4e4dfdd565ec627a70f023b7e1f028 Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 25 May 2020 16:50:39 -0700 Subject: [PATCH 12/26] fixing merge leftovers --- adafruit_icm20x.py | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 0997390..a08b29c 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -82,36 +82,11 @@ _ICM20649_GYRO_CONFIG_1 = 0x01 _ICM20649_ACCEL_SMPLRT_DIV_1 = 0x10 _ICM20649_ACCEL_SMPLRT_DIV_2 = 0x11 -<<<<<<< HEAD -<<<<<<< HEAD _ICM20649_ACCEL_CONFIG_1 = 0x14 -======= -_ICM20649_ACCEL_CONFIG_1 = 0x14 -======= -_ICM20649_ACCEL_CONFIG_1 = 0x14 ->>>>>>> fixing timing issues, formatting -# _ICM20649_ACCEL_CONFIG_2 = 0x15 ->>>>>>> working! + # Bank 3 -<<<<<<< HEAD -_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 -======= + _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 @@ -128,7 +103,6 @@ _ICM20X_UT_PER_LSB = 0.15 # mag data LSB value (fixed) _ICM20X_RAD_PER_DEG = 0.017453293 # Degrees/s to rad/s multiplier ->>>>>>> fixing timing issues, formatting G_TO_ACCEL = 9.80665 # pylint: enable=bad-whitespace @@ -152,21 +126,12 @@ def is_valid(cls, value): """Validate that a given value is a member""" return value in cls.string -<<<<<<< HEAD -<<<<<<< HEAD - -======= ->>>>>>> almost there on mag, missing some bytes -class AccelRange(CV): - """Options for ``accelerometer_range``""" -======= class AccelRange(CV): """Options for ``accelerometer_range``""" pass # pylint: disable=unnecessary-pass ->>>>>>> fixing timing issues, formatting class GyroRange(CV): """Options for ``gyro_data_range``""" From 167e7be4273baf432738328a5cf1ba86258c7701 Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 25 May 2020 18:21:52 -0700 Subject: [PATCH 13/26] renaming --- LICENSE | 2 +- README.rst | 20 +++++++-------- adafruit_icm20x.py | 63 +++++++++++++++++++++++----------------------- docs/conf.py | 18 ++++++------- setup.py | 8 +++--- 5 files changed, 56 insertions(+), 55 deletions(-) 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 727e083..bd0f37d 100644 --- a/README.rst +++ b/README.rst @@ -1,19 +1,19 @@ Introduction ============ -.. image:: https://readthedocs.org/projects/adafruit-circuitpython-icm20649/badge/?version=latest - :target: https://circuitpython.readthedocs.io/projects/icm20649/en/latest/ +.. image:: https://readthedocs.org/projects/adafruit-circuitpython-icm20x/badge/?version=latest + :target: https://circuitpython.readthedocs.io/projects/icm20x/en/latest/ :alt: Documentation Status .. image:: https://img.shields.io/discord/327254708534116352.svg :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,7 +51,7 @@ 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 ============= @@ -95,7 +95,7 @@ Contributing ============ Contributions are welcome! Please read our `Code of Conduct -`_ +`_ before contributing to help this project stay welcoming. Documentation diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index a08b29c..3d0ec44 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -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 @@ -46,7 +46,7 @@ """ __version__ = "0.0.0-auto.0" -__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ICM20649.git" +__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 @@ -63,12 +63,12 @@ # 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 -_ICM20649_I2C_MST_STATUS = 0x17 # I2C Master Status bits +_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 @@ -78,11 +78,11 @@ _ICM20X_REG_INT_ENABLE_1 = 0x11 # Interrupt enable register 1 # 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 +_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 @@ -140,36 +140,37 @@ class GyroRange(CV): class ICM20X: # pylint:disable=too-many-instance-attributes - """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 - :param ~busio.I2C i2c_bus: The I2C bus the ICM20649 is connected to. + + :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(_ICM20649_WHO_AM_I, "hhh") - _raw_gyro_data = Struct(_ICM20649_GYRO_XOUT_H, ">hhh") + _raw_accel_data = Struct(_ICM20X_ACCEL_XOUT_H, ">hhh") + _raw_gyro_data = Struct(_ICM20X_GYRO_XOUT_H, ">hhh") # _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) # Bank 2 - _gyro_range = RWBits(2, _ICM20649_GYRO_CONFIG_1, 1) - _accel_config = Struct(_ICM20649_ACCEL_CONFIG_1, ">B") - _gyro_config1 = Struct(_ICM20649_GYRO_CONFIG_1, ">B") - _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) + _gyro_range = RWBits(2, _ICM20X_GYRO_CONFIG_1, 1) + _accel_config = Struct(_ICM20X_ACCEL_CONFIG_1, ">B") + _gyro_config1 = Struct(_ICM20X_GYRO_CONFIG_1, ">B") + _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(_ICM20649_ACCEL_SMPLRT_DIV_1, ">H") - _gyro_rate_divisor = UnaryStruct(_ICM20649_GYRO_SMPLRT_DIV, ">B") + _accel_rate_divisor = UnaryStruct(_ICM20X_ACCEL_SMPLRT_DIV_1, ">H") + _gyro_rate_divisor = UnaryStruct(_ICM20X_GYRO_SMPLRT_DIV, ">B") @property def _bank(self): @@ -417,7 +418,7 @@ class ICM20948(ICM20X): :param address: The I2C slave address of the sensor """ - _slave_finished = ROBit(_ICM20649_I2C_MST_STATUS, 6) + _slave_finished = ROBit(_ICM20X_I2C_MST_STATUS, 6) _raw_mag_data = Struct(_ICM20948_EXT_SLV_SENS_DATA_00, " Date: Mon, 25 May 2020 19:56:45 -0700 Subject: [PATCH 14/26] refactoring to add retries/reset on mag setup --- adafruit_icm20x.py | 92 +++++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 33 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 3d0ec44..0fc647a 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -61,7 +61,8 @@ _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 +# perhaps refactor to have the bank be part of the definition # Bank 0 _ICM20X_WHO_AM_I = 0x00 # device_id register _ICM20X_REG_BANK_SEL = 0x7F # register bank selection register @@ -425,12 +426,8 @@ class ICM20948(ICM20X): _bypass_i2c_master = RWBit(_ICM20X_REG_INT_PIN_CFG, 1) _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) _i2c_master_control = UnaryStruct(_ICM20X_I2C_MST_CTRL, ">B") - _i2c_master_enable = RWBit(_ICM20X_USER_CTRL, 5) # TODO: use this in sw reset - # _i2c_slave_reset = RWBit(_ICM20X_USER_CTRL, 4) - # _dmp_reset = RWBit(_ICM20X_USER_CTRL, 3) - # _sram_reset = RWBit(_ICM20X_USER_CTRL, 2) - # _i2c_master_reset = RWBit(_ICM20X_USER_CTRL, 1) + _i2c_master_reset = RWBit(_ICM20X_USER_CTRL, 1) _slave0_addr = UnaryStruct(_ICM20X_I2C_SLV0_ADDR, ">B") _slave0_reg = UnaryStruct(_ICM20X_I2C_SLV0_REG, ">B") @@ -464,55 +461,63 @@ def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): super().__init__(i2c_bus, address) self._magnetometer_init() - def _magnetometer_init(self): + @property + def _mag_configured(self): + for tries in range(5): + id_tup = self._mag_id() + # success + if id_tup is not None: + return True + # i2c master stuck, try resetting + else: + self._reset_i2c_master() + 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) - # print("I2C Master bypassed:", self._bypass_i2c_master) - # sleep(0.005) - # TODO: Determine why this does not work sometimes # no repeated start, i2c master clock = 345.60kHz self._bank = 3 sleep(0.100) self._i2c_master_control = 0x17 sleep(0.100) - # print("i2c master control:", bin(self._i2c_master_control)) - # sleep(0.005) - # trace: - # write>0x7F>-0x30$ | write>0x7F>-0x30$ - # write>0x01>-0x17$ | write>0x01>-0x17$ - # write>0x01$ | write>0x01$ - # read>-0x17$ | read>-0x00$ ********* - - # TODO: Determine why this does not work sometimes + self._bank = 0 sleep(0.100) self._i2c_master_enable = True sleep(0.020) - # trace - # write>0x7F>-0x00$ | write>0x7F>-0x00$ - # write>0x03$ | write>0x03$ - # read>-0x00$ | read>-0x00$ - # write>0x03>-0x20$ | write>0x03>-0x20$ - # write>0x7F$ | write>0x7F$ - # read>-0x00$ | read>-0x00$ - # write>0x03$ | write>0x03$ - # read>-0x20$ | read>-0x00$ ********** + def _set_mag_data_rate(self, data_rate=0x08): # https://www.y-ic.es/datasheet/78/SMDSW.020-2OZ.pdf page 9 # set the magnetometer data rate # 0x1 = 10hz Continuous measurement mode 1 # 0x2 = 20hz Continuous measurement mode 2 # 0x4 = 50hz Continuous measurement mode 3 # 0x8 = 100hz Continuous measurement mode 4 - # TODO: Investigate why the above I2C master setup sometimes fails, causing - # this to endlessly loop waiting for the I2C write to the magnetometer to finish - self._write_mag_register(0x31, 0x08) + self._write_mag_register(0x31, data_rate) + + def _magnetometer_init(self): + self._magnetometer_enable() + self._set_mag_data_rate() + + if not self._mag_configured: + return False + + self._setup_mag_readout() + + return True + ################ SAME ABOVE ########### # 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) @@ -521,6 +526,11 @@ def _magnetometer_init(self): self._slave0_ctrl = 0x89 # enable sleep(0.005) + def _mag_id(self): + mag_mfg_id = self._read_mag_register(0x00) + mag_chip_id = self._read_mag_register(0x01) + return (mag_mfg_id, mag_chip_id) + @property def magnetic(self): """The current magnetic field strengths onthe X, Y, and Z axes in uT (micro-teslas)""" @@ -544,11 +554,19 @@ def _read_mag_register(self, register_addr, slave_addr=0x0C): sleep(0.005) self._slave4_reg = register_addr sleep(0.005) - self._slave4_ctrl = 0x80 # enable + self._slave4_ctrl = 0x80 # enable, don't raise interrupt, write register value, no delay sleep(0.005) self._bank = 0 + # add max cycle count while not self._slave_finished: sleep(0.010) + + # if i2c_mst_status & (1<<4): # Check I2C_SLV4_NACK bit [4] + # txn_failed = True + + # if count > max_cycles: + # txn_failed = True + self._bank = 3 mag_register_data = self._slave4_di sleep(0.005) @@ -563,10 +581,18 @@ def _write_mag_register(self, register_addr, value, slave_addr=0x0C): sleep(0.005) self._slave4_do = value sleep(0.005) - self._slave4_ctrl = 0x80 # enable + self._slave4_ctrl = 0x80 # enable, don't raise interrupt, write register value, no delay sleep(0.005) self._bank = 0 + + # add max cycle count # wait for write to mag register to finish") while not self._slave_finished: print(".", end="") sleep(0.010) + + # if i2c_mst_status & (1<<4): # Check I2C_SLV4_NACK bit [4] + # txn_failed = True + + # if count > max_cycles: + # txn_failed = True \ No newline at end of file From 7d15be81561b0fef10534081cfaa5f144b6143c4 Mon Sep 17 00:00:00 2001 From: siddacious Date: Mon, 25 May 2020 20:40:40 -0700 Subject: [PATCH 15/26] fixed :) --- adafruit_icm20x.py | 70 +++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 0fc647a..3658c02 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -61,8 +61,8 @@ _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 -# perhaps refactor to have the bank be part of the definition +# 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 @@ -159,8 +159,6 @@ class ICM20X: # pylint:disable=too-many-instance-attributes _raw_accel_data = Struct(_ICM20X_ACCEL_XOUT_H, ">hhh") _raw_gyro_data = Struct(_ICM20X_GYRO_XOUT_H, ">hhh") - # _i2c_master_duty_cycle_en = RWBit(_ICM20X_LP_CONFIG, 6) - # Bank 2 _gyro_range = RWBits(2, _ICM20X_GYRO_CONFIG_1, 1) _accel_config = Struct(_ICM20X_ACCEL_CONFIG_1, ">B") @@ -197,8 +195,7 @@ def initialize(self): sleep(0.005) self._sleep = False sleep(0.005) - # TODO: method-ify - # self._i2c_master_duty_cycle_en = True #WHY? + sleep(0.005) self.accelerometer_range = AccelRange.RANGE_8G # pylint: disable=no-member @@ -412,7 +409,7 @@ def __init__(self, i2c_bus, address=_ICM20649_DEFAULT_ADDRESS): super().__init__(i2c_bus, address) -class ICM20948(ICM20X): +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. @@ -424,7 +421,6 @@ class ICM20948(ICM20X): _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) @@ -437,7 +433,6 @@ class ICM20948(ICM20X): _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_ctrl = UnaryStruct(_ICM20X_I2C_SLV4_CTRL, ">B") _slave4_do = UnaryStruct(_ICM20X_I2C_SLV4_DO, ">B") _slave4_di = UnaryStruct(_ICM20X_I2C_SLV4_DI, ">B") @@ -463,14 +458,14 @@ def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): @property def _mag_configured(self): - for tries in range(5): - id_tup = self._mag_id() - # success - if id_tup is not None: + 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 - else: - self._reset_i2c_master() return False def _reset_i2c_master(self): @@ -514,9 +509,8 @@ def _magnetometer_init(self): self._setup_mag_readout() return True - ################ SAME ABOVE ########### - # set up slave0 for reading into the bank 0 data registers + # set up slave0 for reading into the bank 0 data registers def _setup_mag_readout(self): self._bank = 3 self._slave0_addr = 0x8C @@ -527,9 +521,7 @@ def _setup_mag_readout(self): sleep(0.005) def _mag_id(self): - mag_mfg_id = self._read_mag_register(0x00) - mag_chip_id = self._read_mag_register(0x01) - return (mag_mfg_id, mag_chip_id) + return self._read_mag_register(0x01) @property def magnetic(self): @@ -554,18 +546,21 @@ def _read_mag_register(self, register_addr, slave_addr=0x0C): 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 + self._slave4_ctrl = ( + 0x80 # enable, don't raise interrupt, write register value, no delay + ) sleep(0.005) self._bank = 0 - # add max cycle count - while not self._slave_finished: - sleep(0.010) - # if i2c_mst_status & (1<<4): # Check I2C_SLV4_NACK bit [4] - # txn_failed = True + finished = False + for _i in range(100): + finished = self._slave_finished + if finished: # bueno! + break + sleep(0.010) - # if count > max_cycles: - # txn_failed = True + if not finished: + return None self._bank = 3 mag_register_data = self._slave4_di @@ -581,18 +576,17 @@ def _write_mag_register(self, register_addr, value, slave_addr=0x0C): sleep(0.005) self._slave4_do = value sleep(0.005) - self._slave4_ctrl = 0x80 # enable, don't raise interrupt, write register value, no delay + self._slave4_ctrl = ( + 0x80 # enable, don't raise interrupt, write register value, no delay + ) sleep(0.005) self._bank = 0 - # add max cycle count - # wait for write to mag register to finish") - while not self._slave_finished: - print(".", end="") + finished = False + for _i in range(100): + finished = self._slave_finished + if finished: # bueno! + break sleep(0.010) - # if i2c_mst_status & (1<<4): # Check I2C_SLV4_NACK bit [4] - # txn_failed = True - - # if count > max_cycles: - # txn_failed = True \ No newline at end of file + return finished From ae4bea2d6ac33af2db60fd56b91905ef27f14f4d Mon Sep 17 00:00:00 2001 From: dherrada <33632497+dherrada@users.noreply.github.com> Date: Tue, 26 May 2020 13:51:39 -0400 Subject: [PATCH 16/26] Fix code block rendering --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index bd0f37d..453bf66 100644 --- a/README.rst +++ b/README.rst @@ -58,7 +58,8 @@ Usage Example For use with the ICM20649: -.. code-block: python3 +.. code-block:: python3 + import time import board import busio @@ -75,7 +76,8 @@ For use with the ICM20649: For use with the ICM20948: -.. code-block: python3 +.. code-block:: python3 + import time import board import busio From 5413a9594565974b1b38faa1e76288a5e2befda7 Mon Sep 17 00:00:00 2001 From: dherrada <33632497+dherrada@users.noreply.github.com> Date: Tue, 26 May 2020 13:54:53 -0400 Subject: [PATCH 17/26] Replace ICM20649 with ICM20X --- docs/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From a5e42f27c797cc1da58c8dad71c7cf76e026a6a8 Mon Sep 17 00:00:00 2001 From: dherrada <33632497+dherrada@users.noreply.github.com> Date: Tue, 26 May 2020 13:57:00 -0400 Subject: [PATCH 18/26] Added second example --- docs/examples.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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: From 2fd26d3b136b5f92b4790c5659f715acc9471caf Mon Sep 17 00:00:00 2001 From: dherrada <33632497+dherrada@users.noreply.github.com> Date: Tue, 26 May 2020 14:51:23 -0400 Subject: [PATCH 19/26] Reverted docs badge change --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 453bf66..71a091d 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,8 @@ Introduction ============ -.. image:: https://readthedocs.org/projects/adafruit-circuitpython-icm20x/badge/?version=latest - :target: https://circuitpython.readthedocs.io/projects/icm20x/en/latest/ +.. image:: https://readthedocs.org/projects/adafruit-circuitpython-icm20649/badge/?version=latest + :target: https://circuitpython.readthedocs.io/projects/icm20649/en/latest/ :alt: Documentation Status .. image:: https://img.shields.io/discord/327254708534116352.svg From ce6322a4209bc819020a776494a9bc88af311e40 Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 26 May 2020 15:18:39 -0700 Subject: [PATCH 20/26] adding filters --- adafruit_icm20x.py | 101 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 96 insertions(+), 5 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 3658c02..13443e6 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -140,6 +140,18 @@ class GyroRange(CV): 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 @@ -160,9 +172,10 @@ class ICM20X: # pylint:disable=too-many-instance-attributes _raw_gyro_data = Struct(_ICM20X_GYRO_XOUT_H, ">hhh") # Bank 2 + _gyro_dlpf_enable = RWBits(1, _ICM20X_GYRO_CONFIG_1, 0) _gyro_range = RWBits(2, _ICM20X_GYRO_CONFIG_1, 1) - _accel_config = Struct(_ICM20X_ACCEL_CONFIG_1, ">B") - _gyro_config1 = Struct(_ICM20X_GYRO_CONFIG_1, ">B") + _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) @@ -170,6 +183,87 @@ class ICM20X: # pylint:disable=too-many-instance-attributes # 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 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 _bank(self): @@ -190,14 +284,11 @@ def __init__(self, i2c_bus, address): def initialize(self): """Configure the sensors with the default settings. For use after calling `reset()`""" - # TODO: method-ify self._bank = 0 sleep(0.005) self._sleep = False sleep(0.005) - sleep(0.005) - self.accelerometer_range = AccelRange.RANGE_8G # pylint: disable=no-member self.gyro_range = GyroRange.RANGE_500_DPS # pylint: disable=no-member From 8035854ea6b52d72fd7f057e646ea8aca26b9fec Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 26 May 2020 15:30:02 -0700 Subject: [PATCH 21/26] adding low power flag --- adafruit_icm20x.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 13443e6..0739808 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -166,6 +166,7 @@ class ICM20X: # pylint:disable=too-many-instance-attributes _bank_reg = UnaryStruct(_ICM20X_REG_BANK_SEL, "hhh") @@ -265,6 +266,17 @@ def gyro_dlpf_cutoff(self, cutoff_frequency): self._gyro_dlpf_enable = True self._gyro_dlpf_config = cutoff_frequency + @property + def low_power(self): + """Enables or disables a low power mode for the sensors digital circuitry""" + self._bank = 0 + return self._low_power_en + + @low_power.setter + def low_power(self, enabled): + self._bank = 0 + self._low_power_en = enabled + @property def _bank(self): return self._bank_reg >> 4 From 2aca353b6ff0541b95bc7badb2fa02ebde0fd74d Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 26 May 2020 16:22:43 -0700 Subject: [PATCH 22/26] reorganizing --- adafruit_icm20x.py | 127 ++++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 60 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 0739808..4483d8b 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -162,16 +162,22 @@ class ICM20X: # pylint:disable=too-many-instance-attributes """ # 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 = 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") + _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) @@ -220,63 +226,6 @@ class ICM20X: # pylint:disable=too-many-instance-attributes ) ) - @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): - """Enables or disables a low power mode for the sensors digital circuitry""" - self._bank = 0 - return self._low_power_en - - @low_power.setter - def low_power(self, enabled): - self._bank = 0 - self._low_power_en = enabled - @property def _bank(self): return self._bank_reg >> 4 @@ -481,6 +430,63 @@ def gyro_data_rate(self, value): 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): + """Enables or disables a low power mode for the sensors digital circuitry""" + 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. @@ -521,6 +527,7 @@ class ICM20948(ICM20X): # pylint:disable=too-many-instance-attributes _slave_finished = ROBit(_ICM20X_I2C_MST_STATUS, 6) + # mag data is LE _raw_mag_data = Struct(_ICM20948_EXT_SLV_SENS_DATA_00, " Date: Tue, 26 May 2020 19:05:56 -0700 Subject: [PATCH 23/26] added data rate property for mag --- adafruit_icm20x.py | 70 +++++++++++++++++++++---- examples/icm20948_mag_data_rate_test.py | 22 ++++++++ 2 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 examples/icm20948_mag_data_rate_test.py diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 4483d8b..e072b81 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -245,6 +245,7 @@ def __init__(self, i2c_bus, address): def initialize(self): """Configure the sensors with the default settings. For use after calling `reset()`""" + self._bank = 0 sleep(0.005) self._sleep = False @@ -253,6 +254,7 @@ def initialize(self): self.accelerometer_range = AccelRange.RANGE_8G # pylint: disable=no-member self.gyro_range = GyroRange.RANGE_500_DPS # pylint: disable=no-member + # TODO: Test these self.accelerometer_data_rate_divisor = 20 # ~53.57Hz self.gyro_data_rate_divisor = 10 # ~100Hz @@ -416,7 +418,6 @@ def gyro_data_rate(self): 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. """ @@ -518,6 +519,27 @@ def __init__(self, i2c_bus, address=_ICM20649_DEFAULT_ADDRESS): 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. @@ -563,6 +585,18 @@ def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): ("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() @@ -600,18 +634,11 @@ def _magnetometer_enable(self): self._i2c_master_enable = True sleep(0.020) - def _set_mag_data_rate(self, data_rate=0x08): - # https://www.y-ic.es/datasheet/78/SMDSW.020-2OZ.pdf page 9 - # set the magnetometer data rate - # 0x1 = 10hz Continuous measurement mode 1 - # 0x2 = 20hz Continuous measurement mode 2 - # 0x4 = 50hz Continuous measurement mode 3 - # 0x8 = 100hz Continuous measurement mode 4 - self._write_mag_register(0x31, data_rate) - def _magnetometer_init(self): self._magnetometer_enable() - self._set_mag_data_rate() + self.magnetometer_data_rate = ( + MagDataRate.RATE_100HZ # pylint: disable=no-member + ) if not self._mag_configured: return False @@ -647,6 +674,27 @@ def magnetic(self): 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 diff --git a/examples/icm20948_mag_data_rate_test.py b/examples/icm20948_mag_data_rate_test.py new file mode 100644 index 0000000..5b3deb7 --- /dev/null +++ b/examples/icm20948_mag_data_rate_test.py @@ -0,0 +1,22 @@ +import time +import board +import busio +from adafruit_icm20x import MagDataRate, ICM20948 + +cycles = 200 +i2c = busio.I2C(board.SCL, board.SDA) +icm = ICM20948(i2c) + +icm.accelerometer_data_rate_divisor = 0 +# 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) From a0e05ce4d428e108558b523b3af3d2b1b195ba5a Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 26 May 2020 19:52:34 -0700 Subject: [PATCH 24/26] updating examples and tested data rates --- adafruit_icm20x.py | 21 ++++++++++++++------ examples/icm20948_accel_data_rate_test.py | 24 +++++++++++++++++++++++ examples/icm20948_gyro_data_rate_test.py | 24 +++++++++++++++++++++++ examples/icm20948_mag_data_rate_test.py | 2 +- 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 examples/icm20948_accel_data_rate_test.py create mode 100644 examples/icm20948_gyro_data_rate_test.py diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index e072b81..69aaf43 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -165,7 +165,7 @@ class ICM20X: # pylint:disable=too-many-instance-attributes _device_id = ROUnaryStruct(_ICM20X_WHO_AM_I, ">B") _bank_reg = UnaryStruct(_ICM20X_REG_BANK_SEL, ">B") _reset = RWBit(_ICM20X_PWR_MGMT_1, 7) - _sleep = RWBit(_ICM20X_PWR_MGMT_1, 6) + _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) @@ -246,15 +246,10 @@ def __init__(self, i2c_bus, address): def initialize(self): """Configure the sensors with the default settings. For use after calling `reset()`""" - self._bank = 0 - sleep(0.005) self._sleep = False - sleep(0.005) - self.accelerometer_range = AccelRange.RANGE_8G # pylint: disable=no-member self.gyro_range = GyroRange.RANGE_500_DPS # pylint: disable=no-member - # TODO: Test these self.accelerometer_data_rate_divisor = 20 # ~53.57Hz self.gyro_data_rate_divisor = 10 # ~100Hz @@ -268,6 +263,20 @@ def reset(self): 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.""" 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 index 5b3deb7..63ba2a6 100644 --- a/examples/icm20948_mag_data_rate_test.py +++ b/examples/icm20948_mag_data_rate_test.py @@ -1,3 +1,4 @@ +# pylint: disable=no-member import time import board import busio @@ -7,7 +8,6 @@ i2c = busio.I2C(board.SCL, board.SDA) icm = ICM20948(i2c) -icm.accelerometer_data_rate_divisor = 0 # 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 From 9e43fc2daa761924f6654f94e621661083f40062 Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 26 May 2020 21:21:37 -0700 Subject: [PATCH 25/26] hiding `low_power` for now --- adafruit_icm20x.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index 69aaf43..f2effac 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -487,13 +487,12 @@ def gyro_dlpf_cutoff(self, cutoff_frequency): self._gyro_dlpf_config = cutoff_frequency @property - def low_power(self): - """Enables or disables a low power mode for the sensors digital circuitry""" + def _low_power(self): self._bank = 0 return self._low_power_en - @low_power.setter - def low_power(self, enabled): + @_low_power.setter + def _low_power(self, enabled): self._bank = 0 self._low_power_en = enabled From 185855a53b2e63864d579a8c743546d7738072f6 Mon Sep 17 00:00:00 2001 From: siddacious Date: Tue, 26 May 2020 21:32:57 -0700 Subject: [PATCH 26/26] adding SparkFun callout --- adafruit_icm20x.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/adafruit_icm20x.py b/adafruit_icm20x.py index f2effac..e595b41 100644 --- a/adafruit_icm20x.py +++ b/adafruit_icm20x.py @@ -608,6 +608,9 @@ def __init__(self, i2c_bus, address=_ICM20948_DEFAULT_ADDRESS): 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