Skip to main content
Senior III
December 9, 2024
Solved

How manage errors while Init VL53L1X

  • December 9, 2024
  • 3 replies
  • 1457 views

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);
	}
}

 

Best answer by John E KVAM

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

3 replies

John E KVAM
ST Employee
December 9, 2024

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

nico23Author
Senior III
December 10, 2024

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.

John E KVAM
ST Employee
December 10, 2024

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. 

nico23Author
Senior III
December 17, 2024

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.

20241217_153805.jpgThe CLK and DATA line just before the crash.

 

20241217_152741.jpg

 

20241217_152751.jpgBoth 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

John E KVAM
John E KVAMBest answer
ST Employee
December 17, 2024

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

nico23Author
Senior III
December 17, 2024

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