I digged a little bit deeper into the I2C theme:
I found one library at github (
https://github.com/eriksl/usitwislave) which is based on Don Blakes library. However the author has rewritten the library in a much better style for understanding.
The problem with USI I2C is: There is one 8-bit shift register (USIDR) for incoming and outgoing data. In Receive mode, the content of that register is copied to an incoming buffer, while sending the content of that register is sent out over the wire. There is a counter running, which generates an overflow interrupt everytime, 8bits are received/sent. The interrupt handler is now responsible to move the content to/from receiving/sending buffers. While transferring to/from buffer the interrupt handler pulls SCL to low, to delay the I2C master.
Whenever you write to I2C, you are only storing data to the buffer; when you are reading from I2C, you are pulling data out of that buffer. The real communication happens interrupt triggered in the background.
What is now missing from my current understanding is an additional state change in the state-engine. As soon, as the slave changes to send state, the overflow interrupt handler should be aware of it and needs to take SCL to low, while there is no data in the outgoing buffer, which could transferred to the USIDR register.
When you look now to the following piece of code (taken from the thread starters example, comments changed):
if (TinyWireS.available()) { // the input buffer is not empty!
received = TinyWireS.receive(); // pull out one byte from input buffer
// unclear status ? ? ?
if (received == 1)
{
blink();
TinyWireS.send(1);
}
}
After pulling out one byte from the input buffer (maybe the last, maybe not) the status is not clear.
When writing a communication protocol, you should first hand make sure, that there are no more bytes in the receive buffer, and you are working on the whole command.
That could be done by checking
! TinyWireS.available() before writing an response to the output buffer.
But that does not solve the problem with reading 0xFF, when there is no output data available in the buffer. Here I miss some piece of data, which pulls SCL low, when receiving an READ command, but the buffer is empty.
When SCL is not pulled to low, the Master reads all the time 0xFF, as SCA is pulled high with the resistors. The only way, preventing the master from reading, is stretching the clock!
However, I have not yet fully understand the details of USI.
The Atmel background information is here:
www.atmel.com/Images/doc2560.pdf
http://www.atmel.com/images/atmel-2586-avr-8-bit-microcontroller-attiny25-attiny45-attiny85_datasheet.pdf Chapter 15
regards
Gogol