cancel
Showing results for 
Search instead for 
Did you mean: 

VL53L1X Timing Issue

mdmottola
Associate II
Posted on May 07, 2018 at 17:27

I'm developing an applications where an array of VL53L1X sensors would be used. During that development effort it became apparent that there were some timing issues while cycling through the sensors and when I expected them to complete ranging. I reverted back to the 

http://www.st.com/content/st_com/en/products/ecosystems/stm32-open-development-environment/stm32cube-expansion-software/stm32-ode-sense-sw/x-cube-53l1a1.html

's example code while troubleshooting this issue. The P-NUCLEO-53L1A1 (X-NUCLEO-53L1A1 & NUCLEO-F401RE) development boards are being used with only the center sensor in place. The modifications made to the example code are the following:

status = VL53L1_SetDistanceMode(Dev, VL53L1_DISTANCEMODE_SHORT);

status = VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, 20000);

status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, 10);

.

.

.

//             status = VL53L1_GetRangingMeasurementData(Dev, &RangingData);

//             if(status==0){

//                printf('%d,%d,%.2f,%.2f\n', RangingData.RangeStatus,RangingData.RangeMilliMeter,

//                RangingData.SignalRateRtnMegaCps/65536.0,RangingData.AmbientRateRtnMegaCps/65336.0);

//             }

Based on Figure 3. VL53L1X autonomous ranging sequence and timings and section 2.5.2 Timing budget and inter-measurement period (particular the below note) from

http://www.st.com/resource/en/user_manual/dm00474730.pdf

, I would have expected the falling edges from the GPIO1 interrupt line to be spaced by 20ms independent of the object placed in front of it.

Note:    If the inter-measurement period is shorter than the timing budget, once the device

            completes the ranging, the next ranging starts immediately.

Probing the GPIO1

interrupt 

line resulted in the attached plots. When no object was placed in front of the sensor the time was 28ms, and when an object was placed in front of the sensor the time varied between 28ms and 37.1ms. Can anyone offer any explanation for this or point out where my misunderstanding of the documentation/API functions is? Timing is very critical in my application especially when obtaining consistent results from multiple sensors.

Thanks,

Matthew

#interrupt #gpio1 #inter-measurement-period #timing-budget #vl53l1x #vl53l1 #timing
9 REPLIES 9
John E KVAM
ST Employee
Posted on May 07, 2018 at 23:56

The documentation on this point is confusing.

The intermeasurement period is the number of milliseconds between start times. It is not the 'gap' bettween ranges.

Change the InterMeasurementPeriod to be greater or equal to the Timing Budget. Please account for the difference in units.

For instance:

   status = VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, 20000);

   status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, 20); // better would be 22

And there appears to be a bug in the  VL53L1_SetInterMeasurementPeriodMilliSeconds(). It is short by about 10%.

So try it with a 22ms.

With some careful testing, I think you can get a consistent repetition rate.


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.
mdmottola
Associate II
Posted on May 09, 2018 at 23:20

I've changed the parameters using the recommendation you specified.  

status = VL53L1_SetDistanceMode(Dev, VL53L1_DISTANCEMODE_SHORT);

status = VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, 20000);

status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, 23);

.

.

.

//             status = VL53L1_GetRangingMeasurementData(Dev, &RangingData);

//             if(status==0){

//                printf(''%d,%d,%.2f,%.2f\n'', RangingData.RangeStatus,RangingData.RangeMilliMeter,

//                RangingData.SignalRateRtnMegaCps/65536.0,RangingData.AmbientRateRtnMegaCps/65336.0);

//             }

The time between starts and in-turn the time between 

the GPIO1

interrupt 

line falling low indicating ranging data ready is much closer to the expected value, being 21.43ms. 

There is still the issue of this time varying though when an object is placed within the FoV of the sensor. When the object (white paper) is very close to the sensor (roughly less than half an inch away) the time remains around 21.43ms. As soon as the object moves above that distance this time doubles to 42.85ms. The datasheet specifies that a 50 Hz ranging frequency should be attainable with a 20 ms timing budget in short distance mode.

Features

? Fast and accurate long distance ranging

   ? Up to 400 cm distance measurement

   ? Up to 50 Hz ranging frequency

