Xiao rp2040 i2c

Just received XIAO RP2040 boards. Using with Arduino IDE, basic operations are OK (Blink LED_BUILTIN, Do various examples like reading internal Temperature, NeoPixel stuff, etc.)

Here’s my problem: Can’t get the I2C to work.

This works:

  uint8_t dev_addr7 = 0x48;
  // This works: 
  // Scope display of SCL and SDA are nominal
  // Return value of zero indicates successful ACK by device
  Wire.begin();
  Wire.beginTransmission(dev_addr7);
  uint8_t err = Wire.endTransmission();
  Serial.printf("I2C probe of 0x%02X returned %u at %lu ms\n", 
                 dev_addr7, err, millis());

If I have a device with that address attached to the I2C pins (SDA on D4, SCL on D5), all is good. It prints the proper return value of zero, the I2C pins show the transfer and show the ACK by the device.

On the other hand, the following code does not wiggle the SDA or SCL pins.

  // This doesn't work: SDA and SCL pins do not wiggle and
  // return value from endTransmission is 4 (Other problem)
  uint8_t buff[2] = {0x45, 0x54};
  Wire.beginTransmission(dev_addr7);
  Wire.write(buff[0]);
  Wire.write(buff[1]);
  err = Wire.endTransmission();
  Serial.printf("After trying to write bytes to 0x%02X: err = %d at %lu ms\n", 
                 dev_addr7, err);

Output looks like this:

I2C Test Compiled on Dec 11 2021 at 16:31:05
D5  = 7, D4  = 6
SCL = 7, SDA = 6
I2C probe of 0x48 returned 0 at 4552 ms
After trying to write bytes to 0x48: err = 4 at 4552 ms

Nothing that involves the I2C hardware Write() function works. Note that the first snippet that I showed invokes a “special case” that doesn’t call the hardware Write() function.

Bottom line: I know the RP2040 I2C module works (I have several other RP2040 boards such as the Arduino Nano 33 BLE and the Arduino Nano RP2040, which I have tested extensively), but am thinking there is something in the SeeedStudio board library that is borked.

Does anyone have any experience with the XIAO RP2040 I2C hardware? Any Suggestions? Anything at all?

My setup:

  • Arduino 1.8.16 on Windows 10
  • Seeed XIAO RP2040 Board package version1.9.3 installed in Arduino Board Manager
  • Board: “Seeed XIAO RP2040” selected in Arduino IDE

Regards,

Dave

The second code does not include Wire.begin();.

Thanks.

I didn’t make clear that the second snipped I posted immediately followed the first one in the same sketch.
Here’s the whole enchilada:

/*
 * Illustration of problem with I2C on XIAO RP2040
 * 
 * davekw7x
 * December, 2021
 */

#include <Wire.h>
void setup(void) {
  Serial.begin(115200);
  
  // Wait until the connection is made
  while (!Serial);
  
  // Give it a little time to setle down 
  delay(100);
  Serial.println("\nI2C Test Compiled on " __DATE__ " at " __TIME__);

  // These are the (default) GPIO pin numbers used by I2C on Wire
  Serial.printf("D5  = %u, D4  = %u\n", D5, D4);
  Serial.printf("SCL = %u, SDA = %u\n", SCL, SDA);

  uint8_t dev_addr7 = 0x48;
  uint8_t err;
  // This works: 
  // Scope display of SCL and SDA are nominal
  // Return value of zero indicates successful ACK by device
  Wire.begin();
  Wire.beginTransmission(dev_addr7);
  err = Wire.endTransmission();
  Serial.printf("I2C probe of 0x%02X returned %u at %lu ms\n", 
                 dev_addr7, err, millis());
  
  // This doesn't work: SDA and SCL pins do not wiggle and
  // return value from endTransmission is 4 (Other problem)
  uint8_t buff[2] = {0x45, 0x54};
  Wire.beginTransmission(dev_addr7);
  Wire.write(buff[0]);
  Wire.write(buff[1]);
  err = Wire.endTransmission();
  Serial.printf("After trying to write bytes to 0x%02X: err = %d at %lu ms\n", 
                 dev_addr7, err);

  // Infinite loop: keep it here
  while (1)
    ;
}
 
void loop(void) {
}

I have tried numerous other sequences, all with the same result: SCL and SDA bits never wiggle when trying to write to a device.

Note also, that I have more than one XIAO RP2040. They all act the same. Namely, everything that I tested, other than the I2C functionality, works as expected.

