Go Down

Topic: Attiny MCU's and TinyWire problems (Read 8026 times) previous topic - next topic

eric_f

Hey guys
So I am building a fairly large project that will incorporate a combination on Attinys's (85, 2313, 4313) and Atmegas (368, 1280), possibly others.

So far I have been using I2C and the Wire library and it's working well, and on the Attinys using the TinyWire(S/M) libraries, and they are working well for the most part.

My problem is this:  I have one MCU (a 4313) that sends a command to each MCU in turn, and waits for a reply to know where it is located.  This works perfectly when it sends anything to an Atmega, but fails when it sends to an Attiny.  I can see with my logic analyzer that the master sends a write to the slave (an 85), then sends a read, but the slave never responds.  I know the wiring is correct, the same slave with another sketch sends data to another MCU with no issue (running as master).  The problem seems to be with the TinyWireS.send() command.  From what I gather it is supposed to push the data into the buffer, and when the master requests it, it gets sent off.  This doesn't seem to happen.  If I put an LED blink directly before, or after, it blinks, so I know that the slave is getting the request from the master, but not responding.

I have been trying to debug this for over a week and getting very frustrated.  If anybody has any ideas, I am more than willing to try them.

Thanks

Eric

nickgammon

Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

eric_f

This is a simplification of the master code.  If the problem is in the master code, it lies in the configureModueles function.
Code: [Select]

void setup() {
for (int pin=0; pin<outputPinCount; pin++) {
pinMode(outputPins[pin], OUTPUT);
}
}

void loop() {
}

// this loops over all the modules and stores their pin configs in EEPROM
void configureModules() {
// setup i2c as master
TinyWireM.begin();
// loop over all th output pins we have
for (uint8_t pin=0; pin<outputPinCount; pin++) {
// enable the outputs in order
digitalWrite(outputPins[pin], HIGH);
// give the module(s) a chance to start up
delay(2000);
// loop over all the slaves
// it could be possible to have more than one slave on each pin
for (uint8_t slave=0; slave<numSlaves; slave++) {
// send a PINGREQUEST to each slave
// TinyWireM.beginTransmission(slaves[slave]);
TinyWireM.beginTransmission(TEMPERATURE);
TinyWireM.write(PINGREQUEST);
// get the returned code to check
uint8_t r = TinyWireM.endTransmission();

// 0 is no errors
if (r == 0) {
// put a small delay, this allows the slave to prepare the buffer before it's requested
delay(50);
// request one byte back from that slave
// TinyWireM.requestFrom(slaves[slave], 1);
TinyWireM.requestFrom(TEMPERATURE, 1);
// if something came back
if (TinyWireM.available()) {
uint8_t command = TinyWireM.read(); // read the data
switch (command) {
// make sure it's a reply
case PINGREPLY:
// store the pin for that slave in EEPROM using the slave's address as EEPROM address
EEPROM.write(slaves[slave], outputPins[pin]); // keep the pin config in eeprom
break;
}
}
}
// small delay for next slave
delay(500);
}
// turn that output off and continue
digitalWrite(outputPins[pin], LOW);
}
}


I believe the problem lies with the slave code, seen below
Code: [Select]

void setup() {
// via tinytune
OSCCAL = 0x9B;
TinyWireS.begin(TEMPERATURE);
}

void loop() {
// something received on the I2C bus
if (TinyWireS.available()) {
// fetch the command we received
uint8_t command = TinyWireS.read();
// find which command was sent
switch (command) {
case PINGREQUEST: {
TinyWireS.write(PINGREPLY);
break;
}
}
}
}



The way this is supposed to work.  The master enables one of it's outputs, sends a "PINGREQUEST" to each slave.  If it gets a reply stores the pin in the EEPROM.  This works perfectly with the Atmegas (currently have 3 of them hooked up) but doesn't work with any of the Attinys (currently have 2 slaves).

I have hard coded the master to only send to one slave (TEMPERATURE) which is defined in another header file along with the command defines.

From what I can tell the slave code gets through the TinyWireS.available(), gets into the switch and successfully finds the PINGREQUEST, but the TinyWireS.write(PINGREPLY) never actually gets seen on the master.

nickgammon

I am not familiar with TinyWire ... can you give a link please?

If it was Wire, that wouldn't work. You need an onRequest handler, which you don't have.

http://www.gammon.com.au/i2c
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

eric_f

Tiny Wire Library
I understand that if this was the Wire library it wouldn't work, but in the TinyWire libraries, the onRequest, and onReceive are not implemented.

Thanks for the link, I'll read through there and see if I can't learn something new  ;)


Poofjunior

#5
Jun 08, 2012, 08:18 am Last Edit: Jun 08, 2012, 08:21 am by Poofjunior Reason: 1
I've also had some trouble with this library recently.  In a few cases, I'll upload the code, the code will run correctly on the first shot, and then I'll unplug and plug the Arduino (connected to an ATtiny via i2c) back in and the code wont run.  Kinda wierd, but I suspect that this has to do with the lack of onRequest() functionality.

