Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SERCOM I2C not working on pins PA08, PA09 #383

Open
garageeks opened this issue Jan 23, 2019 · 15 comments
Open

SERCOM I2C not working on pins PA08, PA09 #383

garageeks opened this issue Jan 23, 2019 · 15 comments

Comments

@garageeks
Copy link

garageeks commented Jan 23, 2019

Hardware platform: Sparkfun SAMD21 Mini Breakout + BME280 sensor + VL53L0X sensor
Software platform: Arduino 1.8.3, Arduino SAMD Boards 1.6.20, Sparkfun SAMD21 boards 1.5.3, Windows 10 Pro 1803

Aim:

  • setup an additional hardware I2C bus on pins PA08, PA09 in addition to the default one on pins PA22, PA23.

Result:

  • different units of the same sensor work on default I2C (SERCOM3) as well as on PA16, PA17 (SERCOM1), but fails to work on pins PA08, PA09 (both SERCOM0 and SERCOM2_ALT)
  • We tested different sensor (VL53L0X), different BME280 libraries (Adafruit and Sparkfun) and different Sparkfun boards but the issue persists.

Steps to reproduce:

  1. Connect sensor SDA, SCL to pin 4, 3 of said board (corresponding to pin PA08, PA09 of SAMD21)
  2. Upload this code:
#include <Wire.h>
#include "wiring_private.h" // pinPeripheral() function
#include <SparkFunBME280.h>

TwoWire myWire(&sercom0, 4, 3);

BME280 bme1; // I2C

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(4, PIO_SERCOM);
  pinPeripheral(3, 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);
}
  1. Sketch is stuck at "Initializing I2C on pins 4,3"
  2. Now connect sensor SDA, SCL to pin 11,13 of the MCU
  3. Upload the code with these changes:
TwoWire myWire(&sercom1, 11, 13);
  pinPeripheral(11, PIO_SERCOM);
  pinPeripheral(13, PIO_SERCOM);
  1. Sketch is running normally and outputting sensor temperature
@facchinm
Copy link
Member

facchinm commented Jan 24, 2019

Hi @garageeks ,
your code is probably stuck here
https://github.com/arduino/ArduinoCore-samd/blob/master/cores/arduino/SERCOM.cpp#L385-L399
maybe due to the fact that sercom0 is being used by Serial1 in most variants.
Would you mind switching to SERCOM2_ALT mode and see if it works?

TwoWire myWire(&sercom2, 4, 3);
  pinPeripheral(4, PIO_SERCOM_ALT);
  pinPeripheral(3, PIO_SERCOM_ALT);

@alexwhittemore
Copy link

Heads up - I imagine that'll solve your problem. But I'm running into my own problem using the alternate SERCOM on those pins, but in slave mode. It seems that "onRequestCallback" always gets handled before "onReceiveCallback" in situations where a write happens quickly before a read for the sake of setting an address.

I'm curious, therefore, if you've run into any oddities using i2c on those pins.

@garageeks
Copy link
Author

Dear @facchinm , apologies for the enormous delay, had to resume this project now.
I'm using the latest Arduino SAMD Boards version 1.8.2 and SparkFun SAMD Boards 1.6.2 now, but this bug is still occurring.
The code in the original post results in this output:

SAMD21 Test Initialization

Initializing I2C on pin 4, 3
Inizialized, looking for sensor

I have tried using sercom2 alternate mode as per instructions, it still freezes.
Oddily enough, if I run a simple I2C scanner routine the device is detected, but then any attempt to use that device causes a freeze.

Unfortunately this is the only SAMD21 board I currently have, could you please try to use a I2C device on pins PA08, PA09 on a Arduino Zero? Maybe the bug is in the SparkFun definitions.
I'm also receiving an ATMEL ICE board soon so if you need low level debugging I can assist you.

@garageeks
Copy link
Author

I have used this software bit-bang I2C emulation library on pins PA08, PA09 and works fine
https://github.com/felias-fogg/SlowSoftI2CMaster

I don't see any issues hardware-wise, could be some wrong SERCOM initialization?

@alexwhittemore
Copy link

