Attiny MCU's and TinyWire problems

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

Post the problem code please?

This is a simplification of the master code. If the problem is in the master code, it lies in the configureModueles function.

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

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.

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.

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 :wink:

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:
**__ <strong>**#include <avr/io.h> #include <avr/interrupt.h> #include <avr/pgmspace.h> #include <usiTwiSlave.h>**</strong> __**
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!) :slight_smile:
```
**#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;
}
__
```**__

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

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

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

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

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

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.

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.

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.