Skip to main content
Tvan .13
Associate II
February 18, 2025
Solved

VL53L3 measured distance decreases when object distance increases

  • February 18, 2025
  • 4 replies
  • 1473 views

I use a VL53L3 with the STSW-IMG033 Ultra Low Power API.

I use the settings in the settings mentioned in AN5769 "Using the VL53L3CX under ultralow-power mode" for maximum detection under daylight:

Full ROI
Macro period 200
Signal limit 1500
Sigma limit 60
Valid distance 400mm
Using interrupt mode: generate only an interrupt when these criteria are met

I need reliable detection of a human standing in front of the sensor at max 400mm.

Without any cover, the sensor functions just right.

WIth a cover glass (I used the cover glass shipped with the VL53L3 Nucleo addon) I get strange results.
The reason I used this cover glass for this test is that it is shipped by ST to use with their reference design.

Upto about 200 mm the measurement is quite reliable. 
When the object distance is increased, the measured distance starts to decrease. Becasue of this I get "valid measurement" interrupts upto 1200mm.

With another cover, the measurement can be 400mm at a distance of about 200mm so the total range is decreased a lot.

I tried a lot of parameter variations, but it does not get better.

 

My question:

1. How can I get a more reliable distance measurement of upto 400 mm (and not beyond) ?
2. How is it possible that a TOF sensor produces a decreasing distance measurement while the actual distance increases?
3. How is it possible that another cover glass can reduce the measured distance so much?

Please note that the ULP API does not provide anything like RefSPADS/Xtalk/Offset calibration options.
And as my core processor has 8K words of flash, the full blown API is no option, also not because of current requirements.

 

Best answer by John E KVAM

It’s a classic case of crosstalk.

There are photons hitting your coverglass and bouncing back.

 

For example, let’s say 100K photons do this.

With a close object you get say 20M photons at 285mm.

That 200K at zero averaged with 20M photons at 285 averages to 282. No big issue.

But let move your target farther away.

Because light dissipates as a square of the distance you will now be getting

0.5M photons at 750mm.

And you have to still average in that 200K at 0.

And 500*750/700 = 535. Now you are significantly short. And it gets worse.

Based on your complaint, I think your crosstalk is a lot worse than 200K.

Your solution is to do the crosstalk calibration. It’s in the user manual for your sensor.

 

Or you can make a better coverglass.

Move the sensor closer to the glass. Make the glass thinner. Make it more optically clear.

Or you can place a gasket between the TX side of the sensor and the RX side.

But the best solution is to place an opaque barrier between the two sides.

But start with the crosstalk calibration. See if that fixes you right up.

Note that the VL53L3 has crosstalk issue until about 80cm. After that the crosstalk does not interfere. Beyond 80cm the zero-distance photons are distinguishable from the target. 

But there is a limit to crosstalk correction. Every photon that bounces back from the glass is one that does not hit the target. So having a quality glass is a must. 

  • john

4 replies

John E KVAM
John E KVAMBest answer
ST Employee
February 19, 2025

It’s a classic case of crosstalk.

There are photons hitting your coverglass and bouncing back.

 

For example, let’s say 100K photons do this.

With a close object you get say 20M photons at 285mm.

That 200K at zero averaged with 20M photons at 285 averages to 282. No big issue.

But let move your target farther away.

Because light dissipates as a square of the distance you will now be getting

0.5M photons at 750mm.

And you have to still average in that 200K at 0.

And 500*750/700 = 535. Now you are significantly short. And it gets worse.

Based on your complaint, I think your crosstalk is a lot worse than 200K.

Your solution is to do the crosstalk calibration. It’s in the user manual for your sensor.

 

Or you can make a better coverglass.

Move the sensor closer to the glass. Make the glass thinner. Make it more optically clear.

Or you can place a gasket between the TX side of the sensor and the RX side.

But the best solution is to place an opaque barrier between the two sides.

But start with the crosstalk calibration. See if that fixes you right up.

Note that the VL53L3 has crosstalk issue until about 80cm. After that the crosstalk does not interfere. Beyond 80cm the zero-distance photons are distinguishable from the target. 

But there is a limit to crosstalk correction. Every photon that bounces back from the glass is one that does not hit the target. So having a quality glass is a must. 

  • john
Tvan .13
Tvan .13Author
Associate II
February 23, 2025

Thank you for the extensive reply.

I have some restrictions as mentioned:
- I have to stay with the VL53L3 ULP API as my core has no flash for the full API
- therefore the crosstalk calibration is no option, the ULP API does not support that
- The cover glass used for testing is borrowed from the Nucleo VL53L3 demo so I'd expect high transparency
- The production cover glass is manufactured especially for infrared communication applications.

 