I'm not convinced it's related at all, but here's a corroborated issue for I2C slave mode failing. Seems sercom/pin independent, in that case.

#398 (comment)

@sslupsky
Copy link

I am using PA08 and PA09 for I2C. I have not noticed any problems at this point.

@sslupsky
Copy link

I should mention that I did come across a problem with the I2C stop bit timing where the stop bit is suppressed if you go to sleep right away. This issue is independent of which sercom port I am using.

@garageeks
Copy link
Author

@sslupsky thank you for your feedback. I'm not using sleep at the moment.
Can you tell me more about your setup? Board model, board core version, library used?
Thank you
Nick

@garageeks
Copy link
Author

@alexwhittemore you're right in saying that PA08 is the only pin on the MCU with a non-maskable interrupt. Maybe is this the issue?

@garageeks
Copy link
Author

Got the ATMEL ICE and currently debugging a sample sketch on Atmel Studio.
The code is stuck in sercom.cpp, line 497, function SERCOM::startTransmissionWIRE(address 126, flag WIRE_WRITE_FLAG)
while ( !isBusIdleWIRE() && !isBusOwnerWIRE() );
Apparently these two conditions are never met.

The funny fact is that this function is called by this instruction in Wire.cpp, line 124, function endTransmission:
if ( !sercom->startTransmissionWIRE( txAddress 63, WIRE_WRITE_FLAG ) )

Why startTransmissionWIRE is called with address 63 and then is working on address 126?

Anyway, I still to wrap my head on this, if you can point into which direction to see, ATMEL Studio debugger is powerful. I can report the status of the SERCOM registers for instance.

Here's the stack trace

FONAtest_2ndGenPlusI2C.elf! SERCOM::startTransmissionWIRE (SERCOM * const this, uint8_t address, SercomWireReadWriteFlag flag, SercomWireReadWriteFlag flag@entry) Line: 497
FONAtest_2ndGenPlusI2C.elf! TwoWire::endTransmission (TwoWire * const this, bool stopBit) Line: 124
FONAtest_2ndGenPlusI2C.elf! TwoWire::endTransmission (TwoWire * const this) Line: 154
FONAtest_2ndGenPlusI2C.elf! LiquidCrystal_I2C::expanderWrite (LiquidCrystal_I2C * const this, LiquidCrystal_I2C * const this@entry, uint8_t _data) Line: 246
FONAtest_2ndGenPlusI2C.elf! LiquidCrystal_I2C::begin (LiquidCrystal_I2C * const this, LiquidCrystal_I2C * const this@entry, uint8_t cols, uint8_t lines, uint8_t dotsize, uint8_t dotsize@entry) Line: 66
FONAtest_2ndGenPlusI2C.elf! LiquidCrystal_I2C::init_priv (LiquidCrystal_I2C * const this, LiquidCrystal_I2C * const this@entry) Line: 46
FONAtest_2ndGenPlusI2C.elf! LiquidCrystal_I2C::init (LiquidCrystal_I2C * const this, LiquidCrystal_I2C * const this@entry, TwoWire & i2c_bus) Line: 40
FONAtest_2ndGenPlusI2C.elf! setup Line: 73
FONAtest_2ndGenPlusI2C.elf! main Line: 47

Here is the sketch code. Standard I2C on pins A4, A5 works fine and it is used to control a MCP23008 I2C expander.

