WinAVR C TWI or i2c or 2-wire example code

EDIT: I figured out my problems. Working code is in the 2nd post. The function with query a TWI device and return 1 byte of data.

This is the actual bus while executing the code.

[

As you can see I’m querying 0x0F which is returning 0x3A as it should. But when I debug TWCR is equal to 0x3B instead of 0x3A after receiving the data. Whats goin on here?](ImageShack - Best place for all of your image hosting and image sharing needs)

Working code!

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

I’m not using the same chip as you, but I’m pretty sure you have to mask off the bottom 3 bits of the status register before you check the status code against the tables in the data sheet. Here’s how I check status for successful data transmission:

if ((TWSR & 0b11111000) != 0x28)
{
     // error code goes here
}

The bottom 2 bits are the prescaler value and the third bit flags an illegal write to TDWR, if I recall correctly. The values in the data sheet don’t include those 3 bits.

TW_STATUS is defined in the avr-libc as you mentioned! Sall good!

http://www.nongnu.org/avr-libc/user-man … __twi.html

(near the bottom)

#define TW_STATUS   (TWSR & TW_STATUS_MASK) 

#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|\
                                _BV(TWS3))