Hello, I'm trying to comunicate with another device using the ATmega88 I2C, I can write very well to the device, but when i try to read i send the stop bit and doesn't work at all, the sda should become high during the clock but it doesn't, so it also has problems during the next start bit.
Why does this happen?
ATmega88 I2C problem
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
-
- Posts: 46
- Joined: Sun Oct 23, 2011 11:17 am
Re: ATmega88 I2C problem
Something in your code. Without seeing your code, nobody can say. FWIW I've had good results working directly with the TWI hardware with the code below. It worked with a DS1307 time-of-day clock, and it illustrates how you write an internal device address, then read back from that address. The magic symbols (except the bus addresses DS1307_W and DS1307_R) are from the AVR Freaks include files.
Code: Select all
#define bit_set(F,B) F |= (1<<(B))
#define bit_clr(F,B) F &= ~(1<<(B))
#define bit_tst(F,B) (F & (1<<(B)))
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 int ds1307_read_buf (unsigned char addr, unsigned char *buf, unsigned char n)
// Read a block of bytes from a given address in the DS1307
{
int result = -1;
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;
result = 0;
bailout:
TWCR = TWI_OP | 1<<TWSTO;
return result;
} // ds1307_read_buf
-
- Posts: 3
- Joined: Mon Oct 21, 2013 12:52 am
Re: ATmega88 I2C problem
readwrite=0 write
readwrite=1 read 1 register
readwrite=2 read 2 registers
I can write without problem, when i read 1 register i can read but i haven't the stop bit and if i try to read 2 registers the program stop work.
readwrite=1 read 1 register
readwrite=2 read 2 registers
I can write without problem, when i read 1 register i can read but i haven't the stop bit and if i try to read 2 registers the program stop work.
Code: Select all
#define START 0xA4
#define SEND 0x84
#define GET 0xC4
#define STOP 0x94
#define TWEN 0x04
#define TWINT 0x80
#define SLA 0x13
#define READ 0x01
#define WRITE 0x00
#define TXC 0x40
#define NULL 0x00
void iquadratoc(char registro,char dato,char readwrite){
TWCR=TWEN;
error=0;
TWCR=START;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x08)error=TWSR;
TWDR=SLA<<1|WRITE;
TWCR=SEND;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x18)error=TWSR;
TWDR=registro;
TWCR=SEND;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x28)error=TWSR;
if(readwrite==0){
TWDR=dato;
TWCR=SEND;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x28)error=TWSR;
}
if(readwrite>0){
TWCR=START;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x10)error=TWSR;
TWDR=SLA<<1|READ;
TWCR=SEND;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x40)error=TWSR;
TWCR=GET;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x50)error=TWSR;
status=TWDR;
TWCR=TWEN;
if(readwrite==2){
TWCR=START;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x10)error=TWSR;
TWDR=SLA<<1|READ;
TWCR=SEND;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x40)error=TWSR;
TWCR=GET;
while((TWCR&TWINT)!=TWINT);
if((TWSR&0xF8)!=0x50)error=TWSR;
status2=TWDR;
}
}
TWCR=STOP;
if(error!=0){
UDR0=error;
while((UCSR0A&0x40)==0);
UCSR0A=UCSR0A|TXC;
}
TWCR=NULL;
}
-
- Posts: 46
- Joined: Sun Oct 23, 2011 11:17 am
Re: ATmega88 I2C problem
On a quick read-through it looks like one problem is at
where you do another repeated START after reading the first byte. Don't do that. Do your reads with TWEA set to enable ACK to continue the series of reads. Make sure that TWEA is reset on the last read.
That may fix things up.
Comment on style: don't be afraid of comments and whitespace. They can help you distinguish the sections of code in your mind, and help you focus your attention while you debug. After I'd finished "reading" it, the code looked like this:
Code: Select all
if(readwrite==2){
TWCR=START;
while((TWCR&TWINT)!=TWINT);
That may fix things up.
Comment on style: don't be afraid of comments and whitespace. They can help you distinguish the sections of code in your mind, and help you focus your attention while you debug. After I'd finished "reading" it, the code looked like this:
Code: Select all
#define START 0xA4 // TWCR: TWINT | TWSTA | TWEN
#define SEND 0x84 // TWCR: TWINT | TWEN
#define GET 0xC4 // TWCR: TWINT | TWEA | TWEN
#define STOP 0x94 // TWCR: TWINT | TWSTO | TWEN
// bits in TWCR:
#define TWEN 0x04
#define TWINT 0x80
#define SLA 0x13 // I2C slave address unshifted
#define READ 0x01
#define WRITE 0x00
#define TXC 0x40
#define NULL 0x00
void iquadratoc (char registro, char dato, char readwrite)
{
TWCR = TWEN;
error = 0;
TWCR = START; // TWCR: TWINT | TWSTA | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x08)
error = TWSR;
TWDR = SLA<<1 | WRITE; // slave write command
TWCR = SEND; // TWCR: TWINT | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x18)
error = TWSR;
TWDR = registro; // write the slave internal address
TWCR = SEND; // TWCR: TWINT | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x28)
error = TWSR;
if (readwrite == 0) { // want to write one byte
TWDR = dato;
TWCR = SEND; // TWCR: TWINT | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x28)
error = TWSR;
}
if (readwrite > 0) { // want to read one or more bytes
TWCR = START; // TWCR: TWINT | TWSTA | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x10)
error = TWSR;
TWDR = SLA<<1 | READ; // slave read command
TWCR = SEND;
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x40)
error = TWSR;
TWCR = GET; // TWCR: TWINT | TWEA | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x50)
error = TWSR;
status = TWDR;
TWCR = TWEN; // ???
if (readwrite == 2) { // want to read 2 bytes
TWCR = START; // TWCR: TWINT | TWSTA | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x10)
error = TWSR;
TWDR = SLA<<1 | READ;
TWCR = SEND; // TWCR: TWINT | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x40)
error = TWSR;
TWCR = GET; // TWCR: TWINT | TWEA | TWEN
while ((TWCR & TWINT) != TWINT);
if ((TWSR&0xF8) != 0x50)
error = TWSR;
status2 = TWDR;
}
}
TWCR = STOP; // TWCR: TWINT | TWSTO | TWEN
if (error != 0) { // send the error status through the UART
UDR0 = error;
while ((UCSR0A & 0x40) == 0);
UCSR0A = UCSR0A | TXC;
}
TWCR = NULL; // disable TWI interface
}
-
- Posts: 3
- Joined: Mon Oct 21, 2013 12:52 am
Re: ATmega88 I2C problem
The row that you commented "????" is the one that resets the TWEA
Please be positive and constructive with your questions and comments.