I2C hangs

I use I2C to communicate with DOF6 ITG3200/ADXL345.
Also arduino should drive single brushed motor (via simple H-bridge driver using pwm).
When motor is disconnected, everything is ok, but when I power the motor, arduino hangs during few seconds.
I discovered that I2C protocol freezes.
Tried pullup resistors, capacitors for power filtering, nothing helps.
Actually hardware isn't main problem for me, I understand that noise overrides I2C signal, ok, but why arduino hangs?
I need some code modification to get I2C not hangs even during high noise, better I have wrong reading from the sensor, that freeze controller (that means my quadcopter crashes).
Is there any new versions of WIRE and TWI libraries?

I need some code modification to get I2C not hangs even during high noise, better I have wrong reading from the sensor, that freeze controller (that means my quadcopter crashes).

Change line 37 to:

if(hang)unfreeze();

Or post your code. Perhaps we can spot the issue.

Change line 37 to:
Code:

if(hang)unfreeze();

Thanks...that made my day! XD

Tried pullup resistors, capacitors for power filtering, nothing helps.

You haven't tryed hard enough especially if you have now removed them. You need external pull up resistors and you need decoupling capacitors. If it still hangs and you are not doing anything silly in the software then you haven't got enough of either.
The only way I2C can hang is if you attempt a multi master configuration and you don't do that with this processor.

i'll post here as i'm having a similar problem with a noisy i2c bus... i have external pull-up resistors (5k), and a de-coupling cap. i have attached a pic, what do you guys think this is amount of noise? acceptable and normal, or not. my application is not quadcopter sensors, but it is next on the project list.

i have seen another version of the Wire library that is a bit more forgiving with timings, i haven't tried it yet - any feed back from anyone?? (blinkM i think)

cheers
jon

acceptable and normal, or not.

That looks pretty good to me, nice straight rise and fall times.

Lefty

I tried itg3200 example. Hangs the same way.
I want to explain once again. Of course lowering noise is my goal (pullups, capacitors, shields etc...),
BUT! the main goal is to be sure - there is no hardware model that can hang code!
If I can somehow get the code hang, that means there is something supposed to be improved in it.
Lowering noise via pullups and other hardware helps to get more clear signal without errors but nobody can guarantee that some parasite impulse can override any that hardware and get the device stuck! I need guarantee, even nosy signal doesn't drive the code to infinity cycle.

// ITG-3200_test
// Copyright 2010-2011 Filipe Vieira & various contributors.
// http://code.google.com/p/itg-3200driver
// Simple test of gyro sensors output using default settings.

#include <Wire.h>
#include <ITG3200.h>

ITG3200 gyro = ITG3200();
float  x,y,z;
int ix, iy, iz;

void setup(void) {
  Serial.begin(9600);
  Wire.begin();      // if experiencing gyro problems/crashes while reading XYZ values
                     // please read class constructor comments for further info.
  delay(1000);
  // Use ITG3200_ADDR_AD0_HIGH or ITG3200_ADDR_AD0_LOW as the ITG3200 address 
  // depending on how AD0 is connected on your breakout board, check its schematics for details
  gyro.init(ITG3200_ADDR_AD0_HIGH); 
  
  Serial.print("zeroCalibrating...");
  gyro.zeroCalibrate(2500, 2);
  Serial.println("done.");
}

void loop(void) {
    while (gyro.isRawDataReady()) {
    /* 
    // Reads uncalibrated raw values from the sensor 
    gyro.readGyroRaw(&ix,&iy,&iz); 
    Serial.print("X1:"); 
    Serial.print(ix); 
    Serial.print("  Y:"); 
    Serial.print(iy); 
    Serial.print("  Z:"); 
    Serial.println(iz); 
    */ 
     
    /* 
    // Reads calibrated raw values from the sensor 
    gyro.readGyroRawCal(&ix,&iy,&iz); 
    Serial.print("X2:"); 
    Serial.print(ix); 
    Serial.print("  Y:"); 
    Serial.print(iy); 
    Serial.print("  Z:"); 
    Serial.println(iz); 
    */ 
     
    // Reads calibrated values in deg/sec    
    gyro.readGyro(&x,&y,&z); 
    Serial.print("X3:"); 
    Serial.print(x); 
    Serial.print("  Y:"); 
    Serial.print(y); 
    Serial.print("  Z:"); 
    Serial.println(z);
  } 
}

Btw, the ADXL345 doesn't hangs.
the one difference I find in it's driver is checking that all the bytes are read

  if(i != num){
    status = ADXL345_ERROR;
    error_code = ADXL345_READ_ERROR;
  }
  Wire.endTransmission();         // end transmission

status and error_code are class public variables and there is no action in this class for such situation. So I suppose this part of code doesn't play any role in freezing situation.

ITG3200_test.pde (1.66 KB)

What you need to find out is where it hangs and in what way.
Is it an infinite loop somewhere Or is it crashing or reaseting the processor. You will have to investigate with some debug print or LEDs.
There is nothing in the code you posted that looks like a problem so it must be in the libraries.

Grumpy_Mike:
What you need to find out is where it hangs and in what way.
Is it an infinite loop somewhere Or is it crashing or reaseting the processor. You will have to investigate with some debug print or LEDs.
There is nothing in the code you posted that looks like a problem so it must be in the libraries.

No crash or resetting processor, just infinite loop.
debug via leds is good idea but I don't know when do I have enough time to do it. I just wonder, maybe someone else had the same problem and found a way out.

I just wonder, maybe someone else had the same problem

I don't recall this ever cropping up on this forum sorry.

I2C hanging has been a problem of mine professionally at work, but that involved FPGAs and multi master buses and was caused by noise spikes locking up the FPGA because it thought another master wanted the bus so not very relevant to your situation.

@ lefty -- thanks..

@kaor -- to me it looks strange that you code is loop() and directly into a while(). a well placed delay(10); at the end of the loop() outside of the while() may be some sort of 'hack' to make it more stable. thats what i would try, i feel your pain with things that sometimes work and sometimes not. good luck.

_J

kaor:
If I can somehow get the code hang, that means there is something supposed to be improved in it.

There are issues with the wire library implementation that can cause a sketch to hang and anyone using it for real applications is likely to run into this problem sooner or later. In twi.c the following loop may in some cases (such as a bus issue) run forever:

  // wait until twi is ready, become master receiver
  while(TWI_READY != twi_state){
    continue;
  }

There are a number of those in twi.c and they all need to be changed in order to avoid hangs. One possibility is to add a timeout and call twi_init if the timer expires. I believe a number of users (me included) have submitted patches, but the official version still has this issue.

Here is one thread with some more information on this issue:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1283887406

@BenF, thanks, good point to work on.

Today I played with leds to debug and figured out that freezes the twi function twi_readFrom.
There is few points in this function, that is unreachable during high noise, not a special one.
I see few loops in this function, that are potential freeze point.
For example this one

  // wait until twi is ready, become master receiver
  while(TWI_READY != twi_state){
    continue;
  }

Setting the CLK_SEL to 0 (Internal oscillator) improved stability but problem still remains.
In the ITG_3200 default init set this register to 1 (PLL with X Gyro reference) as recommended in ITG manual.

Kaor and all,

I am also having occasional hangs (1 or 2 per day) when using the Wire library routines. I have used LEDs to chase the execution down to one (or more) of the wait loops in the twi.c module. I have substituted unaie's modified modules (twi.h and twi.c) that he made available in the http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1283887406 thread, posting of <08.09.2010 at 11:34:27>.

His code implements a timeout counter in each of the (5) wait loops and calls twi_init() if a timeout occurs. I encountered a timeout this morning and the program recovered and continued. So I will keep his modification in my project.

However, in the modification he also changed the buffer allocation to use calls in twi_init(). I don't understand why he did this. I think that the buffers will get re-requested every time there is a timeout with a call to twi_init() and leave unused (not free'ed) buffers, i.e. a memory leak.

I will forward this post to unaie and perhaps he can post here to explain the calls.

73,
Garitron

I just received this in a direct message from Unaie:

Hi Garitron. Callocs are not mine, old twi.cpp asigned buffers dinamically. New twi.cpp asigns them statically, so there are not needed. But good point, in the old version they would need to be freed before calloc to avoid a memory leak. (perhaps this is the reason for the change in new twi version, any wire initialization in arduino would reallocate memory)

Regards
Unaie

That sure answers my question... Thanks Unaie...

73,
Garitron

I don't know if you need to call twi_init in the timeout. It may as well just return a "bad status" as if the other end hadn't responded. The hangs will no doubt be caused by the loops that wait on the interrupt to occur. Your options would seem to be:

  • Fix the electrical problems which cause the hang in the first place (ie. the lack of the correct interrupt)
  • Add a fixed timeout counter to those hard loops (eg. 1000 iterations)
  • Add a timed timeout to the hard loops (eg. 100 uS)
  • Add a watchdog timer that restarts the main loop or otherwise recovers from hangs
  • Slow down the I2C rate so that it copes better with whatever is causing the problem

First of all, let me explain the problem again.
There is problem in the I2C library that tends to hang.
I understand that some times there are ways to avoid hanging via improving/modifying electrical circuit but I want to warn everyone!
You couldn't be sure for 100% that this library doesn't hangs in any case! even with very good and safe circuit!
The more defense you build via schematics the more electrical noise can be produced accidentally, driving Arduino to infinity loop.
In other hands, which is cheaper - to hanging more elements on your hardware to get fake safe sense or improving library making it stable against hardware mistakes?
So the discus should go to the way finding library improvements. Maybe somehow someone sometimes avoids this problem but problem generally still remains!

BTW watchdog is good idea and I though about it too, but it isn't the best way out. It is just temporary solution.
I think this isn't simple and rare problem. Unfortunately I doesn't have enough time to look into the problem deeply and hope I'm not only the one who considers this as serious problem.

Try this library DssCircuits.com is for sale | HugeDomains . It may not fix your problem but it will at least help narrow down where the problem is happening. If your hanging problem is in the requestFrom() code execution then you won't be able to diagnose it with Wire because requestFrom only returns the number of bytes received. The other library, which has a timeout feature, will return the error code where it breaks and you can cross reference it in the datasheet.

BTW if you're using it on 1.0 it won't work as I haven't had a chance to modify the library yet to make it compatible.