2025-08-25 7:27 AM
I've been trying to get two Adafruit VL53L4CD's to work without a multiplexer on my Arduino R4 WiFi, and am getting stuck after getting one reading. I'm largely drawing on the code discussed here, and have also changed up the bits that nh1628 discussed at the end of the thread so that it matched. I am not sure why it seemed to work for them, but not in my case:
#include <Arduino.h>
#include <Wire.h>
#include <vl53l4cd_class.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
// Define I2C bus
#define DEV_I2C Wire
// Define Serial Port
#define SerialPort Serial
// Define Built-IN LED
#ifndef LED_BUILTIN
#define LED_BUILTIN 13
#endif
#define ledPin LED_BUILTIN
// set the pins to shut down the sensors so we can assign addresses one by one
#define gpio_pin_1 4
#define xshut_pin_1 5
#define gpio_pin_2 6
#define xshut_pin_2 7
#define GFX_BL DF_GFX_BL
// Addresses for Sensors
uint8_t sensor_1_address = 0x51;
uint8_t sensor_2_address = 0x28;
volatile int interruptCount = 0;
void measure() {
interruptCount = 1;
}
// Report Storage Structure
char report[64];
// Build sensor objects
VL53L4CD sensor1(&DEV_I2C, xshut_pin_1);
VL53L4CD sensor2(&DEV_I2C, xshut_pin_2);
//this holds the measurement
VL53L4CD_Result_t results1;
VL53L4CD_Result_t results2;
void initSensor(VL53L4CD sensorX, uint8_t sensoradd)
{
// Init sensor1
//Set sensor address.
sensorX.VL53L4CD_SetI2CAddress(sensoradd);
// Configure VL53L4CD satellite component.
sensorX.begin();
// Switch off VL53L4CD satellite component.
sensorX.VL53L4CD_Off();
//Initialize VL53L4CD satellite component.
sensorX.InitSensor();
// Program the highest possible TimingBudget, without enabling the
// low power mode. This should give the best accuracy
sensorX.VL53L4CD_SetRangeTiming(200, 0);
sensorX.VL53L4CD_SetOffset(-10);
// Start Measurements
sensorX.VL53L4CD_StartRanging();
}
//getSensor1Reading
void getSensor1Reading(uint8_t status, uint8_t NewDataReady)
{
sensor1.VL53L4CD_On();
Serial.println("Sensor 1 is on");
if ((!status) && (NewDataReady != 0)) {
// (Mandatory) Clear HW interrupt to restart measurements
sensor1.VL53L4CD_ClearInterrupt();
// Read measured distance. RangeStatus = 0 means valid data
sensor1.VL53L4CD_GetResult(&results1);
snprintf(report, sizeof(report), "Sensor 2: Status = %3u, Distance = %5u mm",
results1.range_status,
results1.distance_mm);
Serial.println(report);
}
sensor1.VL53L4CD_Off();
Serial.println("sensor 1 is off");
}
//getSensor2Reading
void getSensor2Reading(uint8_t status, uint8_t NewDataReady)
{
sensor2.VL53L4CD_On();
Serial.println("Sensor 2 is on");
if ((!status) && (NewDataReady != 0)) {
// (Mandatory) Clear HW interrupt to restart measurements
sensor2.VL53L4CD_ClearInterrupt();
// Read measured distance. RangeStatus = 0 means valid data
sensor2.VL53L4CD_GetResult(&results2);
snprintf(report, sizeof(report), "Sensor 2: Status = %3u, Distance = %5u mm",
results2.range_status,
results2.distance_mm);
Serial.println(report);
}
sensor2.VL53L4CD_Off();
Serial.println("sensor 2 is off");
}
void setup() {
uint8_t status;
// Start the I2C Port and set its clock to 100kHz as the TOF sensors can't handle the faster clock speed of Arduino UNO R4
Wire.begin();
Wire.setClock(100000);
// Initialize the pinMode for the pins
pinMode(ledPin, OUTPUT);
pinMode(gpio_pin_1, INPUT_PULLUP);
pinMode(gpio_pin_2, INPUT_PULLUP);
attachInterrupt(gpio_pin_1, measure, FALLING);
attachInterrupt(gpio_pin_2, measure, FALLING);
// Initialize Serial Bus to write to console.
SerialPort.begin(115200);
// Wait until serial is booted up to continue.
while (!Serial) {delay(20);}
// Start the I2C bus
SerialPort.println("Starting Serial I2C Bus");
DEV_I2C.begin();
delay(100);
SerialPort.println("Initializating Sensors");
initSensor(sensor1, sensor_1_address);
initSensor(sensor2, sensor_2_address);
SerialPort.println("Completed initialization of sensors");
}
void loop() {
Serial.println("top of loop");
// put your main code here, to run repeatedly:
digitalWrite(ledPin, HIGH);
uint8_t NewDataReady1 = 0;
uint8_t NewDataReady2 = 0;
uint8_t status1;
uint8_t status2;
do {
Serial.println("check whether ready");
status1 = sensor1.VL53L4CD_CheckForDataReady(&NewDataReady1);
status2 = sensor2.VL53L4CD_CheckForDataReady(&NewDataReady2);
} while (!NewDataReady1 || !NewDataReady2);
getSensor1Reading(status1, NewDataReady1);
getSensor2Reading(status2, NewDataReady2);
digitalWrite(ledPin, LOW);
delay(100);
Serial.println("bottom of loop");
}
I did some more snooping around and found that the units simply aren't having their I2C addresses changed, so I tried to manually change just a single unit (and leave the second off for the time being):
DEV_I2C.begin();
digitalWrite(xshut_pin_1, LOW);
digitalWrite(xshut_pin_2, LOW);
digitalWrite(xshut_pin_1, HIGH);
sensor1.VL53L4CD_SetI2CAddress(sensor_1_address);
sensor1.begin();
sensor1.VL53L4CD_Off();
sensor1.InitSensor();
sensor1.VL53L4CD_SetRangeTiming(200, 0);
sensor1.VL53L4CD_StartRanging();
And the sensor is just returning the default I2C address that the unit comes with (0x29).
What gives here? Am I doing something wrong? I tested this with an R3 Uno, and got the same results.
Wire diagram for reference:
2025-08-25 8:54 AM
Once you've changed the address of the sensor, don't turn it off. It will revert to the default address.
To accomplish what you want ...
Put both sensors in reset by dropping the Xshut line - or the power I suppose.
Then bring the first one out of reset.
Change the address - and perhaps do the init.
Then bring the second one out of reset.
And change its address and do the init.
If this second sensor is the last one, you could just run without the address change, but I generally change the address of all the devices.
If either of the devices reboot - due to a power glitch or something - they will revert to the default address.
But the import bit is that if you drop the XShut or power them down, they will revert to the 0x29 default address.
- john
2025-08-25 9:14 AM
// Start the I2C bus
SerialPort.println("Starting Serial I2C Bus");
DEV_I2C.begin();
// Put both sensors in reset by dropping the xshut lines
digitalWrite(xshut_pin_1, LOW);
digitalWrite(xshut_pin_2, LOW);
// Bring the first one out of reset
digitalWrite(xshut_pin_1, HIGH);
// Change the address
sensor1.VL53L4CD_SetI2CAddress(0x54);
// If I don't init the software hangs, if I do, the first device is still at 0x29
sensor1.begin();
sensor1.InitSensor();
sensor1.VL53L4CD_SetRangeTiming(200, 0);
sensor1.VL53L4CD_StartRanging();
Hi John, thanks for the response. I'm still getting the same result even when I hard code the I2CAddress here—my I2C monitor is returning 0x29 as the address.