Author Topic: AVR I2C trouble  (Read 3348 times)

0 Members and 1 Guest are viewing this topic.

Offline Dan MoosTopic starter

  • Frequent Contributor
  • **
  • Posts: 357
  • Country: us
AVR I2C trouble
« on: September 19, 2016, 01:34:07 am »
Ok, I am trying to create an I2C library for avr.

My set up: atmega328P, AVR Dragon running debugWire in AVR Studio 7. LCD with I2C backpack (pcf8574 expander chip on back pack). Cheap knock off of Saleae logic analyzer using the Saleae software.
My bit rate is 100K=kHz, as confirmed with the logic analyzer. (mcu running at 8Mghtz, 32 in the BR register, 0's in the prescaler);

My problem is that none of my data bytes are being transmitted. I send a start, send the address+W byte, get an ACK, and then instead of my data being sent, the analyzer shows the stop being sent right away.

I'm not doing any error checking in the code just yet, just watching the relevant registers in the debugger.

After I send a start, I get 0x08 in the TWSR register. My understanding is that this is correct.

After I load the the address into TWDR, I get 0x18 in the TWSR. Again, i believe this is correct. At this point in the process, the logic analyzer shows all is as expected, including an ACK after the address+w is sent.

as I next step the debugger, just BEFORE I load the data to be sent into TWDR, TWSR reads 0x28. To me, this is odd, as that  code means the data has already been sent, and an ACK recieved. (if i read the datasheet right anyway).

I then load the TWDR, and send a stop. TWSR still reads 0x28 at this point.

According to the logic analyzer, all that happened was START->Address+W->ACK->STOP.  No sign of the data byte.

My gut says I'm not handling the setting of the TWINT bit correctly. Its been a source of confusion for me. I feel like my process follows the datasheet's correctly, but other stuff I read seems to conflict. Specifically, my code (and the datasheet as far as I can tell) say to set TWINT HIGH before I do anything, and to wait for it to go LOW before continuing. My other resource, the Make:AVR programming book seems to imply I should wait for it to go HIGH before continuing.

I never see TWINT go low in the debugger, as I thought I should.

Here is the code for my Write, Start, and Stop routines. 

//Send start
void TWI_Start(uint8_t address)
{
   TWCR = (1<<TWINT) | (1<<TWSTA)    | (1<<TWEN);   //TWINT clears interrupt flag (sets it to 1); TWSTA sends start bit; TWEN enables TWI
   
   while(!(TWCR & (1<<TWINT)))                  //check for interrupt flag to have been set to 0 by MCU before continuing
   {
      continue;
   }
   
   TWDR = address;                           //send slave address
   TWCR = (1<< TWINT) | (1<< TWEN);            //clear interrupt flag.
   
}


//write to current slave
void Write_TWI(uint8_t data)
{
   
   TWI_Start(_writeAddress);                                                            
   
   TWCR = (1<<TWINT) | (1<<TWEN);               //clear interrupt flag
   TWDR = data;                                    //load byte to be sent into data register
   TWCR = (1<<TWINT) | (1<<TWEN);               //clear interrupt flag

   
   while(!(TWCR & (1<<TWINT)))                  //check for interrupt flag to have been set to 0 by MCU before continuing
   {
      continue;
   }
   
   TWI_Stop();
}

//Send stop
void TWI_Stop(void)
{
   TWCR = (1<<TWINT) | (1<<TWSTO)    | (1<<TWEN);   //TWINT clears interrupt flag (sets it to 1); TWSTO sends stop bit; TWEN enables TWI
}


 

Offline 2N3055

  • Super Contributor
  • ***
  • Posts: 6662
  • Country: hr
Re: AVR I2C trouble
« Reply #1 on: September 19, 2016, 07:05:04 am »
Did you read this one?
 

Offline rx8pilot

  • Super Contributor
  • ***
  • Posts: 3634
  • Country: us
  • If you want more money, be more valuable.
Re: AVR I2C trouble
« Reply #2 on: September 19, 2016, 04:25:41 pm »
After sending the address, you need to wait until the TWCR INT flag is cleared. Something like.....

Code: [Select]
// Wait for TWINT flag set in TWCR Register
 
  while (!(TWCR & (1 << TWINT)));

Then load the BYTE and repeat - waiting for the TWINT to clear after each segment transmission and then read back to make sure you are getting the correct status code.

EDIT: You already have that line after the BYTE is sent, just do that after each part of the transmission.
« Last Edit: September 19, 2016, 04:34:48 pm by rx8pilot »
Factory400 - the worlds smallest factory. https://www.youtube.com/c/Factory400
 

Offline senso

  • Frequent Contributor
  • **
  • Posts: 951
  • Country: pt
    • My AVR tutorials
Re: AVR I2C trouble
« Reply #3 on: September 20, 2016, 12:07:00 pm »
And if you i2c bus hangs in the right way you will be stuck in that while forever..
And if you are doing i2c from scratch, search for Pete Fleury i2c lib for AVR's..

I got bit so many times by that while that I'm now using it like this:
while(!(TWCR & (1<<TWINT))){
      count++;
      _delay_us(15);
      if(count > 250){
         return 2;
      }
   }

They delay was fine tuned so it wont mess with any i2c comm.
 

Offline rx8pilot

  • Super Contributor
  • ***
  • Posts: 3634
  • Country: us
  • If you want more money, be more valuable.
Re: AVR I2C trouble
« Reply #4 on: September 20, 2016, 05:55:30 pm »
And if you i2c bus hangs in the right way you will be stuck in that while forever..
And if you are doing i2c from scratch, search for Pete Fleury i2c lib for AVR's..

I got bit so many times by that while that I'm now using it like this:
while(!(TWCR & (1<<TWINT))){
      count++;
      _delay_us(15);
      if(count > 250){
         return 2;
      }
   }

They delay was fine tuned so it wont mess with any i2c comm.

I totally agree that un-monitored while loops can get you into trouble. There are many ways to go about it too, just pick a robust method. I chose to have the i2c monitored by the timer interrupt so that other tasks can be executed while it is waiting. Same concept though. Great point.
Factory400 - the worlds smallest factory. https://www.youtube.com/c/Factory400
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf