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

Raspberry Pi Pico (RP2040) - I2C holds SCL low #448

Open
marmil opened this issue Apr 7, 2022 · 5 comments
Open

Raspberry Pi Pico (RP2040) - I2C holds SCL low #448

marmil opened this issue Apr 7, 2022 · 5 comments

Comments

@marmil
Copy link

marmil commented Apr 7, 2022

Hi everybody,

i am currently trying to implement an I2C connection between an ESP32-WROVER and a Raspberry Pi Pico (RP2040). The ESP is configured as master and shall request data from the Pico which is configured as slave. Besides requesting data the master also sends data to the slave.
After encountering some issues that the I2C communication is not working properly i created a minimal example for master and slave where the problem still occurs. Regularly the I2C times out (diagnosed by ESP via Debug messages and Logic analyzer - see below) and no data can be transmitted anymore. Pullups of SDA/SCL should be fine with 3K3.

First the program-code of the slave, then some measures&measurements i already took/did and in the end the despaired beg for help finding the problem which i assume in the I2C implementation.

Slave (Pico) Code:

#include <Arduino.h>
#include <Wire.h>

#define DATABYTES   6

unsigned long lastLEDToggle = 0;
#define LED_INTERVAL 750
bool LEDstatus = HIGH;

#define I2C_SLAVE_ADDRESS 0x18

MbedI2C myI2C(14, 15);
uint8_t tmpRcvdData[DATABYTES];
uint8_t tmpRcvdDataInc;

uint8_t writeBuffer[DATABYTES] = {0x12};

void initCommunication();
void setupCommunication();

void onReceive(int numBytes);
void onRequest();


void setup() {

  pinMode(LED_BUILTIN, OUTPUT);
  
  setupCommunication();

}

void loop() {

  if (millis() - lastLEDToggle > LED_INTERVAL) {

    digitalWrite(LED_BUILTIN, LEDstatus);
    LEDstatus = !LEDstatus;

    lastLEDToggle = millis();

  }

}

void setupCommunication() {
  
  initCommunication();

  myI2C.onReceive(onReceive);
  myI2C.onRequest(onRequest);

}

void initCommunication() {

  myI2C.begin(I2C_SLAVE_ADDRESS);
  myI2C.setClock(800000);

}

void onReceive(int numBytes) {

  tmpRcvdDataInc = 0;

  while (myI2C.available() && tmpRcvdDataInc < DATABYTES) {
    tmpRcvdData[tmpRcvdDataInc] = myI2C.read();
    tmpRcvdDataInc++;
  }

  while (myI2C.available() ) {
    myI2C.read(); // clear buffer
  }
  
  
}

void onRequest() {

  myI2C.write(writeBuffer, DATABYTES);
  
}

What did i try already?

  • Changing the interval of requests and writings by the master: I varied between 200 ms and 10 secs without any change of the problem besides it adapts of course to the varied time
  • Implement a delay between requests and writes on master side: Even with stopping requests and first writing few secs after last request (and other way around) the problem is not solved
  • Vary the I2C frequency: Changing between 100 kHz and 800 kHz did not make any difference
  • Try only requesting or only writing: If i only write from master to slave or only do requests the problem does not occur but that does not fit to my use case

Measurements & Logs

ESP Debug message incl. some serial output i had on master side:

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:10124
load:0x40080400,len:5828
entry 0x400806a8
Requesting Slave
Slave answered 12 0 0 0 0 0
Requesting Slave
Slave answered 12 0 0 0 0 0
Requesting Slave
Slave answered 12 0 0 0 0 0
Requesting Slave
Slave answered 12 0 0 0 0 0
Writing Slave
Requesting Slave
[D][esp32-hal-i2c.c:1353] i2cProcQueue():  Gross Timeout Dead start=0x4e59, end=0x4e8b, =50, max=50 error=1
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdbb4
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb844c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84d4 bits=0
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb8508
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb84b0
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
[I][esp32-hal-i2c.c:311] i2cDumpDqData(): Debug Buffer not Enabled
[I][esp32-hal-i2c.c:354] i2cDumpInts(): Debug Buffer not Enabled
 0
