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

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

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.