2.5.2 Timing budget (TB)

   The VL53L1X timing budget can be set from 20 ms up to 1000 ms.

   ? 20 ms is the minimum timing budget and can be used only in Short distance mode.

What is causing this 50 Hz ranging frequency to not be obtainable when an object is in front of the sensors FoV?0690X0000060B6sQAE.png0690X0000060B72QAE.png

John E KVAM
ST Employee
Posted on May 11, 2018 at 18:20

Try this - I get repeatable 21.7ms ranges. Sometimes 10ms IF there is no target.

        Status = VL53L1_WaitDeviceBooted(Dev);

        Status += VL53L1_DataInit(Dev);

        Status += VL53L1_StaticInit(Dev);

        Status += VL53L1_SetDistanceMode(Dev,

VL53L1_DISTANCEMODE_SHORT

);

        Status += VL53L1_SetPresetMode(Dev,

VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS

);

        Status += VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev,

20000

);

        Status += VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev,

25

);

       

        Status += VL53L1_StartMeasurement(Dev);

        CHECK_STATUS(Status);

        while (1)

        {

                Status = VL53L1_WaitMeasurementDataReady(Dev);

                

Status = VL53L1_GetRangingMeasurementData(Dev, &RangingData);

                Status = VL53L1_ClearInterruptAndStartMeasurement(Dev);

                CHECK_STATUS(Status);

               

                printf('R:%5d,S:%3d,AR:%7.2f,SR:%7.2f,Sm%7.2f\n',

                               

                                RangingData.RangeMilliMeter,

                                RangingData.RangeStatus,

                                RangingData.AmbientRateRtnMegaCps/65536.0,

                                /* signal rate per SPAD, normalized to 200 SPADs */

                                (RangingData.SignalRateRtnMegaCps/65536.0)/(RangingData.EffectiveSpadRtnCount/256.0)*200.,

                                RangingData.SigmaMilliMeter/65536.0

                          );

        }


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.
mdmottola
Associate II

Posted on May 29, 2018 at 23:04

I've implemented the suggested code within the AutonomousLowPowerRangingTest function of the example code while still using hardware interrupts from the VL53L1X:

static VL53L1_RangingMeasurementData_t RangingData;

static VL53L1_UserRoi_t roiData = {.TopLeftX=0,.TopLeftY=15,.BotRightX=15,.BotRightY=0};

//static VL53L1_UserRoi_t roiData = {.TopLeftX=6,.TopLeftY=9,.BotRightX=9,.BotRightY=6};

printf(''Autonomous Ranging Test\n'');

status = VL53L1_WaitDeviceBooted(Dev);

status += VL53L1_DataInit(Dev);

status += VL53L1_StaticInit(Dev);

status += VL53L1_SetPresetMode(Dev, VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS);

status += VL53L1_SetDistanceMode(Dev, VL53L1_DISTANCEMODE_SHORT);

status += VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, 20000);

status += VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, 25);

status += VL53L1_SetUserROI(Dev, &roiData);

status += VL53L1_StartMeasurement(Dev);

One thing that I did have to change was swapping the order of VL53L1_SetDistanceMode & VL53L1_SetPresetMode function calls. If I performed the SetDistanceMode prior to the SetPresetMode I could get the code/sensor to freeze up as I moved the detection object away from the sensor at around 360mm. Also the sensor was reporting VL53L1_RANGESTATUS_WRAP_TARGET_FAIL ranging errors when objects were close. From the API it mentions the VL53L1_SetDistanceMode function uses VL53L1_DISTANCEMODE_LONG. I haven't looked further into this issue or what was causing the sensor to freeze up. I'm assuming it has to do with using a 20ms timing budget in a distance mode other than short. Can you provide a brief description of what the three defined preset modes do (VL53L1_PRESETMODE_LITE_RANGING, VL53L1_PRESETMODE_AUTONOMOUS, VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS)? I couldn't find any in the documentation.

With the above settings, ~3ms time between measurements was achieved. Three things were observed with the above setup.

  •  
  •  
  •  
  •  
  • ROI affects distance readings
  • Objects entering/exiting the FoV affects the time between measurements
  • ROI affects the minimum inter-measurement period

