ATTiny2313 / I2C Sporadic communications

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

Hi,
First time posting, long time reading. I'm going nuts over what should be a simple I2C communication between two ATTiny2313 AVRs. I have sporadic success in transferring data from the Master to the Slave. Been on this for 2 days straight and can't figure out what's wrong. On the oscillo I can see that when the sequence works, the slave sends an ACK, on most times when it doesn't work, there is no ACK. Is there anything I need to add in the code to perform the ACKs?

Both ATTinys are on breadboards. I'm using 2.2K pull ups. I have a red LED and white LED on the slave to tell me if the bit was received or not and a blue LED to tell me when the master sends.

I've added a LED to display the error on the Master. I flashes 1 time for error 0x01 (the slave did not ack the address). I get that is the address was wrong, but in this case, some messages are going through with the address ack'd and some don't.

I'm using the TinyWireM and TinyWireS libraries. I'm sure it's something stupid, but just can't seem to figure it out. It looks like some synchronization not working properly. Do I need to calibrate the clock? I'm using the internal 8MHz.

How long is the data available on the wire when the "available()" method is called? How is the Slave ready for receiving?

Any help is much appreciated. I'm trying to get a sensor value back to another ATTiny2313.

Master:

#include 
#include 

#define F_CPU 8000000UL
#define bit(x) (1 << (x)) 
#define set_bits(x,y) ((x) |= (y)) 
#define clear_bits(x,y) ((x) &= (~(y))) 

int sig=4;
volatile int data=0;

void setup()
{
   set_bits(DDRB, bit(sig));
   TinyWireM.begin();
}

void loop()
{
     data++;
     if ( data == 8 ) { data = 0; }
     clear_bits(PORTB, bit(sig));
     delay(100);
     set_bits(PORTB, bit(sig));
     TinyWireM.beginTransmission(0x01);
     TinyWireM.send(data);
     TinyWireM.endTransmission();
     TinyWireM.requestFrom(0x01,1);
     uint8_t rsp = TinyWireM.receive();
     delay(100);
     clear_bits(PORTB, bit(sig));
}

Slave:

#include 
#include 
#include 

#define I2C_SLAVE_ADDR  0x01
#define F_CPU 8000000UL

#define bit(x) (1 << (x)) 
#define set_bits(x,y) ((x) |= (y)) 
#define clear_bits(x,y) ((x) &= (~(y))) 

int red = 3;
int white = 4;
int yellow = 0;

void setup()
{
  set_bits(DDRB, bit(white)|bit(red)|bit(yellow));
  blink(white,5);
  blink(red,5);
  blink(yellow,5);
  TinyWireS.begin(I2C_SLAVE_ADDR);
}

void loop()
{
  byte byteRcvd = 0;
  if (TinyWireS.available())
  { 
    byteRcvd = TinyWireS.receive();    // first byte is command
    blink(white,2);
    byteRcvd += 10;
    TinyWireS.send(byteRcvd);
    blink(yellow,2);
  } else { 
    blink(red, 2);
    delay(100);
  }
}

