stickbreaker / arduino-esp32

Arduino core for the ESP32
38 stars 24 forks source link

i2c from second core fails (MCP23017) #30

Closed chinswain closed 6 years ago

chinswain commented 6 years ago

Hardware:

Board: LOLIN32 Core Installation/update date: Main + latest stickbreaker patched i2c files IDE name: Arduino IDE Flash Frequency: 40Mhz Upload Speed: 115200

Description:

The below code works great when calling checkRpmPins(); from within the main loop, however, when calling mcp.digitalRead(0); from a second core task I get the below error. When using digitalRead(0);

I'm guessing a timing issue when using the second core? I'm not sure if anyone's tried calling from the second core for i2c? I'm counting the RPM value from 16 fans (hall effect sensors) so timing is critical which is why I'm complicating things. :)

Sketch:

#include <Wire.h>
#include "Adafruit_MCP23017.h"

#define NUM_RPM (sizeof(rpmPins)/sizeof(rpmPins[0]))

int rpmPin = 0;
static volatile uint16_t rpmcounter;

Adafruit_MCP23017 mcp;
TaskHandle_t Task1;

void checkRpmPins() {

  static bool lastPinState;

  if (mcp.digitalRead(rpmPin) != lastPinState) {
    lastPinState = !lastPinState;
    if (lastPinState) {
      rpmcounter++;
    }
  }
}

void coreTask( void * parameter)
{
  while (true) {
    vTaskDelay(1);
  }
}

void setup() {
  Serial.begin(115200);
  mcp.begin();      // use default address 0

  mcp.pinMode(0, INPUT);
  mcp.pullUp(0, HIGH);

  xTaskCreatePinnedToCore(
    coreTask,   /* Function to implement the task */
    "coreTask", /* Name of the task */
    10000,      /* Stack size in words */
    NULL,       /* Task input parameter */
    0,          /* Priority of the task */
    &Task1,       /* Task handle. */
    0);  /* Core where the task should run */

  delay(100);

}

void loop() {
  checkRpmPins();
  static unsigned long lastmillis = 0;
  int rpm;

  if (millis() - lastmillis >= 1000) {

    lastmillis = millis();

    rpm = rpmcounter * 30;
    rpmcounter = 0;

    Serial.print("fan ");
    Serial.print(": ");
    Serial.print(rpm);
    Serial.print("\t");

    Serial.println();
  }

}

Debug Messages:

[E][esp32-hal-i2c.c:593] i2cDumpDqData(): [0] 40 W STOP buf@=0x3ffc24ce, len=1, pos=1, eventH=0x0 bits=0
[E][esp32-hal-i2c.c:609] i2cDumpDqData(): 0x0000: .                                12 
[E][esp32-hal-i2c.c:948] i2cDumpInts(): 1 row  count   INTR    TX     RX
[E][esp32-hal-i2c.c:951] i2cDumpInts(): [01] 0x0001 0x0202 0x0002 0x0000 0x00002340
[E][esp32-hal-i2c.c:951] i2cDumpInts(): [02] 0x0001 0x0040 0x0000 0x0000 0x00002340
[E][esp32-hal-i2c.c:951] i2cDumpInts(): [03] 0x0001 0x0020 0x0000 0x0000 0x00002340
[I][esp32-hal-i2c.c:971] i2cProcQueue(): Bus busy, reinit
[E][esp32-hal-i2c.c:620] i2cDumpI2c(): i2c=0x3ffc1060
[E][esp32-hal-i2c.c:621] i2cDumpI2c(): dev=0x60027000 date=0x16042000
[E][esp32-hal-i2c.c:623] i2cDumpI2c(): lock=0x3ffc5d78
[E][esp32-hal-i2c.c:625] i2cDumpI2c(): num=1
[E][esp32-hal-i2c.c:626] i2cDumpI2c(): mode=1
[E][esp32-hal-i2c.c:627] i2cDumpI2c(): stage=3
[E][esp32-hal-i2c.c:628] i2cDumpI2c(): error=5
[E][esp32-hal-i2c.c:629] i2cDumpI2c(): event=0x3ffc5dfc bits=112
[E][esp32-hal-i2c.c:630] i2cDumpI2c(): intr_handle=0x3ffc5e2c
[E][esp32-hal-i2c.c:631] i2cDumpI2c(): dq=0x3ffc5dd8
[E][esp32-hal-i2c.c:632] i2cDumpI2c(): queueCount=1
[E][esp32-hal-i2c.c:633] i2cDumpI2c(): queuePos=0
[E][esp32-hal-i2c.c:634] i2cDumpI2c(): byteCnt=1

