Skip to main content
Visitor II
August 12, 2020
Question

Is there a demo for VL53L3CX that help me to understand how to manage different ToFs together? Something similar to the MultiRangingSensor demo for VL53L1X.

  • August 12, 2020
  • 7 replies
  • 1977 views

Hi, my name is Vincenzo.

I am working with the ToF VL53L3CX. Lately I wrote some applications to make 6 sensors work. At first I thought that the applications were working well, but now I realized that if I set too high timing budgets I had a performance problem. Since when I work with only one sensor everything works correctly, I thought the problem was in the way I manage the 6 ToF.

For this reason, I was wondering if there was a project made by you where multiple sensors are managed.

Thank you in advance for your support.

Vincenzo

    This topic has been closed for replies.

    7 replies

    ST Employee
    August 18, 2020

    ​Hi Vincenzo, it is the same principle, you can use the MultiRangingSensor demo for the L1X. Julien

    VNavaAuthor
    Visitor II
    August 26, 2020

    I have to correct my last comment. Unfortunately, the high TB ​​performance issues have not been resolved. They came back as soon as I went from 4 to 6 ToF. Probably for 4 ToF it was not perceptible, I don't know.

    I report below the code I am currently using to control the 6 ToF. The principle should be the same as that of VL53L1X except for the StartMeasurement function I mentioned earlier

    int main(void)

    {

     uint8_t byteData;

     uint16_t wordData;

     uint8_t ToFSensor = 0;

     uint8_t newI2C = 0x52;

     VL53LX_MultiRangingData_t MultiRangingData;

     VL53LX_MultiRangingData_t *pMultiRangingData = &MultiRangingData;

     int no_of_object_found=0,j;

     /* MCU Configuration----------------------------------------------------------*/

     /* Reset of all peripherals, Initializes the Flash interface and the Systick. */

     HAL_Init();

     /* Configure the system clock */

     SystemClock_Config();

     /* Initialize all configured peripherals */

     MX_GPIO_Init();

     MX_USART2_UART_Init();

     MX_I2C1_Init();

     HAL_GPIO_WritePin(X_SHUT_1_GPIO_Port, X_SHUT_1_Pin, GPIO_PIN_RESET);

     HAL_GPIO_WritePin(X_SHUT_2_GPIO_Port, X_SHUT_2_Pin, GPIO_PIN_RESET);

     HAL_GPIO_WritePin(X_SHUT_3_GPIO_Port, X_SHUT_3_Pin, GPIO_PIN_RESET);

     HAL_GPIO_WritePin(X_SHUT_4_GPIO_Port, X_SHUT_4_Pin, GPIO_PIN_RESET);

     HAL_GPIO_WritePin(X_SHUT_3_GPIO_Port, X_SHUT_5_Pin, GPIO_PIN_RESET);

     HAL_GPIO_WritePin(X_SHUT_4_GPIO_Port, X_SHUT_6_Pin, GPIO_PIN_RESET);

     /* Bring the sensors out of the reset stage one by one and set the new I2C address */

      for (ToFSensor=0;ToFSensor<6;ToFSensor++)

      {

      switch(ToFSensor)

      {

      case 0:

      Dev=&dev1;

      break;

      case 1:

      Dev=&dev2;

      break;

      case 2:

      Dev=&dev3;

      break;

      case 3:

      Dev=&dev4;

      break;

      case 4:

      Dev=&dev5;

      break;

      case 5:

      Dev=&dev6;

      break;

      }

      TurnOnSensor(ToFSensor);

      Dev->comms_speed_khz = 400;

      Dev->I2cHandle = &hi2c1;

      Dev->comms_type = 1;

      Dev->I2cDevAddr=0x52;

      HAL_Delay(2);

      newI2C = Dev->I2cDevAddr + (ToFSensor+1)*2;

      status = VL53LX_SetDeviceAddress(Dev, newI2C);

      Dev->I2cDevAddr=newI2C;

      VL53LX_RdByte(Dev, 0x010F, &byteData);

      printf("\n\rVL53LX Model_ID: %02X\n\r", byteData);

      VL53LX_RdByte(Dev, 0x0110, &byteData);

      printf("VL53LX Module_Type: %02X\n\r", byteData);

      VL53LX_RdWord(Dev, 0x010F, &wordData);

      printf("VL53LX: %02X\n\n\r", wordData);

    status = VL53LX_WaitDeviceBooted(Dev);

    status = VL53LX_DataInit(Dev);

    status = VL53LX_SetDistanceMode(Dev, VL53LX_DISTANCEMODE_SHORT);

    status = VL53LX_SetMeasurementTimingBudgetMicroSeconds(Dev, 500000);

    status = VL53LX_StartMeasurement(Dev);

      }

    while(1)

    {

    for (ToFSensor=0;ToFSensor<6;ToFSensor++)

    {

    switch(ToFSensor)

    {

    case 0:

    Dev=&dev1;

    break;

    case 1:

    Dev=&dev2;

    break;

    case 2:

    Dev=&dev3;

    break;

    case 3:

    Dev=&dev4;

    break;

    case 4:

    Dev=&dev5;

    break;

    case 5:

    Dev=&dev6;

    break;

    }

    status = VL53LX_WaitMeasurementDataReady(Dev);

    if(!status)

    {

    status = VL53LX_GetMultiRangingData(Dev, pMultiRangingData);

    if(status == 0)

    {

    no_of_object_found=pMultiRangingData->NumberOfObjectsFound;

    printf("Count=%5d, ", pMultiRangingData->StreamCount);

    printf("#Objs=%1d ", no_of_object_found);

    for(j=0;j<no_of_object_found;j++)

    {

    if(j!=0)printf("\n\r\t\t   ");

    printf("status=%d, D=%5dmm, Signal=%2.2f Mcps, Ambient=%2.2f Mcps",

    pMultiRangingData->RangeData[j].RangeStatus,

    pMultiRangingData->RangeData[j].RangeMilliMeter,

    pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,

    pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);

    }

    }

    status = VL53LX_ClearInterruptAndStartMeasurement(Dev);

    printf ("\n\r");

    }

    }

    printf("_______________________________________________________________________________\n\n\r");

    }

    }

    Can you tell me why these performance problems arise when I use multiple ToFs (let's consider the case of 6 ToF) and high timing budgets (200-500ms)?

    In fact, if I use low timing budget (20ms) these problems do not seem to exist.

    Thanks in advance for your support.

    VNavaAuthor
    Visitor II
    August 24, 2020

    Thanks Julien!

    My doubt is related to the fact that the way of managing the timing of the two ToF types seems different. I hope I can explain my problem well. I have tried two strategies to manage different VL53L3CX ToF (let's consider the case of 6 ToF).

    ------------------FIRST STRATEGY--------------------

    do

    {

    for(ToF=0; ToF<6;ToF++)

    {

    start = HAL_GetTick();

    if(ToF==0)

    {

    printf("____________________________________________________________________________________");

    }

    status = VL53LX_GetMeasurementDataReady(Dev[ToF], &NewDataReady);

    while (NewDataReady == 0)

    {

    status = VL53LX_GetMeasurementDataReady(Dev[ToF], &NewDataReady);

    }

    if((!status)&&(NewDataReady!=0)){

    status = VL53LX_GetMultiRangingData(Dev[ToF], pMultiRangingData);

    no_of_object_found=pMultiRangingData->NumberOfObjectsFound;

    printf("\n\r ToF %d  Count=%5d, ", ToF, pMultiRangingData->StreamCount);

    printf("#Objs=%1d ", no_of_object_found);

    for(j=0;j<no_of_object_found;j++){

    if(j!=0)printf("\n\r\t\t\t   ");

    printf("status=%d, D=%5dmm, Signal=%2.2f Mcps, Ambient=%2.2f Mcps",

    pMultiRangingData->RangeData[j].RangeStatus,

    pMultiRangingData->RangeData[j].RangeMilliMeter,

    pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,

    pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);

    }

    if (status==0){

    status = VL53LX_ClearInterruptAndStartMeasurement(Dev[ToF]);

    }

    }

    }

    }

    while (1);

    -----------------------SECOND STRATEGY------------------------

     for( ; ; )

     {

     for(ToF=0; ToF<6; ToF++)

     {

     status = VL53LX_GetMeasurementDataReady(Dev[ToF], &NewDataReady[ToF]);

     while (NewDataReady[ToF] == 0)

     {

     status = VL53LX_GetMeasurementDataReady(Dev[ToF], &NewDataReady[ToF]);

     }

     if(status !=0)

     {

     while(1)

     {

     printf("\n\rERROR!!!");

     }

     }

     }

     for(ToF=0; ToF<6; ToF++)

     {

     if(NewDataReady[ToF]!=0)

     {

     status = VL53LX_GetMultiRangingData(Dev[ToF], pMultiRangingData);

     if(status !=0)

     {

     while(1)

     {

     printf("\n\rERROR!!!");

     }

     }

     no_of_object_found=pMultiRangingData->NumberOfObjectsFound;

     printf("ToF %d Count=%5d, ",ToF, pMultiRangingData->StreamCount);

     printf("#Objs=%1d ", no_of_object_found);

     for(j=0;j<no_of_object_found;j++)

     {

     if(j!=0)printf("\n\r\t\t\t  ");

     printf("status=%d, D=%5dmm, Signal=%2.2f Mcps, Ambient=%2.2f Mcps",

     pMultiRangingData->RangeData[j].RangeStatus,

     pMultiRangingData->RangeData[j].RangeMilliMeter,

     pMultiRangingData->RangeData[j].SignalRateRtnMegaCps/65536.0,

     pMultiRangingData->RangeData[j].AmbientRateRtnMegaCps/65536.0);

     }

     printf("\n\r");

     }

     }

     for(ToF=0; ToF<6; ToF++)

     {

     status = VL53LX_ClearInterruptAndStartMeasurement(Dev[ToF]);

     if(status !=0)

     {

     while(1)

     {

     printf("\n\rERROR!!!");

     }

     }

     }

     printf("\n\r__________________________________________________________________________________\n\r");

     }

    Both strategies are preceded by reset, set, initialization of the devices and the launch of the StartMeasurement driver function for each of the ToF.

    In the first strategy I would like to execute the flow of instructions: VL53LX_GetMeasurementDataReady (Dev [ToF], & NewDataReady) -> VL53LX_GetMultiRangingData (Dev [ToF], pMultiRangingData) -> VL53LX_ClearInterruptAndStart [ToFeasurement] one ToF at a time

    In the second strategy, on the other hand, I throw every single instruction 6 times before moving on to the next instruction.

    Both of these strategies seem to work well for small timing budgets (8-30 ms), but when setting high timing budgets the ToFs don't work well. I believe this means that I am mishandling the 6 ToFs.

    I could not verify if this also happens for the ToF VL53L1X, but comparing the two User Manuals I realized that while the VL53L3CX provide the information of the i-th measurement while the measurement (i + 1) is carried out, in the case of the VL53L1X the information of the i-th measurement is obtained during the inter-measured.period preceding the measurement (i + 1).

    0693W000003Q7JiQAK.png

    Considering all this, I would like to know if the performance problem, in the case of 6 ToF, is related to different aspects of timing compared to the VL53L1X or if I did not write the code well and I did not respect the ranging flow for the VL53L3CX.

    Thanks again for answering my question

    Vincenzo

    VNavaAuthor
    Visitor II
    August 25, 2020

    Update

    I bought 4 VL53L1Xs to make a short comparison with the L3CXs. I eliminated the X-NUCLEO-53L3A1 to have a setup similar to that of the system with 6 VL53L3CX. I used the MultiSensorRanging demo and modified it to eliminate the X-NUCLEO and control 4 ToF instead of 3. I didn't notice any performance issues unlike the VL53L3CX case. At this point I wonder if I probably made some mistakes when I wrote the code to control the 6 VL53L3CX TOFs or if I have to think of some precautions due to the fact that in the case of the L3CX I have no inter-measured period.

    VNavaAuthor
    Visitor II
    August 26, 2020

    Update

    I rewrote the code for VL53L3CX, as you advised me, based on the code written for VL53L1X. ToF performance problems no longer occur. Thanks Julien!

    However, while in the case of the VL53L1X inside the while(1){} loop I repeat the StartMeasurement() function continuously, in the case of the VL53L3CX I execute this function only once, before entering the while(1){} loop and immediately after the initialization functions. After all, if I remember correctly, within the UM of the VL53L3CX API, the ranging flow requires that the startmeasurement is carried out once and then, after choosing the preferred mode (driver/host polling or interrupt) the getData-ClearInterrupt cycle is repeated continuously.

    Thanks again.

    Vincenzo

    ST Employee
    August 26, 2020

    Hi Vincenzo,

    What do you mean by performances problem when the TB is high ?

    Julien

    VNavaAuthor
    Visitor II
    August 26, 2020

    Thanks Julien.

    I am using a NUCLEO-F401RE to control 6 ToF VL53L3CX.

    Previously I used only one ToF, and for any Timing Budget selected, the ToF recognized the presence of an object (even 2 objects) and gave me the exact distance.

    Then I decided to make several ToF work sequentially(like the demo MultiRangingSensor for VL53L1X), up to 6 ToF. I noticed that by working with 6 ToF, setting high TB, 2 or 3 sensors could not detect objects, and often the detected objects were accompanied by range status different from zero. The curious thing is that always using 6 sensors, but setting low TB (about 20 ms) then those problems that I listed before do not arise, In fact, All 6 ToFs detected the presence of objects with range status = 0.

    I hope what I wrote is understandable.

    Vincenzo

    VNavaAuthor
    Visitor II
    October 13, 2020

    Hi Julien,

    I would like to inform you that my high TB ​​performance issue can be considered solved. The cause was in the connections I had made. The connections were too long for the I2C protocol set in fast mode (400 kHz). Probably, at this speed the parasitic abilities did not have the time to discharge and there were problems for the I2C protocol. I reduced the length of the connections as much as possible and reduced the pull-up resistor value from 3.6k to 1.2k, this value is for fast mode. With this configuration, even if I configure high TBs, all sensors seem to work fine. Thank you.

    I observed that using i2c speed = 100kHz I can also use a pull-up resistor value of 4.7k as in your 2D LIDAR application with vl53l1x. Also in this case, reducing the length of the connections as much as possible. The application works fine.

    Probably if you use flying connections instead of printed connections on the board it is preferable to use I2C speed at 100 kHz.

    Thank you for all!

    Vincenzo

    ST Employee
    October 13, 2020

    ​Hi Vincenzo,

    Thank you for sharing your experiences with the community. Actually if there is no specific reason I would recommend to use the standard 100 Khz I2C instead of the fast mode (400 Khz).

    Julien