espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.31k stars 7.35k forks source link

I2C ReWrite #839

Closed stickbreaker closed 6 years ago

stickbreaker commented 6 years ago

I have published a rewrite of the I2C subsystem that should solve the I2C stability Issues, It is NOT a drop-in replacement for Wire(). There are hardware differences between the AVR and ESP32 that require a different strategy.

It is a ALPHA TEST version, DO NOT use it in ANY PRODUCTION ENVIRONMENT.

To try it you can simply download the zip and OVERWRITE your arduino-esp32 sdk.

This fork is base off of espressif/master from 11/11/2017 It changes: cores\esp32\esp32-hal-i2c.c cores\esp32\esp32-hal-i2c.h tools\sdk\include\soc\soc\i2c_reg.h tools\sdk\include\soc\soc\i2c_struct.h libraries\Wire\src\Wire.cpp libraries\Wire\src\Wire.h README.md

stickbreaker:arduino-esp32

Chuck.

stickbreaker commented 6 years ago

@lonerzzz yes, and @me-no-dev changed my direction. What I am now going to do is make a simple 😄 device driver that is based on this queue model. What I envision is a OpenI2c() being preformed by each task, it is returned a 'handle' that is an xEventGroupHandle_t all subsequent MASTERMode send/receive use this handle. In addtion each data Block(dq) can have its own xEventGroupHandle_t (EG) the dq EG will be updated during ISR, after the ISR completes the task EG will be updated. The OpenI2c() would have some control bits to either merge dq's with other tasks are isolate them for this task.

I can see how this model would co-exist between bot IDF and Arduino. I am going to open a new branch in my repo and start on this model.

I plan on doing any required fixes to the current master until this branch is working. Chuck.

stickbreaker commented 6 years ago

@jlhavens Identified a problem with using EventGroups from an ISR, While WiFi is init'ing the FreeRTOS Timer Daemon gets starved. It cannot dispatch all of its messages, so, it's queue overflow. EventGroups uses the Timer Daemon to handle updates from ISR's. I have implemented recovery from this failure. If this failure occurs when my ISR is attempting to signal it has completed I2C transactions, a 50ms delay is encountered. This delay is seen by the APP, it does not effect the I2C stability. @jlhavens, reported 800 minutes of continuous one second ads1115 & bmp280.

pieterlagrange commented 6 years ago

@stickbreaker Thank you for the fix. I'm interfacing an AMG8833 thermal sensor and it is working after copying your six files.

stickbreaker commented 6 years ago

@pieterlagrange That's good to hear.

Chuck.

stickbreaker commented 6 years ago

Looks like it is working for everyone that has tried it. I'm closings this issue. If you have any more comments open an issue in stickbreaker/arduino-esp32

Chuck.

rtwfroody commented 6 years ago

Why is this issue closed? It's not fixed in this repo, is it?

With https://github.com/stickbreaker/arduino-esp32 I am able to reliable read my RTC, but without it only works for a short time.

stickbreaker commented 6 years ago

This Issue was opened to introduce my fork. It was closed after multiple comments that confirmed my fork was functional and useful. @me-no-dev was working on adapting my fork to merge, My coding style differs greatly from the 'standard' for this repo. I haven't heard any response from @me-no-dev since Late November 2017 or Early December 2017. I haven't merged any of my new work into my fork since he stated he was working on a merge.

I don't know what the current status of this repo is, nothing has been added, changed in almost a month.

I'm kind of worried about the silence.

Chuck.

dpharris commented 6 years ago

Chuck--

What is the name of your branch?

David

On Sat, Jan 13, 2018 at 11:58 AM, chuck todd notifications@github.com wrote:

This Issue was opened to introduce my fork. It was closed after multiple comments that confirmed my fork was functional and useful. @me-no-dev https://github.com/me-no-dev was working on adapting my fork to merge, My coding style differs greatly from the 'standard' for this repo. I haven't heard any response from @me-no-dev https://github.com/me-no-dev since Late November 2017 or Early December 2017. I haven't merged any of my new work into my fork since he stated he was working on a merge.

I don't know what the current status of this repo is, nothing has been added, changed in almost a month.

I'm kind of worried about the silence.

Chuck.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/espressif/arduino-esp32/issues/839#issuecomment-357461732, or mute the thread https://github.com/notifications/unsubscribe-auth/AAg4SosyxBOrMbqG8CsBSohzApanqQWMks5tKQragaJpZM4Qg1h7 .

stickbreaker commented 6 years ago

@dpharris my fork is at stickbreaker/arduino-esp32

It is almost up to date with main branch. My last sync was ~ 28Nov2017

Chuck.

dpharris commented 6 years ago

Thanks!

David

On Sat, Jan 13, 2018 at 2:00 PM, chuck todd notifications@github.com wrote:

@dpharris https://github.com/dpharris my fork is at stickbreaker/arduino-esp32 https://github.com/stickbreaker/arduino-esp32

It is almost up to date with main branch. My last sync was ~ 28Nov2017

Chuck.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/espressif/arduino-esp32/issues/839#issuecomment-357470516, or mute the thread https://github.com/notifications/unsubscribe-auth/AAg4Sp2HxfFUiYdzOVAKr-FmwVtMWqwqks5tKSdzgaJpZM4Qg1h7 .

kristsm commented 6 years ago

Hi! Using esp32 arduino framework through platformio. I have BME280 and MLX90614 connected. And have the same i2c issues - I2C timeout after ~1 minute of readings. I replaced the files from stickbreaker's fork and merged them into platformio's esp32 arduino framework directory. And it got worse, here are the log file: [E][esp32-hal-i2c.c:1149] i2cProcQueue(): Busy Timeout start=0x12d8d, end=0x12dbf, =50, max=50 error=0 [E][esp32-hal-i2c.c:609] i2cDumpI2c(): i2c=0x3ffc1d14 [E][esp32-hal-i2c.c:610] i2cDumpI2c(): dev=0x60013000 date=0x16042000 [E][esp32-hal-i2c.c:611] i2cDumpI2c(): lock=0x3ffda064 [E][esp32-hal-i2c.c:612] i2cDumpI2c(): num=0 [E][esp32-hal-i2c.c:613] i2cDumpI2c(): mode=1 [E][esp32-hal-i2c.c:614] i2cDumpI2c(): stage=3 [E][esp32-hal-i2c.c:615] i2cDumpI2c(): error=0 [E][esp32-hal-i2c.c:616] i2cDumpI2c(): event=0x3ffda13c bits=0 [E][esp32-hal-i2c.c:617] i2cDumpI2c(): intr_handle=0x3ffcd248 [E][esp32-hal-i2c.c:618] i2cDumpI2c(): dq=0x3ffdac7c [E][esp32-hal-i2c.c:619] i2cDumpI2c(): queueCount=1 [E][esp32-hal-i2c.c:620] i2cDumpI2c(): queuePos=0 [E][esp32-hal-i2c.c:621] i2cDumpI2c(): byteCnt=0 [E][esp32-hal-i2c.c:582] i2cDumpDqData(): [0] ec W STOP buf@=0x3ffc6fe2, len=1, pos=1, eventH=0x0 bits=0 [E][esp32-hal-i2c.c:598] i2cDumpDqData(): 0x0000: . f8 [E][esp32-hal-i2c.c:942] i2cDumpInts(): row count INTR TX RX [E][esp32-hal-i2c.c:945] i2cDumpInts(): [01] 0x0001 0x0002 0x0002 0x0000 0x00012d8d [E][esp32-hal-i2c.c:945] i2cDumpInts(): [02] 0x0003 0x0100 0x0000 0x0000 0x00012db4

Perhaps the problem is with the platformio's esp32 arduino framework fork, which can't be used together with stickbreaker's updated I2C files?

kristsm commented 6 years ago

Ok, my code uses esp-now and if I disable everything related to esp-now, it works with stickbreaker's updated files. Have to see how long and then will try to find out where the problem lies in relation to the esp-now or the code I use for esp-now functionality.

me-no-dev commented 6 years ago

@stickbreaker had to move away from Arduino to finish some other tasks back now and onto updating everything

kristsm commented 6 years ago

Just wanted to inform everyone that yesterday I tried to compile with Platformio's platform = https://github.com/platformio/platform-espressif32.git#feature/stage

And it seems that with the latest Platformio's Arduino fork (without stickbreaker's mods) the I2C with my BME280 and MLX90614 parallel readings is working without problems!

echoGee commented 6 years ago

I tried using stickbreaker's mods (5 files) with an mpu6050. But getting the following error. I am assuming the error is the same as earlier, but with more debug logs by @stickbreaker . Error seems to be very similar to @kristsm https://github.com/espressif/arduino-esp32/issues/839#issuecomment-358620299

