2019-07-11 06:51 AM
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
2019-07-11 08:04 AM
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.
2019-07-11 09:35 AM
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.
2019-07-11 10:51 PM
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
2 Boards return
1 Board returns
1 Board returns
1 Board returns
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.
2019-07-15 11:08 AM
2019-07-16 12:59 AM
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
2019-07-18 04:17 AM
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
2019-07-24 02:57 PM
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.
2019-07-26 01:59 AM
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).
2019-07-26 07:36 AM
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.