cancel
Showing results for 
Search instead for 
Did you mean: 

Programm stops at StaticInit Function

joel.vonrotz
Associate II

Hello Community

After a long time of figuring out the api and file structure, I got the I2C communication working. I copied the Single Range Measurement Example from the API-ZIP into my programm. Additionally I ran the I2C-Verification Code, which came out good.

Following is my code:

// ====================================
 
#include "mbed.h"
#include "vl53l0x_api.h"
#include "vl53l0x_platform.h"
 
I2C i2c(p9, p10);
BusOut led(LED1, LED2, LED3, LED4);
Serial pc(USBTX, USBRX, 9600);
VL53L0X_Dev_t vl_device;
 
void i2c_test(void);
int rd_write_verification(uint8_t addr, uint32_t expected_value);
 
void i2c_test(void)
{
  int err_count = 0;
  int expected_value = 0;
 
  uint8_t buff[4] = {0x11, 0x22, 0x33, 0x44};
  uint8_t ChipID[4];
  int i = 0;
 
  for (i = 0; i < 4; i++)
  {
    VL53L0X_RdByte(&vl_device, 0xC0 + i, &ChipID[i]);
  }
  expected_value = ChipID[0] << 24 | ChipID[1] << 16 | ChipID[2] << 8 | ChipID[3];
  if (rd_write_verification(0xc0, expected_value) < 0)
    err_count++; // check the chip ID
 
  VL53L0X_WriteMulti(&vl_device, 0x4, buff, 4); // check WriteMulti
  if (rd_write_verification(0x4, 0x11223344) < 0)
    err_count++;
 
  VL53L0X_WrDWord(&vl_device, 0x4, 0xffeeddcc); // check WrDWord
  if (rd_write_verification(0x4, 0xffeeddcc) < 0)
    err_count++;
 
  VL53L0X_WrWord(&vl_device, 0x4, 0x5566); // check WrWord
  VL53L0X_WrWord(&vl_device, 0x6, 0x7788);
  if (rd_write_verification(0x4, 0x55667788) < 0)
    err_count++;
 
  for (i = 0; i < 4; i++)
  {
    VL53L0X_WrByte(&vl_device, 0x04 + i, buff[i]);
  }
  if (rd_write_verification(0x4, 0x11223344) < 0)
    err_count++;
  if (err_count > 0)
  {
    pc.printf("i2c test failed - please check it\n");
  }
  pc.printf("\n\n\r");
}
int rd_write_verification(uint8_t addr, uint32_t expected_value)
{
  uint8_t bytes[4], mbytes[4];
  uint16_t words[2];
  uint32_t dword;
  VL53L0X_ReadMulti(&vl_device, addr, mbytes, 4);
  for (int i = 0; i < 4; i++)
  {
    VL53L0X_RdByte(&vl_device, addr + i, &bytes[i]);
  }
  for (int i = 0; i < 2; i++)
  {
    VL53L0X_RdWord(&vl_device, addr + i * 2, &words[i]);
  }
  VL53L0X_RdDWord(&vl_device, addr, &dword);
 
  pc.printf("expected   = %8x,\n", expected_value);
  pc.printf("read_multi = %2x, %2x, %2x, %2x\n", mbytes[0], mbytes[1], mbytes[2], mbytes[3]);
  pc.printf("read_bytes = %2x, %2x, %2x, %2x\n", bytes[0], bytes[1], bytes[2], bytes[3]);
  pc.printf("read words = %4x, %4x\n", words[0], words[1]);
  pc.printf("read dword = %8x\n", dword);
 
  if ((mbytes[0] << 24 | mbytes[1] << 16 | mbytes[2] << 8 | mbytes[3]) != expected_value)
    return (-1);
  if ((bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3]) != expected_value)
    return (-1);
  if ((words[0] << 16 | words[1]) != expected_value)
    return (-1);
  if (dword != expected_value)
    return (-1);
  return (0);
}
 
void print_pal_error(VL53L0X_Error Status)
{
  char buf[VL53L0X_MAX_STRING_LENGTH];
  VL53L0X_GetPalErrorString(Status, buf);
  pc.printf("API Status: %i : %s\n", Status, buf);
}
 
