Wire library hang problem, again.

Hi guys,

I’m new in town, so please be gentle. :slight_smile:

I have searched around web to solve this issue but had no luck.

Known problem is that Arduino Wire library can hang if SCL or SDA line is held low by any reason.
By reading forums I have found WSWire library may be solution but I do not know how to include it since I get conflict when I try to include WSWire.h instead of Wire.h in my code.

Even simple code like this fail to compile.

#include <WSWire.h>   //https://github.com/steamfire/WSWireLib

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

void loop() {
  while(1);
}

I am getting a bunch of messages…

libraries\Wire\Wire.cpp.o (symbol from plugin): In function `TwoWire::available()’:

(.text+0x0): multiple definition of `TwoWire::available()’

libraries\WSWireLib-master\WSWire.cpp.o (symbol from plugin):(.text+0x0): first defined here

.
.
.

libraries\WSWireLib-master\utility\twi.c.o (symbol from plugin):(.text+0x0): first defined here

libraries\Wire\utility\twi.c.o (symbol from plugin): In function `twi_readFrom’:

(.text+0x0): multiple definition of `twi_releaseBus’

libraries\WSWireLib-master\utility\twi.c.o (symbol from plugin):(.text+0x0): first defined here

libraries\Wire\utility\twi.c.o (symbol from plugin): In function `twi_readFrom’:

(.text+0x0): multiple definition of `__vector_24’

libraries\WSWireLib-master\utility\twi.c.o (symbol from plugin):(.text+0x0): first defined here

collect2.exe: error: ld returned 1 exit status

exit status 1
Error compiling for board Arduino Pro or Pro Mini.

I have cut off rest off messages since it’s all similar.

Why I can not include WSWireLib in my project and is there any better solution to fix Wire hang problem_

I know it is possible to modify twi.h file to add timeout function but I do not like to modify standard library.

I am using last relase Arduino IDE 1.8.5.

Sorry for my poor English. It’s not my native language.

Best regards.

You should fix your I2C bus. It is not a fault tolerant bus, it is supposed to work 100%.

The WSWireLib is 6 years old. Since then a bugs have been solved in the Arduino Wire library.

The twi.cpp helper files is linked twice. That is the problem.
I suggest to remove all 'Wire' and 'Wire-alike' libraries from your user custom "libraries" folder.
The normal Wire library is in the standard system files of the Arduino.

In the settings, turn on the extra compiler output. Compile the sketch and check the Wire library that is used.
Once you have that, you could try the WSWireLib again, perhaps you can put those files into your own project.

In my opinion it is a terrible major bug that an external event can stop the code in an embedded system.

Koepel thanks for your help.

You should fix your I2C bus. It is not a fault tolerant bus, it is supposed to work 100%.

Yes you’re right, but again, it should not crush my whole code due of some stupid peripheral device fail for any reason.

The WSWireLib is 6 years old. Since then a bugs have been solved in the Arduino Wire library.

In my case MCU program probably hangs in dead while loop. For example here is one of the functions from original twi.ccp file.

/* 
 * Function twi_stop
 * Desc     relinquishes bus master status
 * Input    none
 * Output   none
 */
void twi_stop(void)
{
  // send stop condition
  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);

  // wait for stop condition to be exectued on bus
  // TWINT is not set after a stop condition!

  while(TWCR & _BV(TWSTO)){
    continue;
  }

  // update twi state
  twi_state = TWI_READY;
}

There is potentially dead while loop and this code is from last Arduino IDE release. This may be harmful since there is no way to go out of this loop except by watchdog reset or similar way. This like problems may be a night mere for programmers since there is no any warning this can happens.

The twi.cpp helper files is linked twice. That is the problem.
I suggest to remove all ‘Wire’ and ‘Wire-alike’ libraries from your user custom “libraries” folder.
The normal Wire library is in the standard system files of the Arduino.

I am not sure I do understand you here.
Is that means I must physically remove all the library files that are using standard Wire library even they are not included in project?
If in my code, I do not have #include <Wire.h> directive why than linker makes problem with that library?

In the settings, turn on the extra compiler output. Compile the sketch and check the Wire library that is used.
Once you have that, you could try the WSWireLib again, perhaps you can put those files into your own project.

I’ll try this.

Thanks man. I hope I’ll solve this problem soon.

Best regards…

In the settings, you see the sketchbook location.
That is where your projects are.

Along with your projects, there is also a folder "libraries" in the sketchbook location. Check that folder for libraries that have to do with I2C.

The normal Arduino Wire library should not be there.

n the settings, you see the sketchbook location.
That is where your projects are.

Along with your projects, there is also a folder "libraries" in the sketchbook location. Check that folder for libraries that have to do with I2C.

The normal Arduino Wire library should not be there.

Yes there are some I2C libraries including WSWireLib but standard Arduino Wire library is not there.

Arduino Wire library is located in "C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire" folder.

Does it matter if there is some other I2C libraries in my sketchbook location if that libraries aren't included in current project? Should I remove libraries I do not use in current project?

They could be independent. They don't have a "twi.c" I assume ? That's okay, you can keep those.

For a Pro or Pro Mini board, that is the normal ATmega328P.

Let me test the WSWireLib... I have copied the "WSWire" folder into the "libraries" folder and compiled your sketch with Arduino IDE 1.8.5 without problem. Not even a message that two libraries are found.
I use linux, but translated into Windows, then my "twi.c" is in: Documents \ Arduino \ libraries \ WSWire \ utility \ twi.c

Somehow you have mixed things.

Wow, thanks man I know now that the problem is on my side but I must figure it out.

OK I'm back in business again. :slight_smile:

I have cleaned my library folder from all libraries and by adding one by one have figured out that I have two different LiquidCrystal_I2C libraries that uses the same constructors and bothof lib's includes Wire.h.
That was a problem. Now after cleaning a mess I can compile without errors reported.