An object (white paper) was approximately 360mm from the sensor. When the full 16x16 ROI was used the distance being reported was between 357-362mm. When the ROI was changed to a centered (not necessarily optically centered...) 4x4 one the distance being reported was between 327-336mm. I've read through the explanation provided in the following thread:

https://community.st.com/s/feed/0D50X00009XkVt1SAF

I haven't yet performed offset calibration to see if this minimizes the issue.

When an object enters/exits or crosses the sensors FoV the time between measurements varies at that moment. Using the code above with nothing in the sensors FoV (aside from the ceiling of the room...) I moved my hand across the sensors FoV relatively close to the sensor. See Fig1a-c for the variation in time between measurements (2ms, 23ms, and 2ms).

0690X0000060BQoQAM.png

0690X0000060BPzQAM.png

0690X0000060BQ4QAM.png

Fig2 shows the readings obtained during a single instance of me moving my hand across the sensor.

0690X0000060BQ9QAM.png

This instance doesn't correspond to the same instance the scope images were taken; they are just used as an example.

I'm assuming the shorter time could be attributed to when a low signal rate occurs, potentially resulting in ranging error 2. What is the cause of this longer time? Is there a software solution to minimize this from occurring?

In our application objects are moving relatively quick to meet a spec'd throughput hence this being a concern.

The recommended code specified 25 for the inter-measurement period, as mentioned prior this resulted in 3ms between measurements (shorter time caused by bug in VL53L1_SetInterMeasurementPeriodMilliSeconds function as previously explained). Below are the time between measurements when incrementally decreasing the inter-measurement period with the different ROIs mentioned above while using a timing budget of 20ms.

4x4 ROI:

25: 3ms

24: 3ms

23: 3ms; when the object was approximately 73cm (not above or below; very narrow distance range) away from the sensor the time between measurements varies (similar to what was observed above)

22: 4ms; when the object was less than ~73cm away from the sensor the time between measurements doubled (similar to what was observed earlier in this discussion)

16x16 ROI:

25: 3ms

24: 3ms

23: 4ms when the object was less than ~73cm away from the sensor the time between measurements doubled (similar to what was observed earlier in this discussion)

You reported being able to obtain 7ms, while I was only able to obtain 3ms. This is about a 1.5ms difference. Can you offer an explanation for this?

I would like to avoid edge-cases while also achieving the quickest ranging frequency; using 25 for the inter-measurement period with a potential 1.5ms variation (if this variability can be attributed to sensor-to-sensor variation) is close to where timing errors start to be observed with a 16x16 ROI.

John E KVAM
ST Employee
Posted on May 31, 2018 at 18:43

There were a lot of questions in there. I'm not sure I will get them all.

>>>Can you provide a brief description of what the three defined preset modes 

  • VL53L1_PRESETMODE_LITE_RANGING - Does a range A; Provides result;  does a range B; provides Result. Needs the VL53L1_ClearInterruptAndStartMeasurement to continue – 10ms min timing budget in SHORT mode, 16ms with LONG mode. This is best for predictable timing. But the timing here is for only the range A or B, not both.

  • VL53L1_PRESETMODE_AUTONOMOUS, Does a range A, then range B (Needs the VL53L1_ClearInterruptAndStartMeasurement to continue) – 46ms min timing budget

  • VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS – Does range A, then B; No need to read or clear the interrup, will continue to range. 20ms min timing budget. Intermeasurement period should be 5ms longer than the timing budget.

  • For consistent timing and the fastest results use LITE_RANGING mode.

VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS was there to make things easy. But you want fast. So skip the LPA - and use  VL53L1_PRESETMODE_LITE_RANGING and DISTANCE_MODE_SHORT instead.

Then you can shorten your timing budget. You don't need a Inter-measurement period, as you will read the result and start again with:

    status = VL53L1_GetRangingMeasurementData(Dev, &RangingData);

    if(status==0){

     printf('%d,%d,%.2f,%.2f,%d\n', RangingData.RangeStatus,RangingData.RangeMilliMeter,

      RangingData.SignalRateRtnMegaCps/65536.0,RangingData.AmbientRateRtnMegaCps/65336.0,HAL_GetTick());

    }

    status = VL53L1_ClearInterruptAndStartMeasurement(Dev);

