Cannot read ATmega328PB configured as a I2C slave (writing OK)

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

I'm having the hardest time figuring this one out, after many hours of search and debugging I'm at a loss with an incredibly simple code not performing what I want.

 

Namely I have an ATmega328PB running as a slave on TWI0 bus. Configuration is done as follows:

 

void TWI_config()
{
  TWAR0 = (0x0b << 1);
  TWCR0 = _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWEN);
  sei();
}

ISR(TWI0_vect)
{
  TWCR0 = _BV(TWIE) | _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
}

 

And this is what my logic analyser shows:

 

With the following analysed:

 

Essentially I am acknowledging everything, I removed the data processing even to understand what's wrong with the reading part... but I cannot get the MCU to acknowledge SLA+R command.

 

The slave acknowledges and processes all write requests, as many as I'd throw at it, but not the read requests. Does anybody have any idea on what's going on? It feels like it distinguishes the read/write flag as if it was different devices.

 

This topic has a solution.
Last Edited: Wed. Jul 17, 2019 - 07:02 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

See AVR 311 app note for slave twi operation.
Jim

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
stack gold/silver https://www.onegold.com/join/713...

 

 

 

 

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

What value resistors do you have on your I2C lines?

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

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

ki0bk wrote:
See AVR 311 app note for slave twi operation. Jim

I've read through it many times, the closest thing to my issue is

The TWI may or may not acknowledge its address, depending on settings in the TWCR.

In the example I have the TWEA bit is always set in TWCR0, meaning every single request should be acknowledged, read or write... yet it doesn't happen. Maybe I missed something else?

 

Brian Fairchild wrote:
What value resistors do you have on your I2C lines?

I use 10k resistors, it seems to be working well enough. The acknowledge it is pulling the line low so that should be definitely appearing.

Last Edited: Wed. Jul 17, 2019 - 05:43 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've narrowed down the problem. It seems the stop-start condition is not properly processed or not processed fast enough.

 

The master has the following logic: SLA+W, address, stop-start, SLA+R, etc. as per the I2C definition. I added a 1ms delay in the slave ISR to simulate a badly programmed heavy processing task. I noticed the following sequence:

 

SLA+W -> Ack + 1ms, data -> Ack + 1ms, stop-start + 1ms (red), SLA+R -> NAck (yellow, no delay here!), SLA+W...

 

 

I feel there shouldn't be a 1ms delay immediately after the stop-start sequence, the slave should arbitrate its address immediately at this point.

 

To test out the theory I set a delay of 2ms on the master device between writing data and the SLA+R commands, to stretch the stop-start command, and then everything worked as expected:

 

 

And here's the analysed I2C data:

 

In reality I don't have the power to influence the master stop-start delay and I really don't understand how come the stop-start condition is messing up the slave... all seems perfectly legal here.

 

More notes: the slave is running at 8MHz, in the beginning I wanted to run at 1MHz, but that was way to slow for the slave to even catch its own address, so I changed the fuses to get the 8MHz. Perhaps it's still too slow and the stop-start is borderline not working?

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

It seems I solved the issue. In the AVR 311 app note there is a point that caught my eye:

 

The TWINT Flag is set after

  • the TWI has transmitted a START/REPEATED START condition
  • the TWI has transmitted SLA+R/W
  • the TWI has transmitted an address byte
  • the TWI has lost arbitration
  • the TWI has been addressed by own Slave address or general call
  • the TWI has received a data byte
  • a STOP or REPEATED START has been received while still addressed as a Slave
  • a bus error has occurred due to an illegal START or STOP condition

 

That might be the reason the process seems to be "triggered" after the stop-start condition. The slave is being addressed, so how can I stop the slave from being addressed?

 

After I got the data from the master I acknowledged the reception. However, this shouldn't be done, as it indicates the end of the exchange and thus the slave not being addressed anymore.

 

The problem was that my master wouldn't request reading if the slave didn't acknowledge the reception of the data. I removed the requirement for the acknowledge after the SLA+W + data from the master and now everything works as expected.

 

I'm surprised about the fact that I couldn't find anybody else having a similar issue as it feels like a common mistake.

Last Edited: Wed. Jul 17, 2019 - 09:06 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Go on. AVR311 is a fairly pointless example. I would prefer emulation of a real hardware chip.
.
All the same. AVR311 does what it says. Study it. Adapt it for a practical application.
From memory the 328PB behaviour is exactly like 328PA or any legacy AVR.
.
If you sit down and design a Slave, we might help you to implement it. Vagueness will get you nowhere.
.
A practical way to develop Master and Slave is with two Arduinos.
Develop your project with the Wire library.
Then replace the Wire Slave with your homegrown Slave.
.
David.

Last Edited: Wed. Jul 17, 2019 - 07:12 AM