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:
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:
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;
}