The VL53L1_ClearInterruptAndStartMeasurement() will start the next range. Put in the Inter-measurement period if you want the range timing predictable. Otherwise the timing will depend on your response to the interrupt.

Reducing the ROI will reduce the number of Single Photon Avalanche Diodes (SPADs) in play. This will reduce your overall distance. More SPADs = more photons detected = more distance and more accuracy. Only compensation for it is a longer timing budget.


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.

Posted on May 31, 2018 at 23:04

Matthew –

I replied via the web site, but thought I would reply directly.

If you want predictable results, don’t use Autonomous. It makes things easy, but you want fast and reliable.

Go with VL53L1_PRESETMODE_LITE_RANGING.

Full details are on the community Forum.

Let me know if I failed to answer any of your questions.

- 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.
mdmottola
Associate II
Posted on June 04, 2018 at 23:50

It is still unclear to me when the range result registers of the sensor are updated and what causes the GPIO1 interrupt line of the sensor to toggle (for

VL53L1_PRESETMODE_LITE_RANGING

). If you can answer the three questions made bold below I will have a better understanding of the single sensor to continue development of the multi-sensor approach.

I've changed the example code to the following: 

  static VL53L1_RangingMeasurementData_t RangingData;

  //static VL53L1_UserRoi_t roiData = {.TopLeftX=6,.TopLeftY=9,.BotRightX=9,.BotRightY=6};

  static VL53L1_UserRoi_t roiData = {.TopLeftX=0,.TopLeftY=15,.BotRightX=15,.BotRightY=0};

  printf(''Autonomous Ranging Test\n'');

  status = VL53L1_WaitDeviceBooted(Dev);

  status = VL53L1_DataInit(Dev);

  status = VL53L1_StaticInit(Dev);

  //status = VL53L1_SetPresetMode(Dev, VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS);

  status = VL53L1_SetPresetMode(Dev, VL53L1_PRESETMODE_LITE_RANGING);

  status = VL53L1_SetDistanceMode(Dev, VL53L1_DISTANCEMODE_SHORT);

  status = VL53L1_SetMeasurementTimingBudgetMicroSeconds(Dev, 20000);

  status = VL53L1_SetInterMeasurementPeriodMilliSeconds(Dev, 25);

  status = VL53L1_SetUserROI(Dev, &roiData);

  status = VL53L1_StartMeasurement(Dev);

  HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin,GPIO_PIN_SET);

  if(status){

    printf(''VL53L1_StartMeasurement failed \n'');

    while(1);

  }

  if (isInterrupt){

    do // interrupt mode

    {

      __WFI();

      if(IntCount !=0 ){

        HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin,GPIO_PIN_RESET);

        do

        {

        }

        while(HAL_GPIO_ReadPin(B1_GPIO_Port,B1_Pin)==GPIO_PIN_SET);

        IntCount=0;

        status = VL53L1_GetRangingMeasurementData(Dev, &RangingData);

        if(status==0){

        printf(''%d,%d,%.2f,%.2f\n'', RangingData.RangeStatus,RangingData.RangeMilliMeter,

          RangingData.SignalRateRtnMegaCps/65536.0,RangingData.AmbientRateRtnMegaCps/65336.0);

        }else{

          printf(''VL53L1_GetRangingMeasurementData failed \n'');

        }

        status = VL53L1_ClearInterruptAndStartMeasurement(Dev);

        if(status == 0){

          HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin,GPIO_PIN_SET);

        }else{

          printf(''VL53L1_ClearInterruptAndStartMeasurement failed \n'');

        }

      }

    }

    while(1);

  }

  else{

...

I am using the user push button B1 to simulate when I can service the single sensor that has interrupted to get range results. As mentioned prior the long-term goal is to have an array of multiple VL53L1X sensors, so there will be delay.

Below is when the 

VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS preset mode is used and no object crosses the sensors FoV.

0690X0000060L6gQAE.png

As expected the sensor is continuously ranging as you described represented by the 

overlaid green ranging pulse times. I've marked particular instances when the VL53L1_GetRangingMeasurementData function is called with green numbers 1-4. Particular instances when the sensor is ranging are marked with green letters A-F.

The sensor's results register is updated with ranges from the labeled A range and obtained from the 1 GetRangingMeasurementData function call. 

My confusion arise with respect to the results returned by the 2 GetRangingMeasurementData function call. I've seen two things mentioned with respect to this:

  • A clear interrupt is mandatory to allow the next ranging data to be updated. [DS12385 - 2.4 Ranging description]

  • To get consistent results, it is mandatory to call this function after getting the ranging

    measurement.

If this function is not called, the next ranging will start and the results will be updated. But,

the data ready status flag will not be updated, and the physical interrupt pin will not be

cleared. [UM2356 - 2.4.6 Clear source of interrupt]

These two statements are contradictory. If the first statement is true I would expect the 2 

GetRangingMeasurementData function call to return ranges from the B ranging. If the second statement is true I would expect the 

GetRangingMeasurementData function call to return ranges from the

 D ranging.

Can you clarify which of the two is actually occurring?

As mentioned prior there is some variability with respect to ranging times due to objects crossing the sensors FoV and associated range result errors being generated as shown below. 

0690X0000060L6hQAE.png

The speculated overlaid green ranging pulse times could be permutated in any order. This issue is minimized when 

VL53L1_PRESETMODE_LITE_RANGING is used due to the fact only one ranging is performed per result.

Below is when the

VL53L1_PRESETMODE_LITE_RANGING

preset mode is used. When running in

VL53L1_PRESETMODE_LITE_RANGING

 the timing budget doesn't corresponding to the time the sensor is ranging. Prior you mentioned an approximate 10% error in the VL53L1_SetInterMeasurementPeriodMilliSeconds when using the

VL53L1_PRESETMODE_LOWPOWER_AUTONOMOUS preset mode.

 Is there a scaling factor for the ranging time when using this preset mode?0690X0000060L6vQAE.png

Similar notation is used as above. In this case an integer number of ranging pulses wouldn't fit between the times that the sensor is being serviced to obtain range results. This is expected based on your provided description; ranging won't begin until the VL53L1_ClearInterruptAndStartMeasurement function is called. What I didn't expect were the short pulses of the sensors GPIO1 interrupt line following this delay and calling the

VL53L1_ClearInterruptAndStartMeasurement

. I would have expected the line to be high for approximately 13ms while ranging is occurring and then remain low while the results are obtained and interrupt is cleared again resulting in a 19.43ms high/low pulse time. 

Can you explain the reason for this short pulse designated near the green '?' below '2' in the image above?

I'm assuming the

GetRangingMeasurementData function call would return ranges from the

 B ranging. I'm unsure what results would be returned by the 3 GetRangingMeasurementData function call since there was no time to perform a proper ranging.

Can you clarify which range results would be reported by the 2 & 3 GetRangingMeasurementData function call?

This pulse would add large overhead when using 'N' number of sensors if calling both the 

VL53L1_GetRangingMeasurementData and 

VL53L1_ClearInterruptAndStartMeasurement twice is required to obtain valid range results.

Understanding these nuisance with a single sensor will help me determine the best approach for selecting a preset mode, timing budget, and development of interrupt handling/scheduling for multiple sensor to optimize synchronicity/consistency for our particular application. 

John E KVAM
ST Employee
Posted on June 05, 2018 at 01:24

Matthew - This is getting too long to follow. Let's start a new thread next time.

The crux of your questions is are from the continuous nature of the chip. It runs until you stop it.

If you don't call

ClearInterruptAndStartMeasurement(), the device will still collect the data. As soon as you make the call, the data (which is already collected) will trigger the interrupt. Unfortunately the data will be a bit stale, having been collected just after the last data you read. So consider tossing out that sample. So to answer  your last question 2 is collected immediately after 1 (before the gap). 3 would be collected after the gap, just after the 'glitch'.

>>> Can you clarify which of the two is actually occurring?

The data is collected, but cannot be reported until you acknowledge the interrupt - so the sensor is stalled at this point.

>>>Can you explain the reason for this short pulse?

Having already collected the data, the sensor is just waiting for you to read the prior result, and it will immediately send you a new one.

>>Can you clarify which range results would be reported by the 2 & 3 GetRangingMeasurementData function call?

Perhaps a better way to say it is the C measurement is done before the gap, and reported just after the gap, then the next measurement takes off.

- 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.
Posted on June 07, 2018 at 22:40

Understood, thank you for the clarification.