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?

30 REPLIES 30

Okay, I now added the VL53L0X_ResetDevice() function before each device's VL53L0X_DataInit(). The reading still doesn't change for the second sensor. Should I reset the device before each reading, or just before the DataInit?

I then added a new struct in order to save sensors in different structs. It also didn't change anything.

I added a new variable to save the distance data in separate variables rather than overwriting one. The second sensor now only gives a reading of 0. So it would seem that the data isn't being updated when VL53L0X_PerformSingleRangingMeasurement() is called.

I checked the range status for sensor 2, it also gives 0.

When I switch the sensors (through the previously done XShut method). The 2nd sensor gives a reading, but the first sensor does not.

I also tried switching the sensors off (by bringing xshut low) when not in use. But that didn't do anything either.

I added the status+= and found a value of 236 when resetting the second sensor. If I remove the reset and just use DataInit() the status = 236. The initialization, reset and address change of the first sensor gave 0 values.

So I have established the device fails to reset. I don't know how to fix this other than physically disconnect and reconnecting the device. It then starts giving its own readings.

FPayn.1
Associate II

I'm planning to use two arrays of three VL53L0X sensors each in a robotics application using a Teensy (Arduino-ish) microcontroller. I have one array of three sensors working already, using the technique described by John. I have a fairly detailed post, with software on my blog site at https://www.fpaynter.com/2020/06/replacing-hc-sro4-ultrasonic-sensors-with-vl53l0x-arrays/

KNawa.1
Associate II

I have similar situation. I want to use 2 sensors, but when they are both online(XSHUT=1) measurement data is wrong and random when I use one sensor data is OK. I add my code maybe I do something wrong...

Config:

#define sensor_qty 2			// max. 2
 
#define original_addr 	0x52
#define sensor1_addr 	0x53
#define sensor2_addr 	0x54

main:

uint8_t Message[64];
uint8_t MessageLen;
 
VL53L0X_RangingMeasurementData_t RangingData[sensor_qty];
VL53L0X_Dev_t  vl53l0x_c[sensor_qty]; 			// center module
 
VL53L0X_DEV    Dev  = &vl53l0x_c[0];
VL53L0X_DEV    Dev1 = &vl53l0x_c[1];
 
//
// VL53L0X initialisation stuff
//
uint32_t refSpadCount;
uint8_t isApertureSpads;
uint8_t VhvSettings;
uint8_t PhaseCal;
 