Right now, I've just had success with some example code from the usiTwiSlave library, that I discovered here:
http://code.google.com/p/codalyze/wiki/I2COnATtiny45

I discovered it from Jochen Toppe's blog.http://jtoee.com/2009/12/connecting-multiple-avrarduinos-via-i2ctwi/   Jochen's kindly posted some awesome example code where he's communicating with an Arduino and an ATtiny2313 via i2c.

Getting the code to compile from the repository (the first link) was a bit tricky, though. The two files you'll want are in this directory:

blinkm-simulator/docs/ATtiny45_i2c/I2C_slave_code

I created a new library in my Arduino sketchbook called usiTwiSlave and dropped the two files: usiTwiSlave.c and usiTwiSlave.h inside there.  Then, I changed the .c extension to a .cpp extension on usiTwiSlave.c .  (The compiler complains about some of the library's methods being "undefined" otherwise, since it's not actually compiling the .c file.)

(Don't forget to restart the IDE after adding a new library!)

To get Jochen's Arduino code working, I changed Wire.send to Wire.write an Wire.receive to Wire.read.

To get his ATtiny2313 working on an '85, I added these headers:

Code: [Select]

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <usiTwiSlave.h>


Note: some weirdness that I don't really understand, hehe.  I noticed that the compiler complains at me if I put #include <usiTwiSlave.h> at the top of these headers, but it's A-ok with compiling this code if that statement is at the bottom of the list. :~

One final note: to upload this, I configured my Arduino IDE to support the ATtiny85 using the High-Low Tech tutorial for Arduino 1.0.  Lastly, I'm using a Sparkfun "AVR pocket programmer" to upload code to the ATtinys (although I don't think that matters).

All-in-all, I got Jochen's examples to work (Thanks, Jochen)!  I hope yours go just as well.  

Here's my working modified version of Jochen's code below for the ATtiny85:
(The Arduino version is just "copy 'n' pasted" from his blog with #include <Wire.h> at the top!)   :)

Code: [Select]

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <usiTwiSlave.h> // Why on earth this has to be at the bottom, I have no idea.

// attiny85 code
int main(void)
{
 // initialize as slave with id 1
 usiTwiSlaveInit(1);

 // enable interrupts (must be there, i2c needs them!)
 sei();

 // handle commands
 while (1)
 {
   // check if data is in the i2c receive buffer
   if(usiTwiDataInReceiveBuffer())
   {
     // get it
     uint8_t b = usiTwiReceiveByte();
     // echo it back
     usiTwiTransmitByte(b);
   }
   // Do something else while waiting for the TWI transceiver to complete.

   asm volatile ("NOP" ::);
 }
 return 0;
}




Poofjunior

Whoops!  Quick note on the discrepancy:  It looks like if you actually go to Jochen's blog, you'll find a link to his repository with what looks like an identical library.  It looks like they're both the same, and they're both written by Donald Blake (thanks Donald)!


Jochen's Repository:
http://code.google.com/p/tinkercode/source/browse/#svn/trunk/automation-framework/i2c

The other Repository (in the first post)
http://code.google.com/p/codalyze/wiki/I2COnATtiny45

eric_f

A quick reply, the code posted in Jochen's repo is a newer version with added features it seems.
The "Change Activity" in the one I have, acquired from the playground says
Quote

Change Activity:

    Date       Description
   ------      -------------
  16 Mar 2007  Created.
  27 Mar 2007  Added support for ATtiny261, 461 and 861.
  26 Apr 2007  Fixed ACK of slave address on a read.

and the other one says
Quote

Change Activity:

    Date       Description
   ------      -------------
  16 Mar 2007  Created.
  27 Mar 2007  Added support for ATtiny261, 461 and 861.
  26 Apr 2007  Fixed ACK of slave address on a read.
  04 Jul 2007  Fixed USISIF in ATtiny45 def
  12 Dev 2009  Added callback functions for data requests


I will be looking into this further tomorrow.
Thanks

Pedro_Santos

Hello,

I'm planning to connect an Atiny to an Atmega using the I2c bus. Did you manage to get it working? Thank you very much.

Gratefully,

Pedro Santos

rambo

I just managed to get this to work, the onReceive support is a bit cludgy but see https://github.com/rambo/TinyWire/blob/master/TinyWireS/examples/attiny_i2c_slave/attiny_i2c_slave.ino

You need my version of the TinyWireS from that repo.

eric_f


I just managed to get this to work, the onReceive support is a bit cludgy but see https://github.com/rambo/TinyWire/blob/master/TinyWireS/examples/attiny_i2c_slave/attiny_i2c_slave.ino

You need my version of the TinyWireS from that repo.


Thanks rambo, I will be looking in to this.  As for my other issue, I hooked everything up to my logic analyzer and discovered the timings were all off.  Once I ran the Attiny chips at 8mhz then a lot more of the functionality started working as expected. 

Go Up