`
#include <Arduino.h> // required before wiring_private.h
#include "wiring_private.h" // pinPeripheral() function
#include <Adafruit_Sensor.h>
#include "Adafruit_MCP23008.h"
#include "Wire.h"
#include <LiquidCrystal_I2C.h>

#define ioRightLedPin 7
#define ioModemPin 3

TwoWire Wire1(&sercom0, 4, 3);

//I2C expander library init
Adafruit_MCP23008 mcp;

LiquidCrystal_I2C lcd(0x3F,16,2);

// this is a large buffer for replies
char replybuffer[255];
Uart Serial1 (&sercom4, 5, 2, SERCOM_RX_PAD_3, UART_TX_PAD_2); //GPRS modem - alt SERCOM pins

void SERCOM4_Handler()
{
Serial1.IrqHandler();
}

void setup() {
while (!SerialUSB);

SerialUSB.begin(115200);
Serial1.begin(115200);
SerialUSB.println(F("FONA basic test"));
SerialUSB.println(F("Initializing....(May take 3 seconds)"));
Wire1.begin();
Wire.begin();
pinPeripheral(0, PIO_SERCOM_ALT);
pinPeripheral(1, PIO_SERCOM_ALT);
pinPeripheral(2, PIO_SERCOM_ALT);
pinPeripheral(3, PIO_SERCOM);
pinPeripheral(4, PIO_SERCOM);
pinPeripheral(5, PIO_SERCOM_ALT);
pinPeripheral(6, PIO_SERCOM);
pinPeripheral(7, PIO_SERCOM);
pinPeripheral(11, PIO_SERCOM);
pinPeripheral(13, PIO_SERCOM);

mcp.begin();
delay(100);
mcp.pinMode(3, OUTPUT);
mcp.pinMode(7, OUTPUT);
delay(100);
mcp.digitalWrite(3, HIGH);
mcp.digitalWrite(7, HIGH);

intI2Cscanner();
SerialUSB.println(F("Initializing LCD."));
lcd.init(Wire1); // initialize the lcd

// Print a message to the LCD.
lcd.backlight();
lcd.print("Welcome!");
delay(3000);
lcd.clear();
SerialUSB.println(F("Ready to accept AT commands."));
}

void loop () {
if (Serial1.available()) {
int inByte = Serial1.read();
SerialUSB.write(inByte);
lcd.print(char(inByte));
}

// read from port 0, send to port 1:
if (SerialUSB.available()) {
int inByte = SerialUSB.read();
Serial1.write(inByte);
}
}

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

SerialUSB.println(F("Int I2C 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.
Wire1.beginTransmission(address);
error = Wire1.endTransmission();

if (error == 0)
{
  SerialUSB.print(F("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(F("Unknown error at address 0x"));
  if (address<16)
    SerialUSB.print("0");
  SerialUSB.println(address,HEX);
}    

}
if (nDevices == 0)
SerialUSB.println(F("No I2C devices found"));
else
SerialUSB.println(F("done"));

}`

@alexwhittemore
Copy link

@garageeks

you're right in saying that PA08 is the only pin on the MCU with a non-maskable interrupt. Maybe is this the issue?

That is true, but I'm pretty certain it's not the issue, since Chris over on that other issue I linked reproduced the problem on a different set of pins neither of which have NMI on them.

Our issues may be completely unrelated, and likely are. I came here because the pins are the same and yours was one of the first existing issues I found, but the overlap may end there.

@garageeks
Copy link
Author

@facchinm Dear Martino, the issue is still ongoing, I tried different boards, different SW releases, but I cannot make I2C work on pins PA08, PA09, both SERCOM0 and SERCOM2_ALT won't work.
I'd be more than happy to help you in debugging this if you can point me in the right direction.

@sslupsky you have it working, could you please share which board are you using, and which board version in the Arduino IDE are you using? If you have a sample code to try, it would be awesome.

@sslupsky
Copy link

I am using the MKR WAN 1300 and 1310. I will dig up my initialization and post it.

@sslupsky
Copy link

Hi @garageeks

I checked my configuration and for that interface I am using the default configuration for the board I am using (MKR WAN 1300 and 1310). These variants specify that PA08/PA09 are assigned to the TwoWire interface "Wire" using SERCOM2. Here is a snippet from the variant.h for the MKR WAN 1300:

// Wire
#define PIN_WIRE_SDA        (11u)
#define PIN_WIRE_SCL        (12u)
#define PERIPH_WIRE         sercom2
#define WIRE_IT_HANDLER     SERCOM2_Handler

Have you got pull up resistors on those pins? The Sparkfun Mini board does not have pull ups so you need to add them or ensure that the board you are using has them and they are connected.

@DeltaAerospace
Copy link

DeltaAerospace commented Oct 18, 2023

I am getting the same issue using PA08 and PA09 on the ATSAMD21G18A-AU with an Arduino Zero bootloader on a custom PCB.--I2C Scanner does not work though.
-Normal I2C on PA22 and PA23 still work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants