Why is I2C wire returning 1 for all addresses in arduino uno q?

I am running the standard I2C scanner on the Arduino Uno Q and I wanted to connect an MPU6050. I have already tried connecting SDA/SCL to PIN A4/A5 and D20/D21 but all the addresses return an error value of 1 which from the docs is DATA_TOO_LONG_FOR_TRANSMIT_BUFFER = 1, is 1 the expected error when device for a given I2C does not exist?
I tried Wire, Wire1 and Wire2 but all of them return the same error. Are there more wires and which one corrosponds to which I2C, how do I find similar information? Should I lookup datasheet of the STM chip?

Here is my code:

#include <Wire.h>

// Set I2C bus to use: Wire, Wire1, etc.
#define WIRE Wire
byte val = 0;
void setup() {
  WIRE.begin();

  Serial.begin(9600);
  while (!Serial)
     delay(10);
  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);
    Wire.write(val);
    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("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }
    Serial.print("I2C error at address 0x");
    Serial.print(address,HEX);
    Serial.print(" is ");
    Serial.println(error);
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

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

Hi @kingk321 !

Unfortunately I don't have access to an UNO Q but you find information about its I2C here

https://docs.arduino.cc/tutorials/uno-q/user-manual/#i2c

and you could check

  • Do you get the same error if nothing is wired to the I2C pins?
  • Are the UNO Q pin voltage and the input voltage of your MPU6050 the same?
  • Does the MPU6050 come with pullup resistors (usually they have but better double-check...)
  • Did you try the I2C pins of the QWIIC connector?

Just some hints to get further ...

Good luck!
ec2021

1. Pictorial view of MPU6050 Breakout Board (Fig-1).


Figure-1:

2. Schematic of MPU6050 Breakout Board.


Figure-2:

1.
SDA and SCL header pins of UNO Q forms the I2C Bus and behaves exactly the same way the I2C Bus of UNO R3 behaves except that UNO Q is a 3.3V device. So, always connect 5V device/sensor with UNO Q using level shifter.

2
From the figures of post #3, if you are convinced the MPU6050 is a 3.3V device, then make the following connection:

UNO Q       MPU
5V          VCC
GND         GND
SDA         SDA
SCL         SCL
GND         AD0       (address 0x68)

3.
Upload the following scanner program and check that MPU6050 isdetcected at address 0x68.

#innclude<Arduino_RouterBridge.h>
#include<Wire.h>
byte busStatus;

void setup()
{
  Bridge.begin();
  Serial.begin(9600);
  Wire.begin();
  for (int i2cAddress = 0x00; i2cAddress < 0x7F; i2cAddress++)
  {
    Wire.beginTransmission(i2cAddress);
    busStatus = Wire.endTransmission();
    if (busStatus == 0x00)
    {
      Serial.print("I2C Device found at address: 0x");
      Serial.println(i2cAddress, HEX);
    }

    else
    {
      Serial.print("I2C Device not found at address: 0x");
      Serial.println(i2cAddress, HEX);
    }
  }
}

void loop()
{

}

Open the attached datasheet of STM32U585 MCU of UNO Q board. Serac for SDA text, you will find that there are four I2C buses that are supported by MCU.
STM32U585XX (1).PDF (7.0 MB)

From ARDUINODOCS, find the header pins (SDA/SL) for I2C Bus. In the sketch use Wire.begin();.

Hi @kingk321.

This is how the code is implemented:

Here is the documentation for the i2c_write function of Zephyr OS, which is called by the Wire library's endTransmission function:

https://docs.zephyrproject.org/latest/doxygen/html/group__i2c__interface.html#ga2cc5f49493dce89e128ccbfa9d6149a0

Return values

0 If successful.
-EIO General input / output error.

And, to be comprehensive, the documentation for the EIO macro:

https://docs.zephyrproject.org/latest/doxygen/html/group__system__errno.html#ga70979f50f9c83e5aebab3d6a1bd4cf35

#define EIO   5

So the endTransmission function from the variant of the Wire library bundled with the "Arduino UNO Q Board" platform returns 0 on success, and 1 on any type of error. It doesn't provide the standardized granular error codes claimed by the documentation (which is done by the Wire libraries bundled with other Arduino boards platforms).

I have submitted a report of the inaccuracy of the information in the Wire library reference as it applies to the UNO Q (and other boards of the Zephyr-based platforms) to the responsible parties at Arduino. Thanks for bringing this to our attention. I apologize for any confusion caused by this inaccuracy in the documentation.

Normally, I write --

Wire.beginTransmission(slaveAddress);
byte busStatus = Wire.endTransmission();   //default arg is true for stop
if(busStatus != 0)
{
    Serial.print("Bus error!");
    while(true);
}
Serial.println("Slave is present.");

What I see above in the referred quote -- are those lines have defined the endTransmission() method? I mean that the calling to endTransmission() executes all those lines in the background?

I'm not sure "background" is the best way to describe it, as this might be seen as implying it is done asynchronously as the sketch thread proceeds. However, you are correct that when you make a function call like Wire.endTransmission(), the code lines shown in your quote are indeed executed.

In this case where you don't pass an argument to the function, they are actually executed via this overload of the function:

(that this just provides a default value of true for the stopBit parameter)

Hi @GolamMostafa !

What you see in detail is that

  • the referred code converts the return value of i2c_write to either 1 or 0
  • your code just checks whether there is an error or not, it does not differentiate or print a specific error code

However the endTransmission should return different error numbers depending on the cause

see https://docs.arduino.cc/language-reference/en/functions/communication/wire/endTransmission/

Returns
A byte value indicating the status of the transmission:

0: success.
1: data too long to fit in transmit buffer.
2: received NACK on transmit of address.
3: received NACK on transmit of data.
4: other error.
5: timeout.

The reduction to 0 and 1 is misleading and the cause has been discovered by @ptillisch ...

The above function clearly returns 1-byte data which is either 0x00 or non-zero (1).

When there are five write() operations within beginTransmission()/endTransmission(), there are six (1 + 5) ACK (0) signals returned by the slave (Fig-1 for a single write()). These ACK signals are effectively combined (logically ANDed, considering their active-low nature) to determine whether the entire transmission was successful. The final result is then reported to the user program as 0, indicating a successful transmission cycle. Therefore, returning 0 for success and 1 for error appears quite logical to me.


Figure-1:

The above bytes values 0x00 - 0x05 are created by the application program depending on the status values (Fig-2) produced following I2C transactions. The status values can be observed if one goes with register level proramming.


Figure-2:

Where did you see that?

The slave transmits an ACK by pulling the SDA line low. If there are two write() operations, there will be two ACK events. Including the ACK generated during the address match, there are a total of three ACK events. Based on these ACK responses, the MCU derives a single busStatus value, which is then returned by the Wire.endTransmission() function. I hope this explanation makes sense.

No. You did not answer my question.
Why do you think that all the ACK/NACK are logically ANDed?

When Wire.beginTransmission(slaveAdd) is seen by compiler, the data bytes that followed by write() code are begin to be queued for onward transmission byte-by-byte and to be initiated by Wire.endTransmission(). All the operations following the recognition of slaveAdd must be successful to generate the final decisin of "Data transfer ok", and this is the fact that has prompted me to use the term ANDed. Hope, I have been able to explan to some extent.

Well you have edited the post I was refering too twice already making my comments irrelavent. So now you see what I mean.

Thank you very much for elping to understand I2C transaction in a better way.

The main issue with the realization that is in question is that it does not apply to the general description of the function endTransmission.

That's independent from how it works in detail.

I tried out this setup using an Arduino Uno Q, your sketch, and this Adafruit MP6050 breakout board, along with this cable, and it worked using the recently released 0.55.2 ArduinoCore-zephyr. The MPU6050 was consistently detected at address 0x68 using your sketch.

It worked if I used either the 5V or 3.3V power for the MP6050 breakout board. The Adafruit board has voltage level translators for SCL/SDA, your breakout board does not. They both have pull-up resistors on SCL/SDA.

I could not get the Adafruit MPU6050 breakout board to work with Stemma connector on the Uno Q or the Uno R4 WiFi. I tried two different cables. On the schematics for the Uno R4 it shows pull-up resistors and a 3.3 logic interface to the 5V MCU. That means there are two sets of pull-up resistors when connecting to the Stemma connector; one on the breakout board and one on the Uno R4. When connecting to the pin header, there is only one set.