SAMD21 Mini breakout: Can't get new I2C bus working with SERCOM

Hi to all,

For my new project I need to reconfigure the SERCOMs to get three UART and three I2C buses.

I have been following these guides:

[<LINK_TEXT text=“https://learn.adafruit.com/using-atsamd … a-new-wire”>https://learn.adafruit.com/using-atsamd21-sercom-to-add-more-spi-i2c-serial-ports/creating-a-new-wire</LINK_TEXT>

[https://www.arduino.cc/en/Tutorial/SamdSercom

The three UART work, however I cannot get the secondary Wire to work.

The hardware is a Sparkfun SAMD21 Mini and three BME280 sensors, connected to pins as follows, with 4k7 pullups (SDA, SCL): (A4, A5), (4, 3), (11, 13)

I carefully selected the pins out of the table in the SAMD21 datasheet, they should be correct.

The first bus is default and works, the 2nd is on SERCOM0 and the 3rd on SERCOM1.

This is the test code for a single Wire:

#include "wiring_private.h" // pinPeripheral() function
#include <Wire.h>
#include <SparkFunBME280.h>

TwoWire myWire(&sercom0, 4, 3);

BME280 bme1; // I2C

void SERCOM0_Handler(void);

void SERCOM0_Handler(void) {
    myWire.onService();
}

void setup() {
  // put your setup code here, to run once:
 SerialUSB.begin(115200);
  while (!SerialUSB) {
    ; // wait for serial port to connect
  }

  SerialUSB.println("SAMD21 Test Initialization");
  SerialUSB.println();

   SerialUSB.println("Initializing I2C on pin 4, 3");

  
  myWire.begin();
  pinPeripheral(3, PIO_SERCOM);
  pinPeripheral(4, PIO_SERCOM);
  SerialUSB.println("Inizialized, looking for sensor");
   if(bme1.beginI2C(myWire) == false) {
    SerialUSB.println("Sensor NOT found!");
  } else {
    SerialUSB.println("Sensor found");
  }
}

void loop() {
  // put your main code here, to run repeatedly:
    SerialUSB.print("Sensor 2 temp: ");
    SerialUSB.println(bme1.readTempC(), 2);
    delay(5000);
}

The sketch will be stuck at “Inizialized, looking for sensor”.

Tried to do the same with Adafrult BME280 library, still stuck.

If I run the I2C scanner code, the device is correctly found at address 0x77 so at least something is clicking.

Need to change anything in variants.cpp / variants.h?

Any other advice?

Thank you!

Nick](https://www.arduino.cc/en/Tutorial/SamdSercom)](Creating a new Wire | Using ATSAMD21 SERCOM for more SPI, I2C and Serial ports | Adafruit Learning System)

Looks like we’ve added our own tutorial on this since you posted. Feel free to check this out. I ended up using those pins in my example, but on Sercom 2. Also it looks like you don’t need the Handler Function for this. Let us know if you were able to figure this out or if you have any other questions.

https://learn.sparkfun.com/tutorials/ad … amd-boards

Hi,

I come back on this point because I am also trying to add another I2C interface to the SAMD21 Mini Breakout.

In detail I don’t want to use the existing one on Sercom3 (D20 and D21) due to the “non breadboard friendly” configuration.

I’ve read the tutorial (Sparkfun’s one) mentioned above by @agentsmithitaly and if my understanding is correct I should be able to use Sercom4 (A1 and A2) because they are not used by any other Serial interface on this board.

My aim is to display some test text on a Adafruit SSD1306 128x32 Oled display, of course connected via I2C, but nothing happens… display is properly powered ON but no text appears!

My code is as follows, is there any clear mistake that I am not able to see?

(I triple checked connections on the breadboard, everything seems fine)

#include <SPI.h>
#include <Wire.h> 
#include "wiring_private.h" // pinPeripheral() function
#include <Adafruit_SSD1306.h> // DISPLAY lib

//A1 SDA, A2 SCL
TwoWire myWire(&sercom4, A1, A2);
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(128, 32, &Wire, OLED_RESET);

void setup() {
  SerialUSB.begin(9600);
  myWire.begin();
  pinPeripheral(A2, PIO_SERCOM_ALT);
  pinPeripheral(A1, PIO_SERCOM_ALT);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    SerialUSB.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  SerialUSB.println("OLED begun");
  // Show initial display buffer contents on the screen -- the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds
  // Clear the buffer.
  display.clearDisplay();
  display.display();
  // text display tests
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println("SETUP TEXT TEST");
  SerialUSB.println("DEBUG end Setup");
  delay(3000);
}

void loop() {
  display.print("TEST");
  delay(10);
  yield();
  display.display();
  SerialUSB.println("DEBUG end Loop");
}

I reply to myself because I have the feeling to be missing something BIG about the SAMD21 Mini breakout.

I tried to do a simple ISC scan with my new ISC on the desired Sercom4, this is the code:

#include <Wire.h>
#include "wiring_private.h" // pinPeripheral() function

//NOW A1 SDA, A2 SCL
TwoWire myWire(&sercom4, A1, A2);

void setup()
{
  myWire.begin();
  //Wire.begin();
  SerialUSB.begin(9600);
  SerialUSB.println("\nI2C Scanner");
}


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

  SerialUSB.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.
    
    myWire.beginTransmission(address);
    error = myWire.endTransmission();
    //Wire.beginTransmission(address);
    //error = Wire.endTransmission();

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

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

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

2 problems/doubts:

Serial output is completely blank, not even the SerialUSB.println(“\nI2C Scanner”); in the setup seems to be working. As it is not working the SerialUSB.println(“OLED begun”); from the original OLED code I posted before. This is 1st and biggest doubt.

In this ISC scanner code there are also - commented - the normal wire lines for normal I2C scan, if I comment all the myWire related lines and uncomment the Wire , so restoring the original I2C Scanner code, I get weird output, see attached screenshot. In this case nothing is connected to the I2C bus, so this is 2nd doubt I have.

Any suggestion? I start feeling lost :slight_smile:

I2C problem.png

When you see a device on every address, that sometimes indicates something is stuck on the bus holding one of the lines high or low.

And what if there is nothing on the bus, like in my case?

I ran the I2C scanner with just the Samd21 breakout :frowning:

If nothing is showing, it could be multiple issues including the fact that nothing is on the bus, which would be the expected output.

Other things that it could be assuming you have a working I2C device attached:

  • you’re physically using the wrong pins.

  • you don’t have pull up resistors on the bus

  • there’s a broken connection somewhere

  • another device on the bus might be causing a problem

  • you might not have the sercoms setup correctly or are using incompatible pins

  • something is wrong with your code.

Starting with a known good setup and code would be a good idea just to make sure everything is working properly. Once that’s going for you just make small changes and test between every change. That way you know where to start looking for the cause.

Hi @YellowDog and thanks for your reply.

Your notes are correct, but I still don’t know how to approach my situation.

  • setup is the simplest possible, i.e. the SAMD21 mini breakout only

  • is is working (blink example with the 3 leds) so there shouldn’t be any serious HW issue

  • I don’t have anything connected to the bus - or to any other pin - so no broken connection o no device causing problems

  • code is the simplest possible (standard I2C_scan example) so I don’t see anything wrong with it

  • apart my main issue with the “new” I2C on a new sercom, in the I2C_scanner code I use the standard sercoms so I should be avoiding also the " you might not have the sercoms setup correctly or are using incompatible pins" issue.

In the light of this, any specific suggestion for my situation?

Even if there is a test to do, any idea would be appreciated :slight_smile:

You might start with a known good example like the one below and get that working with your code but on the same pins in the example first, then you can start tailoring things to your pins.

https://learn.sparkfun.com/tutorials/ad … ing-an-i2c

Global set the “Potential” SDA to A1 and “Potential” SCL to A2 :

TwoWire myWire(&sercom4, A1, A2);

In setup():

myWire.begin();

It will initialize the pins as defined in the variant folder. In this case as ADC1 and ADC2 as that is default setup to connect to ADC. As you want to connect to SERCOM4 , make sure to add always after being() in Setup() :

pinPeripheral(A2, PIO_SERCOM_ALT);
pinPeripheral(A1, PIO_SERCOM_ALT);

This will set A1 pin and A2 pin to connect to SERCOM_ALT (as defined in the datasheet ). A1 Pin is now connected to SERCOM4:0 (or SDA) and A2 pin is now connected SERCOM4:1 (or SCL).

Now as YellowDog pointed out, BOTH SCL and SDA line needs a pullup (SDA and SCL will only pull to GND)

Hi

it took me some time but I followed both your suggestions and now it is working, thanks so much!

The only mystery left is why with the SAMD21 any SerialUSB.println that I put in the setup() doesn’t show me ANYTHING on serial monitor.

In the loop() OK, in the setup() no. Any clue?

Try setting setting a loop after SerialUSB.begin(9600);:

{ delay(500); } while(!SerialUSB);

On some boards, the ports need time to stabilize and connect to the monitor