void print_range_status(VL53L0X_RangingMeasurementData_t *pRangingMeasurementData)
{
  char buf[VL53L0X_MAX_STRING_LENGTH];
  uint8_t RangeStatus;
 
  /*
     * New Range Status: data is valid when pRangingMeasurementData->RangeStatus = 0
     */
 
  RangeStatus = pRangingMeasurementData->RangeStatus;
 
  VL53L0X_GetRangeStatusString(RangeStatus, buf);
  pc.printf("Range Status: %i : %s\n", RangeStatus, buf);
}
 
VL53L0X_Error rangingTest(VL53L0X_Dev_t *pMyDevice)
{
  VL53L0X_Error Status = VL53L0X_ERROR_NONE;
  VL53L0X_RangingMeasurementData_t RangingMeasurementData;
  int i;
  FixPoint1616_t LimitCheckCurrent;
  uint32_t refSpadCount;
  uint8_t isApertureSpads;
  uint8_t VhvSettings;
  uint8_t PhaseCal;
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    pc.printf("Call of VL53L0X_StaticInit\n");
    Status = VL53L0X_StaticInit(pMyDevice); // Device Initialization
    print_pal_error(Status);
  }
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    pc.printf("Call of VL53L0X_PerformRefCalibration\n");
    Status = VL53L0X_PerformRefCalibration(pMyDevice,
                                           &VhvSettings, &PhaseCal); // Device Initialization
    print_pal_error(Status);
  }
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    pc.printf("Call of VL53L0X_PerformRefSpadManagement\n");
    Status = VL53L0X_PerformRefSpadManagement(pMyDevice,
                                              &refSpadCount, &isApertureSpads); // Device Initialization
    pc.printf("refSpadCount = %d, isApertureSpads = %d\n", refSpadCount, isApertureSpads);
    print_pal_error(Status);
  }
 
  if (Status == VL53L0X_ERROR_NONE)
  {
 
    // no need to do this when we use VL53L0X_PerformSingleRangingMeasurement
    pc.printf("Call of VL53L0X_SetDeviceMode\n");
    Status = VL53L0X_SetDeviceMode(pMyDevice, VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode
    print_pal_error(Status);
  }
 
  // Enable/Disable Sigma and Signal check
  if (Status == VL53L0X_ERROR_NONE)
  {
    Status = VL53L0X_SetLimitCheckEnable(pMyDevice,
                                         VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, 1);
  }
  if (Status == VL53L0X_ERROR_NONE)
  {
    Status = VL53L0X_SetLimitCheckEnable(pMyDevice,
                                         VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, 1);
  }
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    Status = VL53L0X_SetLimitCheckEnable(pMyDevice,
                                         VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 1);
  }
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    Status = VL53L0X_SetLimitCheckValue(pMyDevice,
                                        VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
                                        (FixPoint1616_t)(1.5 * 0.023 * 65536));
  }
 
  /*
     *  Step  4 : Test ranging mode
     */
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    for (i = 0; i < 10; i++)
    {
      pc.printf("Call of VL53L0X_PerformSingleRangingMeasurement\n");
      Status = VL53L0X_PerformSingleRangingMeasurement(pMyDevice,
                                                       &RangingMeasurementData);
 
      print_pal_error(Status);
      print_range_status(&RangingMeasurementData);
 
      VL53L0X_GetLimitCheckCurrent(pMyDevice,
                                   VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, &LimitCheckCurrent);
 
      pc.printf("RANGE IGNORE THRESHOLD: %f\n\n", (float)LimitCheckCurrent / 65536.0);
 
      if (Status != VL53L0X_ERROR_NONE)
        break;
 
      pc.printf("Measured distance: %i\n\n", RangingMeasurementData.RangeMilliMeter);
    }
  }
  return Status;
}
 