What you write makes sense. Although for me it is still hard to grasp that, when measuring time of flight, these "valid detections" happen when the range is way further than the limit.

Anyway, I designed and 3d printed a cover gasket with 2 holes to fill the gap between the VL53L3 and the cover glass. The hole size does matter so it seems. When I take the exclusion cones from the datasheet, take the 2mm distance between sensor and cover glass and calculate the hole diameter at 2 mm, then the crosstalk still appears to happen. The detection is not cut off at the physical distance limit, but this unwanted effect is less, as expected.

Making the holes smaller makes the crosstalk effects disappear. Positive side effect is that the field of view is narrowed, which is good in my application.

My answer is more elaborate than "thanks, a gasket works" because I struggled a lot to get the detections reliable. And most probably others could benefit.

 

Thank you, a gasket works :)

John E KVAM
ST Employee
February 24, 2025

Even though you have a solution, you mentioned that having a narrower field of view would be better. 

We have a VL53L4CX which is the same chip, but with an 18-degree FoV. Software is the same - once you get past the different ChipID. 

I might also suggest you can do crosstalk testing on a few of your parts as they come off the line. Then switch over to the real software and put those numbers in your entire production run. 

Or you can just take a guess at your crosstalk numbers and use that. If you still have the issue, increase the crosstalk number until your under-ranging just goes away. 

If you do it this way, make sure your glass quality is good and the air gap between sensor and glass is consistent.

- john

Tvan .13
Tvan .13Author
Associate II
February 26, 2025

During a small production series it appear that still something extra is required in order to get the product reliable.

Crosstalk calibration or entering general values that match this setup appears to be necessary.

What I make of your suggestion about guessing numbers is that that would be just a handful of variables. The GUI application also suggests a handful of numbers.

When I look at the full API, the caldata struct is this (used by VL53LX_SetCalibrationData):

typedef struct {

uint32_t struct_version;

VL53LX_CustomerNvmManaged_t customer;

VL53LX_additional_offset_cal_data_t add_off_cal_data;

VL53LX_optical_centre_t optical_centre;

VL53LX_xtalk_histogram_data_t xtalkhisto;

VL53LX_gain_calibration_data_t gain_cal;

VL53LX_cal_peak_rate_map_t cal_peak_rate_map;

VL53LX_per_vcsel_period_offset_cal_data_t per_vcsel_cal_data;

uint32_t algo__xtalk_cpo_HistoMerge_kcps[VL53LX_BIN_REC_SIZE];

} VL53LX_CalibrationData_t;

 

I have been looking quite extensively into this, but this structure is huge.

Which variables and/or VL53L3 registers actually contain the  relevant crosstalk, refSPAD and offset calibration data?

So I know which vaules from the structure to extract in the test setup, and in which registers I write them in my small firmware.

John E KVAM
ST Employee
February 26, 2025

The easiest way to go is to buy the P-Nucleo-53L3A1 evaluation kit and use that to simulate your device. (In the US it's only $56 dollars and ST is a European company, it should be available at your parts distributor.)

Take your coverglass, and using the spacers provided, simulate your air gap. 

Use the GUI to do the crosstalk test and have a look at the results. 

You will end up with a file that looks like this:

[GENERAL_INFO]
RANGING_MODE=Ranging
REF_SPADS_CALIBRATED=True
XTALK_CALIBRATED=True
OFFSET_CALIBRATED=True
[REF_SPADS]
REF_SPADS_CAL_STATUS=0
REF_SPAD_ENABLES=BF EF FF FF 6F 0F
REF_SPAD_ENABLE_COUNT=7
REF_SPAD_LOCATION=1
[OFFSET]
OFFSET_CAL_STATUS=0
INNER_OFFSET=18
OUTER_OFFSET=18
REF_PEAK_SIGNAL_RATE=0
REF_ACTUAL_EFF_SPADS=0
REF_DISTANCE=0
REF_REFLECTANCE=0
COVERGLASS_TRANSMISSION=0
HISTO_GAIN_FACTOR=0.986328
STD_RANGING_GAIN_FACTOR=0.981934
[XTALK]
XTALK_CAL_STATUS=0
XTALK_PLANEOFFSET_KCPS=13.00586
XTALK_XPLANE_GRADIENT_KCPS=0
XTALK_YPLANE_GRADIENT_KCPS=0
XTALK_SHAPE_ZONE_ID=0
XTALK_SHAPE_TIMESTAMP=0
XTALK_SHAPE_FIRST_BIN=0
XTALK_SHAPE_BUFFER_SIZE=12
XTALK_SHAPE_NUMBER_OF_BINS=12
XTALK_SHAPE_PHASE_CAL_RESULT_REF_PHASE=5.208984
XTALK_SHAPE_PHASE_CAL_RESULT_VCSEL_START=6
XTALK_SHAPE_CAL_CONFIG_VCSEL_START=9
XTALK_SHAPE_VCSEL_WIDTH=2.5
XTALK_SHAPE_FASTOSC_FREQUENCY=11.80981
XTALK_SHAPE_ZERO_DISTANCE_PHASE=2.208984
XTALK_SHAPE_BIN_DATA=0 0.378906 0.436523 0.18457 0 0 0 0 0 0 0 0

The XTALK_SHAPE_BIN_DATA is the number of photons received from the coverglass - normalized.)

