2025-04-22 12:20 AM
I'm having an issue with a breakout board housing a VL53L1X sensor where, between the breakout board and MCU, the only connections are power, gnd, sda and scl through a PCA9617ADPJ I2C buffer. I've set it up for continuous ranging at about 200ms timing budget and is usually accurate for my purpose of just detecting if something is within about 1-2 meters. I have my codes set up so if the sensor status returns 255 VL53L1_RANGESTATUS_NONE, the code will attempt to reinitialize the sensor for re-connection. However, sometimes it will randomly enter this state when plugged in normally. While I'm still yet to figure out WHY it enters this state, my big issue is that once it reports VL53L1_RANGESTATUS_NONE and reinitializes, the ranging accuracy is hopelessly screwed up, where hovering a target about 4cm in front of the sensor reports a maxed out distance value of 8043mm, and linearly scales from there as an object gets closer. The absolute worst part about this is that a physical reset of the MCU does absolutely nothing to fix the issue. It will initialize like normal and start polling, but report VL53L1_RANGESTATUS_SIGNAL_FAIL if I'm outside that tiny 4cm distance, and VL53L1_RANGESTATUS_RANGE_VALID when within it. The only fix is physically cutting off supply voltage to the sensor by cutting power to my board, or disconnecting and reconnecting my breakout board. Once one of those two things are done, the issue is gone. I'm sure there's possibly some EMI or interference issue I need to figure out on my end for what's introducing these issues in the first place, but is there some deeper thing I can check for in this sensor to figure out why it gets stuck in this inaccurate state even after reinitializing? While the "simple" fix would be to implement a way on my board to cut power to the sensor, I'm not finding an obvious way in the API to even detect when the sensor is in this erroneous state, let alone recover from it.
2025-04-22 7:13 AM
Your problem is the sensor did a partial reboot. This can happen when noise on the XShut line causes it, but is not held low long enough to do a complete reboot. The only solution is to drop the XShut down for a few milliseconds and then bring it back up.
And put a good-sized pull up on that line.
The other issue is the : PCA9617ADPJ I2C buffer. I hate those things. Not this one in particular - but they all have the same issues. They kind of screw up the I2C signal, and that bus is pretty iffy to start with. But if you need the length or if you MCU is not compatible with the sensors I2C, then you are kind of stuck.
(If you think your I2C bus is stuck, check it with a voltmeter. The I2C clock and data lines should be high when not in use. The I2C "Bus stuck low" is legendary issue. And it's caused by noise on the line.
I'd really consider hooking up controllable power pin to the sensor. And hook up the XShut as well. If you ever get stuck, you have a way to clear the issue.
- john
2025-04-27 11:18 PM - edited 2025-04-29 9:59 AM
Thank you for the reply, definitely gave me some things to look into. Can at least confirm my I2C is high when not in use. I'm on a custom board running a STM32G0 MCU that didn't have many available GPIO pins, but was able to repurpose another one for XSHUT. Didn't think I'd need it as I'd be running the sensor constantly, but I can make it work. That being said, I now have a new issue that I don't know is related, but maybe worth asking here.
Right now, at times, the code gets stuck in the while loop of VL53L1_WaitValueMaskEx while doing VL53L1_WaitMeasurementDataReady in my main loop. First off, I'm wondering if you have any insight on how I can check what values are being passed here to keep it stuck in this loop with STM32CubeIDE?
Secondly, my purpose is constant polling, and the API documentation says to use VL53L1_GetMeasurementDataReady instead of VL53L1_WaitMeasurementDataReady for this. However, neither the API documentation nor the provided code examples use this code, nor show where the arg *pRangingMeasurementData comes from. I was assuming pulling from the GPIO pin of the sensor would work, but I don't have a spare input pin nor was it made clear that this was what it's looking for. I stole and modified a snipped from VL53L1_poll_for_range_completion to be active low which seems to work, but if I ever get a range status 255 VL53L1_RANGESTATUS_NONE (disconnecting the sensor for example), then calling my sensor initialization function no longer works as expected and the ranging status keeps returning VL53L1_RANGESTATUS_NONE. I'm wondering if there's a different process for using this function and/or it's more prone to errors in general? I can share the initialization function if needed but it's seems to work fine upon first startup, can be manually called at any point while the main loop is running, and it used to work to recover from an error when I initially used VL53L1_WaitMeasurementDataReady instead of VL53L1_GetMeasurementDataReady
Edit: This is what works for me with non-blocking polling:
VL53L1_RangingMeasurementData_t RangingData;
VL53L1_Dev_t vl53l1_c;
VL53L1_DEV Dev = &vl53l1_c;
uint8_t data_ready;
// Initialization...
while (1) {
//...
VL53L1_GetMeasurementDataReady( Dev, &data_ready);
VL53L1_GetRangingMeasurementData( Dev, &RangingData );
vl_status = RangingData.RangeStatus;
//...
// VL53L1_ClearInterruptAndStartMeasurement( Dev ); // Can be commented out and still works, not needed?
}
2025-04-28 9:36 AM
if the USB is ever low when not in use you have an issue. Generally this is caused by noise on the line, so shorter cables, better pull-ups, twisted pair maybe, better shielding or ground planes. The internet is full of ideas on how to combat noise on I2C. It's a common problem.
If you are using interrupts, you really do need to call ClearInterruptAndStartMeasurement(0).
and if you start reading the result, you need to call this, or the sensor will stall.
Your last 4 lines above look good to me.
And there are reasons you get a bad status. No target or a target in rapid motion will cause a bad status. A weak signal or a signal so spread out the algo gives you a sigma fail.
And on rare occasions you can get a 255 which simply means the sensor got such odd data that it gave up without a specific reason. Just clear the interrupt and keep going. The next range should work.
But in all these cases, clear the interrupt and strart the next measurement. Even if you aren't using the interrupt line, this is the correct call.
By default, if you say call start, the sensor will range continuously until you say stop. You should not have to call start again. Or initialize again.
there are examples in the API directory Easy way is to do what they do.