Requesting Slave
[I][esp32-hal-i2c.c:1138] i2cProcQueue(): Bus busy, reinit
[W][esp32-hal-i2c.c:1419] i2cCheckLineState(): invalid state sda(21)=0, scl(22)=1
[D][esp32-hal-i2c.c:1427] i2cCheckLineState(): Recovered after 3 Cycles
[D][esp32-hal-i2c.c:1353] i2cProcQueue():  Gross Timeout Dead start=0x52cf, end=0x5301, =50, max=50 error=1
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdbb4
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb844c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84d4 bits=0
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb8508
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb84b0
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=-1
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
[I][esp32-hal-i2c.c:311] i2cDumpDqData(): Debug Buffer not Enabled
[I][esp32-hal-i2c.c:354] i2cDumpInts(): Debug Buffer not Enabled
0
Requesting Slave
[I][esp32-hal-i2c.c:1138] i2cProcQueue(): Bus busy, reinit
[W][esp32-hal-i2c.c:1419] i2cCheckLineState(): invalid state sda(21)=1, scl(22)=0
[D][esp32-hal-i2c.c:1427] i2cCheckLineState(): Recovered after 1 Cycles
[E][esp32-hal-i2c.c:1434] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init sda=1, scl=0
0
Requesting Slave
[D][esp32-hal-i2c.c:1344] i2cProcQueue():  Busy Timeout start=0x5b36, end=0x5b68, =50, max=50 error=1
[E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbdbb4
[I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000
[I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffb844c
[I][esp32-hal-i2c.c:323] i2cDumpI2c(): num=0
[I][esp32-hal-i2c.c:324] i2cDumpI2c(): mode=1
[I][esp32-hal-i2c.c:325] i2cDumpI2c(): stage=3
[I][esp32-hal-i2c.c:326] i2cDumpI2c(): error=1
[I][esp32-hal-i2c.c:327] i2cDumpI2c(): event=0x3ffb84d4 bits=0
[I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffb8508
[I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffb84b0
[I][esp32-hal-i2c.c:330] i2cDumpI2c(): queueCount=1
[I][esp32-hal-i2c.c:331] i2cDumpI2c(): queuePos=0
[I][esp32-hal-i2c.c:332] i2cDumpI2c(): errorByteCnt=0
[I][esp32-hal-i2c.c:333] i2cDumpI2c(): errorQueue=0
[I][esp32-hal-i2c.c:334] i2cDumpI2c(): debugFlags=0x00000000
[I][esp32-hal-i2c.c:311] i2cDumpDqData(): Debug Buffer not Enabled
[I][esp32-hal-i2c.c:354] i2cDumpInts(): Debug Buffer not Enabled
[W][esp32-hal-i2c.c:1419] i2cCheckLineState(): invalid state sda(21)=1, scl(22)=0
[D][esp32-hal-i2c.c:1427] i2cCheckLineState(): Recovered after 1 Cycles
[E][esp32-hal-i2c.c:1434] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init sda=1, scl=0

The I2C can only be reset correctly after first restarting the Pico and then the ESP32.

I also checked the bus with a Logic analyzer:
Annotation 2022-04-07 171810
Annotation 2022-04-07 172026
Blue: SDA / Red: SCL

As promised here: Please help me :) - for me it looks like the I2C implementation has some issue with the I2C drivers of the Pico.

@marmil marmil changed the title Raspberry Pi Pico (RP2040) - I2C holds SCL down Raspberry Pi Pico (RP2040) - I2C holds SCL low Apr 7, 2022
@TareObjects
Copy link

Hi.

I am having the same trouble.

My platform is Mr.Earle Philhower version and I am using XIAO PR2040. Both SDA and SCL are pulled up at 4.7K.

The moment master send something, SCL is low. And it freezes without giving any information, so there is no clue to the solution.

@waynepiekarski
Copy link
Contributor

In the past, I've use ATmega328p devices and had problems with the I2C bus getting stuck randomly. However, at some point the Wire library added a setWireTimeout() method, where it will not get stuck in an I2C transaction any more. https://www.arduino.cc/reference/en/language/functions/communication/wire/setwiretimeout/ This isn't perfect because if one of the I2C peripherals gets stuck, you need to power cycle those peripherals to do a full bus recovery. But I found the setWireTImeout() method very useful in ensuring the software doesn't get stuck and you can then do something about it.

However, the RP2040 mbed implementation does not support setWireTimeout yet, and this would be helpful to have. It is an optional Wire feature (see URL above). I've only just started working with RP2040 and noticed this missing when I tried to port my code from ATmega328p.

@zmechu
Copy link

zmechu commented Jan 2, 2024

Hello @waynepiekarski - how about your porting setWireTimeout() into RP2040. I'm also very interested in that function - it is very useful for handling problems over I2C communication.

@waynepiekarski
Copy link
Contributor

Hello @waynepiekarski - how about your porting setWireTimeout() into RP2040. I'm also very interested in that function - it is very useful for handling problems over I2C communication.

I didn't do any implementation work for setWireTimeout(). It looks like the underlying mbed library used on the RP2040 doesn't support timeouts either last time I checked.

@thinksilicon
Copy link

Hey, I opened an isssue with arduino-esp32 thinking that it was a problem over there. After some debugging it seems like it is a problem with ArduinoCore-mbed.

Any chance this could be looked into?

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