Libraries used:

https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library

Digital read function:

uint8_t Adafruit_MCP23017::digitalRead(uint8_t pin) {
    uint8_t bit=bitForPin(pin);
    uint8_t regAddr=regForPin(pin,MCP23017_GPIOA,MCP23017_GPIOB);
    return (readRegister(regAddr) >> bit) & 0x1;
}
stickbreaker commented 6 years ago

@chinswain The ISR executes on the core that it was registered on. The ISR is registered during the first Wire.endTransmission() or Wire.requestFrom().

The Bus_Busy status is created/monitored by the hardware. The I2C hardware monitors the signal on the i/o pins, it does not know which core is accessing it. I don't see how this error could be generated by using different cores. Check your pullups.

Chuck.

chinswain commented 6 years ago

Sorry chuck, didn't even think about that... I have a logic analyser and oscilloscope on the way which should help tune the pull ups.

This module has 10k pull ups built in (seem fine on their own, does having two i2c interfaces have any impact on the pull ups required or do the same rules apply to each?), I'll remove them and test with some lower ones (DIP version also ordered).

On a related note, I've managed to get i2c over 10 metres with the latest changes!

Fixed code for reference:


#include <Wire.h>
#include "Adafruit_MCP23017.h"

int rpmPin = 0;
static volatile uint16_t rpmcounter;

Adafruit_MCP23017 mcp;
TaskHandle_t Task1;

void checkRpmPins() {

  static bool lastPinState;

  if (mcp.digitalRead(rpmPin) != lastPinState) {
    lastPinState = !lastPinState;
    if (lastPinState) {
      rpmcounter++;
    }
  }
}

void coreTask( void * parameter)
{
  mcp.begin();      // use default address 0
  mcp.pinMode(0, INPUT);
  mcp.pullUp(0, HIGH);

  while (true) {
    vTaskDelay(1);
    checkRpmPins();
  }
}

void setup() {
  Serial.begin(115200);

  xTaskCreatePinnedToCore(
    coreTask,   /* Function to implement the task */
    "coreTask", /* Name of the task */
    10000,      /* Stack size in words */
    NULL,       /* Task input parameter */
    0,          /* Priority of the task */
    &Task1,       /* Task handle. */
    0);  /* Core where the task should run */

  delay(100);

}

void loop() {

  static unsigned long lastmillis = 0;
  int rpm;

  if (millis() - lastmillis >= 1000) {

    lastmillis = millis();

    rpm = rpmcounter * 30;
    rpmcounter = 0;

    Serial.print("fan ");
    Serial.print(": ");
    Serial.print(rpm);
    Serial.print("\t");

    Serial.println();
  }

}
stickbreaker commented 6 years ago

@chinswain i2c was designed for usage on one board with a total bus length < 1m. With a long bus, pullup values must be calibrated to bus capacitance. They make transceivers/ bus extenders for long lines. You could be seeing crosstalk, reflection spikes, good luck.

Chuck.

chinswain commented 6 years ago

@stickbreaker I'm using a pair of P82B715 break outs to boost the current. Once the oscilloscope arrives I can start some proper calibration.

wanqbabay commented 5 years ago

