0
\$\begingroup\$

Problem Description

I'm working on a project involving multiple Proximity sensors (AdaFruit VCNL4040). There are 8 such sensors interfaced through a I2C multiplexer (NXP PCA9547). Additionally I need to add an extra sensor which I have to interface directly with the I2C bus. The extra sensor is the same type as the ones being multiplexed and has the same I2C address.

enter image description here

Code

Creation of MUX and sensor objects.

#include <Arduino.h>
#include "PCA9547.h"
#include <Adafruit_VCNL4040.h>

PCA9547 i2c_select = PCA9547();
Adafruit_VCNL4040 proxy_mux = Adafruit_VCNL4040();
Adafruit_VCNL4040 proxy_extra = Adafruit_VCNL4040(); //

setup() function. Note that I'm using the same object of the class AdaFruit_VCNL4040 to interface with the multiplexed sensors(proxy_mux), and a second one for the extra-sensor (proxy_extra).

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);

  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH); //RESET pin for MUX (HIGH for operation

  Wire.begin(); //Join i2c bus

  i2c_select.attatch(Wire);
  i2c_select.setAddress(0,0,0);
  i2c_select.disable();

    // Start with the setup of the extra sensor. 
  if (!proxy_extra.begin()) {
    Serial.println("Couldn't find VCNL4040 chip");
    while (1);
  }

  proxy_extra.enableProximity(true);
  proxy_extra.enableProximityInterrupts(VCNL4040_PROXIMITY_INT_CLOSE_AWAY);
  proxy_extra.setProximityLowThreshold(100);
  delay(200);
  proxy_extra.setProximityHighThreshold(120);
  delay(200);

    //Enable the Multiplexed sensors
  for (int i = 0; i < 8; i++){
    i2c_select.enable(i);
    if (!proxy_mux.begin()) {
      Serial.println("Couldn't find VCNL4040 chip");
      while (1);
    }
  }
    
    //Sensor settings for the Multiplexed sensors. 
  for (int i = 0; i < 8; i++){
    i2c_select.enable(i);
    proxy_mux.enableProximity(true);

    proxy_mux.enableProximityInterrupts(VCNL4040_PROXIMITY_INT_CLOSE_AWAY);
    proxy_mux.setProximityLowThreshold(100);
    delay(200);
    proxy_mux.setProximityHighThreshold(120);
    delay(200);

  }
}

loop() function and printing MUX'ed sensor values.

void printProximityValues(){

    unsigned int vals[8];

    for (int i = 0; i < 8; i++){
        // WeightStackSensor::tcaselect(i);
        i2c_select.enable(i);
        vals[i] = proxy_mux.getProximity();
        delay(50);
    }

    char valsString[128];
    sprintf(valsString,
    "%u,%u,%u,%u,%u,%u,%u,%u,",
    vals[0],
    vals[1],
    vals[2],
    vals[3],
    vals[4],
    vals[5],
    vals[6],
    vals[7]);
  
    Serial.println(valsString);
    i2c_select.disable();

}

void loop() {
  // put your main code here, to run repeatedly:
  printProximityValues();
  delay(100);

  int extra_val = proxy_extra.getProximity();
  Serial.print("EXTRA:");
  Serial.println(extra_val);

}

Behaviour

Values from the Multiplexed sensors only appear if the Extra sensor is actuated. If there is no proximity values read via the Extra sensor, then proximity readings from the MUX'ed sensor appear as 0.

Example output

Both Multiplexed Sensors and Proximity Sensors

MUX Sensors actuated and Extra Sensor NOT actuated -WRONG BEHAVIOUR. The MUX proximity values should be around 260 ~ 300

16:10:19.737 -> MUX VALS: 0,0,0,0,0,0,0,0 |EXTRA:0
16:10:20.267 -> MUX VALS: 0,0,0,0,0,0,0,0 |EXTRA:0
16:10:20.829 -> MUX VALS: 0,0,0,0,0,0,0,0 |EXTRA:0
16:10:21.392 -> MUX VALS: 0,0,0,0,0,0,0,0 |EXTRA:0

MUX sensors actuated and Extra Sensor Actuated

16:07:49.735 -> MUX VALS: 282,260,260,266,292,256,305,256 |EXTRA:308
16:07:50.265 -> MUX VALS: 292,258,256,275,288,256,309,306 |EXTRA:311
16:07:50.827 -> MUX VALS: 293,288,262,276,294,260,306,292 |EXTRA:309
16:07:51.390 -> MUX VALS: 292,273,261,276,292,256,304,308 |EXTRA:307

It seems that the sensor values follow the values of the Extra sensor?

Disabling Extra sensor and disconnecting it

Proximity values are high for the multiplexed sensors which is the correct functionality.

16:15:26.425 -> MUX VALS: 308,379,365,236,289,198,171,173 |
16:15:26.954 -> MUX VALS: 307,378,364,224,273,189,161,165 |
16:15:27.484 -> MUX VALS: 297,376,356,216,258,176,149,153 |
16:15:28.047 -> MUX VALS: 296,365,351,218,270,182,153,155 |

The MUX sensors and the Extra-sensor, if separated, work correctly. However if it seems like the MUX sensor values are not appearing unless the Extra sensor is actuated. Why does it seems like they are not decoupled and dependant on eachother, which should not be the case?