int main()
{
  i2c.frequency(100000);
  VL53L0X_Error Status = VL53L0X_ERROR_NONE;
 
  VL53L0X_Version_t vl_version;
  VL53L0X_DeviceInfo_t vl_deviceInfo;
 
  vl_device.i2c_device = &i2c;
  vl_device.i2c_address = 0x29;
 
  pc.printf("VL53L0X API Simple Ranging example\n\n");
  int32_t status_int;
  int32_t init_done = 0;
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    status_int = VL53L0X_GetVersion(&vl_version);
    if (status_int != 0)
      Status = VL53L0X_ERROR_CONTROL_INTERFACE;
  }
 
  /*
     *  Verify the version of the VL53L0X API running in the firmrware
     */
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    if (vl_version.major != 1 ||
        vl_version.minor != 0 ||
        vl_version.build != 2)
    {
      pc.printf("VL53L0X API Version Error: Your firmware has %d.%d.%d (revision %d). This example requires %d.%d.%d.\n",
                vl_version.major, vl_version.minor, vl_version.build, vl_version.revision,
                1, 0, 2);
    }
  }
 
  // End of implementation specific
  if (Status == VL53L0X_ERROR_NONE)
  {
    pc.printf("Call of VL53L0X_DataInit\n");
    Status = VL53L0X_DataInit(&vl_device); // Data initialization
    print_pal_error(Status);
  }
 
  if (Status == VL53L0X_ERROR_NONE)
  {
    Status = VL53L0X_GetDeviceInfo(&vl_device, &vl_deviceInfo);
  }
  if (Status == VL53L0X_ERROR_NONE)
  {
    pc.printf("VL53L0X_GetDeviceInfo:\n");
    pc.printf("Device Name : %s\n", vl_deviceInfo.Name);
    pc.printf("Device Type : %s\n", vl_deviceInfo.Type);
    pc.printf("Device ID : %s\n", vl_deviceInfo.ProductId);
    pc.printf("ProductRevisionMajor : %d\n", vl_deviceInfo.ProductRevisionMajor);
    pc.printf("ProductRevisionMinor : %d\n\n\n\r", vl_deviceInfo.ProductRevisionMinor);
 
    if ((vl_deviceInfo.ProductRevisionMinor != 1) && (vl_deviceInfo.ProductRevisionMinor != 1))
    {
      pc.printf("Error expected cut 1.1 but found cut %d.%d\n",
                vl_deviceInfo.ProductRevisionMajor, vl_deviceInfo.ProductRevisionMinor);
      Status = VL53L0X_ERROR_NOT_SUPPORTED;
    }
  }
  i2c_test();
  if (Status == VL53L0X_ERROR_NONE)
  {
    Status = rangingTest(&vl_device);
  }
}

I added some printfs inside the vl53l0x_api.cpp file to check, where exactly the error happened (see attachment). Also the attached text file shows all the printed text (including I2C Verification info).

I really hope it's fixable.

Sincerely, Joel von Rotz

9 REPLIES 9
John E KVAM
ST Employee

Well done on the I2C verification - that proves you didn't get a wrong value because of a byte-swap issue.

And you did well to debug as far as you did.

There are only 3 places you can get error 50, and they are all in

Status = enable_ref_spads(Dev...)

I've not seen this error, so I have 2 questions:

1) Does it happen on more that one sensor?

2) What happens if you just keep going?

The reason I ask is that the enable_ref_spads() function reads some data in the NVM having to do with the SPADS, and updates it.

It could be something in the NVM is wrong - that would be in the first 2 places.

Or it could be in the last, verification, step. If it's there the chip may run just fine, but the verification check is wrong.

Let me know.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.
John E KVAM
ST Employee

I got a message that seemed to indicate it's a power rail issue.

Several things to do here.

1) Get a scope and look for a voltage drop. Starving the sensor of current is our most common issue.

2) If you can, hook the sensor to a known power supply. (I use the power pin from the P-Nucleo-53L0A1.)

If that works then you have a direction to go.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

Hi John

