I2C interference by serial communication

This is a re-post, previously I did a post on a different section here on the forum. I will try my luck in this Due dedicated section.

I have this problem driving me insane the last couple of weeks.

My setup is:

Arduino Due (genuine)
Adafruit MTK3339 GPS
Adafruit 10DOF IMU

The IMU is connected to pin 20 and 21 (SCL, SDA) on the Due (have tried SCL1 and SDA1 as well). I'm powering the IMU with 3.3V, so the builtin lever shifter in the IMU is not active.

The GPS is connected to the Serial2, powered by 3.3V, using 9600 baud setting, only NMEA $GPRMC sentence active.

I have a test sketch reading the IMU sensors (rate, acceleration, magnetic), and reading the GPS NMEA sentence.

Occasionally (<5 min) the I2C communication fails. The bus gets locked and I have to power toggle or toggle the SCL wire a couple of times (slave is holding SDA low).

The failures seems to occur about the same time as the GPS sends its message. If I tell the GPS to be silent, but still active, I never see this issue (running four hours, reading sensors at around 200 Hz).

The I2C communication fails on different places, the following places (functions in Wire.c) are the ones I have observed so far:

TWI_WaitByteSent(), reason: timeout
TWI_WaitByteSent(), reason: ARBLST
TWI_WaitByteReceived(), reason: timeout
TWI_WaitTransferComplete(), called from requestFrom(), reason: timeout
TWI_WaitTransferComplete(), called from endTransmission(), reason: timeout

Interesting is that the TXRDY bit is set when it fails in the TWI_WaitTransferComplete() and TWI_WaitByteSent() functions. I don't know if this means something.

Sometimes I stumble upon a NACK, but that does not hang the bus.

I have tried different I2C frequencies, different GPS NMEA output rates and baud rates. Nothing helps. I have tried to separate the I2C wires as far as possible from the serial wires (in case of EMC issue). Added capacitor to the 3.3V (voltage taken from the Due). No difference.

Turning interrupts OFF (using "noInterrupts()") during I2C communication did no difference as well.

I have been diving in the Arduino code libs after clues - the Wire/TwoWire/TWI code is a bloody mess. But obviously it works when the GPS isn't sending NMEA.

I'm using 1.5.8, so the Wire library fix shall be included.

Please advice before I permanently goes insane and take up knitting as a hobby instead.

Let me know what else information you need.

I've seen something simiiar at times, using a ProMini with an I2C LCD and RS232. In my case, the display will, at random, get scrambled and start displaying garbage, as though the I2C communications got out of sync, or the display was never initialized. The LCD needs to be re-initialized to cure it. It always comes down to noise. I would add a 10-100uF electrolytic capacitor on the regulated power supply of each device, and stiff pull-up resistors, a few hundred ohms, on the I2C lines, to make them more noise-immune.

Regards,
Ray L.

Hi Ray,

I'm heading into that direction as well, adding more capacitance. At the moment I'm travelling so I have no spare components available (just traveling with bare minimum: Due+IMU+GPS, and my cross country skies).

When I previously tried adding capacitance (1 uf electrolyte + some film capacitor) I also observed the voltage ripple on the 3.3 VDC bus, it made no change. But maybe the high frequency ripple is not the devil here, maybe the bus sags during the NMEA message transfer, i.e. greater valued capacitors would do the trick.

In terms of pull-ups there is 1k (Due side) in parallell with 10k (IMU side), so ~0.9K that is. At least I thought. But looking in the IMU schematic again(Adafruit 10DOF Schematic) makes me a bit curious what happens when "Vin" is not present, i.e. when I power the IMU with 3.3 VDC directly. Then the 10k:s on the 5 VDC SCL/SDA side results in a 20k connection between SCL and SDA, is that acceptable? However, I experience the same problem when powering the IMU through "Vin" with 3.3 VDC (should be OK according to the documentation).

Anyway, I will try to reduce the pull-ups by powering the IMU through "Vin" and paralleling the existing resistors (1k || 10k). My understanding is that I can go down to 0.5k before damaging the Due - correct? Still I can do nothing about the 10k pull-ups on the "other" side of the MOSFETs (reluctant to solder the IMU), is that a problem? The lines are very short on that side?

Regards, Robin L

The IMU is connected to pin 20 and 21 (SCL, SDA) on the Due...

pin 20 = SDA, pin 21 = SCL

If you can detect when the failure occurs, then perhaps, as a workaround, the code from this thread could re-establish control by setting SCL as output, toggling it 8 times, then setting it back to input.