[E][esp32-hal-i2c.c:1151] i2cProcQueue(): Busy Timeout start=0xa429, end=0xa45b, =50, max=50 error=0 [E][esp32-hal-i2c.c:609] i2cDumpI2c(): i2c=0x3ffc103c [E][esp32-hal-i2c.c:610] i2cDumpI2c(): dev=0x60013000 date=0x16042000 [E][esp32-hal-i2c.c:612] i2cDumpI2c(): lock=0x3ffda1b0 [E][esp32-hal-i2c.c:614] i2cDumpI2c(): num=0 [E][esp32-hal-i2c.c:615] i2cDumpI2c(): mode=1 [E][esp32-hal-i2c.c:616] i2cDumpI2c(): stage=3 [E][esp32-hal-i2c.c:617] i2cDumpI2c(): error=0 [E][esp32-hal-i2c.c:618] i2cDumpI2c(): event=0x3ffda300 bits=0 [E][esp32-hal-i2c.c:619] i2cDumpI2c(): intr_handle=0x3ffda288 [E][esp32-hal-i2c.c:620] i2cDumpI2c(): dq=0x3ffda264 [E][esp32-hal-i2c.c:621] i2cDumpI2c(): queueCount=1 [E][esp32-hal-i2c.c:622] i2cDumpI2c(): queuePos=0 [E][esp32-hal-i2c.c:623] i2cDumpI2c(): byteCnt=0 [E][esp32-hal-i2c.c:582] i2cDumpDqData(): [0] d0 W STOP buf@=0x3ffc3406, len=2, pos=2, eventH=0x0 bits=0 [E][esp32-hal-i2c.c:598] i2cDumpDqData(): 0x0000: k. 6b 80 [E][esp32-hal-i2c.c:944] i2cDumpInts(): row count INTR TX RX [E][esp32-hal-i2c.c:947] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x0000a429 [E][esp32-hal-i2c.c:947] i2cDumpInts(): [02] 0x0003 0x0100 0x0000 0x0000 0x0000a450 [E][esp32-hal-i2c.c:1151] i2cProcQueue(): Busy Timeout start=0xa4bc, end=0xa4ee, =50, max=50 error=0 [E][esp32-hal-i2c.c:609] i2cDumpI2c(): i2c=0x3ffc103c [E][esp32-hal-i2c.c:610] i2cDumpI2c(): dev=0x60013000 date=0x16042000 [E][esp32-hal-i2c.c:612] i2cDumpI2c(): lock=0x3ffda1b0 [E][esp32-hal-i2c.c:614] i2cDumpI2c(): num=0 [E][esp32-hal-i2c.c:615] i2cDumpI2c(): mode=1 [E][esp32-hal-i2c.c:616] i2cDumpI2c(): stage=3 [E][esp32-hal-i2c.c:617] i2cDumpI2c(): error=0 [E][esp32-hal-i2c.c:618] i2cDumpI2c(): event=0x3ffda300 bits=0 [E][esp32-hal-i2c.c:619] i2cDumpI2c(): intr_handle=0x3ffda288 [E][esp32-hal-i2c.c:620] i2cDumpI2c(): dq=0x3ffda264 [E][esp32-hal-i2c.c:621] i2cDumpI2c(): queueCount=1 [E][esp32-hal-i2c.c:622] i2cDumpI2c(): queuePos=0 [E][esp32-hal-i2c.c:623] i2cDumpI2c(): byteCnt=0 [E][esp32-hal-i2c.c:582] i2cDumpDqData(): [0] d0 W STOP buf@=0x3ffc3406, len=2, pos=2, eventH=0x0 bits=0 [E][esp32-hal-i2c.c:598] i2cDumpDqData(): 0x0000: k. 6b 80 [E][esp32-hal-i2c.c:944] i2cDumpInts(): row count INTR TX RX [E][esp32-hal-i2c.c:947] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x0000a4bc [E][esp32-hal-i2c.c:947] i2cDumpInts(): [02] 0x0004 0x0100 0x0000 0x0000 0x0000a4ed

lonerzzz commented 6 years ago

Do you know how long your device is expected to take? You are getting a timeout so either your device is not responding at all or is responding after the 50ms timeout period. If it is a longer response time that you need, that can be set in the API. If not, you need to use a scope and test to see if something is getting sent.

eldadwasserman commented 6 years ago

Hi All... I am developing with ESP-IDF development environment and I am reading now from BMP280 every 50 msec. everything is working ok. I would like also to read from the MLX90614 via the I2C, is anyone here succeed to do it ?

I will be more than happy to get some help in this issue... a code sample how to read from the MLX90614 will be very helpful.

Eldad

eldadwasserman commented 6 years ago

Hi kristsm... maybe you can help in this issue ? (I am using ESP-IDF)...

echoGee commented 6 years ago

@lonerzzz , The device is an MPU6050. The delay isn't 50 ms . The scope just pulls high or sometimes low. I can't figure out if its the MPU or the ESP thats doing it.

lonerzzz commented 6 years ago

If you cannot figure it out, try inserting a low value resistor (100 to 300 ohms) in series on the SDA line, one on the MPU and the other on the ESP with the pull-up on the main line between . Then use your scope and capture the signal on either side of the resistor for each of the MPU and ESP. Where you see a small voltage difference is the device that is pulling low. Only the pull-up should be pulling the line up.

echoGee commented 6 years ago