uint16_t sensorMeasure[sensor_qty];
  Dev->I2cHandle = &hi2c1;
   Dev1->I2cHandle = &hi2c1;
   Dev->I2cDevAddr = Dev1->I2cDevAddr = original_addr;
 
   HAL_GPIO_WritePin(TOF_XSHUT1_GPIO_Port, TOF_XSHUT1_Pin, GPIO_PIN_RESET); 	// Disable XSHUT
   HAL_GPIO_WritePin(TOF_XSHUT2_GPIO_Port, TOF_XSHUT2_Pin, GPIO_PIN_RESET); 	// Disable XSHUT
   HAL_Delay(10);
 
   // addr change 1st sensor
   HAL_GPIO_WritePin(TOF_XSHUT1_GPIO_Port, TOF_XSHUT1_Pin, GPIO_PIN_SET); 		// Enable XSHUT
   HAL_Delay(20);
 
   //VL53L0X_ResetDevice(Dev);
   VL53L0X_WaitDeviceBooted(Dev);
   VL53L0X_DataInit( Dev );
   MessageLen = sprintf((char*)Message,"Addr change 1: %i \n\r\n\r", VL53L0X_SetDeviceAddress(Dev, sensor1_addr));
   HAL_UART_Transmit(&huart1, Message, MessageLen, 100);
   Dev->I2cDevAddr = sensor1_addr;
 
	  VL53L0X_WaitDeviceBooted( Dev );
	  //VL53L0X_DataInit( Dev );
	  VL53L0X_StaticInit( Dev );
	  VL53L0X_PerformRefCalibration(Dev, &VhvSettings, &PhaseCal);
	  VL53L0X_PerformRefSpadManagement(Dev, &refSpadCount, &isApertureSpads);
	  VL53L0X_SetDeviceMode(Dev, VL53L0X_DEVICEMODE_SINGLE_RANGING);
 
	  // Enable/Disable Sigma and Signal check
	  VL53L0X_SetLimitCheckEnable(Dev, VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, 1);
	  VL53L0X_SetLimitCheckEnable(Dev, VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, 1);
	  VL53L0X_SetLimitCheckValue(Dev, VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, (FixPoint1616_t)(0.1*65536));
	  VL53L0X_SetLimitCheckValue(Dev, VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, (FixPoint1616_t)(60*65536));
	  VL53L0X_SetMeasurementTimingBudgetMicroSeconds(Dev, 33000);
	 VL53L0X_SetVcselPulsePeriod(Dev, VL53L0X_VCSEL_PERIOD_PRE_RANGE, 18);
	 VL53L0X_SetVcselPulsePeriod(Dev, VL53L0X_VCSEL_PERIOD_FINAL_RANGE, 14);
 
 
   //  addr change 2nd sensor
   HAL_GPIO_WritePin(TOF_XSHUT2_GPIO_Port, TOF_XSHUT2_Pin, GPIO_PIN_SET); 		// Enable XSHUT
   HAL_Delay(20);
 
   //VL53L0X_ResetDevice(Dev1);
   VL53L0X_WaitDeviceBooted(Dev1);
   //VL53L0X_DataInit( Dev1 );
   MessageLen = sprintf((char*)Message,"Addr change 2: %i \n\r\n\r", VL53L0X_SetDeviceAddress(Dev1, sensor2_addr));
   HAL_UART_Transmit(&huart1, Message, MessageLen, 100);
   Dev1->I2cDevAddr = sensor2_addr;
 
	  VL53L0X_WaitDeviceBooted( Dev1 );
	  VL53L0X_DataInit( Dev1 );
	  VL53L0X_StaticInit( Dev1 );
	  VL53L0X_PerformRefCalibration(Dev1, &VhvSettings, &PhaseCal);
	  VL53L0X_PerformRefSpadManagement(Dev1, &refSpadCount, &isApertureSpads);
	  VL53L0X_SetDeviceMode(Dev1, VL53L0X_DEVICEMODE_SINGLE_RANGING);
 
	  // Enable/Disable Sigma and Signal check
	  VL53L0X_SetLimitCheckEnable(Dev1, VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, 1);
	  VL53L0X_SetLimitCheckEnable(Dev1, VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, 1);
	  VL53L0X_SetLimitCheckValue(Dev1, VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, (FixPoint1616_t)(0.1*65536));
	  VL53L0X_SetLimitCheckValue(Dev1, VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, (FixPoint1616_t)(60*65536));
	  VL53L0X_SetMeasurementTimingBudgetMicroSeconds(Dev1, 33000);
	 VL53L0X_SetVcselPulsePeriod(Dev1, VL53L0X_VCSEL_PERIOD_PRE_RANGE, 18);
	 VL53L0X_SetVcselPulsePeriod(Dev1, VL53L0X_VCSEL_PERIOD_FINAL_RANGE, 14);

measure loop:

	  	if(VL53L0X_PerformSingleRangingMeasurement(Dev, &RangingData[0]) == 0){
		  	if(RangingData[0].RangeStatus == 0){
		  		sensorMeasure[0]= RangingData[0].RangeMilliMeter;
		  	}else{
		  		//MessageLen = sprintf((char*)Message, "STATUS1: %i\n\r", RangingData.RangeStatus);
		  		//HAL_UART_Transmit(&huart1, Message, MessageLen, 100);
		  	}
	  	}else{
	  	  //MessageLen = sprintf((char*)Message, "BRAK POMIARU!\n\r");
	  	  //HAL_UART_Transmit(&huart1, Message, MessageLen, 100);
	  	}
 
 
	  	if(VL53L0X_PerformSingleRangingMeasurement(Dev1, &RangingData[1]) == 0){
		  	if(RangingData[1].RangeStatus == 0){
		  		sensorMeasure[1]= RangingData[1].RangeMilliMeter;
		  	}else{
		  		//MessageLen = sprintf((char*)Message, "STATUS2: %i\n\r", RangingData.RangeStatus);
		  		//HAL_UART_Transmit(&huart1, Message, MessageLen, 100);
		  	}
	  	}else{
	  		//MessageLen = sprintf((char*)Message, "BRAK POMIARU!\n\r");
	  		//HAL_UART_Transmit(&huart1, Message, MessageLen, 100);
	  	}
 
 
  		MessageLen = sprintf((char*)Message, "Pomiar odleglosci: %imm     %imm\n\r", sensorMeasure[0], sensorMeasure[1]);
  		HAL_UART_Transmit(&huart1, Message, MessageLen, 100);

Hi,
I have been using 7ea VL53L0X in my robotics projects for quite some time with no problems after I figured out how to initialize them to unique addresses (this must be done each time in setup()). Here is a link to my blog site where you can see how it is done. You should be able to copy/paste my setup() function into your code and modify for just 2ea VL53L0X
Hope this helps,
Frank

