Problem reading Vl6180X laser sensor

DigiKey support,
I was told by STMicroelectronics that I could get technical assistance on this site for their VL6180X laser sensor device.

I get good distance measurements using an Arduino sketch but can’t use that platform on my final product. Instead I’m using a pic18f46k22 microcontroller but the measured value of the distance at register 0X62 always reads zero.

The device is configured exactly as shown in the Arduino_VL6180X.cpp file and I can successfully read the VL6180X slave address at register 0x212. All voltages for the sensor are 3.3.

I have used a pic and I2C with other devices and I’m getting all the acknowledgements with the VL6180X.

My code for reading the measurement is:

int readDistance(void)
{
int distance = 0;
I2C_Master_Start();
I2C_Master_Write(0x29 << 1);  // TOF050C I²C address write
I2C_Master_Write(0x18);       // VL6180X_REG_SYSRANGE_START
I2C_Master_Write(0x01);       // start a distance measurement
\__delay_us(100);              // wait for measurement to complete

I2C_Master_RepeatedStart();
I2C_Master_Write(0x29 << 1);  // TOF050C I²C address write
I2C_Master_Write(0x62);       // register to read distance
I2C_Master_RepeatedStart();
I2C_Master_Write((0x29 << 1) | 1); // TOF050C I²C address read
distance  = I2C_Read_Byte(1); // Read the measured distance
I2C_Master_Stop();
return (distance);
}  // end unsigned int readDistance(void)

I must be doing something wrong.

Hello,
Welcome to the DigiKey TechForum. I’m not familiar with this type of setup.

Maybe one of the engineers that monitor the TechForum, can help with this.

Hello @jerdonaldson,

Since you have working Arduino code that you are trying to replicate, it would be a great help if you could share that with us as well. Am I correct in assuming that you are using the Adafruit VL6180 Library? Adafruit_VL6180X.cpp was the closest in name I could find to the “Arduino_VL6180X.cpp” file you mentioned.

Also, can you explain why you are only waiting 100us before attempting to read the range measurement? I may be missing something, but Section 2.7.1 of the VL6180 datasheet suggests it should take on the order of milliseconds for a single range measurement to complete, especially with averaging. I would suggest polling bit 2 of the VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO register as done in the Adafruit library instead of a simple delay.

uint8_t Adafruit_VL6180X::readRange(void) {
  // wait for device to be ready for range measurement
  while (!(read8(VL6180X_REG_RESULT_RANGE_STATUS) & 0x01))
    ;

  // Start a range measurement
  write8(VL6180X_REG_SYSRANGE_START, 0x01);

  // Poll until bit 2 is set
  while (!(read8(VL6180X_REG_RESULT_INTERRUPT_STATUS_GPIO) & 0x04))
    ;

  // read range in mm
  uint8_t range = read8(VL6180X_REG_RESULT_RANGE_VAL);

  // clear interrupt
  write8(VL6180X_REG_SYSTEM_INTERRUPT_CLEAR, 0x07);

  return range;
}

Matt_Mielke,
Thanks for the reply.

In the Arduino sketch I do use the Adafruit_VL6180X.cpp. But in my pic microcontroller program I don’t have a library.

I missed that spec in the data sheet about 3.2 ms between reads. The device I was working with suggested much less. I’ll update my code and try it.

In the long run I have to read nine of these sensors in sequence and then do some code. After that’s complete I will wait enough time to not re-read any sensor before about 30ms.

I’ll let you know the results. It may be a few days.
Jerry

Matt_Mielke,
Finally updated my code to wait 4ms between readings and got some scope shots.

START.jpg are the waveforms for the first three steps that initiate a measurement.
READ.jpg are the waveforms for the last four steps that read the distance.

I placed the time measurement lines on the 9th clock to show the acknowledgements. According to the data sheet this should be enough to get a reading but as you can see I just get zero.

