Memorial day is 05/25/2015 – Orders will ship out on May 26th. There will not be any deliveries or shipping on Monday. Any order placed after 11am ET on Friday May 22nd will not start to ship out until Tuesday May 26th.

I2C freezes ATmega
Moderators: adafruit_support_bill, adafruit

I2C freezes ATmega

by uhe on Sat Sep 01, 2012 8: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 4:50 pm
Location: metric world

Re: I2C freezes ATmega

by mwilson on Sat Sep 01, 2012 10: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 11:17 am
Location: Maynooth, Canada

Re: I2C freezes ATmega

by mwilson on Sat Sep 01, 2012 10: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 11:17 am
Location: Maynooth, Canada

Re: I2C freezes ATmega

by uhe on Sat Sep 01, 2012 2: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 4:50 pm
Location: metric world

Re: I2C freezes ATmega

by mwilson on Sun Sep 02, 2012 11: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 11:17 am
Location: Maynooth, Canada

Re: I2C freezes ATmega

by adafruit on Sun Sep 02, 2012 1: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

adafruit
 
Posts: 11905
Joined: Thu Apr 06, 2006 4:21 pm
Location: nyc

Re: I2C freezes ATmega

by uhe on Mon Sep 03, 2012 12:24 pm

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 4:50 pm
Location: metric world

Re: I2C freezes ATmega

by tldr on Tue Sep 04, 2012 11: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 1:34 am