AVR TWI/i2c

Electronics Computer Programming Q&A
Post Reply
User avatar
Chupa
Posts: 41
Joined: Thu Nov 06, 2008 2:22 pm
Contact:

AVR TWI/i2c

Post by Chupa » Wed Mar 25, 2009 2:21 pm

EDIT: I have solved my issues and the posted code is now working for anyone interested.

I'm having problems using an AVR to interface with a LIS3LV02DL accelerometer via TWI.

I cant seem to get the code right on the AVR to do this. What I have was mostly taken directly from the AVR data sheet for the part (atmega48p)

I know the device is working because I can use my PICkit SA to talk to the device via i2c.

In these tests im trying to query the WHO_AM_I register of the device, 0x0F, which should return a 0x3A.

This is me using my PIC KIT SA to successfully query the device:
Image
The transmission is as follows:
[Start][0x1D+W][Ack][0x0F][Ack][Repeated Start][0x1D+R][Ack][0x3A][Nack]

As you can see the device returns the 0x3A and all is well.

Now here is where I try to use the AVR to do the same thing:
Image
The transmission is as follows:
[Start][0x1D+W][Ack][0x0F][Ack][Repeated Start][0x1D+R]

It appears the device isn't Acking after sending that Address+R.

The following is the current code Im using on the AVR, which is producing this result:
The function is returning a 6 when I call it.

Any help would be appreciated! Thanks!

Code: Select all

#include <avr/io.h>
#include <util/twi.h>

#define SLA_W 0b00111010  //the i2c adress of the acell WRITE
#define SLA_R 0b00111011   //the i2c adress of the accell READ

#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))
#define NOP asm("nop")


void twi_setup(void){
//   PORTC|= (1<<PORTC5) | (1<<PORTC4); //enable pull ups on i2c bus
//   DDRC |= (1<<DDC5) | (1<<DDC4);  //port c outputs
   TWSR|=(0<<TWPS1)|(0<<TWPS0); //presclaer 0
   TWBR=0x02;   // 0x02 with a presacler of 0 will give a feq of 400KHz
   TWCR|=(1<<TWEN); //enable TWI
   }


int16_t twi_read(uint8_t SUB)
   {
   uint8_t DATA;
   //send ST and check for ST

   TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //send start
   while (!(TWCR & (1<<TWINT)))  // wait for status bits to indicate something was transmitted on the bus
      ;
   if (TW_STATUS != TW_START){ //check status to see if it was a sucessful start transmission, 0x08
      NOP;
      return 1; //return, error
      }

   //send SAD+W and check for SAK
   TWDR = SLA_W; //load READ adreess into register
   TWCR = (1<<TWINT) | (1<<TWEN); //send it
   while (!(TWCR & (1<<TWINT))) // wait for status bits to indicate something was transmitted on the bus
      ;    
   if (TW_STATUS != TW_MT_SLA_ACK){ //check to see if it was an ACK after the adress, 0x18
      NOP;
      return 2; //return, error
      }

   //send SUB and check for SAK
   TWDR = SUB; //send dummy register
   TWCR = (1<<TWINT) | (1<<TWEN); //send it
   while (!(TWCR & (1<<TWINT))) // wait for status bits to indicate something was transmitted on the bus
      ;
   if (TW_STATUS != TW_MT_DATA_ACK ){ //check to see if it was an ACK after the data, 0x28
      NOP;
      return 3; //return, error
      }

   //send SR and check for SR
   TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); //send repeated start
   while (!(TWCR & (1<<TWINT))) // wait for status bits to indicate something was transmitted on the bus
      ;
   if (TW_STATUS != TW_REP_START){ //check to see if the repeated start send was good or not, 0x10
      NOP;
      return 4; //return, error
      }

   //send SAD+R and check for SAK
   TWDR = SLA_R;
   TWCR = (1<<TWINT) | (1<<TWEN); //send it
   while (!(TWCR & (1<<TWINT))) // wait for status bits to indicate something was transmitted on the bus
      ;
   if (TW_STATUS != TW_MR_SLA_ACK){ //check to see if it was an ACK recieved after the SLA+R adress, 0x40
      NOP;
      return 5; //return, error
      }
   

   TWCR = (1<<TWINT) | (1<<TWEN); //Start transmission to recieve the data from the salve
   while (!(TWCR & (1<<TWINT))) // wait for status bits to indicate something was transmitted on the bus
      ;
   DATA = TWDR;   //load the returned data
   if (TW_STATUS != TW_MR_DATA_NACK){ //check to see if the data was recieved and return with a NACK, 0x58
      NOP;
      return 6; //return, error
      }
   TWCR = (1<<TWINT) | (1<<TWSTO) | (0<<TWEN); //send a stop
   return DATA;
   } 
---
Wait... what?

LoomVortex
Posts: 2
Joined: Fri Feb 26, 2010 4:47 am
Contact:

Re: AVR TWI/i2c

Post by LoomVortex » Fri Feb 26, 2010 5:09 am

Hi,

I have same kind of problem using I2C and LIS3LV02DL sensor. Query of the device returns successfully 0x3A.

http://koti.kainuu.com/alphamind/images ... _0x0Fh.bmp

But when i´m trying to read acceleration data example OUTX_L (register 0x28) it just sends 0x00 (nothing). Same happends on all axis. What can be the problem? Transfer should be same... only register changes, right?

http://koti.kainuu.com/alphamind/images ... _0x28h.bmp

Any help would be appreciated! Thanks!

LoomVortex
Posts: 2
Joined: Fri Feb 26, 2010 4:47 am
Contact:

Re: AVR TWI/i2c

Post by LoomVortex » Sun Feb 28, 2010 11:52 pm

Ok, now it works. I thought that default configuration register values were "correct", but clearly not :P

Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests