adafruit / Adafruit_LSM6DS

Arduino library for LSM6DS
Other
47 stars 39 forks source link

Cannot Change Device I2C Address to 0x6B #39

Closed markwu2001 closed 11 months ago

markwu2001 commented 11 months ago

I found this issue on a livestream; the recording can be found here. The issue boils down to the inability to easily swap the I2C address to 107 or 0x6B.

Repo Steps:

  1. For my application, I'm using the LSM6DS3TR-C. In hardware, just solder the I2C address pad on the back to change the IMU address to 0x6B.

  2. Open the adafruit_lsm6ds3trc_test.ino example. This is what I am uploading to the Arduino Nano.

    1. In VS Code, I searched for every reference to 0x6A and replaced it with 0x6B. See below for the 4 references in the entire library.

Adafruit_ISM330DHCX.h #define ISM330DHCX_CHIP_ID 0x6B ///< ISM330DHCX default device id from WHOAMI

Adafruit_LSM6DS.h #define LSM6DS_I2CADDR_DEFAULT 0x6B ///< LSM6DS default i2c address

Adafruit_LSM6DSL.h #define LSM6DS3TRC_CHIP_ID 0x6B ///< LSM6DSL default device id from WHOAMI

Adafruit_LSM6DSL.h

define LSM6DSL_CHIP_ID 0x6B ///< LSM6DSL default device id from WHOAMI

  1. You will get a "Failed to find LSM6DS3TR-C chip" message in the Serial Monitor and the program will enter an infinite loop. See code from the adafruit_lsm6ds3trc_test.ino example.

    if (!lsm6ds3trc.begin_I2C()) {
    Serial.println("Failed to find LSM6DS3TR-C chip");
    while (1) {
      delay(10);
    }
    }

Root Cause: After tracing back through the library functions and placing print statements, this was as far as I could get.

lsm6ds3trc.begin_I2C() -> Let's look at begin.I2C() with some println statements I added in.

boolean Adafruit_LSM6DS::begin_I2C(uint8_t i2c_address, TwoWire *wire,
                                   int32_t sensor_id) {
  delete i2c_dev; // remove old interface

  i2c_dev = new Adafruit_I2CDevice(i2c_address, wire);
  delay(100);
  Serial.println("Created i2c device");

  //starts the I2C peripheral
  if (!i2c_dev->begin()) {
    return false;
    delay(100);
    Serial.println("i2c bus not started");
  }
  delay(100);
  Serial.println("i2c bus started");

  return _init(sensor_id);
}

The only reason we arrived in the infinite loop in the adafruit_lsm6ds3trc_test.ino example is if _init(sensor_id) at the end of this function returns false. Let's dig into _init(). (In my testing, I was able to get the message "i2c bus started" in the serial monitor.)

bool Adafruit_LSM6DS3::_init(int32_t sensor_id) {
  // make sure we're talking to the right chip
  if (chipID() != LSM6DS3_CHIP_ID) {
    return false;
  }
  _sensorid_accel = sensor_id;
  _sensorid_gyro = sensor_id + 1;
  _sensorid_temp = sensor_id + 2;

  temperature_sensitivity = 16.0;

  reset();

  // call base class _init()
  Adafruit_LSM6DS::_init(sensor_id);

  return true;
}

As we can see here, the only way we can get a false on the sensor_id boolean is if chipID() doesn't pass. So let's dig into chipID().

uint8_t Adafruit_LSM6DS::chipID(void) {
  Adafruit_BusIO_Register chip_id = Adafruit_BusIO_Register(
      i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, LSM6DS_WHOAMI);
  // Serial.print("Read ID 0x"); Serial.println(chip_id.read(), HEX);

  // make sure we're talking to the right chip
  return chip_id.read();
}

I haven't fully understood how the Adafruit_BusIO_Register library works, but it seems like this library doesn't handle the case of changing the I2C address to 0x6B.

Next Steps: I'm not sure if this is adequate for an issue report and if I should dig deeper in that library, but could somebody with knowledge of the Adafruit_BusIO library and with knowledge of how that interacts with other libraries take a look? I think it's just a missed edge case when this library was written.

markwu2001 commented 11 months ago

Update:

I found out that unfortunately, the LSM6DS3TRC's WHOAMI Address is coincidentally the same as its I2C Address. This is at the root of the problem with chipID() I believe.

Screenshot 2023-10-27 at 8 21 37 PM

So the new steps I did to attempt to change the I2C address modified step 3. earlier Now, I just installed the library fresh and changed one line of code:

Adafruit_LSM6DS.h #define LSM6DS_I2CADDR_DEFAULT 0x6B ///< LSM6DS default i2c address

Now I cannot get past lsm6ds3trc.begin_I2C()

boolean Adafruit_LSM6DS::begin_I2C(uint8_t i2c_address, TwoWire *wire,
                                   int32_t sensor_id) {
  delete i2c_dev; // remove old interface
  delay(100);
  Serial.println("1");

  i2c_dev = new Adafruit_I2CDevice(i2c_address, wire);
  delay(500);
  Serial.print("2");

  if (!i2c_dev->begin()) {
    delay(100);
    Serial.print("3");
    return false;
  }
  delay(100);
  Serial.print("4");

  return _init(sensor_id);
}

Results from Console:

Screenshot 2023-10-27 at 8 25 55 PM

I believe i2c_dev->begin() is the new problem now which is out of scope for this issue. I will be closing it because I need to further investigate it.