I2C communication with portenta breakout with I2C_0 and I2C_2?

Hi, I've recently been using the portenta H7 lite with the portenta breakout for I2C for communication with a humidifier sensor, the SHT4x (address = 0x44)). I was only able to see and read data from the sensor connected to the I2C_1 port. No addresses were found on the I2C_0 and I2C_2.

To test if the sensor was detectable I was using the example scanning code from arduino project hub (https://create.arduino.cc/projecthub/abdularbi17/how-to-scan-i2c-address-in-arduino-eaadda), and changing which wire were activated (example: replacing Wire.begin() with Wire1.begin()).

If I have understood correctly this is equivalent: Wire = Breakout.I2C_0, Wire1 = Breakout.I2C_1 and Wire2=Breakout.I2C_2. In the scanning code, I therefore replaced which wire I wanted to test and also changed the wiring on the Portenta breakout to be on the correct I2C port.

So my question is what did I do wrong? or why don't I detect my sensor on I2C_0 and I2C_2? This is important for me as I would like to communicate in the future with several sensors for a project, and thus would like to use I2C_0 and I2C_2.

I couldn't find much literature so thought I'd ask here hopefully getting some answers and helping others with the same problem. Thanks!

This is the adapted scanning code for I2C_1. It runs and finds several addresses (internal components I think) but also my sensor (address 0x44). It also worked if I used Wire1 instead of Breakout.I2C_1.

//this code is adapted for the I2C_1 port of the portenta breakout

#include <Arduino_PortentaBreakout.h>

void setup() {

  Breakout.I2C_1.begin();
  Serial.begin(9600);
  while (!Serial);  // wait for serial monitor
  Serial.println("\nI2C Scanner");
}

void loop() {
  int nDevices = 0;

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

  for (byte 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.
    Breakout.I2C_1.beginTransmission(address);
    byte error = Breakout.I2C_1.endTransmission();

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

      ++nDevices;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
    } else if (error == 1) {
      Serial.println("1: data too long to fit in transmit buffer.");
    } else if (error == 2) {
      Serial.println("2: received NACK on transmit of address.");
    } else if (error == 3) {
      Serial.println("3: received NACK on transmit of data.");
    } else if (error == 5) {
      Serial.println("5: timeout");
    }
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  } else {
    Serial.println("done\n");
  }
  delay(5000);  // Wait 5 seconds for next scan
}

After changing to the wires to I2C_0.
The following code is used for the I2C_0 port. It runs but doesn't find any devices and returns "0 I2C devices found". The arduino only receives "NACK", which is the error message N°2 in the code below.

//this code is adapted for the I2C_0 port of the portenta breakout

#include <Arduino_PortentaBreakout.h>

void setup() {

  Breakout.I2C_0.begin();
  Serial.begin(9600);
  while (!Serial);  // wait for serial monitor
  Serial.println("\nI2C Scanner");
}

void loop() {
  int nDevices = 0;

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

  for (byte 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.
    Breakout.I2C_0.beginTransmission(address);
    byte error = Breakout.I2C_0.endTransmission();

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

      ++nDevices;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16) {
        Serial.print("0");
      }
      Serial.println(address, HEX);
    } else if (error == 1) {
      Serial.println("1: data too long to fit in transmit buffer.");
    } else if (error == 2) {
      Serial.println("2: received NACK on transmit of address.");
    } else if (error == 3) {
      Serial.println("3: received NACK on transmit of data.");
    } else if (error == 5) {
      Serial.println("5: timeout");
    }
  }
  if (nDevices == 0) {
    Serial.println("No I2C devices found\n");
  } else {
    Serial.println("done\n");
  }
  delay(5000);  // Wait 5 seconds for next scan
}

Sorry your code is not readable. Please read the following and use code tags.

Have you verified that the I2Cs you want to use have pull-ups?
What I have seen:
Portenta H7 has 3 I2C devices and pins on breakout board.
But just ONE has a pull-up there. I think it is the one for the I2C bus where also the onboard PMIC is connected to.

So:

  • check, if you have or if you NEED pull-ups (external) - user I2C pins need still a pull-up
  • check also I2C slave addresses: if you connect external I2C devices on the I2C bus used also for
    onboard devices (PMIC, crypto ...) - you could have a conflict with I2C slave addresses

I have just checked and adding external pull-up resistors solved my problem! Thanks a lot for your help.

The I2C_0 and I2C_2 were indeed "open drain" pins and needed to be connected to with a pull-up resistor.

Cool!
I2C is always Open Drain (needs external pull-ups).

Hi, can you please explain where should I add the external pull-up resistors?
Thanks!

Hi, I can show you which setup I used.
To add the pull-up resistors, I used a breadboard (from arduino uno). It made the connections easy to make. I personally used 2200 Ohm resistors because I had some available. I think generally 1k-10k Ohm resistors are used for external pull-up resistors.

Below is a picture and schematic of my setup. The SCL (Yellow cable) is connected to my sensor and the SCL_0 of the portenta. The SDA (White/grey cable) is connected to my sensor and the SDA_0 of the portenta. The red cable is connected to the 3.3v of the portenta.

Breadboard connections:


Schematic of my setup:

And what is the issue?
2.2K is OK, for 100 Kbps.
Any faster I2C clock, e.g. 1 MHz, might need a lower resistance value (speed correlates with pull-up values - the faster the lower resistance (and higher current!)).

No idea on which Portenta H7 I2C you have wired.
Just to be carful: one I2C bus on Portenta H7 is already used for onboard chips (PMIC, Crypto).
This has a pull-up already (another one as parallel makes the pull-up stronger).
And this I2C bus has already slave devices on it: avoid a conflict with devices using the same slave address for I2C.