Regards,

Dave

You need:

Wire.endTransmission ();

See example:

Wire.beginTransmission (4); // transmit to device # 4
Wire.write ("x is "); // sends five bytes
Wire.write (x); // sends one byte
Wire.endTransmission (); // stop transmitting

Thanks, but…

Result is the same: No code that involves Wire.write() results in SDA and SCL pins wiggling. (And endTransmission() returns a value of 4).

The bottom line is: The same sequence (byte-at-a-time or bytes in an array or string literal) that works for me on other Arduino boards, including the Nano RP2040 Connect, does NOT work on the XIAO RP2040. Since the RP2040 hardware I2C interface is OK, I believe there is an “Issue” with the Seeed software in the board package for the XIAO RP2040.

Period. Full Stop.

Regards,

Dave

Well, I found a bug in the Seeed XIAO RP2040 board package that borked the I2C.

Here’s a summary:
The RP2040 has two I2C ports, i2c0 and I2c1. Not all pins can be assigned to a given port. It’s in the RP2040 data sheet.

The XIAO RP2040 designates package pins 5 and 6 to be SDA and SCL for I2C using i2c0. These are Arduino pins D4 and D5 (connected to RP2040 GIO Pins P6 and P7) respectively.

Now, here’s the flaw in the ointment: There are two I2C modules on the RP2040, ic0 and ic1. The Arduino Wire object uses ic0 and Wire1 uses ic1.

The Seeed package software defines SDA and SCL to be GIO pins P6 and P7, but these pins can NOT be used with ic0, so I2C for those connections with Wire is doomed. Period.

I tried to imagine (and even tested some ideas) ways to implement user-level software workarounds, but came to the conclusion that library changes would be necessary.

As an outsider, I am not able to peer into the minds of the actual code implementers. (See Footnote). However, I came up with what I think are minimum library changes to make my test program work. Note that I haven’t tested EVERYTHING that might be affected by my changes but, so far, I think my approach is valid.

Here’s the changes: I edited lines 61-65 in the file
Seeduino\hardware\rp2040\1.9.3\variants\Seed_XIAO_RP2040\pins_arduino.h

As follows

#define SDA  (28u) /* Change from (6u) davekw7x */
#define SCL  (29u) /* Change from (7u) davekw7x */

#define PIN_WIRE1_SDA  (6u) /*  Change from (26u) davekw7x */
#define PIN_WIRE1_SCL  (7u) /*  Change from (27u) davekw7x */

And now all is well (at least to the extent that I have tested). I2C looks good on the 'scope, and the target device works as expected.

Some output from the attached slightly-more-edifying test program:

I2C Test Compiled by davekw7x on Dec 20 2021 at 12:01:40
Board is Seeed XIAO RP2040

I changed definitions for SCL, SDA, PIN_WIRE1_SCL, and PIN_WIRE1_SDA
in 'variants\Seed_XIAO_RP2040\pins_arduino.h'
  For Wire
    #define SDA  (28u) /* Change from (6u) davekw7x */
    #define SCL  (29u) /* Change from (7u) davekw7x */
  For Wire1
    #define PIN_WIRE1_SDA  (6u) /*  Change from (26u) davekw7x */
    #define PIN_WIRE1_SCL  (7u) /*  Change from (27u) davekw7x */

With these modifications, here are the default 'Arduino' pin connections
for the Seeed XIAO RP2040
  For Wire
    SCL is 'Arduino' D3 = GPIO29, and SDA is 'Arduino' D2 = GPIO28
  For Wire1
    SCL is 'Arduino' D5 = GPIO7, and SDA is 'Arduino' D4 = GPIO6

I2C probe of 0x48 on Wire1 returned 0 at 350 ms
After trying to write bytes to 0x48 on Wire1: err = 0 at 350 ms

Bottom line IWFMYMMV (It Works For Me; Your Mileage May Vary).

Would appreciate feedback from Seeed support people, as I couldn’t find a way to submit an “official” bug report.

Regards,

Dave
I2CForForum.zip (1.5 KB)

2 Likes

I use Wire (I2C0) and Wire1 (I2C1) properly in the sketch.

When using Wire (I2C0)
Wire.setSDA (D2);
Wire.setSCL (D3);
Wire.begin ();

When using Wire1 (I2C1)
Wire1.setSDA (D4);
Wire1.setSCL (D5);
Wire1.begin ();

I checked some sketches and they are working fine.

1 Like

Thanks!

Regards,
Dave