I hooked the module board (it's a custom made board based on the schematic of the Adafruit VL53L0X Board) and measured the 3.3V Supply. I didn't notice any voltage drops, the max voltage drop seen was roughly 60mV.

Also I looked at the values in the StaticInit-function (in the vl53l0x_api.cpp file).

/* set the ref spad from NVM */
count = (uint32_t)VL53L0X_GETDEVICESPECIFICPARAMETER(Dev, ReferenceSpadCount);
ApertureSpads = VL53L0X_GETDEVICESPECIFICPARAMETER(Dev, ReferenceSpadType);

I have 9 exactly the same modules, but this code snipplets gives different data back:

4 Boards return

  • count = 8
  • Aperture Spads = 0

2 Boards return

  • count = 7
  • Aperture Spads = 0

1 Board returns

  • count = 6
  • Aperture Spads = 0

1 Board returns

  • count = 5
  • Aperture Spads = 0

1 Board returns

  • count = 17
  • Aperture Spads = 0

Should I be somewhat worried?

I can also confirm, that with the Arduino Library from Pololu (updated to the mbed platform), the sensor works without a problem. The hardware seems to work.

Joel – It’s impossible to have 0 aperture SPADs. Somehow the NVM was not programmed correctly. So do this: Take the average number of aperture SPADs from your working sensors. Should be something in single digits. And then add the statement just after the read: If (ApertureSpads ==0) ApertureSpads = whatever your average was. Then do a lot of testing to make sure everything works. The RefSpad calibration is supposed to modify that value in the NVM, but it can’t start at 0. * john [sensor2]VL53L1X – Time of Flight Sensor John KVAM | Tel: (408) 919-8502 | Mobile: (650) 521-2084 STMicroelectronics | 2755 Great America Way, 3rd Floor | Santa Clara, CA 95054 Introduction to Time-of-Flight<> and SensorExpo Time-of-Flight<>

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

Hi John

The pololu library is a reversed engineered library, so I don't have access to these kinds of information or I haven't found a way on how to gain access to said information. But I found out, that the spad init error is happening inside the enable_ref_spads function during the comparison of a spadArray with the checkSpadArray. The first 5 elements are correct, the last one is incorrect.

/* Compare spad maps. If not equal report error. */
while (i < size) 
{
  if (spadArray[i] != checkSpadArray[i])
  {
    status = VL53L0X_ERROR_REF_SPAD_INIT;
    break;
  }
  i++;
}
 i    spadArray   checkSpadArray
[0]   0x7F        0x7F
[1]   0x00        0x00
[2]   0x00        0x00
[3]   0x00        0x00
[4]   0x00        0x00
[5]   0x00        0x0E
[6]   ?           ?

I'm sorry if I waste your time, but I seriously want this to work. I've been working on this thing since last monday, I can't get it to work and I'm starting to have doubts.

- Joel

Hi John

The pololu library is a reversed engineered library, so I don't have access to these kinds of information or I haven't found a way on how to gain access to said information. But I found out, that the spad init error is happening inside the enable_ref_spads function during the comparison of a spadArray with the checkSpadArray. The first 5 elements are correct, the last one is incorrect.

    /* Compare spad maps. If not equal report error. */
    while (i < size) 
    {
      if (spadArray[i] != checkSpadArray[i])
      {
        status = VL53L0X_ERROR_REF_SPAD_INIT;
        break;
      }
      i++;
    }
 i    spadArray   checkSpadArray
[0]   0x7F        0x7F
[1]   0x00        0x00
[2]   0x00        0x00
[3]   0x00        0x00
[4]   0x00        0x00
[5]   0x00        0x0E
[6]   ?           ?

I'm sorry if I waste your time, but I seriously want this to work. I've been working on this thing since last monday, I can't get it to work and I'm starting to have doubts.

- Joel

John E KVAM
ST Employee

it appears the board is trying to read the number of ref-spads and it doesn't get a good answer.

Try calling VL53L0X_set_reference_spads() Prior to trying to init the chip.

But setting the ref spads to something legal - perhaps (3,0) it will force the chip to actually do the refSpad management.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

I somewhat got it to work without the set_reference_spads alternative. I simply removed all the Status comparisons in the example code. I don't know why this works.

Since I've done this there is a little problem now: sometimes the sensor responds with 20mm constantly (for about 5-10 samples).

John E KVAM
ST Employee

Doing the RefSpad Calibration is important - but as you saw, the sensor will re-calibrate after a few samples.

Perhaps a better approach is to run the sensor for a while as you have and do a get_reference_spads(). Then write those to your chip in subsequent reboots.

But as you have seen, it does self-correct. Might not always be as quick as 5-10 samples for all conditions however.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.