Hi ! @stickbreaker I have met the same question: if i creat the task on Core (1)or run the function in the loop, i can get the right datas from the I2C bus (the sensor: MAX30102). However ,if i creat the task on Core (0),the question appears: here it the log: [E][esp32-hal-i2c.c:630] i2cDumpI2c(): i2c=0x3ffc10cc [E][esp32-hal-i2c.c:641] i2cDumpI2c(): dev=0x60013000 date=0x16042000 level=VERBOSE [E][esp32-hal-i2c.c:643] i2cDumpI2c(): lock=0x3ffd2a8c [E][esp32-hal-i2c.c:645] i2cDumpI2c(): num=0 [E][esp32-hal-i2c.c:646] i2cDumpI2c(): mode=1 [E][esp32-hal-i2c.c:647] i2cDumpI2c(): stage=3 [E][esp32-hal-i2c.c:648] i2cDumpI2c(): error=5 [E][esp32-hal-i2c.c:649] i2cDumpI2c(): event=0x3ffd2b10 bits=112 [E][esp32-hal-i2c.c:650] i2cDumpI2c(): intr_handle=0x3ffea498 [E][esp32-hal-i2c.c:651] i2cDumpI2c(): dq=0x3ffd2b40 [E][esp32-hal-i2c.c:652] i2cDumpI2c(): queueCount=1 [E][esp32-hal-i2c.c:653] i2cDumpI2c(): queuePos=0 [E][esp32-hal-i2c.c:654] i2cDumpI2c(): byteCnt=1 [E][esp32-hal-i2c.c:604] i2cDumpDqData(): [0] ae W STOP buf@=0x3ffc50aa, len=1, pos=1, eventH=0x0 bits=0 [E][esp32-hal-i2c.c:620] i2cDumpDqData(): 0x0000: . 00 [E][esp32-hal-i2c.c:968] i2cDumpInts(): 0 row count INTR TX RX [E][esp32-hal-i2c.c:971] i2cDumpInts(): [01] 0x0001 0x0202 0x0002 0x0000 0x000034b9 [E][esp32-hal-i2c.c:971] i2cDumpInts(): [02] 0x0001 0x0040 0x0000 0x0000 0x000034b9 [E][esp32-hal-i2c.c:971] i2cDumpInts(): [03] 0x0001 0x0020 0x0000 0x0000 0x000034b9 [I][esp32-hal-i2c.c:1002] i2cProcQueue(): Bus busy, reinit [E][esp32-hal-i2c.c:1246] i2cReleaseISR(): Error releasing ISR=258 [E][Wire.cpp:137] initHardware(): invalid state sda=0, scl=1

[E][Wire.cpp:155] initHardware(): Bus Invalid State, TwoWire() Can't init [E][esp32-hal-i2c.c:1193] i2cProcQueue(): Busy Timeout start=0x3532, end=0x3532, =0, max=50 error=1 [E][esp32-hal-i2c.c:630] i2cDumpI2c(): i2c=0x3ffc10cc [E][esp32-hal-i2c.c:641] i2cDumpI2c(): dev=0x60013000 date=0x16042000 level=VERBOSE [E][esp32-hal-i2c.c:643] i2cDumpI2c(): lock=0x3ffd2a8c [E][esp32-hal-i2c.c:645] i2cDumpI2c(): num=0 [E][esp32-hal-i2c.c:646] i2cDumpI2c(): mode=1 [E][esp32-hal-i2c.c:647] i2cDumpI2c(): stage=3 [E][esp32-hal-i2c.c:648] i2cDumpI2c(): error=1 [E][esp32-hal-i2c.c:649] i2cDumpI2c(): event=0x3ffd2b10 bits=110 [E][esp32-hal-i2c.c:650] i2cDumpI2c(): intr_handle=0x3ffeb18c [E][esp32-hal-i2c.c:651] i2cDumpI2c(): dq=0x3ffd2b40 [E][esp32-hal-i2c.c:652] i2cDumpI2c(): queueCount=1 [E][esp32-hal-i2c.c:653] i2cDumpI2c(): queuePos=0 [E][esp32-hal-i2c.c:654] i2cDumpI2c(): byteCnt=0 [E][esp32-hal-i2c.c:604] i2cDumpDqData(): [0] af R STOP buf@=0x3ffc5024, len=1, pos=0, eventH=0x0 bits=0 [E][esp32-hal-i2c.c:620] i2cDumpDqData(): 0x0000: . 00 [E][esp32-hal-i2c.c:968] i2cDumpInts(): 0 row count INTR TX RX [E][esp32-hal-i2c.c:971] i2cDumpInts(): [01] 0x0002 0x0002 0x0001 0x0000 0x00003532 [E][esp32-hal-i2c.c:971] i2cDumpInts(): [02] 0x0002 0x0200 0x0000 0x0000 0x00003532 [E][esp32-hal-i2c.c:1193] i2cProcQueue(): Busy Timeout start=0x359f, end=0x35d1, =50, max=50 error=1 [E][esp32-hal-i2c.c:630] i2cDumpI2c(): i2c=0x3ffc10cc [E][esp32-hal-i2c.c:641] i2cDumpI2c(): dev=0x60013000 date=0x16042000 level=VERBOSE [E][esp32-hal-i2c.c:643] i2cDumpI2c(): lock=0x3ffd2a8c [E][esp32-hal-i2c.c:645] i2cDumpI2c(): num=0 [E][esp32-hal-i2c.c:646] i2cDumpI2c(): mode=1 [E][esp32-hal-i2c.c:647] i2cDumpI2c(): stage=3 [E][esp32-hal-i2c.c:648] i2cDumpI2c(): error=1 [E][esp32-hal-i2c.c:649] i2cDumpI2c(): event=0x3ffd2b10 bits=100 [E][esp32-hal-i2c.c:650] i2cDumpI2c(): intr_handle=0x3ffeb18c [E][esp32-hal-i2c.c:651] i2cDumpI2c(): dq=0x3ffd2b40 [E][esp32-hal-i2c.c:652] i2cDumpI2c(): queueCount=1 [E][esp32-hal-i2c.c:653] i2cDumpI2c(): queuePos=0 [E][esp32-hal-i2c.c:654] i2cDumpI2c(): byteCnt=0 [E][esp32-hal-i2c.c:604] i2cDumpDqData(): [0] 5f R STOP buf@=0x3ffc5024, len=1, pos=0, eventH=0x0 bits=0 [E][esp32-hal-i2c.c:620] i2cDumpDqData(): 0x0000: . 00 [E][esp32-hal-i2c.c:968] i2cDumpInts(): 0 row count INTR TX RX [E][esp32-hal-i2c.c:971] i2cDumpInts(): [01] 0x0001 0x0002 0x0000 0x0000 0x0000359f [E][esp32-hal-i2c.c:971] i2cDumpInts(): [02] 0x0002 0x0200 0x0000 0x0000 0x0000359f [I][esp32-hal-i2c.c:1002] i2cProcQueue(): Bus busy, reinit [E][esp32-hal-i2c.c:1193] i2cProcQueue(): Busy Timeout start=0x3639, end=0x3639, =0, max=50 error=1