\$\endgroup\$
5
  • 2
    \$\begingroup\$ You have eight channels but nine sensors. You have address conflicts. \$\endgroup\$
    – CL.
    Nov 1, 2021 at 9:22
  • 1
    \$\begingroup\$ "Additionally I need to add an extra sensor which I have to interface directly with the I2C bus. The extra sensor is the same type as the ones being multiplexed and has the same I2C address." Why do you think this will work? It's the exact problem your mux was presumably meant to solve (but you're defeating the mux with the extra sensor). \$\endgroup\$
    – TypeIA
    Nov 1, 2021 at 9:29
  • \$\begingroup\$ If setting the channel control register to "no channel selected", wouldn't I able to read the extra-sensor registers while ignoring the sensors connected to the multiplexer? The 'i2c_select.disable()' function sets the control register to 0 which should be a "no channel selected" command. \$\endgroup\$
    – jquinno
    Nov 1, 2021 at 9:48
  • 2
    \$\begingroup\$ No, I was wrong, the other comments are correct. When you set mux to "no channels" you should be able to read extra sensor. BUT when you select any channel you still have that extra sensor connected, and it will interfere with selected one \$\endgroup\$
    – Maple
    Nov 1, 2021 at 9:50
  • 1
    \$\begingroup\$ The multiplexor allows 8 devices with the same address to coexist on the same I2C bus, but it does not change the I2C address of the device. Your 9th is in conflict with the one multiplexed. You could disable multiplexor to read 9th, but 9th will ALWAYS conflict with all others. No solution. \$\endgroup\$ Nov 1, 2021 at 9:55

3 Answers 3

2
\$\begingroup\$

You can't read oŕ write to any sensor behind the mux at address X, because you already have a sensor that is always on the bus at same address X reacting on the same reads and writes, and you can't make the always connected sensor to ignore that in any way.

\$\endgroup\$
1
\$\begingroup\$

There is no software solution. You will have to add a new multiplexer at a new address for the 9th or move 9th to a new I2C port (if available).

The multiplexer allows 8 devices with the same address to coexist on the same I2C bus, but it does not change the I2C address of the device.

Your 9th is in conflict with the one that is currently being multiplexed. You could disable multiplexor (via control register - no channel selected) to read the 9th, but the 9th will ALWAYS conflict with all others. The multiplexer enables SCK and SDA to one of the 8 busses.

From PCA9547 - 8-channel I2C-bus multiplexer with reset:

enter image description here

From: Application Note - AN262_2 PCA954X Family of I²C / SMBus Multiplexers and Switches:

Once one or several channels have been selected, the device acts as a wire, allowing the master on the upstream channel to send commands to devices on all the active downstream channels, and devices on the active downstream channels to communicate with each other and the master.

The 9th and the 1 on the enabled channel will always conflict (0x60). You have an upstream device AND a downstream device. Effectively, 0x60 will select two devices.

\$\endgroup\$
1
\$\begingroup\$

You need either MUX with more channels, or second MUX configured with different address, or different sensor which allows address selection for that 9th device.

UPDATE:

This means that I won't be able to set the exta-sensor registers. As soon as I enable the MUX and attempt to write to the registers, the extra-sensor's registers would be overwritten?

Of course you will be able to set extra-sensor registers.

  • I could not find any I2C MUX with more than 8 channels, so I think you can ignore first option;

  • If you go with extra MUX you will enable only one of the two MUXes and then you will be talking to one of the slave sensors on that MUX. This includes both setting its registers and reading its data.

Your code will look like this:

  1. enable MUX 1
  2. select MUX1 channels one by one and read (or write) registers of the sensor on current channel
  3. disable MUX 1, enable MUX 2
  4. select MUX2 channels one by one and read (or write) registers of the sensor on current channel
  • If you find similar sensors with configurable address, you will set one address for all MUX-ed sensors and different address for extra sensor. Then when MUX is disabled you will use extra sensor address to talk to that one sensor. When MUX is enabled you will use common address to talk to one sensor currently connected via MUX. Again, this includes both setting its registers and reading its data.

Your code will look like this:

  1. enable MUX
  2. select MUX channels one by one and read (or write) registers of the sensor on current channel using address 1
  3. disable MUX
  4. read (or write) registers of the extra sensor using address 2

Note, that whatever option you choose, you always working with one sensor at a time. Meaning, you cannot set registers of all MUX-ed sensors simultaneously, your software has to go through them one by one. And then you disable MUX and do it one more time for extra sensor.

\$\endgroup\$
3
  • \$\begingroup\$ This means that I won't be able to set the exta-sensor registers. As soon as I enable the MUX and attempt to write to the registers, the extra-sensor's registers would be overwritten? \$\endgroup\$
    – jquinno
    Nov 1, 2021 at 10:08
  • \$\begingroup\$ @jquinno The extra sensor is always seeing what you are sending to the other 8 sensors and it doesn't know you are trying to talk to a different sensor. \$\endgroup\$
    – user253751
    Nov 1, 2021 at 14:24
  • \$\begingroup\$ @jquinno see an update \$\endgroup\$
    – Maple
    Nov 1, 2021 at 18:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.