Good advice. I'm using that one as well. The problem though is the time it takes to detect the erroneous state (my quadcopter will crash), probably I just need to decrease the countdown variable in the Wire lib. Starts to get messy though. Better writing a new lib from scratch (throw in DMA as well..).

Anyway. I manage to solve the problem by placing a resistor (4.7k) in series with the TX line of my GPS (i.e. the line connected to the Due's RX pin). I did this as a random act after concluding that adding capacitors and additional pull-ups did not help.

Why did my fix solve the problem?

Thanks.

Typically the series resistance is much less than this. It improves noise immunity and reduces ringing on the lines, EMI, signal reflection. In the example here, they use 330Ω series resistance and 4.7K pullup resistors:

Series resistors on I2C lines

Topic: I2C (Wire) pull up resistors, Arduino Due, 20 (SDA0-3), 21 (SCL0-3)

Thank you for the fast reply!

Feeling stupid. I should know that.

OK. I will try add some series resistance to the SCL and SDA lines as well. Then I possibly can lower the value of the resistor I added between the GPS and Due (GPS --- RS232 ("TTL") --> Due).

dlloyd:
Typically the series resistance is much less than this. It improves noise immunity and reduces ringing on the lines, EMI, signal reflection. In the example here, they use 330Ω series resistance and 4.7K pullup resistors:

Series resistors on I2C lines

Topic: I2C (Wire) pull up resistors, Arduino Due, 20 (SDA0-3), 21 (SCL0-3)

That certainly solved my problem! Thank you for pointing this out.

For anyone stumbling upon this thread with a similar problem:

I'm using 330 ohm resistors in series with the default pull-ups (1k, 1.5k in the schematics) of the Due on pin 20 and 21, plus the built-in pull-ups in the Adafruit 10DOF IMU (10k).

My SCL clock is set to 400 kHz.

No resistors needed for the GPS RS232 TX line (as previously indicated).

I would also check that the 3.3V rail is holding up under those loads and
add a separate 3.3V regulator if not. Or at least check what current
it is rated to provide.

rblilja:
That certainly solved my problem! Thank you for pointing this out.

For anyone stumbling upon this thread with a similar problem:

I'm using 330 ohm resistors in series with the default pull-ups (1k, 1.5k in the schematics) of the Due on pin 20 and 21, plus the built-in pull-ups in the Adafruit 10DOF IMU (10k).

My SCL clock is set to 400 kHz.

No resistors needed for the GPS RS232 TX line (as previously indicated).

Well... I had asked you in another thread if you had found a solution to the problem, and it seems you have. I have tried it here (a 1K resistor in the TX->RX line) and it seems ok so far.

Ill get to that better solution pointed by dlloyd in time.

Thanks to both!

Greetings.

1 Like

Good to hear that you manage to solve a similar problem as well. I have not seen your question in this other thread you refer to - sorry.

By the way, what do you mean by "TX->RX line", you are not speaking about I2C - right? Please observe that I in the end only implemented resistors (330 ohm) on the I2C signals (SDA and SCL). I removed the resistors in series on the UART lines.

Hi rblija. In fact, the problem I had was identical to yours, with exactely the same hardware. So I found your first post, wrote something there, and then I found this one, where you said up there:

Anyway. I manage to solve the problem by placing a resistor (4.7k) in series with the TX line of my GPS (i.e. the line connected to the Due's RX pin).

I could not yet try the nice circuit presented later by dloyd, so I just tested this first one, and the blocking stopped.

In my arduino code, i have to pickup these data and send them serially to a RaspPi, together with other data... Im still having bugs with it, but im betting it is something with my code, or because I have not yet put together the nice circuit with all the resistances and all, but Ill get there!

Anyway, the solution you guys came up with is great. Tnx.

I am having a similar problem. Arduino Due, Gps being received on Serial2 and an I2c LCD connected to pins 20 21. The LCD is from robotshop and it is supposed to work on the Due.
After a short period the gps data hangs and the LCD goes blank. When the LCD is disabled in the code the GPS works fine.
The solution mentioned in this post was to add 330 ohm resisters in series on the I2C lines from the LCD.
Before I do this I want to confirm that this will not cause a problem with the Due or LCD. Are these resistors correctly sized or should they be smaller or larger. I am not an electronics buff.
The solution also did not require any pull up resister other than those already connected on the Due
Regards

Placing resistors in series as described in previous posts will not damage your Due nor LCD. My issues did not reappear.

That fixed the problem
Many thanks