2024-12-09 12:48 AM
I'm using the VL53L1X ULD API to drive 4 sensors and, sometimes, the function VL53L1X_SensorInit returns error VL53L1_ERROR_CONTROL_INTERFACE while initializing the third or four sensor (the first two are always initialized correctly).
The sensor boot up correctly and returns correct measurements, tho.
What's the best practice to manage this error? Is it correct to use something like
statusRadar = VL53L1X_SensorInit(dev_address);
while(statusRadar) {
statusRadar = VL53L1X_SensorInit(dev_address);
}
My init function is like
static void VL53L1_init(void) {
uint16_t ToFAddresses[4] = {0x54, 0x56, 0x58, 0x5A};
uint16_t dev_address = 0x52;
uint8_t byteData, sensorState=0;
// Reset the 4 ToF sensors on the expansion board
for (ToFSensor = 0; ToFSensor < NUMERO_RADAR; ToFSensor++) {
statusRadar = XNUCLEO53L1A1_ResetId(ToFSensor, 0);
}
// Bring the sensors out of the reset stage one by one and set the new I2C address
for (ToFSensor = 0; ToFSensor < NUMERO_RADAR; ToFSensor++) {
statusRadar = XNUCLEO53L1A1_ResetId(ToFSensor, 1); // Bring sensor out of reset
while(sensorState==0){
statusRadar = VL53L1X_BootState(dev_address, &sensorState);
HAL_Delay(1);
}
//Device Initialization and setting
statusRadar = VL53L1X_SensorInit(dev_address);
statusRadar = VL53L1X_SetI2CAddress(dev_address, ToFAddresses[ToFSensor]);
statusRadar = VL53L1X_SetDistanceMode(ToFAddresses[ToFSensor], 2); /* 1=short, 2=long */
statusRadar = VL53L1X_SetTimingBudgetInMs(ToFAddresses[ToFSensor], 33); /* in ms possible values [20, 50, 100, 200, 500] */
statusRadar = VL53L1X_SetInterMeasurementInMs(ToFAddresses[ToFSensor], 40); /* in ms, IM must be > = TB */
statusRadar = VL53L1X_StartRanging(ToFAddresses[ToFSensor]);
HAL_Delay(1);
}
}
2024-12-09 08:58 AM
if you get an init failure, you have a hardware issue. Get a scope and look at the I2C line. Do you see square edges - or something that looks like a sine wave? With multiple I2C devices on a line, you are worried about the accumulative capacitance. You are going to have to adjust some pull-ups somewhere. Or shorten your wires.
But you could also be starving the sensors of power. the sensors draw rather a lot of power in short bursts, so you might look there.
The init will not fail if the baud rate is good and the hardware correct.
- john
2024-12-09 11:49 PM
I'll try to see what's happening on the I2C line with a scope but, I noticed that, if I handle those errors with a block code like:
//Device Initialization and setting
statusRadar = VL53L1X_SensorInit(dev_address);
int retry_count = 0;
while (statusRadar && retry_count < MAX_RETRIES) {
retry_count++;
HAL_Delay(retry_count); // Short delay between retries
statusRadar = VL53L1X_SensorInit(dev_address);
}
they all boot correctly and no errors appear at the end of every sensor's boot.
2024-12-10 08:21 AM
An I2C is a very un-reliable bus. Get the sensors running and introduce a bit of electrical noise. If your I2C is so flakey that it doesn't boot every time, you are going to get a failure. And when it fails you will see one of the I2C lines is stuck low. It means either the senor or the host clocked a non-existent bit, and the two are now out of sync.
A bit of shielding, or a cap change should fix it. Maybe a stronger pull-up. There are tons of articles on how to tune an I2C bus.
But on your code, I'd introduce a bit that cycled either the power or the X-shut line before retrying the boot. Then you could guarantee a solid restart mechanism.
2024-12-17 12:27 AM
Thanks for the answer @John E KVAM .
After various tests, we found that some static charges generate electrical noise in some instances. This electrical noise disturbs the I2C and causes it to crash.
The microcontroller is able to put back on a HIGH state both the data and the clock line but it seems that, even after de-initializing and initializing the I2C and sending the 10 pulse on the clock line, the I2C lines won't recover.
Besides improving the connections and isolating them, my question is, is there a way to recover the I2C besides turning off both the I2C and the VL53L1X sensors?
Does toggling the X-shut mean that I need to re-init the sensors with address, timing budget, etc?
2024-12-17 08:22 AM
After analyzing the CLK and DATA line before the crash I've noticed that the STM32F091 I'm using is trying to reset the CLK line sending 9 pulses but the clock won't restart as intended.
The CLK and DATA line just before the crash.
Both lines when the I2C crashed and won't recover
On the board of the VL53L1X, we're using an SBLC6-2SC6 to suppress noise and a PCA9507D to convert the 5V level of the line to the 3V level of the VL53L1X. Pull-up resistors are 2.7kOhm and the GND of the VL53L1X has the two capacitators described in the datasheet 4,7uF and 100nF. We even have put BAV99 diodes on the XSHUT line.
The strange part is why the CLK line won't recover
2024-12-17 08:32 AM
It's your level shifter. Why? Because it's always your level shifter. I hate those things.
Are you sure you need it? You have a STM32F091 - and I think all STM32s can do 3v3 I2C. I could be wrong however; I'm not an expert on STM32s
But have a look. See if you can avoid the level shifter. It will save you some money and I think it will work better.
- john
2024-12-17 08:35 AM
We put the level shifter because the I2C is 3 to 4 meters long and, with a 5V signal on the line, it should, theoretically, be more solid, shouldn't it?
Yeah, the STM32F091 can drive a 3V3 I2C line
I'll look at the level shifter, thanks for the heads-up