cancel
Showing results for 
Search instead for 
Did you mean: 

VL53L4CX reports "ready" incorrectly; does it support one-shot?

kosmamoczek
Associate II

Background:

  • I'm building a battery-powered device with an extremely tight energy budget (14mAh battery).
  • I take a ranging once every 10 seconds (configurable, can be down to 1s).
  • We need good accuracy indoors in close distances (up to 2m).
  • Outdoors and at larger distances we prefer to have more distance and less precision.
  • For initial testing I set the ranging profile to long and the timing budget to 33ms.

My initial choice has been VL53L4CX, based on the datasheet information and my utter lack of experience. However:

  1. The device doesn't seem to handle GetMeasurementDataReady correctly - it immediately returns true after I execute StartMeasurement. Test code and code output below.
  2. I'm really struggling to lower the power consumption in one-shot mode. It seems that the minimal time needed to acquire a measurement is about 60ms between StartMeasurement and StopMeasurement - really stretching my power budget.
  3. I have since learned that VL53L4CX sends the raw data to the host for processing - this is not ideal for us, since we really want to conserve power, and this is a lot of data to send over I2C and then process on a slow MCU.
  4. I have also learned that there is a "lite" version of the driver - something I might want to take advantage of, in the spirit of keeping things simple and not eating through the tiny battery.

Based on those, two questions:

  1. Is there a way to have good, fast, low-power one-shot measurements on the VL53L4CX? Or is that device just not built for that kind of operation and should be used for continuous high-performance measurements only?
  2. If not, what would be the best replacement for our use case?

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.

 

1 ACCEPTED SOLUTION

Accepted Solutions
John E KVAM
ST Employee

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. 


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

View solution in original post

3 REPLIES 3
John E KVAM
ST Employee

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

 


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.

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.

John E KVAM
ST Employee

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. 


If this or any post solves your issue, please mark them as 'Accept as Solution' It really helps. And if you notice anything wrong do not hesitate to 'Report Inappropriate Content'. Someone will review it.