Skip to main content
joel.vonrotz
Associate II
July 11, 2019
Question

Programm stops at StaticInit Function

  • July 11, 2019
  • 4 replies
  • 3135 views

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

This topic has been closed for replies.

4 replies

John E KVAM
ST Employee
July 11, 2019

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.

John E KVAM
ST Employee
July 11, 2019

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.

joel.vonrotz
Associate II
July 12, 2019

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.

John E KVAM
ST Employee
July 15, 2019
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<>
John E KVAM
ST Employee
July 24, 2019

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.

joel.vonrotz
Associate II
July 26, 2019

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
July 26, 2019

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.