Issue with I2C on Photon


#38

Hey all. I finally got back around to testing this.

I wasn’t sure if this fix is in any release branches, so I decided to try the develop branch. Unfortunately, after getting my local firmware build working with the develop branch it still doesn’t appear work. I’m getting the same behavior as before.

After digging around a bit I found that the earlier fix may have been reverted? Here’s the change I found.

Satish or other Particle folks, do you have any new info on this?

Thinking about the change a little more I think this should not be a timeout condition anyway. If a NACK is received it should be possible to detect that immediately without any delay waiting for a timeout.

Thanks a lot,
Erin


#39

I did a little more digging. I think the problem is that it’s stuck waiting for the “master transmitter mode selected” event but instead we get a “slave ack failure” event.

I tried coding a fix and it seems to address the immediate problem, though I’m not sure if the return values are correct (could use some enums or constants for those) or if it affects any other conditions.

I forked the firmware repo and checked a change in here if you’d like to have a look:

It’s still freezing up when I try to run a more complicated test using the modulo protocol. I’m not sure why, or where it’s stuck. Hmm, I think it’s time to go order a programmer shield. :smile:


#40

@modulo, did you see the STM32F20x I2C errata:

STM32F2’s I2C limitation(from ERRATA):
1)Start cannot be generated after a misplaced STOP
2)Mismatch on the “Setup time for a repeated Start condition” timing parameter

I suspect you may be seeing condition 1) and the only solution is a soft reset of the I2C channel. I’m trying to get to this with the Particle team. Nice work! :smiley:


#41

I hadn’t seen that, @peekay123. Thank you for sharing. Hmmm.


#42

@modulo, for your convenience, here is the link.


#43

Hey all! A new release candidate is available that brings greater reliability to the I2C interface. Particle Firmware Updates Thread


#44

I tried the new release candidate and it works much better. I actually got the photon discovering and controlling Modulos for the first time. Yay! Even better, it seems quite solid in the face of bus errors. Hot plugging works now too!

However, there is still an issue. After a slave address has been nacked, there is a 100ms delay before the program continues. This causes really terrible performance since it’s stuck waiting for a timeout most of the time. In a simple example I tried, bus utilization was only about 2.5%. A slave address NACK is a normal condition, not a bus error, so I think it should be possible to handle it without a timeout.

I believe the fix should be similar to what I did in the change above: while waiting for MASTER_RECEIVER_MODE_SELECTED, check to see if the slave address ack failed. If it did, bail immediately rather than waiting for a timeout. That said, when I tried my change in the new latest branch I couldn’t get it to work. Any thoughts on why that might be? Is I2C_EVENT_SLAVE_ACK_FAILURE not actually the right way to detect a nack? Maybe generating a stop isn’t the correct way to handle it?

Thanks again for the progress on this!


#45

cc: @satishgn


#46

I suspect there may several events firing in succession and the I2C_EVENT_SLAVE_ACK_FAILURE is just missed. The I2C_CheckEvent() just returns the last event, not any event that has recently happened. I think a better way to definitely catch it is to check the flags associated with this error. There is an I2C_FLAG_AF: Acknowledge failure flag but now that I think of it we are handling errors in an interrupt now, clearing them as soon as they are set. Perhaps we can set our own volatile flag for AR if it is seen, and check for that in the polled loop waiting for MASTER_RECEIVER_MODE_SELECTED… then immediately timeout, generate STOP and SW reset for good measure :smile: @satishgn what do you think?


#47

Hey @BDub and @satishgn. I was wondering if you had a chance to look into setting a flag instead of timing out? It sounds liked a reasonable solution but I haven’t had a chance to try it yet.


#48

I have not, but just brought this up internally and will file a Github issue so we don’t lose track of it. Thanks for the reminder!


#49

@modulo please give this PR a test :smile:


#50

Original example code:

void setup() {
    Wire.begin();
}

void loop() {
    Wire.beginTransmission(8);
    Wire.write('M');
    Wire.endTransmission();
}

New timeout with no slave actually present, bus continuing to retry in under 1ms with photon connected to the cloud.

In manual mode, things are much faster… once we get the issues sorted with task switching you might be able to see similar times with system threading enabled. Currently system threading has some issues where it’s corrupting i2c though, so be on the lookout for an update about that in a future firmware release. Anyhoo, here’s the i2c retying after just 70us in manual mode:


#51

Just added some code to ensure we wait for the STOP bit to actually send. SW Reset was occurring too quickly and preventing it from being generated. Thanks for testing and pointing this out @modulo :wink:


#52

It’s working! Hurray! Thanks so much for all the work on this. It’s really great!


IIC hangs when D3 is interrupt
#53

I think this or a similar issue may have been reintroduced in 0.4.7. When the slave device is not connected, my call to Wire.endTransmission() is hanging on my photon - I think it never returns.

Here is some sample code that shows the problem, based on @modulo’s sample code:

void setup() {
    Wire.begin();
}

void loop() {
    // set LED to red for a second
    RGB.control(true);
    RGB.color(255, 0, 0);
    delay(1000);

    Wire.beginTransmission(8);
    Wire.write('M');
    Wire.endTransmission();

    // return LED to default cyan for a second
    RGB.control(false);
    delay(1000);
}

When I run this code against 0.4.6 or 0.4.5, it works as expected: the LED cycles between cyan and red. But when I run it against 0.4.7, the code hangs with the LED set to red, and I have to put the photon into safe mode to load new firmware. This is only a problem when no slave device is connected.

Thanks in advance!


#54

I tested the Modulo library with 0.4.7. It works, which indicates that it is not completely locking up on NACKs (at least in my case), but it is less immune to bus errors. On 0.4.6 I can’t get the photon to hang when plugging and unplugging devices. On 0.4.7 it does hang sometimes.


#55

Ah, yes, I should have mentioned the problem is intermittent. When building against 0.4.7, I do occasionally see a couple cycles of cyan and red before it gets stuck at red. I think Wire.endTransmission() is hanging maybe 80% of the time for me.


#56

I have the same i2c problem with firmware 0.4.7. Unplugging/replugging SDA with 0.4.6 recovers ok, but hangs with 0.4.7 – requires the reset button.

In my application, photon is the master and just writing, not expecting a response. Code:

void loop() {
  Wire.beginTransmission(17);
  Wire.write("r");
  retc=Wire.endTransmission();
  if (retc!=0) {
     Wire.reset();
     delay(1000);
  }
  delay(1000);
}

#57

0.4.9 has the fix an will be released tomorrow (if all goes as planned)

If you have a local toolchain you can already try it out.