Strangely Thanks again

stickbreaker commented 5 years ago

This error report show you were writing to 0x57 a byte of zero. ((0xAE is 0x57 << 1 ) | 1 )

E][esp32-hal-i2c.c:604] i2cDumpDqData(): [0] ae W STOP buf@=0x3ffc50aa, len=1, pos=1, eventH=0x0 bits=0 [E][esp32-hal-i2c.c:620] i2cDumpDqData(): 0x0000: . 00 [E][esp32-hal-i2c.c:968] i2cDumpInts(): 0 row count INTR TX RX

This line shows two bytes loaded into tx Fifo, and a transaction Start was issued. at tick 0x34b9ms

[E][esp32-hal-i2c.c:971] i2cDumpInts(): [01] 0x0001 0x0202 0x0002 0x0000 0x000034b9

This line show that the i2c Peripheral sent one character out (the i2c Address byte)

[E][esp32-hal-i2c.c:971] i2cDumpInts(): [02] 0x0001 0x0040 0x0000 0x0000 0x000034b9

This line shows that something kept SDA low, the i2c peripheral interpreted it as another master device using the bus. (Arbitration Error). This error terminated the transaction.

[E][esp32-hal-i2c.c:971] i2cDumpInts(): [03] 0x0001 0x0020 0x0000 0x0000 0x000034b9

The following errors are all a cascade of loosing control of the I2C bus. I would verify you have 2.4k or 3.3k pullups on both SDA and SCL. the Builtin WEAK pullups of the ESP32 are not strong enough to allow successful I2C communications.

The following shows a hardware problem, SDA is held low.

[I][esp32-hal-i2c.c:1002] i2cProcQueue(): Bus busy, reinit [E][esp32-hal-i2c.c:1246] i2cReleaseISR(): Error releasing ISR=258 [E][Wire.cpp:137] initHardware(): invalid state sda=0, scl=1

Part of the reset sequence releases the Interrupt, but this error ISR=258 reports the the interrupt is attached to the other core. There is an upstream (IDF) patch that fixes this cross core interrupt release issue. It will be included in the Next Arduino-ESP32 release.

This Stickbreaker ESP32 fork is stale, try using the main branch of Arduino-ESP32, (not the Release 1.0.0, the current Dev Code).

Chuck.

wanqbabay commented 5 years ago