Unfortunately this is not end of my root problem because my code still hangs if I pull SCL or SDA line to the ground by 100 ohms resistor.

I have changed timeout function in WSWireLib twi.ccp file to set high an unused pin

//Nirea. Time Out
static volatile uint32_t twi_toutc;
uint8_t twi_tout(uint8_t ini)
{
	if (ini) twi_toutc=0; else twi_toutc++;	
	if (twi_toutc>=100000UL) {
		twi_toutc=0;
		twi_init();
		
		digitalWrite(A3, HIGH);	// debug
		
		
		return 1;
		
	}
    return 0;  
}

Now I can see timeout occurs but some of higher functions do not release program flow control back and program hangs.

I must try to debug and find where is the problem.

In my sketch on I2C port I am using DS3232RTC library from

//https://github.com/JChristensen/DS3232RTC

and NewLiquidCrystal library from

I'll try to find the source of the problem by elimination...

Here is update ...

WSWireLib actually works as it should be. I've soldered the LEDs to the debug pin and changed the debug code in twi.h so it tohggle the LED every time the timeout occurs.
Now I see LED start flashing after I pull down any I2C port pin and it blinks for a while after what the program works OK again.
It looks like WSWireLib works good, but LiquidCrystal_I2C does not handle I2C port error report and repeatedly tries to write something to the I2C LCD expander, which takes a while and during that period my program is frozen. For now I do not know how to handle this but at least my program now will not longer hang forever.

If any news I'll update here...

What is wrong with your I2C bus ? Are the wires too long ? Do you use a flat ribbon cable ? Is there a lot of electrical noise from motors or so ? Are SDA and SCL wires too close to each other in a cable ? Is the ground connected properly ?

What is wrong with your I2C bus ? Are the wires too long ? Do you use a flat ribbon cable ? Is there a lot of electrical noise from motors or so ? Are SDA and SCL wires too close to each other in a cable ? Is the ground connected properly ?

Well, I use RTC and LCD on single I2C bus. Due it is supplied from battery I am trying to prolong battery life by cutting off the power to the RTC and LCD and by putting MCU to the sleep.
LCD is powered up by user button triggered ISR, and RTC is powered up on 8 sec wake up period just to check time lap. Wires aren't long. Around 10cm to the display.

All this really work for a days, but occasionally program stops and I must to restart MCU to get it back. Since this bug is unpredictable I had much of pain to catch up I2C makes me a trouble. It is not really a big deal if this happens but it become a problem if it hangs my program forever. I can activate watchdog timer for this case but I can not accept something freeze my program just like that.

Yes I know I2C bus is not of "hot plug" kind and maybe I am doing things a dirty way.
I'm not an expert but many things in real world electronic circuits may go wrong and there must be a way to handle this type of error.

Wire library is last time modified in 2012. Maybe it's time for Arduino team to edit this library for next release.
WSWireLib is old and may not be an ideal solution, but at least it's a solution. Actually WSWireLib is a modified Wire library so why not replace them if it will make things better?

It's my opinion and doesn't mean it's correct but I see on the web that many people had similar problems.

Koepel thank you for your effort to help me.

Regards...

When something on the I2C bus is powered down, that might cause the SDA and SCL to be pulled low. That could be seen as a I2C start or stop condition. Did you measure how much current the RTC and display use ? Can you just turn off the backlight ? Does the Due keep the SDA and SCL high during sleep ?

When the SDA and SCL are indeed pulled low, try to add enough delay. Perhaps issue a fake stop condition to release the bus.

Is everything connected to the I2C bus running at 3.3V ? If not, you need a level shifter.

The I2C bus was never designed for these things. It was designed by Philips to be used in TVs on the same pcb board. For example to store settings in a eeprom. You are asking for trouble, and that's what you get :smiley_cat:

When something on the I2C bus is powered down, that might cause the SDA and SCL to be pulled low. That could be seen as a I2C start or stop condition.

Yes you've right. Somehow, illegal port state occurs, and that make confusion on port possible on bout sides, master and slave.

Did you measure how much current the RTC and display use ? Can you just turn off the backlight ? Does the Due keep the SDA and SCL high during sleep ?

It may be I made some confusion here because of my bad English. I am actually using Arduino Pro Mini 3.3V 8MHz board. All is supplied from 3.7V LiPo battery.
I have made some current consumption measurements but I do not remember correct data.
Total current consumption when all is off and MCU is in sleep mode is around 250uA.
RTC ON cca 1.5mA.
LCD ON backlight OFF cca 15mA.
Backlight ON cca 35mA.
This is all from my head but not far away from correct data. It saves me a lot of autonomy when I do turn off LCD and RTC.

I have not checked SCL and SDA state during sleep to be honest.
I'm doing a 100ms delay after I turn on the device to leave time for power up and stabilize. After that I call Wire.begin() to reinit I2C port.
Before I do call for any I2C operated function I additionally check for SDA and SCL state to see if any is held low and do not try to access port if so to avoid hanging. It may save me a lot of trouble but if something goes wrong during port is already accessed then hang may occur. There WSWireLib may help to get me out of freezing forever.

When the SDA and SCL are indeed pulled low, try to add enough delay. Perhaps issue a fake stop condition to release the bus.

Yes as I have explained I do not access port if not in, to say idle state.

Is everything connected to the I2C bus running at 3.3V ? If not, you need a level shifter.

Yes all is directly on LiPo battery potential.

The I2C bus was never designed for these things. It was designed by Philips to be used in TVs on the same pcb board. For example to store settings in a eeprom. You are asking for trouble, and that's what you get :smiley_cat:

Yes, yes, I know...looking for the devil... :smiling_imp: