Go Down

Topic: I2C freezes arduino (Read 9 times) previous topic - next topic

unaie

Hi. I have a I2C network with slaves. My problem is that periodically Arduino Freezes. This bug can be also forced if you put a screewdriver on I2C Analog Pins 4 or 5 during a moment. Arduino freezes and it is in unrecoverable state until next reset.

Investigating, the problem is <twi.c> blocking behavior without timeouts. (endless loops "while")

Code: [Select]

uint8_t twi_writeTo(...
...
while(TWI_READY != twi_state){
   continue;
 }
...
while(wait && (TWI_MTX == twi_state)){
   continue;
 }
...


I have "solved" it with a counter timeout in all "while" loops. Now Arduino doesn't freezes, but I cannot found, there is no way to initialize or recover again the I2C Network without Reset Arduino.

Investigating more, the reason is in Interrupt Vector Code:

Code: [Select]

SIGNAL(TWI_vect)
switch(TW_STATUS){
...
case TW_MT_SLA_NACK:  // address sent, nack received
  twi_stop();
...


it it always entering with TW_MT_SLA_NACK code an then twi_stop, and from here I don't know how to continue.

I think this is a severe problem with Arduino and I2C networks, because any bus problem freezes arduino by code, or if you avoid freezing I2C network is unrecoverable.

Any trail or solution?








deSilva

A good analysis of some hidden bug..
I think you should not just leave the wait loops, but rather re-initialize the TWI hardware completly in that time-out case. This might need more changes in the library...

BenF

#2
Sep 08, 2010, 08:29 am Last Edit: Sep 08, 2010, 08:32 am by borref Reason: 1
Quote
I have "solved" it with a counter timeout in all "while" loops. Now Arduino doesn't freezes, but I cannot found, there is no way to initialize or recover again the I2C Network without Reset Arduino.


I handle this pretty much the way you suggest (using a 5000 microseconds timeout), but when a state timeout is detected (assuming a bus issue), I call twi_init. For this to be effective, you also need to add the following statement to the top of twi_init:

Code: [Select]

void twi_init(void)
{
 // disable twi module (to allow for reinitialize)
 TWCR = 0;

 // ... original code follows

 // initialize state
 twi_state = TWI_READY;



unaie

OK with your solution, TWCR = 0 is the key. Now I2C autorecover after failure.

These are my "final" twi.c and twi.h:

http://liken.otsoa.net/pub/ntwi/twi.h
http://liken.otsoa.net/pub/ntwi/twi.c

Expecting for a better and elegant solution...



Go Up