Multiple wire.begin()

Hi

I have a project that keeps having problems with the I2C bus. Hardware wise everything is okay. When I load an I2C scanner program everything is fine and the corresponding examples also work.
Something does not seem to work well together.
During a closer analysis I found out that there are different libraries called.

wire.beginn ();

Adafruit_MCP23017.cpp

..
..
void Adafruit_MCP23017 :: begin (uint8_t addr, TwoWire * theWire) {
   if (addr> 7) {
     addr = 7;
   }
   i2caddr = addr;
   _wire = theWire;
   _wire-> begin ();
   // set defaults!
..
..
..

Adafruit_BME280.cpp

..
..
bool Adafruit_BME280 :: init () {
   // init I2C or SPI sensor interface
   if (_cs == -1) {
     // I2C
     _wire-> begin ();
   } else {
..
..
..

My question now is, is this possibly causing interference on the I2C bus?

Hallo
ich habe da ein Projekt in dem immer wieder Probleme mit dem I2C-Bus habe. Hardware mäßig ist alles okay. Wenn ich ein I2C-Scanner Programm lade ist alles in Ordnung und auch die entsprechenden Beispiele funktionieren.
Nur im zusammenspiele funktioniert anscheinend etwas nicht.
Bei ein einer genaueren Analyse habe ich herausgefunden das verschieden Bibliotheken

wire.beginn();

aufgerufen.

Adafruit_MCP23017.cpp

..
..
void Adafruit_MCP23017::begin(uint8_t addr, TwoWire *theWire) {
  if (addr > 7) {
    addr = 7;
  }
  i2caddr = addr;
  _wire = theWire;
  _wire->begin();
  // set defaults!
..
..
..

Adafruit_BME280.cpp

..
..
bool Adafruit_BME280::init() {
  // init I2C or SPI sensor interface
  if (_cs == -1) {
    // I2C
    _wire->begin();
  } else {
..
..
..

Meine Frage ist jetzt, führt das vielleicht zu Störungen auf dem I2C-Bus?

Adafruit does that a lot, calling Wire.begin() inside a library that uses I2C. It will not cause a problem on the hardware I2C bus, and as far as I know it is not a problem in software either.

The Wire.begin() resets everything to default. That might reset the bus speed back to its default of 100kHz. That is not a big problem.

Wire.begin();   // set clock to default of 100kHz
Wire.setClock(400000);  // set clock to 400kHz
Wire.begin();   // set clock to default of 100kHz

This is the first Wire.begin(): https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library/blob/master/Adafruit_MCP23017.cpp#L125

This is the second Wire.begin(): https://github.com/adafruit/Adafruit_BME280_Library/blob/master/Adafruit_BME280.cpp#L99

I can’t see a problem.

MagierPhil:
Hardware wise everything is okay.

You have not convinced me. I can say that in a better way: if you think that the hardware is okay, then I think that there is 50% chance that the problem is in the hardware :wink:

The MCP23017 runs at 3.3V and at 5V.
The BME280 runs at 3.3V.
Which Arduino board do you use ? Which modules are they (a link to where you bought them please) ? Do you use cables for the I2C bus ? Is there a OLED somewhere ? What is connected to the MCP23017 ? and so on.

Please show the full sketch.

MagierPhil:
Something does not seem to work well together.

When you write that on this forum, then we ask: “what is something ?”, “how do you know ?”, “what do you expect and what does happen ?”, “Can you explain the problem ?”.
As far as we know, every time you use them both, a black cat drops from the ceiling and a sea shanty choir knocks at your door, while the gravity turns upside down for 5 seconds.

This appears to be a hardware problem, can you post a schematic, not a frizzy thing, showing all power, ground, and interconnections. Please also give links to the hardware items you used.

Hi
I use an Arduino Due Board and I know that the different I2C ICs use different voltages. I have a level shifter (5V) for the BME280 and the MCP23017 signal part.
I also have a DS3231SN on the 3.3v part.

The project is pretty big and still a bit confused and before I look any further, I wanted to ask if it might be due to wire.beginn ().

As I said, the examples (projects) work and here is the output from the I2C scanner …
(Arduino Playground - I2cScanner)
Scanning …
I2C device found at address 0x20!
I2C device found at address 0x68!
I2C device found at address 0x76!
done

0x20 ← MCP23017
0x68 ← DS3231
0x76 ← BME280

The MCP23017 module is my own project / board and controls 6X relays and it works.
Now at least I know that I have to look for the bug in my code.

Sorry, I’m having trouble publishing the schematics … the forum doesn’t like the files. Try again later.

Here my MCP23017 board.

And here the main board. With connections for 1-Wire (DS18B20), I2C, 3X channels NeoPixel LEDs, 2X PWM fan control, SPI -> W5100 Ethernet Shield and 2.9inch E-Paper E-Ink Display Module Red / Black / White.

Und hier das Haupt-Board. Mit Verbindungen für 1-Wire (DS18B20), I2C, 3X Kanäle NeoPixel LEDs, 2X PWM Lüfter Steuerung, SPI -> W5100 Ethernet Shield und 2.9inch E-Paper E-Ink Display Module Red / Black / White.

And yes I know the schematics are not perfect.
For example, the connector JP4 is superfluous because the DUE already has internal pull-up resistors and JP1 and JP2 are measuring points so that I can more easily pick up or change the signals.
There is another level shifter for the NeoPixel (J1).
For this I will move the fan PWM pins (D2 + D3) in the next version of the circuit diagram to due pins (D35 + D37) so that I can get the internal PWM signals.(GitHub - antodom/pwm_lib: This is a C++ library to abstract the use of the eight hardware PWM channels available on Arduino DUE's Atmel ATSAM3X8E microcontroller.)

Before you started to make this, you should have asked: “Shall I use the Due for my project”, then we could have answered: “No”.
You also could have asked: “Hi Koepel, where is that page about I2C to scare others ?” :o

The Due has pullup resistors of 1k or 1k5 at SDA and SCL. That is a mistake. Can you remove them from the Due board ?

I can try to calculate the sink current (assuming the Due has 1k5):
3.3V/60k + 3.3V/1k5 + 3.3/4k7 + 5V/10k + 3.3V/10k + 5V/10k = 4.2 mA
That is too much sink current. The level shifters make the signal weaker. So there are at least two things on your I2C bus that are not optimal.

Do you use a level shifter after a level shifter for the BME280 ? Then please read this that I wrote to scare others for the I2C bus: https://github.com/Koepel/How-to-use-the-Arduino-Wire-library/wiki/How-to-make-a-reliable-I2C-bus.

FTR-K1CK005W: Fujitsu FTR-K1 Series relays, SPDT, 400mW, 5V, AgSnO2 contacts.
It takes only 80mA for the coil. That is a low current for a relay coil, but the coils in the circuit can still ruin your day. It depends for example on the ground path.

The NeoPixels want a 5V signal, but also the DS18B20 has less trouble with noise when using a 5V 1-Wire bus. Can you make your design to allow an optional extra level shifter ?

You have not answered the question what does actually go wrong. I even gave that extra attention with the cat dropping from the ceiling story :wink:

Hi

I had done some research on the Arduino Due but found nothing that bad. I had read that the I2C pull-ups are not as described in the official document, but I hadn’t thought that the Arduino was selling non-working hardware.
On the other hand, I mostly use parts that are lying around here in the shop.
For example the DUE and the BME280 board.
I hadn’t found your Koepel · GitHub page yet, now you have one more reader :wink:

Regarding the sink current bill, I once did not close JP4, so the 4.7k is not included in the bill. But now I could unsolder the 1.5k from the Due and close JP4, then after a quick calculation I have 2.26mA.
(3.3V / 60k) + (3.3V / 4.7k) + (5V / 10k) + (5V / 10k) + (5V / 10k) = 2.2571mA

I would not like to replace the DUE, is it that bad? I liked it because of the large memory, so I could still play around with an HTML website.

The NeoPixels are connected again through a level shifter (74HCT125N) and I have shielded lines for the I2C, NeoPixels and 1-Wire Bus Singal lines.

To be honest, I don’t understand the relay part. Maybe it’s because I don’t speak native English. What do you mean it could ruin my day?
The relays should switch a Raspi-4 on and off every now and then (maybe every few days or weeks).

By the way, after two days my project works fine, no idea why? It just stood on the desk without power, now it works ???

But I’m a bit disappointed anyway, the W5100 Ethernet Shield is pretty crap. The chip gets pretty hot …

I once attached my project (zip). The code isn’t pretty and it’s still in development, so I hate to show it.
The mistake from the beginning was simply that the I2C components did not respond. No more.

The output now looks like this …
Clock, BME280 etc work …

Debug_Serial
Scanning...
Adresse : 32
Adresse : 104
Adresse : 118
done

Debug_anfang
DS3231Online     = 1
UnixTime()       = 1615914554
_TimeUpdateDelay = 1615916414
Temperatur::Temperatur()
Adresse : 118
Versuch     = 0 BME280 Aktiv = 1
MQTT_Connet() = True
BME280Aktiv = True
DS3231Online = True
(1) Message arrived [ServerBox/Relais/1/] 1
(2) ServerBox/Relais/1/ = 0
Relais1 = 1

DUE-Test11.zip (13.4 KB)

If you remove the 1k5 or 1k from the Due board, check if your level shifter has pullup resistors on both sides of the mosfet. A pullup resistors of 10k on both sides is okay.
The pullup resistor at the low-side to 3.3 Volt and the pullup resistor on the high-side to 5 Volt.

Your BME280 module has onboard level shifters and a voltage regulator.
That means the SDA and SCL have to go through two level shifters. That is a problem. Others have problems with that as well. Is there a way that you can fix that ? Can you buy a BME280 without level shifters and connect it to the 3.3V I2C bus ?
You could connect your MBE280 module to the 3.3V I2C bus. That is not ideal, but better than two level shifters in the signal path.

Are there wires to the I2C display or wires to the BME280 module ? Are SDA and SCL next to each other in a flat ribbon cable ?

The I2C bus might not be the cause of the problem, but you don't have a good I2C bus. I prefer to fix that first.

I prefer more debug output in your sketch. You could add a few more messages.
For example:

void Relais::Relais1(bool boo_In)
{
  Serial.print("Relais1 = ");
  Serial.println(boo_In);

  Serial.println("debug: before mcp");
  mcp.digitalWrite(7, boo_In);
  Serial.println("debug: after mcp");
}

The Wire library for the AVR family boards (Arduino Uno) has a low level timeout. I don't know if the Wire library for the Due has that.

The W5100 does get really hot !
It is also very low level Ethernet, and because of that not very reliable.
The ESP32 has Wifi at a higher level and is therefor more reliable.

About those relays:
They have coils and the flyback diode catches the reverse current peak. However, that reverse current peak has to go through wires and through pcb traces. That peak might influence other things. Current peaks are bad, they can ruin your day.
The current that has gone through the coil has to go via the GND traces of the pcb to the GND of the power connector and then back into the power supply. That is the ground current. It should not influence the I2C bus.

You use millis() in the wrong way.
If you do this: _SendNext = millis() + _SendDelay
then there is a problem after 50 days when millis() rolls over.

If you remove the 1k5 or 1k from the Due board, check if your level shifter has pullup resistors on both sides of the mosfet. A pullup resistors of 10k on both sides is okay.
The pullup resistor at the low-side to 3.3 Volt and the pullup resistor on the high-side to 5 Volt.

Understood and checked

Your BME280 module has onboard level shifters and a voltage regulator.
That means the SDA and SCL have to go through two level shifters. That is a problem. Others have problems with that as well. Is there a way that you can fix that ? Can you buy a BME280 without level shifters and connect it to the 3.3V I2C bus ?
You could connect your MBE280 module to the 3.3V I2C bus. That is not ideal, but better than two level shifters in the signal path.

Okay, I looked at ebay, a new BME280 for 3,3Volt is not so expensiv.

Are there wires to the I2C display or wires to the BME280 module ? Are SDA and SCL next to each other in a flat ribbon cable ?

No displays with I2C. Wires not relay. But I use shielded wires, I think they are called microphone cables.

Thanks for the help in the Code. I know the bug, I only forgot to fix it.
As I said, it's no nice Code.

->ESP32

Wifi is no option. My plan is to buy a new Shield, Ethernet Shield 2 with a W5500. That has more Options, so you can get more information if the LINE is Up.... I hope this will work better.

About those relays:
They have coils and the flyback diode catches the reverse current peak. However, that reverse current peak has to go through wires and through pcb traces. That peak might influence other things. Current peaks are bad, they can ruin your day.
The current that has gone through the coil has to go via the GND traces of the pcb to the GND of the power connector and then back into the power supply. That is the ground current. It should not influence the I2C bus.

Also understood, will keep an eye on the problem.

You use millis() in the wrong way.
If you do this: _SendNext = millis() + _SendDelay
then there is a problem after 50 days when millis() rolls over.

Yes I know. I used millis() more as a fallback. I built it in more for testing and plan to take it out at the end. Normally I want to use the DS3231 and Unixtime, getting the time from the NTP server works fine. I also thought about using the Adruino as a time server in case of a failure in the internet connection but that's just a plan.

MagierPhil:
But I use shielded wires, I think they are called microphone cables.

That could be the problem.
Can you tell more ? Is SDA next to SCL ? Or is each wire shielded ? Shielded with GND ? Is that GND also used to power what is at the end of the cable ? How long is the cable ?
As soon as you combine the words "I2C" and "cable", then you are asking for trouble. After reading "How to make a reliable I2C bus" you should know that the I2C bus was not designed to put in a cable.

MagierPhil:
Yes I know. I used millis() more as a fallback.

Even if you use millis() as a quick fix, you should not do it wrong. Do not calculate a time in the future.

Grab a timestamp: previousMillis = millis();
Calculate how many time has passed: if ( millis() - previousMillis >= interval)
See the Blink Without Delay example.

The wire is 80cm long and looks like

I'm not 100% sure, but they look very similar to what I found. Here are 2 more pictures of how I wired it and how it looks in real life.

That's okay. The shielding creates extra capacitance, you could lower the speed to 50kHz with Wire.setClock(50000);.
To compensate for the extra capacitance, normally the pullups are made stronger. You have calculated it to be between 2mA and 3mA (without the 1k or 1k5 from the Due), so that is okay.

Have you seen page 60 ? https://www.nxp.com/docs/en/user-guide/UM10204.pdf.

ARRRG think I found the error, the DS3231 module has a shot.

I disassembled everything and forgot to plug in the clock module, everything has been fine since then.

*Sigh * eyes roll

The one with the Wire.setClock (50000); I think about it.

I think I read the User Guide. But that with the crosstalk between the lines makes sense ...

I'm glad you found it :smiley:

Does that mean that your I2C was working with two level shifters to the BME280 ? Then you are in luck, others are not so lucky.
Those microphone cables might even help to reduce spikes and noise in the rest of the I2C bus, because of the extra capacitance.

I have seen a lot of libraries in the last few days. Is the library checking if it actually received real data from the DS3231 ? I think it does not. You should at least put a test in setup() to check if it is connected before using it.

So as it is. Without the clock module everything works, approx. 10 resets and 5 times new software installation. With the module after 2 resets, no clients can be found on the I2C bus ......

When I take the clock module out again, the fault is gone.

I'll see what the voltage of the soldered-on battery says, that's all I can do with this tiny thing.

Look for a replacement module right away, mine somewhere I would have seen 2 more.

For test and debug purposes I have installed an I2C address scanner and the NeoPixels light up red when there is an I2C fault.

Thanks for your time!!!!!!!!!!!!! ???

Hi
so another update. The DS3231 is not defective, but it is still the culprit.
Apparently it is a known problem that when the CPU is reset in connection with a DS3231 module, the I2C bus gets stuck in an undeveloped state.

Read through the details for yourself. (Reliable Startup for I2C Battery Backed RTC - Why the Arduino Wire library is not enough.)

I came up with it because with 3 different modules in 2 different designs, it always produced the same error for me.
Error: 1 or a maximum of 2 resets and the I2C bus was no longer accessible and only switching off completely (de-energizing) and removing all I2C components fixed the error.

To the solution:
In the setup, as early as possible and BEFORE the I2C bus is used, I execute the function int I2C_ClearBus ().
Goal achieved, the project has now been running for 2-3 days and has gone through a dozen resets and the I2C bus is always stable.

void setup() {
  Serial.begin(9600);
  Serial.println("Debug_Serial");
  int rtn = -1;
  for (int int_run = 0; int_run < 5; int_run++ )
  {
    int rtn = I2C_ClearBus();
    if (rtn != 0)
    {
      Serial.println(F("I2C bus error. Could not clear"));
      if (rtn == 1)
      {
        Serial.println(F("SCL clock line held low"));
      }
      else if (rtn == 2)
      {
        Serial.println(F("SCL clock line held low by slave clock stretch"));
      }
      else if (rtn == 3)
      {
        Serial.println(F("SDA data line held low"));
      }
    }
    else
    {
      break;
    }
     delay(100);
  }
  MQTTclient.setServer(MQTTServer, MQTTServerPort);
  MQTTclient.setCallback(MQTT_Callback);
  Ethernet.begin(mac, ip);
  Wire.begin();

In my defence, my initial idea that something was wrong with starting/initializing the I2C bus was correct. But I was looking in the wrong place (would probably not have happened if I had an oscilloscope or bus analyser).
Nevertheless, once again THANKS to Koepel. It was very exciting to talk to you and I learned a lot.

The DS3231 has a reset pin. Is the Due reset without resetting the DS3231 ?
Why is the Due reset ? Is that because of a Ethernet lockup ?

Thank you for not giving up and going a great length to get to the bottom of this problem.
It was missing on my Github, so I have added this page (it is a first version, it needs some work): How to unlock a stuck I2C bus · Koepel/How-to-use-the-Arduino-Wire-library Wiki · GitHub

The Due Resets when I press the Reset Button :slight_smile: . It is a easy way of observing the startup behaviour.

And I call it "Reset" when I setup new software, because it also produces the same error. I'm not sure if this is really a CPU reset, but I think so ....

Later my little device will control a small server box and communicate via MQTT. One of the sticking points is that the Aduino starts before the MQTT server, so it has to get along without it for a while. I still have to think about something if the MQTT doesn't start properly.

  • DS3231 sensors to control CPU, power supply and hard disk temperature.
  • BME280 ambient air, temperature and pressure
  • Relay to start the various servers individually or to reset them hard in an emergency. (Should also be a way of saving energy when I don't need the servers, I can completely disconnect them from the power supply.)
  • PWM fan to cool.

The whole thing nicely packed in a metal box and covered with wood.
Plus a couple of colorful LEDs (NeoPixels) to sell it to my girlfriend better. I hope she thinks it looks like art :smiley:
Oh yes, and an e-paper display for status information.