I2C freezes ATmega

by uhe on Sat Sep 01, 2012 7:39 am

I'm trying to read some data out of an i2c IO-expander but sometimes the ATmega freezes completely.
I was able to trak the cause of this down to the point where it waits for a read to be finished.
Code: Select all | TOGGLE FULL SIZE
while(!(TWCR & (1<<TWINT)));

Does that ring a bell? Are there some known errors with this?
"I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
uhe
 
Posts: 178
Joined: Mon Sep 03, 2007 3:50 pm
Location: metric world

Re: I2C freezes ATmega

by mwilson on Sat Sep 01, 2012 9:02 am

That by itself won't cause a problem. It's meant to wait until TWI has finished the operation it's doing. Is it doing an operation? Going into your wait code twice in a row without starting an operation in between will hang.

In my own code I prefer to wrap things in a way that's still pretty hardware-centric, but structured enough to prevent the problem I've described:

Code: Select all | TOGGLE FULL SIZE
static unsigned char twi_op (unsigned char op)
{
   TWCR = op;
   while (! bit_tst (TWCR, TWINT)) ;   // wait for TWINT
   return TWSR & 0xF8;
} // twi_op

#define TWI_OP   (1<<TWINT | 1<<TWEN)

static void ds1307_read_buf (unsigned char addr, unsigned char *buf, unsigned char n)
{
   int j;
   if (twi_op (TWI_OP | 1<<TWSTA) != 0x08)   // START condition
      goto bailout;
   
   TWDR = DS1307_W;      // WRITE command
   if (twi_op (TWI_OP) != 0x18)   goto bailout;

   TWDR = addr;   // DS1307 address
   if (twi_op (TWI_OP) != 0x28)   goto bailout;

   if (twi_op (TWI_OP | 1<<TWSTA) != 0x10)   // Repeated START
      goto bailout;
   TWDR = DS1307_R;         // READ command
   if (twi_op (TWI_OP) != 0x40)   goto bailout;
   
   for (j=0; j < n-1; j++) {      // read all bytes except the last with following ACK
      if (twi_op (TWI_OP | 1<<TWEA) != 0x50)   goto bailout;
      buf[j] = TWDR;
   }
   if (twi_op (TWI_OP) != 0x50)   goto bailout;   // read the last byte without ACK
   buf[n-1] = TWDR;
bailout:   
   TWCR = TWI_OP | 1<<TWSTO;
} // ds1307_read_buf


(bit_tst is a macro that does the
Code: Select all | TOGGLE FULL SIZE
(REGISTER & (1 << BIT_NUMBER))
)
Also, the above is AVR-only because of all the 0x?? status constants that come straight from the datasheet.

Barring that, which port expander are you using?
mwilson
 
Posts: 46
Joined: Sun Oct 23, 2011 10:17 am
Location: Maynooth, Canada

Re: I2C freezes ATmega

by mwilson on Sat Sep 01, 2012 9:06 am

Actually, this is nonsense, isn't it? My code is very interesting and all, but my discussion of the hanging thing is flat-out wrong. Have you got the TWI interface turned on? What IS the device you're dealing with?
mwilson
 
Posts: 46
Joined: Sun Oct 23, 2011 10:17 am
Location: Maynooth, Canada

Re: I2C freezes ATmega

by uhe on Sat Sep 01, 2012 1:24 pm

I'm using a ATmega168 connected to an MAX7318 (IO expander with interrupt) which has two MAX6818 (debouncer and ESD protection) at it's 16 I/O pins. The IRQ output of the MAX7318 is connected to INT0. For I2C I'm using the I2C lib from Peter Fleury.
I have a bunch of buttons connected to the MAX6818 and most of the time everything is working but sometimes the whole thing freezes.

My code goes like:
Code: Select all | TOGGLE FULL SIZE
while(1) {
  someADCstuff();
  if((IRQ_0 & 0x1)){
    IRQ_0 &= ~0x1;
    readIOexpander();
  }
}

