cancel
Showing results for 
Search instead for 
Did you mean: 

Adding multiple vl53l0x sensors

ADP1114
Associate II

Hi all

I have successfully implemented a single vl53l0x sensor, but wish to add more. I found the "AN4846 Application note Using multiple VL53L0X in a single design" documentation:

https://www.st.com/content/ccc/resource/technical/document/application_note/group0/0e/0a/96/1b/82/19/4f/c2/DM00280486/files/DM00280486.pdf/jcr:content/translations/en.DM00280486.pdf

Under "VL53L0X API management" it specifies:

In vl53L0x_platform.h API file set VL53L0x_SINGLE_DEVICE_DRIVER macro to 0 so that API implementation will be automatically adapted to a multi-device context.

But I cannot find anything called "VL53L0x_SINGLE_DEVICE_DRIVER" in the vl53L0x_platform.h file.

Where can I find it? Or has the files updated without the documentation being updated? If so should this step just be skipped?

1 ACCEPTED SOLUTION

Accepted Solutions
John E KVAM
ST Employee

​If you have one working, you are all set. There is a bit of a trick to it though.

Start with all sensors in shutdown.

Then bring up the first one by raising the shutdown pin. The sensor will come up to the default address.

Issue the command to change address.  - SetI2CAddress

Then bring up the second sensor.

Issue the command to change address. 

Repeat until all sensors have different addresses. - I use 0x62, 0x64, 0x66, 0x68, 0x6A...

Technically you don't have to change the address of the last one, but if you do you can use the default address as a health check. If you ever ping it and get an answer, one or more of your sensors has reset.

Then the trick is to insure you have the correct address set when making calls.

The psudo-code would look like this (it's for an L1X chip, but yours is similar:

void ResetAndInitializeAllSensors(void)
{
	VL53L1X_ERROR status;
 
	uint8_t i, Sensor, temp;
	int16_t Offset;
 
	ResetAllSensors();
	HAL_Delay(10);
	for (i = 0; i < NumOfTOFSensors; i++)
	{
		Dev[i] = 0x52;
		TurnOnSensor(i);
		HAL_Delay(5);
		do {
			status = VL53L1X_BootState(Dev[i], &temp);
			HAL_Delay(5);
			if (status) {
				UART_Print("BootState returned bad status\n");
			}
 
		} while (temp != 3);
 
 
		status += VL53L1X_SensorInit(Dev[i]);	/* Initialize sensor  */
		status += VL53L1X_SetI2CAddress(Dev[i], DevAddr[i]);	/* Change i2c address Left is now 0x62 and Dev1 */
 
		CHECK_ERROR(status);
 
		Dev[i] = DevAddr[i];
		//status += VL53L1X_SensorInit(Dev[i]);	/* Initialize sensor  */
	}
	UART_Print("All Chips booted\n");


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

View solution in original post

20 REPLIES 20
John E KVAM
ST Employee

​If you have one working, you are all set. There is a bit of a trick to it though.

Start with all sensors in shutdown.

Then bring up the first one by raising the shutdown pin. The sensor will come up to the default address.

Issue the command to change address.  - SetI2CAddress

Then bring up the second sensor.

Issue the command to change address. 

Repeat until all sensors have different addresses. - I use 0x62, 0x64, 0x66, 0x68, 0x6A...

Technically you don't have to change the address of the last one, but if you do you can use the default address as a health check. If you ever ping it and get an answer, one or more of your sensors has reset.

Then the trick is to insure you have the correct address set when making calls.

The psudo-code would look like this (it's for an L1X chip, but yours is similar:

void ResetAndInitializeAllSensors(void)
{
	VL53L1X_ERROR status;
 
	uint8_t i, Sensor, temp;
	int16_t Offset;
 
	ResetAllSensors();
	HAL_Delay(10);
	for (i = 0; i < NumOfTOFSensors; i++)
	{
		Dev[i] = 0x52;
		TurnOnSensor(i);
		HAL_Delay(5);
		do {
			status = VL53L1X_BootState(Dev[i], &temp);
			HAL_Delay(5);
			if (status) {
				UART_Print("BootState returned bad status\n");
			}
 
		} while (temp != 3);
 
 
		status += VL53L1X_SensorInit(Dev[i]);	/* Initialize sensor  */
		status += VL53L1X_SetI2CAddress(Dev[i], DevAddr[i]);	/* Change i2c address Left is now 0x62 and Dev1 */
 
		CHECK_ERROR(status);
 
		Dev[i] = DevAddr[i];
		//status += VL53L1X_SensorInit(Dev[i]);	/* Initialize sensor  */
	}
	UART_Print("All Chips booted\n");


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

Ah, thank you so much, does that mean the gpio pin isn't needed when working with multiple sensors?

I can successfully change the address of a single device and obtain the range data. But as soon as I want to add a second device I don't get any feedback from the second device. For now I just want to get the concept to work, so I apologize, my code isn't as neat. Could my problem be the way I am defining the device?

Here is my code:

vl53Dev[0].Id=1;

   vl53Dev[0].I2cHandle=&hi2c1;

   vl53Dev[0].DevLetter='a';

   vl53Dev[0].I2cDevAddr=0x52;

   vl53Dev[1].Id=2;

   vl53Dev[1].I2cHandle=&hi2c1;

   vl53Dev[1].DevLetter='b';

   vl53Dev[1].I2cDevAddr=0x52;

   //Sensor 1

   HAL_GPIO_WritePin(XShut1_GPIO_Port,XShut1_Pin,1);

   VL53L0X_DataInit(&vl53Dev[0]);

   HAL_Delay(10);

   VL53L0X_SetDeviceAddress(&vl53Dev[0],0x62);

   HAL_Delay(10);

   vl53Dev[0].I2cDevAddr=0x62;

   //Sensor 2

   HAL_GPIO_WritePin(XShut2_GPIO_Port,XShut2_Pin,1);

   VL53L0X_DataInit(&vl53Dev[1]);   

   HAL_Delay(10);

   VL53L0X_SetDeviceAddress(&vl53Dev[1],0x64);

   HAL_Delay(10);

   vl53Dev[1].I2cDevAddr=0x64;

Edit: I changed my code to look a bit better and more understandable

John E KVAM
ST Employee

Try this - you said you got the initial sensor working. So change the HAL_GPIO_WritePin(XShut1_GPIO_Port,XShut1_Pin,1); to XShut2 and hit the other shutdown pin.

This will prove that both sensors are working and you don't have a hardware issue somewhere.

Once we know both are working - then we have to figure out what is going on.

There is a point of vulnerability just after having changing the I2C address - if you do it wrong, you lose the communication.

But your code looks fine to me.

Is vl53dev[0] identical to vl53dev[1] when you start out? I'm reasonably certain nothing in that structure matters except the address, but make them identical anyway.

Generally I like to use a "Status += " in front of all my function calls. You don't have to continue checking it, but during debug it's handy to look at. if it is ever non-zero, you know something went wrong.

Try changing the address PRIOR to doing the DataInit(). That might tell you something.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

I switched the XShut pins and the other sensor works just fine.

The only difference between vl53dev[0] and vl53dev[1] was the Id and DevLetter (I declared it because it was declared in the example code).

I made them identical and it didn't change anything. I switched the DataInit() and HAL_GPIO_WritePin(), but unfortunately it didn't change anything either. :(

I should probably mention, the way I am testing whether there is a reading is through the HAL_I2C_IsDeviceReady() function. I tried to remove the test just to see what output the second address would give me. It gives the exact same reading as the other device, even though my hand is only covering one device. I iterate the readings in the while(1) loop and display it on an lcd. The LCD also uses I2C, so I don't know whether that would have an influence? The LCD address is 0x4E.

The code in the while loop before removing the test is:

if(HAL_I2C_IsDeviceReady(&hi2c1,0x52,2,10)==HAL_OK)

         {

            lcd_send_cmd(0x01); //clear lcd

            HAL_Delay(1000);

            lcd_send_string("Reading at 52");

            HAL_Delay(1000);

         }

      if(HAL_I2C_IsDeviceReady(&hi2c1,0x62,2,10)==HAL_OK)

      {

         VL53L0X_PerformSingleRangingMeasurement(&vl53Dev[0],&DistanceData);

         lcd_send_cmd(0x01);

         HAL_Delay(100);

         lcd_send_string("Ready");

         HAL_Delay(1000);

         RangeInmm=DistanceData.RangeMilliMeter;

         sprintf(reading,"%d",RangeInmm);

         lcd_send_string("-->62Range: ");

         lcd_send_string(reading);

         lcd_send_string(" ");

         HAL_Delay(1000);

      }

      else

      {

         lcd_send_string("No reading 62");

         HAL_Delay(1000);

         lcd_send_cmd(0x01);

         HAL_Delay(1000);

      }

      if(HAL_I2C_IsDeviceReady(&hi2c1,0x64,2,10)==HAL_OK)

         {

            VL53L0X_PerformSingleRangingMeasurement(&vl53Dev[1],&DistanceData);

            lcd_send_cmd(0x01);

            HAL_Delay(100);

            lcd_send_string("Ready");

            HAL_Delay(1000);

            RangeInmm=DistanceData.RangeMilliMeter;

            sprintf(reading,"%d",RangeInmm);

            lcd_send_string("-->64Range: ");

            lcd_send_string(reading);

            HAL_Delay(1000);

         }

         else

      {

         lcd_send_string("No reading 64");

         HAL_Delay(1000);

         lcd_send_cmd(0x01);

         HAL_Delay(1000);

      }

John E KVAM
ST Employee

if you have one sensor working you don't need a HAL_I2C_IsDeviceReady(). Skip that step and just assume the I2C is ready. I have no idea what that does - it's an STM32 function, and the Sensor does not know about it.

Decide if the sensor is working by telling it to start and seeing if it ranges.

The extra ping makes no sense.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.

Okay, I removed it, but the sensors give the same reading (exact digits) even though I am holding an object at different distances.

The second sensor doesn't cause a change in value, but the first sensor does..

John E KVAM
ST Employee

Make VERY sure BOTH parts were in reset before you started!!

If both sensors receive the change address command, you will get this type of behavior.

When you make a call try using getting the Status on all your calls. i.e. Status+= VL53L0X_PerformSingleRangingMeasurement().

I'm guessing because you use the same structure for both, when the second fails your structure remains unchanged.

Or you can zero the structure between calls.

When you get the &DistanceData structure back from the PerformSingleRangingMeasurement() function, look at the .RangingStatus. It could be the range fails for some reason. If you get a non-zero RangeStatus it will give you an idea of what went wrong.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question. It helps the next guy.