2024-08-27 06:16 PM
Background:
My initial choice has been VL53L4CX, based on the datasheet information and my utter lack of experience. However:
Based on those, two questions:
Sample code:
_Noreturn void APP_Main(void) {
printf("\nTOF TEST\n");
// Power DC/DC for initialization.
Power_DCDC_Enable(true);
VL53LX_Error ret;
int32_t ret32;
uint8_t ready;
// bind I2C bus to TOF driver
VL53L4CX_IO_t tof_i2c_io = {
.Address = VL53L4CX_DEVICE_ADDRESS,
.Init = CUSTOM_VL53L4CX_I2C_INIT,
.DeInit = CUSTOM_VL53L4CX_I2C_DEINIT,
.WriteReg = CUSTOM_VL53L4CX_I2C_WRITEREG,
.ReadReg = CUSTOM_VL53L4CX_I2C_READREG,
.GetTick = BSP_GetTick,
};
ret32 = VL53L4CX_RegisterBusIO(&tof, &tof_i2c_io);
if (ret32 != 0) {
printf("TOF: can't bind bus\n");
}
// Wait for the device to finish booting. This is technically optional.
// Ideally we should replace this function with something that sleeps.
ret = VL53LX_WaitDeviceBooted(&tof);
if (ret != 0) {
printf("TOF: WaitDeviceBooted failed: %d\n", ret);
}
// Perform mandatory initialization.
ret = VL53LX_DataInit(&tof);
if (ret != 0) {
printf("TOF: DataInit failed: %d\n", ret);
}
// Configure the distance mode.
ret = VL53LX_SetDistanceMode(&tof, VL53L4CX_PROFILE_LONG);
if (ret != 0) {
printf("TOF: SetDistanceMode failed: %d\n", ret);
}
// Configure the timing budget.
ret = VL53LX_SetMeasurementTimingBudgetMicroSeconds(&tof, 33000);
if (ret != 0) {
printf("TOF: SetMeasurementTimingBudgetMicroSeconds failed: %d\n", ret);
}
// Check the ready flag - should be zero
ret = VL53LX_GetMeasurementDataReady(&tof, &ready);
if (ret != 0) {
printf("TOF: GetMeasurementDataReady failed: %d\n", ret);
} else {
printf("TOF: GetMeasurementDataReady = %d\n", ready);
}
// Set up interval timer.
Power_Init(3);
printf("Entering main loop.\n");
while (true) {
// Wait for the next measurement to be requested.
while (!Power_Interval_Passed()) {
Power_Stop();
}
printf("----------------------------------------\n");
ret = VL53LX_GetMeasurementDataReady(&tof, &ready);
if (ret != 0) {
printf("TOF: GetMeasurementDataReady failed: %d\n", ret);
} else {
printf("TOF: GetMeasurementDataReady = %d\n", ready);
}
printf("TOF: StartMeasurement\n");
ret = VL53LX_StartMeasurement(&tof);
if (ret != 0) {
printf("TOF: StartMeasurement failed: %d\n", ret);
}
ret = VL53LX_GetMeasurementDataReady(&tof, &ready);
if (ret != 0) {
printf("TOF: GetMeasurementDataReady failed: %d\n", ret);
} else {
printf("TOF: GetMeasurementDataReady = %d\n", ready);
}
// This doesn't work and exits immediately.
printf("TOF: WaitMeasurementDataReady\n");
ret = VL53LX_WaitMeasurementDataReady(&tof);
if (ret != 0) {
printf("TOF: WaitMeasurementDataReady failed: %d\n", ret);
};
#if 0
// Add a delay to let the sensor gather enough data.
Power_Stop_Until_Ms(60);
#endif
printf("TOF: StopMeasurement\n");
ret = VL53LX_StopMeasurement(&tof);
if (ret != 0) {
printf("TOF: StopMeasurement failed: %d\n", ret);
}
VL53LX_MultiRangingData_t measurement;
printf("TOF: GetMultiRangingData\n");
ret = VL53LX_GetMultiRangingData(&tof, &measurement);
if (ret != 0) {
printf("TOF: GetMultiRangingData failed: %d\n", ret);
}
printf("TOF: targets found: %d distance: %d\n", measurement.NumberOfObjectsFound, measurement.RangeData[0].RangeMilliMeter);
printf("TOF: Done.\n");
}
}
Result:
TOF TEST
TOF: GetMeasurementDataReady = 0
Entering main loop.
----------------------------------------
TOF: GetMeasurementDataReady = 0
TOF: StartMeasurement
TOF: GetMeasurementDataReady = 1
TOF: WaitMeasurementDataReady
TOF: StopMeasurement
TOF: GetMultiRangingData
TOF: targets found: 0 distance: 8191
TOF: Done.
Note how the device immediately reports itself as ready, even though it's not possible to perform a ranging yet.
However, uncommenting the 60ms delay leads to a successful measurement:
TOF TEST
TOF: GetMeasurementDataReady = 0
Entering main loop.
----------------------------------------
TOF: GetMeasurementDataReady = 0
TOF: StartMeasurement
TOF: GetMeasurementDataReady = 1
TOF: WaitMeasurementDataReady
TOF: StopMeasurement
TOF: GetMultiRangingData
TOF: targets found: 2 distance: 101
TOF: Done.
Solved! Go to Solution.
2024-08-28 10:08 AM
The VL53L1CB works the same way as your VL53L4CX. The use histograms. And your MCU does the work precluding using threshold interrupts.
the VL53L1CX works the same way as the VL53L4CD - No histograms. We call the algo Sigma-Delta although it's not quite the same as the algo you get when you google it. The work is all done on the chip, you get threshold interrupts and the VL53L1CX has plenty of distance. The lens we put on the receive side gathers more light, and you can even cut down your TimingBudget a bit and get the same accuracy as our other sensors.
A really good choice. But that lens is expensive, so you end up paying a bit for the sensor. The L1 are a touch larger, but it's still pin compatible.
2024-08-28 07:34 AM
In order to do a complete range we need to take two sub-ranges. This is to detect - and deal with - aliasing.
Time-of-flight (ToF) aliasing occurs when the time interval between emitted pulses in a ToF measurement system is too short relative to the distance being measured. This can lead to incorrect distance calculations because the reflected pulse from a distant target may not return before the next pulse is emitted.
The solution is to do two ranges with different pulse repetition intervals.
IN the VL53L4CX, in continuous mode, we do one half-range in 33ms return that data to you and do the next, check for aliasing, and return the data to you. All but the first range is checked for aliasing.
But in single shot mode we have to do both ranges before you get a answer, so you don't have any aliasing issues. Hence, 2x the ranging time.
What to do...
The VL53L4CD works the way you want. And is really our lowest power, lowest cost device. But it's limited to 1.3M. We spec the max distance for our parts and unless everything is perfect you can't really achieve that. But the L4CD is different. You can get 1.3 in anything but sunlight.
The L4CD still takes 2 sub-ranges, but when you spec 33ms all the work is done inside the 33ms. And the sensor does all the work. You can also set a threshold to only get an interrupt when something comes close.
If you really need that 2m. Then the way to go is the VL53L0X. That part was our first 940nm sensor and is still our best seller.
Both the L4CD and the L0X are pin compatible with your L4CX. No hardware changes. Just swap the software.
And all the function calls in our code are one-for-one. You swap them fairly quickly.
- john
2024-08-28 09:40 AM - edited 2024-08-28 09:41 AM
Thank you so much - this explains a lot of problems I've been facing. One more question - would VL53L1CX also work the same way? That extra bunch of cm would be very nice. Cost is not a factor.
2024-08-28 10:08 AM
The VL53L1CB works the same way as your VL53L4CX. The use histograms. And your MCU does the work precluding using threshold interrupts.
the VL53L1CX works the same way as the VL53L4CD - No histograms. We call the algo Sigma-Delta although it's not quite the same as the algo you get when you google it. The work is all done on the chip, you get threshold interrupts and the VL53L1CX has plenty of distance. The lens we put on the receive side gathers more light, and you can even cut down your TimingBudget a bit and get the same accuracy as our other sensors.
A really good choice. But that lens is expensive, so you end up paying a bit for the sensor. The L1 are a touch larger, but it's still pin compatible.
2024-09-14 07:07 PM
I'm back here to confirm that VL53L1CX is working wonders in my application. My device can now run for about 7-10 days on a 14mAh battery, sampling once every 10 seconds. One of the few remaining secrets was keeping the TOF powered at all times - the cost of reinitialization was just too high.
Thanks once again for your advice - you've saved me countless hours of trial and error. :)