Using VL53L4CD with TCA multiplexer

Breakout boards, sensors, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
davidestevens
 
Posts: 35
Joined: Thu Oct 20, 2022 7:44 am

Using VL53L4CD with TCA multiplexer

Post by davidestevens »

hi,

I appear to have bitten off more than I can chew again!
My current project, after getting systems using the close and long range ToF sensors working, is to make a new one using 4 medium range sensors (VL53L4CD). Unfortunately the supplied (STM) library is not as easy for me to figure out as the Adafruit libraries for the other sensors I'm using.

First, a related question... the wiring image on the VL53L4CD page shows power and I2C connected. The STM _HelloWorld example says that the GPIO & XSHUT pins also need connecting. I tried a single sensor, and it worked without the latter 2 pins connected, but I'm wondering if they _should be connected when using the multiplexer. And if so, is it ok to connect all the GPIO and XSHUT pins on the sensors to the same 2 minds on the Arduino, or do I need to define 4 separate pairs on the Arduino? (At the moment, I have both those sensors connected to A1 & A2 on the Arduino.)

OK. Using the STM example code, I connected one sensor to an Arduino Micro, and that worked.
Then I connected 2 sensors on the first 2 I2C inputs on the multiplexer, and ran the port scan sketch. Both sensors are seen.
Then I started modifying the _HelloWorld sketch with multiplexer code from one of my existing working sketches. One sensor is being read successfully, the second one is printing to serial, but only a value of 0 (so presumably it's not actually reading data from the sensor).
Here's the complete sketch so far...

Code: Select all

/* Includes ------------------------------------------------------------------*/
#include <Arduino.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <vl53l4cd_class.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>


#define DEV_I2C Wire
#define SerialPort Serial

#define TCAADDR 0x70

#ifndef _BV
#define _BV(bit) (1 << (bit)) 
#endif


void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

// Components.
VL53L4CD sensor_vl53l4cd_sat(&DEV_I2C, A1);

/* Setup ---------------------------------------------------------------------*/

void setup()
{
  SerialPort.begin(115200);

  // Initialize I2C bus.
  DEV_I2C.begin();

tcaselect(0);
sensor_vl53l4cd_sat.begin();  // Configure VL53L4CD satellite component.
sensor_vl53l4cd_sat.VL53L4CD_Off();  // Switch off VL53L4CD satellite component.
sensor_vl53l4cd_sat.InitSensor();  //Initialize VL53L4CD satellite component.
sensor_vl53l4cd_sat.VL53L4CD_SetRangeTiming(200, 0); // Program the highest possible TimingBudget, without enabling the
  // low power mode. This should give the best accuracy
sensor_vl53l4cd_sat.VL53L4CD_StartRanging(); // Start Measurements



}

void loop()
{
  uint8_t NewDataReady = 0;
  VL53L4CD_Result_t results;
  uint8_t status;
  char report[64];
 

  tcaselect(0);

  do {
    status = sensor_vl53l4cd_sat.VL53L4CD_CheckForDataReady(&NewDataReady);
  } while (!NewDataReady);

  if ((!status) && (NewDataReady != 0)) {
    // (Mandatory) Clear HW interrupt to restart measurements
    sensor_vl53l4cd_sat.VL53L4CD_ClearInterrupt();

    // Read measured distance. RangeStatus = 0 means valid data
    sensor_vl53l4cd_sat.VL53L4CD_GetResult(&results);
    snprintf(report, sizeof(report), " Distance1 = %5u mm \r\n",
             
             results.distance_mm,
             results.signal_per_spad_kcps);
    SerialPort.print(report);
  }

   tcaselect(1);


  if ((!status) && (NewDataReady != 0)) {
    // (Mandatory) Clear HW interrupt to restart measurements
    sensor_vl53l4cd_sat.VL53L4CD_ClearInterrupt();

    // Read measured distance. RangeStatus = 0 means valid data
    sensor_vl53l4cd_sat.VL53L4CD_GetResult(&results);
    snprintf(report, sizeof(report), " Distance2 = %5u mm \r\n",
             
             results.distance_mm,
             results.signal_per_spad_kcps);
    SerialPort.print(report);
  }
  
  
 

}
Based on previous sketches, I would assume that I need to sent the setup instructions to each instance of the sensors. Ie -

Code: Select all

tcaselect(0);
sensor_vl53l4cd_sat.begin();  // Configure VL53L4CD satellite component.
sensor_vl53l4cd_sat.VL53L4CD_Off();  // Switch off VL53L4CD satellite component.
sensor_vl53l4cd_sat.InitSensor();  //Initialize VL53L4CD satellite component.
sensor_vl53l4cd_sat.VL53L4CD_SetRangeTiming(200, 0); // Program the highest possible TimingBudget, without enabling the
  // low power mode. This should give the best accuracy
sensor_vl53l4cd_sat.VL53L4CD_StartRanging(); // Start Measurements
tcaselect(1);
sensor_vl53l4cd_sat.begin(); 
sensor_vl53l4cd_sat.VL53L4CD_Off();
sensor_vl53l4cd_sat.InitSensor(); 
sensor_vl53l4cd_sat.VL53L4CD_SetRangeTiming(200, 0); 
sensor_vl53l4cd_sat.VL53L4CD_StartRanging(); 
(and eventually the same for tcaselect (2) & (3)).

But when I add that bit of setup code, the sketch loads but fails to run.

In the loop, when I get to tcaselect(1), I removed (perhaps unwisely) the

Code: Select all

do {
    status = sensor_vl53l4cd_sat.VL53L4CD_CheckForDataReady(&NewDataReady);
  } while (!NewDataReady);
If I leave it in, the sketch won't run. Leaving it out, the sketch runs, but Distance2 outputs only 0.
I've tried removing and replacing various other parts of the code. Sometimes it runs, but Distance2 is zero, or it compiles but fails to run at all.
I also tried repeating the definitions just before tcaselect(0) in loop ahead of tcaselect(1), but changing the variable names there and inside the tcaselect instructions (eg changing results to results2 ), but that didn't work. Nor did moving the definitions to after the tca pin select - ie this way round

Code: Select all

 tcaselect(0); 
 uint8_t NewDataReady = 0;
  VL53L4CD_Result_t results;
  uint8_t status;
  char report[64];
So there's something fairly major I'm missing here.

Help?!!

Thanks
David

User avatar
adafruit_support_carter
 
Posts: 29457
Joined: Tue Nov 29, 2016 2:45 pm

Re: Using VL53L4CD with TCA multiplexer

Post by adafruit_support_carter »


User avatar
davidestevens
 
Posts: 35
Joined: Thu Oct 20, 2022 7:44 am

Re: Using VL53L4CD with TCA multiplexer

Post by davidestevens »

Yes, the code in those examples is what I used previously as the basis for my other sensor systems.
Looking at it again, the only obvious thing I can see missing is creating a separate instance. This is where I'm confused by the more complicated library.
So here's my guess -
create instances:
VL53L4CD vl1;
VL53L4CD vl2;

#define vl1 sensor_vl53l4cd_sat
#define vl2 sensor_vl53l4cd_sat

then in void setup replace the first line (sensor_vl53l4cd_sat.begin(); ) with vl1.begin; (etc).

Code: Select all

tcaselect(0);
vl1.begin();
vl1.VL53L4CD_Off();
vl1.InitSensor();
vl1.VL53L4CD_SetRangeTiming(200, 0);
vl1.VL53L4CD_StartRanging(); 
 
Am I even close?

User avatar
adafruit_support_carter
 
Posts: 29457
Joined: Tue Nov 29, 2016 2:45 pm

Re: Using VL53L4CD with TCA multiplexer

Post by adafruit_support_carter »

There's no need for the #define's.

You need to create an instance for each:

Code: Select all

// For each device, create a separate instance.
Adafruit_BME280 bme1;  // BME280 #1
Adafruit_BME280 bme2;  // BME280 #2
Adafruit_BME280 bme3;  // BME280 #3
And after that be sure to channel switch the TCA before talking to any specific instance. For example, when calling begin() in setup():

Code: Select all

  // Before using any BME280, call tcaselect to set the channel.
  tcaselect(0);      // TCA channel for bme1
  bme1.begin();      // use the default address of 0x77

  tcaselect(1);      // TCA channel for bme2
  bme2.begin();      // use the default address of 0x77

  tcaselect(2);      // TCA channel for bme3
  bme3.begin();      // use the default address of 0x77
And when reading the sensors in the loop():

Code: Select all

  // Read each device separately
  tcaselect(0);
  pressure1 = bme1.readPressure();
  tcaselect(1);
  pressure2 = bme2.readPressure();
  tcaselect(2);
  pressure3 = bme3.readPressure();

User avatar
davidestevens
 
Posts: 35
Joined: Thu Oct 20, 2022 7:44 am

Re: Using VL53L4CD with TCA multiplexer

Post by davidestevens »

Yes, thanks, that's all clear to me. I'll try adding that and see what happens.
Is that what's being defined (in the original sketch) under "Components"?

Code: Select all

// Components.
VL53L4CD sensor_vl53l4cd_sat(&DEV_I2C, A1);
So if i just just replace that with

Code: Select all

// Components.
VL53L4CD vl1(&DEV_I2C, A1);
VL53L4CD vl2 (&DEV_I2C, A1);
that'll do it?
Busy cooking supper at the moment, so I'll try that a bit later....

User avatar
adafruit_support_carter
 
Posts: 29457
Joined: Tue Nov 29, 2016 2:45 pm

Re: Using VL53L4CD with TCA multiplexer

Post by adafruit_support_carter »

In general, yes. However, the second parameter is for the XSHUT pin, which sort of muddies the answer for this specific sensor. Are you planning on using the XSHUT pin for each sensor? It's possible to try using the sensors without the XSHUT pin, for example:
https://learn.adafruit.com/adafruit-vl5 ... or/arduino
In that case, you can pass in 0 for the second parameter.

User avatar
davidestevens
 
Posts: 35
Joined: Thu Oct 20, 2022 7:44 am

Re: Using VL53L4CD with TCA multiplexer

Post by davidestevens »

If I don't need it I won't use it (does the cable length make any difference? The sensor is 2m away (with an active terminator) from the TCA).
I'll have another go tomorrow - after a couple glasses of wine is probably not the best time to fiddle with code :-)

by the way, how do you know (eg) what the second parameter is for? Is there some resource that gives all of this (to me) arcane knowledge?
Oh, and is there somewhere that explains what the GPIO and XSHUT pins/functions do?

thanks!

User avatar
adafruit_support_carter
 
Posts: 29457
Joined: Tue Nov 29, 2016 2:45 pm

Re: Using VL53L4CD with TCA multiplexer

Post by adafruit_support_carter »

The pinout page describes the pin functions:
https://learn.adafruit.com/adafruit-vl5 ... or/pinouts
For more detail, would need to look in the datasheet for the VL53L4CD
https://learn.adafruit.com/adafruit-vl5 ... /downloads

Cable length definitely matters. I2C was never meant for long cable runs like two meters:https://learn.adafruit.com/working-with ... ble-length
However, lots of people do this and sometimes it just works. So just try and see and then adapt as needed based on what happens.

Same for the XSHUT pin. Try without first. If it all works, then great. You'd want to consider using the XSHUT pin to better force the VL53L4CD into a known state, via a hardware reset, with each code run.

User avatar
davidestevens
 
Posts: 35
Joined: Thu Oct 20, 2022 7:44 am

Re: Using VL53L4CD with TCA multiplexer

Post by davidestevens »

Great! It's working. In case it's useful to anyone else, here's the sketch (possibly still with some unnecessary bits in it). Now to add 2 more sensor inputs.
(And cable lengths - I have 3m lengths working with the short- and long-range ToF sensors, but the VL53L4CD's don't seem to want to work with anything over 2m. I think that will still allow enough manoeuvrability in my workshops. If I can get the housings finished in time, I will be able to test them out next week)

Code: Select all

/* Includes ------------------------------------------------------------------*/
#include <Arduino.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <vl53l4cd_class.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>


#define DEV_I2C Wire
#define SerialPort Serial

#define TCAADDR 0x70

#ifndef _BV
#define _BV(bit) (1 << (bit)) 
#endif


void tcaselect(uint8_t i) {
  if (i > 7) return;
 
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();  
}

// Components.
// VL53L4CD sensor_vl53l4cd_sat(&DEV_I2C, A1);
VL53L4CD vl1(&DEV_I2C, 0);
VL53L4CD vl2(&DEV_I2C, 0);

/* Setup ---------------------------------------------------------------------*/

void setup()
{
  SerialPort.begin(115200);

  // Initialize I2C bus.
  DEV_I2C.begin();

tcaselect(0);
vl1.begin();  // Configure VL53L4CD satellite component.
vl1.VL53L4CD_Off();  // Switch off VL53L4CD satellite component.
vl1.InitSensor();  //Initialize VL53L4CD satellite component.
vl1.VL53L4CD_SetRangeTiming(200, 0); // Program the highest possible TimingBudget, without enabling the
  // low power mode. This should give the best accuracy
vl1.VL53L4CD_StartRanging(); // Start Measurements

tcaselect(1);
vl2.begin(); 
vl2.VL53L4CD_Off(); 
vl2.InitSensor();  
vl2.VL53L4CD_SetRangeTiming(200, 0); 
vl2.VL53L4CD_StartRanging(); 

}

void loop()
{
  uint8_t NewDataReady = 0;
  VL53L4CD_Result_t results;
  uint8_t status;
  char report[64];
 

  tcaselect(0);

  do {
    status = vl1.VL53L4CD_CheckForDataReady(&NewDataReady);
  } while (!NewDataReady);

  if ((!status) && (NewDataReady != 0)) {
    // (Mandatory) Clear HW interrupt to restart measurements
    vl1.VL53L4CD_ClearInterrupt();

    // Read measured distance. RangeStatus = 0 means valid data
    vl1.VL53L4CD_GetResult(&results);
    snprintf(report, sizeof(report), " Distance1 = %5u mm \r\n",
             
             results.distance_mm,
             results.signal_per_spad_kcps);
    SerialPort.print(report);
  }

   tcaselect(1);

     do {
    status = vl2.VL53L4CD_CheckForDataReady(&NewDataReady);
  } while (!NewDataReady);


  if ((!status) && (NewDataReady != 0)) {
    // (Mandatory) Clear HW interrupt to restart measurements
    vl2.VL53L4CD_ClearInterrupt();

    // Read measured distance. RangeStatus = 0 means valid data
    vl2.VL53L4CD_GetResult(&results);
    snprintf(report, sizeof(report), " Distance2 = %5u mm \r\n",
             
             results.distance_mm,
             results.signal_per_spad_kcps);
    SerialPort.print(report);
  }
  
}

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Products from Adafruit”