Help Implementing i2C Timeouts with SAMD51 boards

I am searching, reading, and trying to digest how to add a timeout feature for i2c using the newer SAMD51 boards (Metro m4).

I have read about I2C Library developed by Wayne Truchsess at DSSCircuits
(Changing the I2C Library... — Rheingold Heavy)
I've tried implementing this and received a large output of errors. I'm open to elaborate here, but curious first if anyone can point me in the right direction, as this was developed for AVR boards and perhaps this is the root cause of these errors.

Simply put I have i2c hangup issues due to noise that can occur in my environment using an i2c touchscreen from Matrix Orbital. Their examples use the wire.h library. I am quite certain I need a timeout on the i2c. My code is rather long, happy to share if needed. I've tried shielding the wires / using pullups / etc. So I would like to keep any response focused on helping to implement a timeout function for those of use who are not experts with Arduino or editing libraries.

Thank you for your time

Is it okay if I give some friendly and constructive notes ? You are too much focused on the timeout, and the I2C bus is not a fault tolerant bus.

First of all, please forget those websites about a timeout. It is so bad. Mainly because it is very outdated and only for AVR boards and it has probably bugs and no one knows if that code is any good.

You can still fix your post and fix that link to a non-existing website.

Have a look at the functions of the Arduino Wire library: https://www.arduino.cc/reference/en/language/functions/communication/wire/
Scroll down and you see that there are three functions for the timeout. The function setWireTimeout() is all that is needed, together with a check of the return value of Wire.endTransmission() and requestFrom(). In my opinion, the example on the setWireTimeout() page is too complex, I see no need to test if the error code is 5 or use the flag.

You have to ask Adafruit if they have implemented the timeout for their Metro M4. That is not an Arduino board.
I don't even know where the I2C library of Adafruit for the SAMD51 is. Adafruit also puts a lot of work in CircuitPython.
I vaguely remember a question a few weeks ago. Someone pinpointed the code line that caused the Wire library for SAMD21 and SAMD51 to stop and there was an issue on Github and maybe it was fixed for some Arduino boards.

Can you give a link to your display and to those examples of Matrix Orbital ?

The I2C bus is not a fault tolerant bus, it should work 100%. It was not designed to go into a cable.
Can you tell what kind of cable you use and how the signals are organized in the cable and how long the cable is and what your pullup is ?
Maybe your I2C bus can be fixed or maybe you need an other solution. The I2C bus is a weak bus after all (because the high level is made with the pullup resistors).

Thank you very much for taking the time to respond. I will review further the functions of the wire library, and will check with Adafruit on compatibility.

I was under the impression the AVR boards are becoming dinosaurs compared to the newer and faster boards, but I could always go back to AVR if needed as a last ditch effort.

I am currently using the standard single wire lines that come with arduino kits (40pin breadboard style wires). They do go through a few din rail terminals and I use 10k pullup resistor on each signal near the board side connection. The total line length is approximately 1ft.

I tried to make a wire using a 2-wire shielded cable I had kicking around, with foil wrapping the wires on the inside, and couldn't get this to work at all. I was bypassing the din rails. I'm open to trying another cable.

I would love to forget about timeouts, if possible. I can go days without a hangup, but any noise from a nearby fan or motor trips it. I have confirmed that I can trip it myself just by turning a fan on next to it.

Matrix Orbital GTT50A: GTT50A-TPR-BLM-B0-H1-CI-V5
https://www.matrixorbital.com/gtt50a

Examples:
https://create.arduino.cc/projecthub/MatrixOrbital/matrix-orbital-gtt-tft-thermometer-stage-1-9d7e44

I kept blue and purple as the colors. They go through a few din rails, and have the pullups on the last din rail before going to the board. I know it's not the prettiest guts of a controller, was hoping to look into a PCB once I had things dialed in.