oops. This involves cutting a trace within the inner layer of a PCB. I couldn't find another way to do this. Checking the scope shows that the MPU respond within few milliseconds. Could the delay be the issue ? I can increase the timeout in API. Do you know which API that is ?

lonerzzz commented 6 years ago

setTimeout is what you need. Cutting a trace is often possible too because you can scrape the solder resist off on either side of the cut and solder in a surface mount capacitor if you have some tweezers to hold it while you solder. When done, you can put a 0 ohm jump in place of your resistor.

stickbreaker commented 6 years ago

@lonerzzz off subject, I think we (@ESP32DE and I) have solved the Spikes on SDA and SCL check out this PR on my fork proposal to i2c

@echoGee the timeout function is Wire.setTimeOut(milliseconds) If you are seeing

[E][esp32-hal-i2c.c:1151] i2cProcQueue(): Busy Timeout start=0xa429, end=0xa45b, =50, max=50 error=0

This error, the i2c hardware has either detected a START from another master (SDA going low while SCL is high) or a prior communication has stalled with the Slave device extending SCL (holding it low) to delay communications while the Slave is processing the last command. The ESP32's i2c hardware has a maximum timeout of about 13.1ms between events(can't be sure, but at least between entire bytes, but hopefully between bits too).

[E][esp32-hal-i2c.c:947] i2cDumpInts(): [01] 0x0001 0x0002 0x0003 0x0000 0x0000a429 [E][esp32-hal-i2c.c:947] i2cDumpInts(): [02] 0x0003 0x0100 0x0000 0x0000 0x0000a450

This part of the debug output show that:

To attempt to recover you should call Wire.reset() when you get this error. Then retry your i2c command.

Chuck.

balzss commented 6 years ago

@stickbreaker thanks for the work you put into this. What do you think the future of the I2C on the arduino-esp32 will be? Maintaining your separate repo and keeping it up to date will cause you a lot of work and leaves the original issue in place (in the esspressif's repo). I've read through the relevant threads to educate myself on the issue an it seem like I2C without your changes is very problematic right now. Am I missing something? Is this some small niche problem that only a couple of us have? Thanks for the answers!

stickbreaker commented 6 years ago

@balzss I don't know what is going to happen, I created my fork because I believe that an interrupt driven I2C subsystem is better than a polling system. I thought if that my proof of concept actually worked, it would be incorporated into the main branch. I don't plan on maintaining a separate fork. I am working on SLAVE mode, I hope that by the time I complete it the main branch be using a interrupt based driver.

As you have concluded, the main branch's i2c is very unstable. Since it handles repeated STARTS (ReSTART) operations in a lackadaisical manner, The success of i2c operations is highly dependent on the how the app is coded. For Example:

Serial.begin(9600); // slow baud, just to delay execution
uint16_t addr=0x1234; // memory address for 24lc512 EEPROM
Wire.beginTransmission(i2cDev);
Wire.write( highByte(add)r);
Wire.write(lowByte(addr));
Wire.endTransmission(false); // ReStart, instead of STop
Serial.println("I have just set the internal address pointer of my 24lc512 EEProm to 0x1234,"
  " and now I am uselessly delaying between execution of a 'repeated Start' operation and the "
  "Next I2c command,\n"
  " if this delay between the endTransaction() and requestFrom() exeeds 13.1 ms the I2C"
 " hardware will fall into a timeout cascade error that should not happen");

Wire.requestfrom(i2cDev,20);
while(Wire.available()){
  Serial.print(Wire.read(),DEC);
  Serial.print(' ');
  }
Serial.println();

This code should work without any issues; But, because I fill up the Serial output buffer, and I am sending data slowly (960 characters a second) the println() call hangs until it can queue all of it's data. since this wait will exceed 13.1ms the i2c hardware will fail into a timeout Cascade. My fork correctly handles ReSTART operations.

My fork was branched November 2017, It is falling behind I don't know if I should level up or let it wither away. Currently it can be manually merged by overwriting about five files. So it is not much of a hardship begin on the main branch. If you need functional I2C you just manually replace the I2C subsystem with my files.

Chuck.

s60sc commented 6 years ago

I was having I2C stability issues in my current ESP32 project, but this rewrite solved them. Many thanks

everslick commented 6 years ago

With latest Arduino-Core + 'stickbreaker's 5 file fork' I2C is pretty much unusable. The last 0-3 bytes of reads are sometimes (often enough) garbage or 0xff. I will dig into it deeper tomorrow. Just wanted to note it somewhere, just in case ...

stickbreaker commented 6 years ago

@everslick Are you getting any error messages? Do you have Debug level set to at least Error? Yours is the first report of problems.

Chuck.

everslick commented 6 years ago

Not yet, I only synced my fork with latest code from you and me-no-dev yesterday and my at24c32 stopped doing anything useful. But I cannot rule out an error on my side ither at this point in time. I will report back either way.