void blink(byte pin, byte times)
{ 
  for (byte i=0; i< times; i++){
    set_bits(PORTB, bit(pin));
    delay (20);
    clear_bits(PORTB, bit(pin));
    delay (10);
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't know if it helps but I have found with a software implementation of the TWI receiver that I need to insert delays on the master side to avoid overrunning slave. the problem happens for me when I do the following


 [FAILS]

and the read operation fails. The following works.....



 [OK]

My setup is a 328P @ 16MHz master running code based on AVR app note and a 328 @ 8MHz slave running arduino wire library. I know that this is a bit weird; it is a test set-up.

I think that the problem is that the slave needs some time to detect the end of the transaction and to prepare itself for the next message.... but the next message has already started. the different clock speed is obviously a factor.

regards
Greg

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

Thanks Greg,
I added a 10ms delay, but same thing. I also added a LED to blink according to the error message the Master gets. It blinks once, which means no ack received on the address from slave. This is consistent with what I see on the scope. But sometimes it works. The slave just doesn't pull the data line down for the ack. Actually looking at the scope, I see that the ACKs from the slave come at various interval. Sometimes at 50us and sometimes 100us. Inconsistent.

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

what about slowing the twi clock right down and see if you get some nice clean waveforms that might give a clearer picture.

regards
Greg

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

Greg,
Thank you. How do I slow down the TWI clock? That might do it. Here's what I noticed on the scope. When the next clock after the data bits (9th cycle) is 25us I don't get an ACK from the slave, but if the 9th clock is more than 50us, I receive the ACK and the correct data stream. If I could slow down just the wait for the ACK from the slave to 50us I might be good. I looked through the code, but couldn't figure out how to slow this down. Any insight is greatly appreciated!

Thanks,
~Stephane

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

googling TinyWireM returned [url]http://www.google.com.au/url?sa=...
playground.arduino.cc%2FCode%2FUSIi2c&ei=v6hdUumEHaneigfw1YHIAg&usg=AFQjCNFSTgqjdZ_VDcRrcUBpQaHTKL1IPQ&bvm=
bv.53899372,d.aGc[/url] searching for clock on that page seems informative.

regards
Greg

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

Greg,
Thanks for all the suggestions. Here's what I've done (to no avail).

- Slowed down TWI by changing the 4us and 4.7us respectively. I was able to see some really nice square waveforms on the scope, same behavior.
- Changed the resistors to various values all the way to 10K. The 10K ones showed distorted patterns. The 2.2K show some really nice square signals.
- Tried 1MHz and 8MHz... same behavior.

After looking at many signals, it looks like sometimes the Tiny hiccups... Some signals either low or high on the clock seem much longer (like 100us) instead of the 5us.

Basically, the SDA line is not pulled down before the last clock cycle for the ACK. I looked at the method that pulls the line down and it should be triggered by the overflow interrupt and it just doesn't happen in some cases. I'm going to continue working on it, but it drives me absolutely nuts!

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

I would slow down to about 1kHz and see what is happening!! Not at all sure that this will solve the problem but I would anyway do it to see what I could observe and learn.

regards
Greg

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

Will do and post the results. Thank you!!

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

did you ever have any success?

regards
Greg

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

@scome98: Just only because I'm curious:
Why did you choose I2C / "TWI" for the intercontroller communication?
In my experience I2C always made more trouble than a simple UART communication. It's also more complicated than SPI. (I know I2C has some interesting features like clock stretching etc.)

In the beginning was the Word, and the Word was with God, and the Word was God.

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

btw I recently came across another I2C issue where it would sometimes work and sometimes not depending on the time between messages. see https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=137557&highlight=

regards
Greg

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

[SOLVED!}
OK... After much debugging, testing and help from a friend we solved it but with some outstanding questions left unanswered. We set the ATTiny to operate at 8MHz instead of 1MHz and it worked right away. Great, but same code - no other changes. I had read that some folks were able to make this work on a 1MHz and would like to have mine doing so as well to save some current consumption.

When running at 1MHz, we discovered that the USI_OVERFLOW_Vect would not be triggered. We added a debug LED and turned it on upon a start condition and off on the overflow. The LED never turns off, which indicates that the overflow does not get triggered. At 8MHz, I can see the LED flash for a short period of time. At 1MHz it just stays on (and then turned off in the main program).

Any idea why at 1MHz, the USI_OVERFLOW interrupt would not get triggered? Other than that, this works great.
Thank you!

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

skotti wrote:
@scome98: Just only because I'm curious:
Why did you choose I2C / "TWI" for the intercontroller communication?
In my experience I2C always made more trouble than a simple UART communication. It's also more complicated than SPI. (I know I2C has some interesting features like clock stretching etc.)

@Skotti, I chose I2C for the number of devices using I2C out of the box like EEPROMs and some sensors. This allows me to use a single bus to communicate with all my devices. I'm making some RGB LED boards and need to send color values to independent boards. I'm mostly new to all this and I2C seemed to be a nifty protocol with no real timing dependency. This was my first device to device communication.

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

@scome98: your project sounds interesting.

On which devices did you lower the frequency?
Only on the slave? Or also on the master?

What is the frequency of your SCL signal?
Maybe it is simply too high to get correctly captured by the slave?!

In the beginning was the Word, and the Word was with God, and the Word was God.

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

skotti wrote:
What is the frequency of your SCL signal?
Maybe it is simply too high to get correctly captured by the slave?!
This is my guess too. data is arriving too fast for the 1MHz device to cope... assuming it is a slave.

regards
Greg

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
I chose I2C for the number of devices using I2C out of the box like EEPROMs and some sensors.

Sure, if you already need to implement this protocol for accessing other devices (ICs), then it it handy to use it also to communicate to other boards. On the other hand, if your system needs to be high reliable, I would not mix the bus for the on-board communication with the bus for inter-device communication. If you have an error 'outside' (for example: short cut between SCL and SDA) some internal functions may fail (EEPROM access).

In the beginning was the Word, and the Word was with God, and the Word was God.