The I2C bus can not deal with crosstalk between SDA and SCL.
If you have wires that stick together for SDA and SCL, then split those wires.
You may keep a SDA wire close to a GND wire, and a SCL wire close to a GND wire.
The GND wire is in my opinion the most important wire of the I2C bus.

10k pullup is only a little pullup. I'm thinking about 1k5 or 2k2 (for the total combined pullup).
Do you know how much pullup the Metro Mini has and the display ?
There is a way to measure in your circuit what the pullup is.

For the AVR family boards, this is possible:

Wire.begin();
Wire.setWireTimeout();

I think that is wrong, the timeout should be a normal part of the Wire library, without using extra functions. The timeout could be used to be able to continue with the sketch for the very rare event that the I2C bus fails. It should not be part of normal communication (such as a checksum for serial communication).

A Arduino Uno has a 5V I2C bus and your display seems to have a 3.3V I2C bus. That means your noise margin will be gone with a Arduino Uno. If you use a Arduino Uno, then you need a I2C level shifter, but that weakens the I2C bus.

Sometimes two resistors of 100Ω are used in the signal path of SDA and SCL to dampen the edges a little. The high-to-low edges from the processor could travel on the I2C bus as noise. The Arduino Uno has hardware inside its chip to filter incoming signals and a slew-rate limiter for outgoing signals. Newer processors don't have those filters.

The display has SDA next to SCL on the connector. That is what everyone does, and it is wrong. Read section 7.5 on page 54 of the official standard I2C document: UM10204.pdf

This is the other topic that I mentioned: SAMD51 I2C Hang Issue

In case you wonder why no one told you that the I2C bus was so wonky, well, the I2C bus was created in 1980 to be able to store data in a EEPROM chip that was soldered right next to the processor inside a television. That makes sense, doesn't it ?

Does your display have a TTL-level Serial/UART/RX-TX communication or is that a other version ? Can you get one of those ? Or did you think that I mentioned all I2C problems by now ? O no, I'm holding back.

[ADDED] I took a look at the examples for the display on Github. They are using the I2C bus in the wrong way, so I made two Issues: here and here.
It depends on the Arduino board and display how bad it is. A Arduino Uno with a common sensor might still work. You might not be so lucky.

Apologies for the noobie question here, but is the value of the 1k5 resistor equal to 1500 ohms, and wouldn't that be much less then 10k (10,000) ohms?

I'm just trying to understand you when you stated 10k pullup is only a little pullup. I'm also trying to test some of the easier adjustments before moving along; such as adjusting the pullup value.

I did test the circuit pullup using that sketch and was getting right around 1ma on both SDA and SCL.

My problem is definitely triggered by turning on a fan or similar noise generating device.

SDA / SCL wires are split. I tried adding inline 200 ohm resistors that I had, with no effect.

Last thing I have tested, I created basic program to scan and read the i2c device. Using the same exact wiring and sketch I can cause the Metro M4 to hang up and have i2c issues, while the arduino Uno board doesn't seem to be affected at all; I can turn the fans nearby off and on many times without an issue.

The only problem I see potentially here is that I am now using 5v logic, I don't currently have a level shifter. I am going to test some screen functions next and see what happens.

1k5 is 1500Ω, that is more pullup then 10k.

The 1k5 pulls SDA and SCL stronger to 3.3V then the 10k does.
Suppose SDA or SCL is 0V and the resistors has to pull the signal to 3.3V.
With 1k5, the current is 3.3/1500 = 2.2 mA
With 10k, the current is 33/10000 = 0.33 mA

If you measured 1mA, that means that something else has also pullup resistors.
You can lower the impedance of the I2C bus (less vulnerable to noise) by moving towards 3mA.
If you replace the 10k with 1k8 or 2k2, then another 1.8 or 1.5 mA is added.

How is your grounding and GND current ?
Grounding is craftsmanship on its own.
The GND that is part of the I2C bus should go directly from the Arduino board to the I2C device. It should not be used for motors or things that need a lot of current.

