P2 i2c Communications Inconsistent

Just thought I would report back. i2C Communications are still extremely inconsistent on the Photon2. At this point, I'm giving up on attempting to use them for our project. Too bad I bought 30 of them on launch day! Maybe something will change in the future and I'll be able to use them.

In case anyone has any further ideas, I've attached a few more logic captures of what I'm seeing currently.

For this test, I am attempting to use a Photon2 in a small project where I was using aPhoton before. I have a bidirectional logic level converter in place. With the Photon, I actually did not have pull up resistors on the 3.3V side. Only on the 5V side. (I'm still not 100% sure if they are supposed to be on both sides.) At any rate, I tested the Photon2 both ways with no difference in results.

The current test is just doing a Wire.requestFrom(10,32, false); (note I tested both with and without the false flag). As the slave, there is an ATTiny85 that is running at 5V and has been programmed to respond to a request with 32 bytes of data. It will be a serial number and then just filler for the remaining bytes.

This works just fine with the Photon and with an Arduino as the master.

Here is a logic capture when using the Photon that does exactly what is expected every time:

When I use a Photon2 in place of the Photon, I see the below results.

And then in a subsequent test, you can see in the next capture that I actually got the correct thing back once, but then on the next try a few seconds later, it failed in the same way as before.

I feel confident something is wrong in the way the Photon2 is handling i2c communications at this point.

Thanks again to everyone who attempted to help!

4 Likes

Wow, you’ve been through a lot already. That’s gotta be really frustrating. I only bought two Photon2s and haven’t yet started my port from the Photon.

Hard to believe that the I2C bus wouldn’t have been tested/implemented properly but that would be a showstopper for me. Another post directs users who need the OneWire bus (which the Photon2 does not support) to use an I2C->OneWire chip…I guess I’ll wait to order them…not to mention the I2C I/O, ADC, & FRAM chips I’ve been planning.

Seems this could be a killer for many projects if the I2C bus has major problems. I hope Particle gets it resolved quickly.

2 Likes

@rickkas7, @Colleen it's time to call in reinforcements here!

3 Likes

Hey folks,

Sorry to hear about the issues y’all are having. This just popped up on the engineering radar so I’m popping in to give a quick update.

I'm happy to announce that we are preparing for a 5.4.1 release right now which will address a number of issues including the USB slowdown mentioned above.

Moreover, we are planning two additional releases over the next six weeks each carrying a juicy feature and an opportunity for further stability tweaks. We are committed to constant improvement of the Photon 2 and I appreciate the bug reports and feedback from the community. I want this product to be great as much as you do!

In relation to the i2c issue, please rest assured that I will personally ensure it is investigated by our engineering team as promptly as possible. We will aim to include a solution in either the upcoming release or in fast follow subsequent updates if it turns out to be something in an sdk layer we are relying on that is harder to update.

Feel free to reply or reach out directly at nick@particle.io - I’ll update this thread when I have a beta release or an update to share.

Cheers,

Nick

6 Likes

@jones_corey apologies, I failed to set this thread to watching so I didn't get updated on your latest reply (I have it set to watching now). Sorry to hear you are still seeing issues and I am wanting to see this through to resolution.

There may be something within deviceOS that is handling the I2C peripheral differently photon 2 VS photon, but it will be hard to diagnose without a live session or without reproducing on my end. However, with your latest logic captures, I see some undesired behavior even in the photon capture that I suspect is the root cause for the issue (last byte of read is ACK'd when it should be NACK'd).

This behavior is different than the captures you shared previously and the client will be outputting data on the next falling edge of SCL. If the next bit to be read is a '0' you run into bus contention thus corrupting the next transaction, but if it is a '1' the host may be able to send a start condition to reset the client. I'll also note this behavior is not seen in the photon 2 captures so something has to be different.

Can you provide the source code for these latest captures (Host and Client)? I and/or engineering are wanting to reproduce this setup on our end so that we can perform additional testing. Also, even if you don't see a difference in behavior, best practice to have pull ups on both sides of the level translator. Again sorry for the poor experience, I am confident we can get this issue resolved!

4 Likes

My apologies @erik.fasnacht, that screenshot is actually not including all of the bytes when connected to the Photon. I had not expanded the window when I took that screenshot. I've included a new screenshot below showing just the end. The last byte from my client does actually have a NAK, not an ACK. I thought that screenshot being cut off might cause a problem when I included it... :upside_down_face:

The below screenshot shows just the end when the Photon is being used and the last byte is always followed by a NAK.

I've got to admit things have changed today, and I'm not entirely sure why. When I went back to capture that previous screenshot, I decided to hook up the Photon2 again with an Arduino nano as the client (logic level converter and 4.7Kohm pull ups on SDA and SCL on both sides) and it appeared everything was working correctly. Including whether or not the third flag in the Wire.requestFrom() call was set to true or false. This is entirely different behavior than I was seeing last week.

As I mentioned before, my actual project setup includes an ATTiny85 as the client device. It was using the TinyWire library found at GitHub - lucullusTheOnly/TinyWire: Composite Master and Slave I2C library for Atmels ATTiny microcontrollers. When I hooked it back up in place of the Arduino nano, I began getting the weird results again (capture below).

At this point, I began to wonder if there could be something wrong with the TinyWire library as it had been abandoned years ago. I found that there were many libraries that had been made over the years. Most split Slave and Master functions into different libraries. So I tried a few others. Landed on this one: GitHub - rambo/TinyWire: My modifications to TinyWire Arduino libs. After that, the Photon2 can now consistently read the data from the ATTiny85!

My working host code running on Photon2:

#include <Wire.h>

String i2cInputString = "";         // a String to hold incoming data
bool i2cStringComplete = false;  // whether the string is complete

byte buffer[32];

uint32_t nextRequestMillis = 0;

void setup() {
    waitUntil(Particle.connected);
    
    Serial.begin(115200);  // start serial for output
  
    delay(1000);
    Serial.println("on");
    
    Wire.begin();
}

void loop() {
    
    i2cLoop();
    receiveI2CEvent();
    
    if (millis() >= nextRequestMillis) {
        Wire.requestFrom(10, 32);    // request 32 bytes from slave device #8
        nextRequestMillis = millis() + 5000;
    }

}

void i2cLoop() {
  while (Wire.available()) {
    // get the new byte:
    char inChar = (char)Wire.read();
    Serial.print(inChar);
    if (inChar == ';') {
      i2cStringComplete = true;
    }
    else if (!i2cStringComplete) {
      // add it to the inputString:
      i2cInputString += inChar;
    }
  }
}

void receiveI2CEvent() {
    if (i2cStringComplete) {
        Particle.publish("app_message", "Received from i2c: " + i2cInputString.substring(2));
        i2cInputString = "";
        i2cStringComplete = false;
    }
}

My ATTiny85 Code:

#include <TinyWireS.h>

//Set initial SerialNumber.
char serialNumber [] = "TESTSERIAL";

byte i2c_address = 10;                                              //Randomly picked to use for all devices.

void setup() {
  TinyWireS.begin( i2c_address );                                  // config TinyWire library for I2C slave functionality
  TinyWireS.onRequest( onI2CRequest );                             // register a handler function in case of a request from a master
}

void loop() {
}

// Request Event handler function
// Called if the master just requests data.
//This would be a request to send the current programmed serial number.
void onI2CRequest() {
  int len = strlen(serialNumber);
  TinyWireS.send('S');
  TinyWireS.send('N');
  for (int i=0;i<len;i++) TinyWireS.send(serialNumber[i]);      //Loop the serialNumber char array to send all the data.
  TinyWireS.send(';');                                          //End sent string with a ; so the master knows we have sent the entire serial number.
}

Note: the above code is also what I was running for this particular test on the Nano. Just substitute the standard Wire library in for the TinyWireS one.

So, at this point, I assumed I should just lose my maker card and be lambasted for wasting everyone's time...

So I went back to prove I wasn't completely crazy and hooked two Photon2s together like one of my earlier tests.

Loaded this code on the host Photon2:

#include <Wire.h>

uint32_t numCharsExpected = 0;
uint32_t numCharsReceived = 0;

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {

  numCharsExpected += 1;
  Wire.requestFrom(8, 1);    // request 6 bytes from slave device #8
  
  delay(5);

  while (Wire.available()) { // slave may send less than requested
    char c = Wire.read(); // receive a byte as character
    numCharsReceived++;
  }
  
  Serial.print("NumCharsExpected = ");
  Serial.print(numCharsExpected);
  Serial.print(" NumCharsReceived = ");
  Serial.println(numCharsReceived);

  delay(500);
}

And loaded this code on the client Photon2:

#include <Wire.h>

void setup() {
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event
}

void loop() {
  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
  Wire.write("s"); // respond with message of 1 byte
  // as expected by master
}

Hooked them together. Three wires between them. SCL, SDA, and GND. Put 4.7K pull up resistors on SCL and SDA to 3.3V. No level shifter of course. We would expect this to send a request for one byte, read one byte and increment the counter.

But we get the following in the serial output after it's been running for a while (it's only received 64 bytes after requesting the data over 3000 times):

