adafruit / Adafruit_VL53L0X

Arduino library for Adafruit VL53L0X
149 stars 118 forks source link

Library sends errors on esp32s3 #64

Closed ZanzyTHEbar closed 1 year ago

ZanzyTHEbar commented 1 year ago

Thank you for opening an issue on an Adafruit Arduino library repository. To improve the speed of resolution please review the following guidelines and common troubleshooting steps below before creating the issue:

If you're sure this issue is a defect in the code and checked the steps above please fill in the following fields to provide enough troubleshooting information. You may delete the guideline and text above to just leave the following details:

Steps to reproduce:

This library calls begin() on the Twowire object, which is an issue when running the sensors on an I2C multiplexer, as the multiplexer needs to call begin() on the TwoWire object itself. This causes the I/O read timeout error to occur.

caternuson commented 1 year ago

Are you following the general code example as shown here? https://learn.adafruit.com/working-with-multiple-i2c-devices/arduino-3

ZanzyTHEbar commented 1 year ago

Of course. I am a c++ developer, i wrote my own multiplexer class (which work's fine in all other tested scenario's). I narrowed the actual issue down to the fact that this Adafruit lib calls the begin method on the twowire object, when the multiplexer has already done this.

#include "multiplexer.hpp"

I2C_Multiplexer::I2C_Multiplexer(TwoWire* pWire, uint8_t addr)
    : _pWire(pWire), _I2CMultiplexer_addr(addr) {}

I2C_Multiplexer::~I2C_Multiplexer() {}

void I2C_Multiplexer::begin(void) {
  _pWire->begin();
}

uint8_t* I2C_Multiplexer::scan(uint8_t port) {
  static uint8_t dev[127] = {0};
  memset(dev, 0, sizeof(dev));
  uint8_t i = 0;
  selectPort(port);
  byte error, address;
  for (address = 1; address < 127; address++) {
    if (address == _I2CMultiplexer_addr)
      continue;
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      dev[i] = address;
      i++;
    }
  }
  return dev;
}

void I2C_Multiplexer::selectPort(uint8_t port) {
  // To prevent multiple expansion modules from colliding, add a parameter to
  // close all channels
  if (port > 8)
    return;
  Wire.beginTransmission(_I2CMultiplexer_addr);
  Wire.write((1 << port) & 0xFF);
  Wire.endTransmission();
}

void I2C_Multiplexer::write(uint8_t port,
                            uint8_t addr,
                            uint8_t reg,
                            uint8_t* buf,
                            uint8_t len) {
  selectPort(port);
  Wire.beginTransmission(addr);
  Wire.write(reg);
  uint8_t i = 0;
  for (i = 0; i < len; i++) {
    Wire.write(*buf);
    buf++;
  }
  Wire.endTransmission();
}

uint8_t I2C_Multiplexer::read(uint8_t port,
                              uint8_t addr,
                              uint8_t reg,
                              uint8_t* data,
                              uint8_t len) {
  selectPort(port);
  int i = 0;
  Wire.beginTransmission(addr);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(addr, len, false);
  while (Wire.available()) {
    data[i++] = Wire.read();
  }
  return i;
}
caternuson commented 1 year ago

Don't currently have access to multiple VL53L0X's. However, connecting a single VL53L0X though a TCA9548 muxer works with this example sketch on a Feather ESP32 S3:

#include <Adafruit_VL53L0X.h>

#define TCAADDR 0x70

Adafruit_VL53L0X lox = Adafruit_VL53L0X();

// Helper function for changing TCA output channel
void tcaselect(uint8_t channel) {
  if (channel > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << channel);
  Wire.endTransmission();  
}

void setup() {
  Serial.begin(115200);
  while(!Serial);
  Serial.println("ESP32 S3 + VL53L0X + TCA Test");

  // NOTE!!! VERY IMPORTANT!!!
  // Must call this once manually before first call to tcaselect()
  Wire.begin();

  // Before using any BME280, call tcaselect to set the channel.
  tcaselect(0);      // TCA channel for bme1
  lox.begin();       // use the default address
}

void loop() {
  VL53L0X_RangingMeasurementData_t measure;

  Serial.print("Reading a measurement... ");
  tcaselect(0);
  lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!

  if (measure.RangeStatus != 4) {  // phase failures have incorrect data
    Serial.print("Distance (mm): "); Serial.println(measure.RangeMilliMeter);
  } else {
    Serial.println(" out of range ");
  }

  delay(100);
}

Here is the output in the Serial Monitor:

Reading a measurement... Distance (mm): 457
Reading a measurement... Distance (mm): 302
Reading a measurement... Distance (mm): 180
Reading a measurement... Distance (mm): 117
Reading a measurement... Distance (mm): 135
Reading a measurement... Distance (mm): 175
Reading a measurement... Distance (mm): 288
Reading a measurement... Distance (mm): 443

So it seems like it's something other than the call the Wire.begin(). All Adafruit Arduino libraries that use I2C make this call internally.

Try using the above example sketch and expand it to two (or more) VL53L0X's and see what happens.

ZanzyTHEbar commented 1 year ago

Alright, i will do so. The issue is harder to pinpoint than i thought. I figured it was caused by multiple calls to begin() causing a IO timeout issue - i'll try the Adafruit example sketch and then dig a little deeper.

ZanzyTHEbar commented 1 year ago

After some extensive testing, the example code works, until i add another sensor. Then, i get the same error as with my code.

This is the exact line of code that fails for me:

void Tof::begin() {
  if (!psensor->begin(id)) {
    log_e("[TOF Sensor]: Failed to boot VL53L0X:  0x%02X", id);
    log_e("[TOF Sensor]: Pausing execution until reset");
    while (1)
      ;
  }
}

psensor being the lox sensor itself. weirdly, if i leave out the id param - the sensor fails to initialize everytime. Even if there is only one of them.

This is my begin statement.

void EventManager::begin(void) {
  //* initialize multiplexer and i2c bus
  multiplexer.begin();
  log_d("[Event Manager]: Multiplexer initialized");
  log_d("[Event Manager]: Scanning for connected sensors");
  // scan for sensors
  for (uint8_t port = 0; port < 8; port++) {
    Serial.printf("Scanning Port: %d \n", port);
    uint8_t* dev = multiplexer.scan(port);
    while (*dev) {
      Serial.printf("Found Device at i2c addr: 0x%02X \n", *dev);
      //* add sensor to the vector
      _tof_sensors.emplace_back(
          new Tof(new Adafruit_VL53L0X(), WIRE_OBJECT, *dev, 0, 1));
      Serial.println("Adding sensor to vector");
      //* initialize sensor
      multiplexer.selectPort(port);
      _tof_sensors.back()->begin();
      dev++;
    }
    Serial.printf("Size of vector: %d \n", _tof_sensors.size());
    Serial.println();
  }
}

If i comment out _tof_sensors.back()->begin(); the error goes away - but obviously the sensors don't start up. So the issue is absolutely to do with the VL53L0x class' -ican't seem to make more than one of them.

ZanzyTHEbar commented 1 year ago

i have done more debugging - turns out the issue was another library. i removed a USBHID library (in favour of another), and the issue went away. Apologies. multiple sensors work fine now.