The XTALK_PLANEOFFSET_KCPS is the scale factor. Increase or decrease as you wish. This is the adjustment. 

The RefSpad cal can be run every bootup. The offset needs to be done on every part for absolute accuracy, but you can skip that as well if you want to. 

But if you can get your eval system to be pretty close to your actual system, you can use the Xtalk numbers you get and use those.

If you are still not satisfied, with the results, then increase the XTALK_PLANEOFFSET_KCPS=13.00586 value and leave the rest alone. 

 

But consider increasing the quality of your coverglass. Read the article:

https://community.st.com/t5/mems-and-sensors/time-of-flight-cover-glass/ta-p/49259

With an OK coverglass you might noticed you are under-ranging, but if the numbers are going down, you have a pretty bad coverglass configuration. You are making the problem kind of hard.

And it really will cut down on how far you can range.

John E KVAM
ST Employee
February 26, 2025

The INNER and OUTER offsets will be the same for the VL53L3. (It's in there for the VL53L1 - which has a lens).

Make them the same. 

Once you have the shape:

XTALK_SHAPE_BIN_DATA=0 0.378906 0.436523 0.18457 0 0 0 0 0 0 0 0

you need only to change the XTALK_PLANEOFFSET_KCPS to increase or decrease the crosstalk.

And note, you can do the crosstalk measurement simply by pointing the sensor straight up - assuming you have a ceiling a couple of meters away or so.

- john

Tvan .13
Tvan .13Author
Associate II
February 27, 2025

I did the calibration using the P-Nucleo-53L3A1 and the GUI.
Also I validated the effects of the calibration and the result is a proper distance measurement. So far so good.

And dug deep in the full API to see where which variables should be written in the VL53L3.

INNER_OFFSET goes to register VL53LX_MM_CONFIG__INNER_OFFSET_MM (address 0x0020-0x0021)
OUTER_OFFSET goes to register VL53LX_MM_CONFIG__OUTER_OFFSET_MM (address 0x00220x0023) 
tested this and the offset of the measurement actually changes accordingly.

I think.XTALK_PLANEOFFSET_KCPS must go to register VL53LX_ALGO__CROSSTALK_COMPENSATION_PLANE_OFFSET_KCPS (address 0x0016-0x0017) 

But in which registers do I write the XTALK_SHAPE_BIN_DATA ?

 

John E KVAM
ST Employee
February 27, 2025

I think you might be working too hard. We have a function that writes the calibration for you. 

VL53LX_Error VL53LX_SetCalibrationData(VL53LX_DEV Dev,
		VL53LX_CalibrationData_t *pCalibrationData)

Just populate what you want in the calibration structure, and call this. 

Otherwise you are going to get wrapped up in what format we use to right floating-point data as integers. 

You don't want to go there. It's too hard. 

Just fill in the structure with what you have and put zeros in for the rest. 

then call the function. 

- john

 

 

Tvan .13
Tvan .13Author
Associate II
February 27, 2025

I actually did check VL53LX_SetCalibrationData

It collects and copies a whole bunch of data.Most variables that are used in VL53LX_SetCalibrationData are not available in the calibration data dump of the GUI. And this is only what I have available.

I followed every function call in this function, even more data arrangements and memcopies.

 

And following all function calls, I do not encounter a function that actually writes the dataset into the VL53L3, but maybe I missed that.

The trouble is mostly

- I can't use the full API on my core, I have only a small amount of program memory
- the calibration parameters produced by the GUI are quite difficult to map to the corresponding registers in the VL53L3

If I know how to map the GUI calibration data, I can just write it to the VL53L3 directly.

Tvan .13
Tvan .13Author
Associate II
March 17, 2025

Please help me out with this.

If a user of the ULP library has the possibility to perform an external coverglass calibration and convert the resulting parameters into a dataset and corresponding registers of the VL53L3, then this would be a a great solution.

This would be helping users like me who have to work with a small and low cost microprocessor, who want to use the VL53L3 as a proximity sensor.

Thanks in advance :)