trouble with two multiplexers sharing i2c bus

I am working on a project that requires me to monitor multiple Li-ion battery packs. right now the system is set up that their are two multiplexers with four battery packs attached to each multiplexer. I am able to use the arduino UNO to communicate to each multiplexer individually and it's attached battery packs via i2c bus. However, if I try and attach both multiplexers to the i2c bus I can read the addresses of the multiplexers but I am not able to get to the battery packs that they are attached to. I am wondering if anyone might now how I can fix this so both of them can be controlled by the one UNO.

Right now I have both SDA and SCL lines connected to 5 volts on the arduino via 4.7kohm pull-up resistors. Their is also an enable pin for each multiplexer that I have connected to the same digital pin for logic low that is used to run the multiplexers. The Arduinos and multiplexers share a common ground.

I am not sure if this would be a problem but I am only powering the Arduino by USB port.

Also, with both enable pins connected to the UNO I noticed that the on LED was illuminated a little. Could anyone tell me if this could be a sign of current flowing when it shouldn't.

attached is the data sheet for the multiplexer. I didn't see anything that would suggest a big power draw.

PCA9546_1 mux datasheet.pdf (115 KB)

Pins 1 and 2 must be different on the two chips. Are they?

@griego39, please do not cross-post.

Pins 1 and 2 must be different on the two chips. Are they?

Pins 1, 2 and 13 set the address and they are set to have different values. Right now with the i2c scanner program the addresses are detected as 0x70 and 0x73.

@griego39, please do not cross-post.

I apologize for double posting. This is the first I posted and I realized I posted to the wrong topic when I started. I didn't see away to remove the post from the installation and troubleshooting topic.

You need to be a bit more specific. What is this LED you speak of?
What testing have you done?
It is good practice when using hardware to write a small sketch to just test the hardware is working before incorporating it into your project.
So we need to see that code and you need to say what it does and what you expect it to do.

What is this LED you speak of?

The UNO has a green LED to indicate the device is powered, labeled ON. This LED became a little illuminated when I connected the enable pins for each multiplexer to one digital pin.

I do use different sketches when working with the project. I will list and describe the codes. Please feel free to contact me with any questions pertaining to the code if I didn't explain them well enough.

I found this code while going through the forum looking for help. this code is designed to search for devices on the i2c bus.

#include <Wire.h>


void setup()
{
  Wire.begin();


  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}