thx, but Your code is for Arduino my is written in Cube based on ST API. I assume here can be an issue...

Are you using the Cube programmer for STM32 as described here <>? I don't think it matters what the language is - you should be able to translate line for line. For example, the following two lines VL53L0X lidar_RF(&Wire1); VL53L0X lidar_RC(&Wire1); Create two VL53L0X objects and associates them with the 'Wire1' I2C port on Arduino. Depending on what library you are using with the cube package, these lines may be a bit different, but they should be there. Then these lines define the Arduino pin numbers used to connect to the XSHUT lines of the sensors: const int RF_XSHUT_PIN = 23; const int RC_XSHUT_PIN = 22; Then the following lines: pinMode(RF_XSHUT_PIN, OUTPUT); pinMode(RC_XSHUT_PIN, OUTPUT); Sets the pin connected to two of my VL53L0X's _XSHUT pin to an output. I have one of these lines for each of the 7 sensors. So, for your cube language, you simply have to use the corresponding API calls to define the pin numbers physically connected to the XSHUT pins of your two sensors. After that, you have to make sure BOTH sensors are held in 'RESET' mode by pulling both their XSHUT lines low, using lines like this: digitalWrite(RF_XSHUT_PIN, LOW); digitalWrite(RC_XSHUT_PIN, LOW); And then initialize each sensor in turn using the cube equivalent of the following lines: //now bring lidar_RF only out of reset and set it's address //input w/o pullups sets line to high impedance so XSHUT pullup to 3.3V takes over pinMode(RF_XSHUT_PIN, INPUT); delay(10); if (!lidar_RF.init()) { Serial.println("Failed to detect and initialize lidar_RF!"); while (1) {} } //from Pololu forum post lidar_RF.setMeasurementTimingBudget(20000); lidar_RF.startContinuous(); lidar_RF.setAddress(DEFAULT_VL53L0X_ADDR + 1); Serial.printf("lidar_RF address is 0x%x\n", lidar_RF.getAddress()); //now bring lidar_RC only out of reset, initialize it, and set its address //input w/o pullups sets line to high impedance so XSHUT pullup to 3.3V takes over pinMode(RC_XSHUT_PIN, INPUT); delay(10); if (!lidar_RC.init()) { Serial.println("Failed to detect and initialize lidar_RC!"); while (1) {} } //from Pololu forum post lidar_RC.setMeasurementTimingBudget(20000); lidar_RC.startContinuous(); lidar_RC.setAddress(DEFAULT_VL53L0X_ADDR + 2); Serial.printf("lidar_RC address is 0x%x\n", lidar_RC.getAddress()); Since the VL53L0X sensors don't know whether they are connected to an Arduino (like my case) or something else entirely (like in your case), they could care less what the language is, as long as you produce the correct voltages in the correct sequence at the sensor connector pins. Does that help?
KNawa.1
Associate II

thx, i will check based on Your advice!

John E KVAM
ST Employee

I have another suggestion that might also help. There is a project on ST.com.:

STSW-IMG017 Embedded SoftwareImaging software2D LIDAR using multiple VL53L1X Time-of-Flight long distance ranging sensors.

This project is for the VL53L1X, but just look over the initialization section. It inits 9 sensors. It also

uses a Nucleo board, so that might help as well.

But I do have to admit that Knawa.1's code is pretty good and should get you rolling.

  • john


Our community relies on fruitful exchanges and good quality content. You can thank and reward helpful and positive contributions by marking them as 'Accept as Solution'. When marking a solution, make sure it answers your original question or issue that you raised.

ST Employees that act as moderators have the right to accept the solution, judging by their expertise. This helps other community members identify useful discussions and refrain from raising the same question. If you notice any false behavior or abuse of the action, do not hesitate to 'Report Inappropriate Content'
John E KVAM
ST Employee

Oops - I found the bug. In your code

#define original_addr 	0x52
#define sensor1_addr 	0x53
#define sensor2_addr 	0x54

your addresses are too close together.

Each I2C device has a write address and a read address. And the read is has the LSB set.

So only use even addresss to set them. That leaves the odd addresses open for the reads.

I use 62,72,82 ... but you could use 54, 56, 58... just as easily.


Our community relies on fruitful exchanges and good quality content. You can thank and reward helpful and positive contributions by marking them as 'Accept as Solution'. When marking a solution, make sure it answers your original question or issue that you raised.

ST Employees that act as moderators have the right to accept the solution, judging by their expertise. This helps other community members identify useful discussions and refrain from raising the same question. If you notice any false behavior or abuse of the action, do not hesitate to 'Report Inappropriate Content'