uint8_t readIOexpander(){
  GPIOR1 = 0;
  INT_0_OFF;                                            // macro to disable the INT0
  i2c_start_wait(addr+I2C_WRITE);            // set device address and write mode
  i2c_write(reg);   
  i2c_start(addr+I2C_READ);                  // restart
  GPIOR1 = i2c_readNak();
  i2c_stop();
  INT_0_ON;
  return GPIOR1;
}

unsigned char i2c_readNak(void) {
   TWCR = (1<<TWINT) | (1<<TWEN); // | (1<<TWIE);
  PORTB |=  _BV(PB0);                             // DEBUG LED ON
   while(!(TWCR & (1<<TWINT)));
  PORTB &= ~_BV(PB0);                             // DEBUG LED OFF
    return TWDR;
}/* i2c_readNak */



ISR(INT0_vect) {
  IRQ_1 |= 0x1;
}


*i2c_*-stuff is from the library and when I'm able to trigger the freeze the debug LED stuff tells me it's the while() in i2c_readNak() where it hangs.


CAPTCHAS FOR LOGGED IN USERES ARE PRETTY ANNOYING BTW!!!
"I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
uhe
 
Posts: 178
Joined: Mon Sep 03, 2007 3:50 pm
Location: metric world

Re: I2C freezes ATmega

by mwilson on Sun Sep 02, 2012 10:34 am

Fascinating. Is that Peter Fleury's library you're using? I've never tried to bit-bang an I2C interface; always used the on-chip peripheral. Two things off the top of my head -- no guarantee they're any righter than my old reply:

1) should your repeated start use i2c_rep_start instead of i2c_start ?
2) since Fleury's library never seems to go anywhere near the on-chip interface, the TWSR register isn't affected by anything the library does. As far as the on-chip TWI interface is concenred nothing is happening. If you're using Fleury's other functions then you'll have to use or mimic his i2c_readNak. Assuming I understand this correctly.

CAPTCHAS -- yeah. just had a great comment shot down from the blog because I got the captcha wrong on the first pass, and when I re-entered it, wordpress killed me for commenting too frequently. Little logic glitch there.
mwilson
 
Posts: 46
Joined: Sun Oct 23, 2011 10:17 am
Location: Maynooth, Canada

Re: I2C freezes ATmega

by adafruit on Sun Sep 02, 2012 12:31 pm

mwilson wrote:CAPTCHAS -- yeah. just had a great comment shot down from the blog because I got the captcha wrong on the first pass, and when I re-entered it, wordpress killed me for commenting too frequently. Little logic glitch there.


hiya! can you email support@adafruit.com we'd like to see which post that was on.

thanks!
adafruit support, phil
User avatar
adafruit
 
Posts: 11643
Joined: Thu Apr 06, 2006 3:21 pm
Location: nyc

Re: I2C freezes ATmega

by uhe on Mon Sep 03, 2012 11:24 am

Is there any alternative to Fleury's lib?

1) one line summary of rep_start: unsigned char i2c_rep_start(unsigned char address){ return i2c_start( address ); }
The datasheet says the same ;)
2) TWSR... may I cite?
These 5 bits reflect the status of the TWI logic and the 2-wire Serial Bus. The different status codes are described
later in this section.

Has anyone found a description of theese status bits anywhere?

At this point I this I'll switch to SPI an polling instead of IRQ driven I2C.
"I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
uhe
 
Posts: 178
Joined: Mon Sep 03, 2007 3:50 pm
Location: metric world

Re: I2C freezes ATmega

by tldr on Tue Sep 04, 2012 10:46 am

uhe wrote:
These 5 bits reflect the status of the TWI logic and the 2-wire Serial Bus. The different status codes are described
later in this section.

Has anyone found a description of theese status bits anywhere?


later, earlier, what difference does it make when you're writing data sheets in trondheim in the dead of winter.

see tables 22-2, 22-3, 22-4 and 22-5.
"If I had known it was harmless, I would have killed it myself." - Phillip K. Dick, A Scanner Darkly
User avatar
tldr
 
Posts: 466
Joined: Thu Aug 30, 2012 12:34 am