Have you seen page 54 ?
You may take a ribbon cable and put SDA and SCL on the outside. You can also take two wires from a ribbon cable for SDA and GND and another two wires for SCL and GND.

It is possible that the display itself can not deal with the noise (either via wires or through the air).
Can you make the fan cause less noise ?

A good project shields the sensitive parts and shields the parts that cause trouble. Reducing the sparks and noise and voltage and current peaks is done when designing the circuit. Optocouplers are used to separate the parts. And I2C is only used on the same PCB.

I understand the pullups better, thank you.
GND from the i2c bus goes directly to the board.

SDA and SCL wires are now separated, I did review page 54 - it seems most board / sensor manufactures ignore the standard. I did share this with Matrix Orbital.

I tried adjusting the pullup resistor values with very odd / mixed results. I put 2X 4700 ohm on each the SDA and SCL. I figured I would see 2.8ma at 3.3V logic and roughly 4ma on 5v logic. Instead I read 1.4ma and 3ma respectively.

Did you see my comment above regarding the Arduino Uno AVR board. With this board I don't seem to have any noise interference so I am moving forward with my project for now Using an AVR type board. I don't have internal pullups activated, I'm wondering if you have any insight on this result. I know you mentioned internal filtering, is there an easy way to replicate this on the SAMD51 boards? I tried putting 200ohm resistors in line on the SDA & SCL with the same results.

I have read it. The SDA and SCL for a Arduino Uno can do maybe 800kHz, but the ATSAMD can do a few MHz. That means that small spikes are ignored by the Uno.

If the 200Ω did not help, then the falling edge of the ATSAMD is not the problem.

Don't pullup to 5V, because then you put 5V (via the resistor) into a 3.3V chip. They don't like that.
Do you have more 4k7 resistors ? Use three for each signal.

I don't know how the GND current to the display is and I don't know how sensitive the Metro board is for noise. You should have better results by now :cry:

A few common solutions to try:

  • Add a capacitor of 100µF to 1000µF to the GND and 3.3V of the Metro board. Sometimes a project starts to work with a large capacitor for the power.
  • Use shielded cables for SDA and SCL. A cable for SDA with a shield with GND and another cable for SCL with a shield with GND. The shielding will also act as capacitors to dampen the I2C bus a little.
  • How bad is your power supply ? If you use a cheap led driver as power supply, then terrible noise will enter the whole circuit. Can you try another power supply ?

There were similar problems on this forum the last months. I'm answering a similar problem right now: https://forum.arduino.cc/t/sbwire-problem-with-nano-33-iot/987526

Thank you Koepel.

Now using the AVR board, I have been able to trip up the i2c a few times, although it is much less often, perhaps this is given the Uno is running 5V for i2c and less affected by noise.

Just to confirm on the shielded cable, you tie the shielding material to ground on the controller side of connection, lcd screen, or both ends?

I am using what I think to be a good power Supply made by Traco (TSR 1-2450) with built in filter capacitors. I added a 100uF Capacitor From Arduino Uno 5v to GND. Now that I am using the UNO I believe the chip / logic is 5V.

Do you think it's possible the screen itself can pickup electrical noise?

Like I said, it is much harder to trip the i2c now that I am using the UNO but I can still do it but it is now very random. I am going to implement a Timer in this case. Last thing to try is the shielded wire I believe. I'm curious though if you run a shielded wire into a DIN rail to allow multiple SDA / SCL signals to the controller, do you defeat the purpose of the shielded cable.

Where do the multiple SDA / SCL signals come from ? What else is picking up noise ?

If there is already a GND in the cable, then the shield is often connected at the begin and not connected at the end.

Yes, the display itself might pickup noise or generate noise.

It is very hard for me (sitting at my desk) to get some feeling what is going on. A good quality oscilloscope and a few measurements should be enough to find the cause.

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