TWI-slave doesn't send acknowledge (ATmega328PB)

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually I try to set up a TWI slave with the ATmega328PB (2 TWI ports).

The master is running with Peter Fleurys I2C library on a ATmega328P (1 TWI port).
With the master I'm checking, if the TWI slave is available on a specific address:

/*************************************************************************
  Issues a start condition and sends address and transfer direction.
  return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
    uint8_t   twst;

	// send START condition
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

	// wait until transmission completed
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

	// send device address
	TWDR = address;
	TWCR = (1<<TWINT) | (1<<TWEN);

	// wail until transmission completed and ACK/NACK has been received
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

	return 0;

}/* i2c_start */

This works fine, as you can see on the picture of the scope (attached).
Now the problem is, that the slave should give an acknowledge, and, as I understand the procedure, should release the SDA-line level back to high (green line).
But SDA is still beeing pulled low by the slave. If I switch off the slave mcu (SDA released), then suddenly the master reports that the slave would be available...

The slave is initialized this way:

void init_twi_slave(uint8_t adr)
{
    TWAR0= adr << 1; // set twi slave address (skip over TWGCE bit)
	TWCR0 &= ~(1<<TWSTA)|(1<<TWSTO);
	TWCR0|= (1<<TWEA) | (1<<TWEN)|(1<<TWIE);
	buffer_adr=0xFF;
	sei();
}

When the master is requesting the slave, the ISR of the slave comes up with the TW_STATUS = 0xA8 (..I send TW_STATUS over UART to check)

ISR (TWI0_vect)
{ ....
...

     case TW_ST_SLA_ACK:      // 0xA8: SLA+R received, ACK returned
     case TW_ST_DATA_ACK:     // 0xB8: data transmitted, ACK received
       if (i2c_state == 1) {
	 i2c_slave_action(0); // Call Read I2C Action (rw_status = 0)

	 TWDR = regdata;      // Store data in TWDR register
	 i2c_state = 0;	      // Reset I2C State
       }	   	  

       TWCR |= (1<<TWINT);    // Clear TWINT Flag
       break;

     case TW_ST_DATA_NACK:    // 0xC0: data transmitted, NACK received
     case TW_ST_LAST_DATA:    // 0xC8: last data byte transmitted, ACK received
     case TW_BUS_ERROR:       // 0x00: illegal start or stop condition
     default:
       TWCR |= (1<<TWINT);    // Clear TWINT Flag
}

Doesn't  TW_STATUS = 0xA8 mean, that the mcu should have already released the SDA line?

Any ideas, how to fix this or where I'm going wrong?

Many Thanks!

 

 

 

 

Attachment(s): 

This topic has a solution.
Last Edited: Fri. Oct 5, 2018 - 12:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What happens when you use Fleury ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'd really do, as Fleurys librarys are very reliable, but I only know the libs for TWI master.

I've been searching for a quite a long time for TWI slave libs, but didn't find any suitable one.

Do you have a link?

 

Many thanks!!

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can anyone suggest a reliable TWI slave library?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you tried anything from:

 

https://github.com/search?q=avr+...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

...many thanks, I'll check this!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are several libraries / app notes for I2C slave.
.
The biggest problem is designing how you want the Slave to behave. I2C is simply a transport mechanism,
.
I always suggest that you find the hardware chip that has "similar" behaviour to your custom Slave.
Then emulate the hardware chip. Write a test suite that can exercise everything documented in the chip datasheet.
.
When that emulation is working 100% adapt it for your custom Slave.
.
Believe me, most of the app note examples are impractical. But emulating a LM75 or DS1307 is something that a human can relate to.
.
David.
.
p.s. developing a Wire.h Slave with a Wire.h Master on two Arduinos is convenient development test bed for the high level behaviour.
When debugged you can place it on top of AVR311 or other app note

Last Edited: Thu. Oct 4, 2018 - 01:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One other confusion is with the addressing, some master/slave expect a 7 bit address, others expect an 8 bit address, using the wrong format address will result in a NAK response to slave addressing.

A logic analyzer is a valuable tool for such troubleshooting, look at one of the saleae clones on Ebay. 

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

...OK, many thanks to all.

TWI slave is running!

 

I just had to add:

TWCR = (1<<TWIE)|(1<<TWINT);       // Enable TWI Interrupt and clear the flag to send byte

to release the SDA line.