Due not working with three VL53L0X ToF sensors (i2c devices)

Hi, I am trying to use three Pololu VL53L0X Time of Flight sensors with an Arduino Due. The code I am using worked with my old Due, but not on my replacement (A000062). When I plug in two sensors it works fine, but as soon as I plug in the third on the SDA/SCL pins it does not work. Again, this exact code worked on my previous Due. I have tried SDA1/SCL1 with the same results.

Is there anything I can do to get this working?

To clarify... All three sensors have been tested individually and they all produce the expected measurements. I also checked each one with i2c_scanner. I can run 2 of them at the same time without issue. The problem occurs when I add a third device to the i2c bus. When the third is added, the serial monitor returns "Failed to boot LOX1 VL53L0X", suggesting that none of the sensors initalize once the third device is added.

Thanks in advance!

Code below.

#include <Adafruit_VL53L0X.h>

#define LOX1 0x30
#define LOX2 0x31
#define LOX3 0x32

// Shutdown pins for VL53L0X (XSHUT)
#define XS_LOX1 30
#define XS_LOX2 31
#define XS_LOX3 32

// Objects for the ToF sensor
Adafruit_VL53L0X lox1 = Adafruit_VL53L0X();
Adafruit_VL53L0X lox2 = Adafruit_VL53L0X();
Adafruit_VL53L0X lox3 = Adafruit_VL53L0X();

// Measurement variables
VL53L0X_RangingMeasurementData_t measure1;
VL53L0X_RangingMeasurementData_t measure2;
VL53L0X_RangingMeasurementData_t measure3;

double sensor1, sensor2, sensor3;

// Process to assign new I2C addresses
void setID() {
  // RESET procedure
  digitalWrite(XS_LOX1, LOW);
  digitalWrite(XS_LOX2, LOW);
  digitalWrite(XS_LOX3, LOW);
  delay(10);
  digitalWrite(XS_LOX1, HIGH);
  digitalWrite(XS_LOX2, HIGH);
  digitalWrite(XS_LOX3, HIGH);

  // Activate L0X1 and reset other sensors
  digitalWrite(XS_LOX1, HIGH);
  digitalWrite(XS_LOX2, LOW);
  digitalWrite(XS_LOX3, LOW);

  // Initialize LOX1
  if (!lox1.begin(LOX1)) {
    Serial.println(F("Failed to boot LOX1 VL53L0X"));
    while (1);
  }

  // Initialize LOX2
  digitalWrite(XS_LOX2, HIGH);
  delay(10);

  if (!lox2.begin(LOX2)) {
    Serial.println(F("Failed to boot LOX2 VL53L0X"));
    while (1);
  }
  // Initialize LOX3
  digitalWrite(XS_LOX3, HIGH);
  delay(10);

  if (!lox3.begin(LOX3)) {
    Serial.println(F("Failed to boot LOX3 VL53L0X"));
    while (1);
  }
}

void readLOX() {
  lox1.rangingTest(&measure1, false); // pass in 'true' to get data print
  lox2.rangingTest(&measure2, false);
  lox3.rangingTest(&measure3, false);

  // Print reading from LOX1
  Serial.print("LOX1: ");
  if (measure1.RangeStatus != 4) {   // if not out of range
    sensor1 = measure1.RangeMilliMeter;
    Serial.print(sensor1);
    Serial.print("mm");
  } else {
    Serial.print("Out of range");
  }

  Serial.print(" ");

  // Print reading from LOX2
  Serial.print("LOX2: ");
  if (measure2.RangeStatus != 4) {   // if not out of range
    sensor2 = measure2.RangeMilliMeter;
    Serial.print(sensor2);
    Serial.print("mm");
  } else {
    Serial.print("Out of range");
  }
  Serial.print(" ");

  Serial.print("LOX3: ");
  if (measure3.RangeStatus != 4) {   // if not out of range
    sensor3 = measure3.RangeMilliMeter;
    Serial.print(sensor3);
    Serial.print("mm");
  } else {
    Serial.print("Out of range");
  }
  Serial.println();
}

void sensorConfig() {
  lox1.configSensor(Adafruit_VL53L0X::VL53L0X_SENSE_DEFAULT);
  lox2.configSensor(Adafruit_VL53L0X::VL53L0X_SENSE_DEFAULT);
  lox3.configSensor(Adafruit_VL53L0X::VL53L0X_SENSE_DEFAULT);

  /* Set desired configurations from the options below:
   *    VL53L0X_SENSE_DEFAULT
        VL53L0X_SENSE_LONG_RANGE
        VL53L0X_SENSE_HIGH_SPEED
        VL53L0X_SENSE_HIGH_ACCURACY
   */
}

void setup() {
  Serial.begin(115200);
  // Wait until serial port opens for native USB devices
  while (!Serial) {
    delay(1);
  }
  pinMode(XS_LOX1, OUTPUT);
  pinMode(XS_LOX2, OUTPUT);
  pinMode(XS_LOX3, OUTPUT);

  Serial.println("Starting...");
  setID();
  sensorConfig();
}

void loop() {
  readLOX();
  delay(100);
}

Manufacturer's page of the VL53L0X : https://www.st.com/en/imaging-and-photonics-solutions/vl53l0x.html with datasheet.

Pololu VL53L0X : https://www.pololu.com/product/2490

Adafruit VL53L0X library : https://github.com/adafruit/Adafruit_VL53L0X

The .begin() function calls Wire.begin() to initialize the I2C bus and calls .setAddress() to set the address while that sensor is selected, as in the example vl53l0x_dual.ino

So when all three are connected, then the first one already fails which did not fail with only two sensors :thinking: Can you show a photo of the wiring ? Do you power the modules with 3.3V to VIN ? Have your removed the pullup resistors from the Due board ? Are they 1k5 or 1k ? Perhaps there is a bug in the library that makes it fail with Wire1.

I used the code on my previous Due (blue board) and it worked beautifully just two days ago. I unfortunately lost it and had to borrow a new one from the lab. The 1k5 pullup resistors have not been removed from this board nor can I remove them, unfortunately. The modules are being powered with 3.3V to VIN.

I measured the voltage at the SDA and SCL pins. With 2 sensors, the output is 3.3V at each pin. With 3 sensors, the output is 2.950V at SDA and 0.724V at SCL. The sensors have pullup resistors as well.

Wiring:

Serial monitor with any 2 sensors plugged in:

Serial monitor with 3 sensors plugged in:


Serial monitor from OLD Due with 3 sensors:

Are those wires attached to each other ? Please make them all loose separate wires. The SDA and SCL may not be next to each other in a flat ribbon cable.

3.3V to VIN is good.

The 1k5 says "152", so they are 1k5 and not 1k. That means it is bad, but not terrible.

Can you upload a empty sketch with the I2C bus enabled, and connect and disconnect the sensors and measure the voltages ?

void setup()
{
  Wire.begin();
}

void loop() {}

The voltage of the I2C bus should not drop when a sensor is connected. It should be close to 3.3V.
The 2.950V for SDA is not okay, but the 0.724V for SCL is plain wrong. Check your wiring. Perhaps a wire from 3.3V to VIN is missing or the module is bad.

Breadboards have bad contacts and jumper wires can be broken.
If you exchange the Due, are all the wires the same ?

Sorry I got my measurements incorrect (wired the module wrong when I went to take a photo and check voltage). SDA is 0.198V and SCL is 3.3V with 3 modules plugged in and adafruit vl53l0x sketch uploaded. Ran the sketch again with the same results. Each one works individually and 2 at a time, but not 3. I also tried swapping out one of the modules for another one with the same outcome.

The wire configurations are exactly the same when changing out the Due. I have tried multiple sets of jumpers and breadboards thinking that something might have been broken. It didn't solve the problem, unfortunately.

Voltages when running the empty sketch with I2C bus enabled:
No sensors: SDA=3.273V; SCL=3.273V
Sensor 1 connected: SDA=3.273V; SCL=3.273V
Sensor 2 connected: SDA=3.273V; SCL=3.273V
Sensor 3 connected: SDA=3.273V; SCL=3.273V

Sensor 1 & 2 connected: SDA=3.273V; SCL=3.273V
Sensor 1 & 3 connected: SDA=3.273V; SCL=3.273V
Sensor 2 & 3 connected: SDA=3.273V; SCL=3.273V

All 3 sensors connected: SDA=3.273V; SCL=3.273V

Those 3.27 voltages are perfect.

Are you saying that the Adafruit library shortcuts the SDA to GND ? Perhaps pin 31 or 32 on the Due is shortcut to SDA pin 20 :scream:
Can you select other pins to select the sensors ? Change all the 30,31,32 to other pins.

There are a few more options, it does not have to be a shortcut. Sometimes a sensor gets confused and keeps the SDA low. Do you have a Logic Analyzer ?

Changed the xshut pins from 30, 31, 32 to 10, 11, 12 and 22, 23, 24, but experienced the same results with both. I don't have a logic analyzer and now I regret not getting one when I had the extra cash :sweat_smile:.

I'm very sorry, but I have no clue what it could be and what else to test :cry:

You could remove those 1k5 pullup resistors from the Due board to make the I2C bus comply with the I2C standard.
You could edit the source code of the Adafruit library to stop it at certain places and see when the SDA is low with a multimeter.
You could buy a Logic Analyzer.
The cheap 24MHz 8 channel logic analyzers work, but the USB connector does easily break.
I'm a big fan of the LHT00SU1, it has also a analog channel. Turn off the analog channel to be able to sample up to 24MHz for the digital inputs.
On the computer I use PulseView/sigrok.

Thank you for trying. I am going to try a multiplexer and if that fails then another Due or a different microcontroller altogether. I'm on a tight timeline for this week, but if the problem persists I will pick up a logic analyzer to see what's going on here.

You could buy a Arduino MKR Zero. I has a SAMD21 processor, which is used in a number of Arduino boards. It is more compatible and has no design fault.

I think you have to wait until the Serial Monitor is connected with while(!Serial); but if you do, then you have to use a timeout to make the board run without the Arduino IDE.

To provide an update to others that come across this... I switched to an ESP32 and have had no issues with it. I also looked at the Teensy 4.0/4.1 and other Arduinos, but price:performance wise, the ESP32 made more sense for my use case.

Thanks for the update. The Due is indeed a board with troubles.