Here’s the code:
int readDistance(void)
{
int distance = 0;
I2C_Master_Start();
I2C_Master_Write(0x29 << 1); // TOF050C I²C address write
I2C_Master_Write(0x18); // VL6180X_REG_SYSRANGE_START
I2C_Master_Write(0x01); // start a distance measurement
I2C_Master_Stop();
__delay_ms(4); // wait for measurement to complete

I2C_Master_Start();
I2C_Master_Write(0x29 << 1); // TOF050C I²C address write
I2C_Master_Write(0x62); // register to read distance
I2C_Master_RepeatedStart();
I2C_Master_Write((0x29 << 1) | 1); // TOF050C I²C address read
distance = I2C_Read_Byte(1); // Read the measured distance
I2C_Master_Stop();
return (distance);
} // end unsigned int readDistance(void)

Jerry Donaldson

(attachments)


Hello @jerdonaldson,

Thanks for the response and the screenshots. Looking again at the datasheet, I see that I missed something in my previous post. From Section 4:

Your code is using 8-bit indexing rather than 16-bit as specified. This can easily be corrected by padding the register addresses as shown.

I2C_Master_Start();
I2C_Master_Write(0x29 << 1); // TOF050C I²C address write
I2C_Master_Write(0x00); // DON'T FORGET ME!
I2C_Master_Write(0x18); // VL6180X_REG_SYSRANGE_START
I2C_Master_Write(0x01); // start a distance measurement
I2C_Master_Stop();

I assume this is why you were able to read the slave address at register 0x0212. You had to use 16-bit indexing to communicate this higher address to the sensor.

I’d also like to point out that 4ms is likely not going to be a long enough delay to allow the ranging to complete. The datasheet shows that the pre-calibration time plus the readout averaging period alone will take 7.5ms (assuming you haven’t changed the default averaging period). On top of this, you have to allow for the range convergence time, which Table 11 indicates may take anywhere from 180us up to nearly 11ms! Figure 20 summarizes this nicely.

I’ll point out again that best practice in this scenario it to utilize the interrupt flags within the sensor to determine when the measurement is complete. This simplest way to do this is by polling the interrupt status register and waiting for the New Sample Ready bit to be set (see the Adafruit code I posted previously). You could also configure the sensor’s GPIO to generate an external interrupt on the PIC, but that requires significantly more effort to get working properly.

Matt_Mielke,
Good stuff.

I have worked with some sensors that had 8 bit register addressing. I’ve just got to read the data sheet more closely.

I added the extra byte for the register addresses and increased the wait time to 20ms. Now I get reasonable distance readings.

I’ll work on using the status register as you suggest.

int readDistance(void)
{
int distance = 0;
I2C_Master_Start();
I2C_Master_Write(0x29 << 1); // TOF050C I²C address write
I2C_Master_Write(0x00); // msb of VL6180X_REG_SYSRANGE_START
I2C_Master_Write(0x18); // lsb of VL6180X_REG_SYSRANGE_START
I2C_Master_Write(0x01); // start a distance measurement
I2C_Master_Stop();
__delay_ms(20); // wait for measurement to complete

I2C_Master_Start();
I2C_Master_Write(0x29 << 1); // TOF050C I²C address write
I2C_Master_Write(0x00); // msb of register byte to read distance
I2C_Master_Write(0x62); // lsb of register byte to read distance
I2C_Master_RepeatedStart();
I2C_Master_Write((0x29 << 1) | 1); // TOF050C I²C address read
distance = I2C_Read_Byte(1); // Read the measured distance
I2C_Master_Stop();
return (distance);
} // end int readDistance(void)

Thanks,
Jerry

Matt_Mielke,
I have run into another problem with a VL6180X laser sensor.

Since you pointed out that the registers have 16 bid addresses I can successfully read distances.

For cross checking I do this with an Arduino and with a pic microcontroller. The problem is the Arduino can measure down to 2cm but the pic only 10cm. I have configured the registers in the pic as they are in the Arduino. The power and I2C voltages are the same. Each has a 1000ms delay between reads.

My project will require the pic and it has to measure distances down to 2cm.

I can’t find anything in the data sheet to explain this.

I have attached the I2C code for the pic and the Arduino sketch.

Hope you can help.
Jerry Donaldson

(attachments)