Thanks a lot @stickbreaker The code is based on the ble_test_repo(I get it from https://github.com/chegewara/esp32-snippets-enchancements-test). And i want to send the sensor data to my phone via the ESP32 ble. The problem is solved by creating the task on core(1). Where can i get the current Dev Code? Thanks again

stickbreaker commented 5 years ago

Main Arduino-esp32 follow install instructions for "development repository" here

wanqbabay commented 5 years ago

hello ! @stickbreaker
i use esp32 I2C to read the data from max30102 and send them to the app via esp32 ble. But something happened and do not how to solve it.

[D][BLEUtils.cpp:1651] dumpGattServerEvent(): GATT ServerEvent: ESP_GATTS_CONF_EVT [D][BLEUtils.cpp:1696] dumpGattServerEvent(): [status: ESP_GATT_OK, conn_id: 0x00] [D][BLEServer.cpp:176] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONF_EVT [D][BLECharacteristic.cpp:196] handleGATTServerEvent(): >> handleGATTServerEvent: ESP_GATTS_CONF_EVT [D][BLECharacteristic.cpp:459] handleGATTServerEvent(): << handleGATTServerEvent [D][BLEServer.cpp:315] handleGATTServerEvent(): << handleGATTServerEvent [D][esp32-hal-i2c.c:1300] i2cProcQueue(): Gross Timeout Dead start=0x85fbe, end=0x85ff0, =50, max=50 error=1 [E][esp32-hal-i2c.c:314] i2cDumpI2c(): i2c=0x3ffbedac [I][esp32-hal-i2c.c:315] i2cDumpI2c(): dev=0x60013000 date=0x16042000 [I][esp32-hal-i2c.c:317] i2cDumpI2c(): lock=0x3ffba83c [I][esp32-hal-i2c.c:319] i2cDumpI2c(): num=0 [I][esp32-hal-i2c.c:320] i2cDumpI2c(): mode=1 [I][esp32-hal-i2c.c:321] i2cDumpI2c(): stage=3 [I][esp32-hal-i2c.c:322] i2cDumpI2c(): error=1 [I][esp32-hal-i2c.c:323] i2cDumpI2c(): event=0x3ffba8c0 bits=200 [I][esp32-hal-i2c.c:324] i2cDumpI2c(): intr_handle=0x3ffbdb14 [I][esp32-hal-i2c.c:325] i2cDumpI2c(): dq=0x3ffe56c8 [I][esp32-hal-i2c.c:326] i2cDumpI2c(): queueCount=1 [I][esp32-hal-i2c.c:327] i2cDumpI2c(): queuePos=0 [I][esp32-hal-i2c.c:328] i2cDumpI2c(): errorByteCnt=0 [I][esp32-hal-i2c.c:329] i2cDumpI2c(): errorQueue=1 [I][esp32-hal-i2c.c:330] i2cDumpI2c(): debugFlags=0x00000000 [I][esp32-hal-i2c.c:349] i2cDumpInts(): Debug Buffer not Enabled [I][esp32-hal-i2c.c:1091] i2cProcQueue(): Bus busy, reinit [V][esp32-hal-i2c.c:1436] i2cInit(): num=0 sda=21 scl=22 freq=0 [V][esp32-hal-i2c.c:1621] i2cSetFrequency(): Fifo threshold=3 [W][esp32-hal-i2c.c:1363] i2cCheckLineState(): invalid state sda(21)=0, scl(22)=1 [D][esp32-hal-i2c.c:1371] i2cCheckLineState(): Recovered after 1 Cycles

Thanks again.

stickbreaker commented 5 years ago

@wanqbabay, which version are you using?

wanqbabay commented 5 years ago

@stickbreaker the latest [D][esp32-hal-i2c.c:1306] i2cProcQueue(): Gross Timeout Dead start=0x33db8, end=0x33dea, =50, max=50 error=1 [E][esp32-hal-i2c.c:318] i2cDumpI2c(): i2c=0x3ffbde10 [I][esp32-hal-i2c.c:319] i2cDumpI2c(): dev=0x60013000 date=0x16042000 [I][esp32-hal-i2c.c:321] i2cDumpI2c(): lock=0x3ffe17b0 [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=0x3ffe15a8 bits=0 [I][esp32-hal-i2c.c:328] i2cDumpI2c(): intr_handle=0x3ffe3f08 [I][esp32-hal-i2c.c:329] i2cDumpI2c(): dq=0x3ffe1924 [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=1 [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 [I][esp32-hal-i2c.c:1097] i2cProcQueue(): Bus busy, reinit [V][esp32-hal-i2c.c:1442] i2cInit(): num=0 sda=21 scl=22 freq=0 [V][esp32-hal-i2c.c:1643] i2cSetFrequency(): Fifo threshold=3

stickbreaker commented 5 years ago

This stickbreaker branch or arduino-esp32 github direct or board manager v1.0.1rc1

stickbreaker commented 5 years ago

Or v1.0.1rc2

wanqbabay commented 5 years ago

where can i get it?

stickbreaker commented 5 years ago

Get rc2

Follow these instructions board manager