The logic capture of this looks like:

So at this point, I don't know exactly what to believe. :slight_smile: It looks like possibly with a change in the Library I was using on the ATTiny85, today I am able to get the results I'd expect.

I suppose I'd still hold that something isn't quite right and other people may have problems with specific use cases. I certainly expected the Photon2 (within reason) to be a drop in replacement for the Photon.

Hopefully this saga hasn't been a total waste of everyone's time and it will help someone else in the future. If there is anything else I can do to help test, please let me know!

2 Likes

Has anyone else had as long of a week as I have?

I took the Library change I had made and tried using it in my original project. It didn’t work. So I left the office for the week.

On the drive home, it occurred to me. Changing the library made the logic captures all look nice. The ATTiny sends back the data correctly every time now, but in all of the testing for my last post, I never once actually verified that the Photon2 was reading back the data. Which was the original problem to begin with… I had focused too much on the fact the logic captures were weird…

Once I put the Photon2 back into my full code, I realized it’s doing the same thing as the Photon2 to Photon2 test is doing. The logic capture all looks normal, but the host Photon2 is still not getting the data.

So, the easiest way to recreate the issue is by just hooking two Photon2s together using the test code from my last post.

I’m going to take a little time off now….

Yes, take some time to relax and recharge. Thanks so much for reporting your findings!

1 Like

We always run these set of regression tests for every platform prior to release. Erik and I are running these tests and checking things out. Will keep you updated.

2 Likes

Just as an update, I believe we're looking at a DeviceOS adjustment to accommodate the above. @Baz will keep you posted.

2 Likes

This fix :

should take care of it , but until it is released in a new Device OS version, you would need to compile it from the code. (Instructions here)

6 Likes

I can confirm that with the fix mentioned by @Baz, this problem is no more! Photon2 works with the test code and also in my original project code. Thanks to everyone in the community for the help troubleshooting and everyone at Particle for getting a fix in place! I'll keep an eye on future DeviceOS updates to see when this PR makes it in.

Thanks again!

9 Likes

The pull request has been merged and is scheduled to go into device OS 5.5.0 due out in a few weeks.

7 Likes

This thread was an adventure!
I had a question about some other lines in 12c_hal.cpp. I'm of course not familiar with this codebase, but there are other !WAIT_TIMED(transConfig_.timeout_ms,... lines that exist inside endTransmission() on line 401. Would those need to be changed to the api-set config-> too? I'm curious if those lines would suffer from same issue of using the same default timeout behavior.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.