VL6180Sketch (854 Bytes)
picSnipit (827 Bytes)

Hey @jerdonaldson,

Sure, I’ll look though your code here soon. In the meantime, it might speed things up if you could provide a bit more detail about the behavior you’re experiencing.

How exactly does the data become inaccurate below these ranges? Does it stop changing, drop down to 0, or just become progressively inaccurate? Any chance you could provide some serial output which clearly demonstrates the issue?

Here’s the other video.

ArduinoReadings.mp4

Hey Jerry,

Not seeing the first one?

Also, I don’t seem to have access to the Google Drive video. Can you make it public?

Matt_Mielke,
You had to scan down to the bottom of the email to get to the first video.

Also here is a shared link to google drive that will have the ArduionReadings.mp4 video.
https://drive.google.com/file/d/1ZCWOh1zEl1QVysSJFwwzdpSZBOywCN1j/view?usp=sharing

Jerry

Thanks, I can see the Arduino video now. The emails you send don’t come to me, but rather are posted as replies to the TechFourm thread you created. If you scroll through, I think you’ll see that the first video link didn’t come through for some reason… Could you re-share the link when you get a chance?

I looked at the code you provided and I’m not seeing what might be causing the issue you described. It’s possible something may have gone awry in the sensor initialization. If you attach the PIC code used to initialize the L6180X, I’d be happy to double check it for you.

Matt_Mielke,
Were you able to retrieve my email that got relegated to the spam file because it looked suspicious?

Jerry Donaldson

Hey @jerdonaldson,

Sorry to leave you hanging, but I’m on vacation this week. I’ll be more responsive when I return on Monday.

I’ve already looked through all of your posts, including the flagged ones that were later unflagged. As far as I can tell, nothing other that what is shown on this thread is available to us. So, my current advice remains the same as my previous advice.

  • Please re-share the video link you’d like me to take a look at.
  • I encourage you to provide the PIC code used to initialize the L6180X. A second set of eyes couldn’t hurt…

Matt_Mielke,
Sorry I didn’t know you were on vacation.

I tried to send you my pic initialization code but got this message:

“Your post was flagged as spam: the community feels it is an advertisement, something that is overly promotional in nature instead of being useful or relevant to the topic as expected.”

It just had my routine and a shared link to my picReadings.mp4.

I’ll send another one but I’ll probably need another site to send it to.

Just enjoy your vacation and Thanksgiving and we’ll pick this up next week.

Jerry Donaldson

Hey @jerdonaldson,

Ah, thanks for sharing the auto response you received. One of the Forum admins was able to recover the links you sent. I can now view the picReadings.mp4 video. However, the PIC initialization code has not been made public, so I’m getting an access denied error. If you could make it public, that’d be great.

I just want to make sure, you did verify the sensor’s accuracy at greater distances using a ruler, correct? So when the target (in this case, the box) is exactly 100mm away, you get a reading of 100mm when using both the Arduino and the PIC? There’s no offset with either setup?

Matt,
The Arduino readings are linear from about 70 mm (3 inches) to 200 mm (8 inches) then it returns 255. All the readings are about 20 mm (0.8 inches) long. Below 3 inches the readings still decrease linearly but are long by 40 mm (1.8 inches).

My fixture always returns 28 mm until the target is 128 mm (5 inches) away from the sensor. Then it starts returning linear values from 29 mm (1.4 inches) out to 160 mm (10 inches) then it returns 255.

Same sensor, same target material. The material is flat, gray and I tried to get it as perpendicular to the sensor as I could.

I don’t manipulate the readings from either fixture.

Looking at the Arduino I2C waveforms I did note that they don’t provide any delay after sending the start signal?

Jerry

Hey @jerdonaldson,

Sound to me like neither setup is working as it should be. Sure the PIC is behaving worse, but the Arduino readings are still way farther off then they should be. What happens if you run Adafruit’s example code without modification? Do you still get ranging errors around 20-40mm?

Matt,
I did run an unmodified Arduino sketch to get those numbers. I could live with adding an offset as long as they are linear.

Did you find any problems with my configuration code?
Jerry