void loop()
{
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknow error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

This code gave me a 0x70 and 0x73 for the two multiplexer addresses. This corresponded to the addresses that we designated them with. Once I knew the address of my device (The multiplexer) i then tried to write to it to set the channel that I wanted to read. The code is as follows.

// --------------------------------------
// i2c_scanner


#include <Wire.h>
byte channel = 0;
void setup()
{
  Wire.begin();

  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
  
}


void loop()
{
  
  byte error, address;
  int nDevices;
   Serial.print("Scanning Channel ");
  Serial.println(channel) ;
  Wire.beginTransmission(0x70);
  Wire.write(channel);
  Wire.endTransmission();
  
  if(channel == 0)
  {
    channel = 1;
  }
  else if (channel >= 1 && channel < 8)
  {
    
    channel = channel << 1;
  }
  else
  {
    channel = 0;
  }
   

  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ ) 
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) 
    {
      Serial.print("Unknow error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

According to the data sheet i needed to send a byte of information to the multiplexer using the following bits 0bxxxxb3b2b1b0.
I was able to set the channel that I wanted to read and search for devices on the i2c bus again. I was able to read the multiplexer address as well as the battery pack address that I was trying to communicate with.

For the next code I had to download and install the i2cmaster library. I used this library because I needed to communicate to the battery pack which is SMBus.

/*

  Code for reading from the Safety status registers. 
  This code will address the proper 4 channel mux and 
  cycle trough the 4 buses to read the status register
  for the 4 battery packs that it's connected too.
  
*/

#include <Wire.h>      // i2c communications
#include <i2cmaster.h> // i2c to SMBus communications

int mux1address = 0x70;   // first mux address
int mux2address = 0x73;   // second mux address
int packAddress = 0x16;   // address for the BQ20Z80 battery pack onitoring chip
int regValue= 0x51;       // Address for Safety Status register
int serReg=0x1C;            // Value to read serial numer
int chanSelect = 0;       // value to display the channel that is selected
int channel = 1;          // value to select channel
int high_byte = 1;        // store high byte
int low_byte =1;          // store low byte
int pec =0;               // value for pack error bytes
int check_high = 0;       // check bit value
int relay = 13;            // relay I/O
int enable = 5;           // Enable I/O
int sernum;
int totBytes;
void setup()
{
  i2c_init(); //connect to i2c bus (use with i2c master library)
  Wire.begin(); //connect i2c bus (Use with Wire library)
  pinMode(relay,OUTPUT);
  pinMode(enable,OUTPUT);
  digitalWrite(enable,LOW);
  digitalWrite(relay,HIGH);
  Serial.begin(9600); // for serial print out
}
void loop()
{
  Serial.println("Reading from first set of battery backs\n");
  delay(2000);
  while(chanSelect <=3)   // loop to read from mux one battery packs
  {
    Wire.beginTransmission(mux1address); //open comms with mux 1
    Wire.write(channel);                 // open channel for battery pack through mux
    Wire.endTransmission();              // end transmission
   
    i2c_rep_start(packAddress+I2C_WRITE); // Send start condition and write bit
    i2c_write(serReg);                 // pointer to safety register
    i2c_rep_start(packAddress+I2C_READ); //send repeated start condition, device will ack
    low_byte = i2c_readAck();   // read byte 1 then send Ack
    high_byte = i2c_readAck();  // read 1 byte and then send ack
    pec = i2c_readNak();        //read error check byte and send Nack to thel the device no more data to to send
    i2c_stop();                 //releas bus end transaction
   sernum=high_byte*256+low_byte;
   // Printout for checking values
    Serial.println("Mux 1\n");         
    Serial.print("Checking Channel ");
    Serial.println(chanSelect);
    Serial.print("Serial number is ");
    Serial.println(sernum);
    
    i2c_rep_start(packAddress+I2C_WRITE); // Send start condition and write bit
    i2c_write(regValue);                 // pointer to safety register
    i2c_rep_start(packAddress+I2C_READ); //send repeated start condition, device will ack
    low_byte = i2c_readAck();   // read byte 1 then send Ack
    high_byte = i2c_readAck();  // read 1 byte and then send ack
    pec = i2c_readNak();        //read error check byte and send Nack to thel the device no more data to to send
    i2c_stop();   
    Serial.println("Safety Status Registers are");
    Serial.print("Binary value High= ");
    Serial.println(high_byte, BIN);
    Serial.print("Binary value Low= ");
    Serial.println(low_byte, BIN); 
    totBytes= high_byte*256+low_byte;
    Serial.print("Two Byte register = ");
    Serial.println(totBytes);
    Serial.print("\n\n");
  
    //delay(3000);
    
    // Check for any errors
    if (totBytes > 0)
    {
      digitalWrite(relay,LOW); // if errors exist trip relay
    }
    channel = channel << 1; //increment channel to check next battery
    chanSelect ++;          //increment number of channel being read
    delay(5000);
    
  }
  
  channel =1;       // reset channel for next mux check
  chanSelect = 0;   // reset chanSelect for next mux check
  
  
  // Check next set of battery packs
/*    while(chanSelect <=3)   // loop to read from mux one battery packs
  {
    Wire.beginTransmission(mux2address); //open comms with mux 2
    Wire.write(channel);                 // open channel for battery pack through mux
    Wire.endTransmission();              // end transmission
   
    i2c_rep_start(packAddress+I2C_WRITE);  // Send start condition and write bit
    i2c_write(regValue);                   // pointer to safety register
    i2c_rep_start(packAddress+I2C_READ);   //send repeated start condition, device will ack
    low_byte = i2c_readAck();   // read byte 1 then send Ack
    high_byte = i2c_readAck();  // read 1 byte and then send ack
    pec = i2c_readNak();        //read error check byte and send Nack to thel the device no more data to to send
    i2c_stop();                 //releas bus end transaction
   
   // Printout for checking values
    Serial.println("Mux 2\n");         
    Serial.print("Checking Channel ");
    Serial.print(chanSelect);
    Serial.print("Hex value High= ");
    Serial.println(high_byte, BIN);
    Serial.print("Hex value Low= ");
    Serial.println(low_byte, BIN);
  
    delay(3000);
    
    // check for error bits
    if (high_byte > 0 || low_byte > 0 )
    {
      digitalWrite(relay,LOW);  //release relay if error exists
    }
    channel = channel << 1; // increment channel for next pack check
    chanSelect ++;  // increment channel being checked
    
  }
  
  channel =1;        // reset value for recheck
  chanSelect = 0;    // reset vaoue for recheck
  
  */
  delay(10000);
}

The code is written to do the following

  1. address and set channel of first mux
  2. address and read serial number register of battery pack
  3. address and read safety register of battery pack
  4. repeat 1 - 3 until all four backs are read
  5. trip relay if safety register has any flags
  6. address and set channel of second mux
  7. repeat 2 - 5

This code works fine for setting the multiplexer and reading the battery pack as long as I connect to one multiplexer at a time. That is why I have the part of my code where I switch multiplexers commented out. Once I connect both multiplexers to the arduino n the code stops setting the channel value for the multiplexer.

Sorry I needed to break this post into 2

I was talking with another person that is on the project with me and he thinks that it might be do to each multiplexer having pullup resistors on the SDA and SCL lines. We are going to try and retest the code today.

griego39:
Their is also an enable pin for each multiplexer that I have connected to the same digital pin for logic low that is used to run the multiplexers. The Arduinos and multiplexers share a common ground.

i think those 2 pins have to be seperate digital outs on the arduino

The UNO has a green LED to indicate the device is powered, labeled ON. This LED became a little illuminated when I connected the enable pins for each multiplexer to one digital pin.

What??
This LED should be on anyway. You should not be connecting anything that is powered to an unpowered Arduino. Therefore I don't understand.

I also don't understand how that code compiles I get

sketch_jun19a:30: error: 'i2c_init' was not declared in this scope

And I don't see where this is declared
I did say:-

Grumpy_Mike:
It is good practice when using hardware to write a small sketch to just test the hardware is working before incorporating it into your project.

.
That code is hardly that is it.

I will try to clarify a little more

What??
This LED should be on anyway. You should not be connecting anything that is powered to an unpowered Arduino. Therefore I don't understand.

With the enables from both of the multiplexers connected to the arduino and the arduino is not being powered the on LED is slightly illuminated. It isn't as strong as when the board is actually being powered. The board only does this when both are connected, whether they are connected to the same digital pin or connected to their own pins.

I am not sure if this is a fault or if this might be a sign that I am doing some damage to the arduino board itself.

I usually connect my hardware to the board before I power it up. Is it recommended to power the board before connecting my devices? I will also double check the schematic to see if the board that the multiplexer is on is already supplying power to the multiplexer.

When you ran the code did you have the i2cmaster library installed. the i2c_init fault may be caused if the library isn't installed since this is a call to that library. The I2cmaster library is NOT a default library installed with the arduino software. I probably should have mentioned this earlier and I apologize for not mentioning in the previous post.

I downloaded the library from
http://homepage.hispeed.ch/peterfleury/avr-software.html

I created an i2cmaster directory in the arduino libraries. arduino/libraries/i2cmaster. I copied the i2cmaster.h and the twimaster.c files into this directory. In order for this to work I had to change twimaster.c to twimaster.cpp.

Here is the link to the forum where I found how to do this.
http://forum.arduino.cc/index.php/topic,21317.0.html

Here is the code that I had used originally just to test the i2c library.

/*

  Code using the i2c_master library for communications
  with the bq20z80 chip (SMBus device).
*/


#include<Wire.h>         //include for Wire library use
#include <i2cmaster.h>  //include for i2cmaster library use

int muxAddress = 0x73; // Address for setting mux
int devAddress = 0x16; // Address for battery back read
int regValue = 0x51;   // Register for safety status
int channel = 1;       // value for selecting the proper battery channel
int data_high = 0;     // high byte
int data_low = 0;      // low byte
int pec=0;             // pack errer byte


void setup()
{
   i2c_init();  //Initialise the i2c bus
 // Wire.begin();
  
  Serial.begin(9600);
  Serial.println("Scanning");
}

void loop()
{
  Serial.println("Testing printout");
  delay(2000);
  Wire.beginTransmission(muxAddress); // connect to mux
  Wire.write(channel);                // send value 0b0001 channel 0
  Wire.endTransmission();            // end transmission
  
  
 // Next set of code is for reading the safety status bytes 
  i2c_rep_start(devAddress+I2C_WRITE); // Send start condition and write bit
  i2c_write(regValue);                 // pointer to safety register
  data_low = i2c_readAck();   // read byte 1 then send Ack
  data_high = i2c_readAck();  // read 1 byte and then send ack
  pec = i2c_readNak();        //read error check byte and send Nack to thel the device no more data to to send
  i2c_stop();                 //releas bus end transaction
  
  Serial.println("output of Safety Status register");
  Serial.print("Hex value High= ");
  Serial.print(data_high, HEX);
  
  Serial.println("output of Safety Status register");
  Serial.print("Hex value Low= ");
  Serial.print(data_low, HEX);
  
  delay(3000);
  
}

This code utilizes the Wire.h library to write to the mux address with the value of the channel that I want to read. I then use the i2cmaster library to communicate to the battery back which is an SMBus device.

I have compiled and used all of the code that I have sent you. The only issue that I am having is when I have both multiplexers connected to the arduino.

If you would like I can send you more code of me using the i2cmaster library. I didn't want to flood the post with all of the test coding that I have done regarding this project.

@jacksons

Thank you for the suggestion but it still comes on a little bit when they are connected to different digital pins.

So we were able to fix our problem by removing the pullup resistors from one of the multiplexers SDA and SCL lines. The code that I had for cycling though the two multiplexers needed to be revised for some minor logical errors.

Thanks to everyone that offered advise

by removing the pullup resistors from one of the multiplexers SDA and SCL lines

Ah it was not clear that you had a pull up on each multiplexer. In any I2C system you only need one pull up resistor on each line for all the devices on the bus.