There is a I2C library for Arduino - "Wire".
If you use two arduino boards, you can use this library to communicate, one board should be masted and another slave.
You can use example sketches provided by this library. I jast made little modifications to show the problem.
Master
#include <Wire.h>
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(57600); // start serial for output
}
void loop()
{
Wire.requestFrom(2, 10); // request 6 bytes from slave device #2
int i=0;
while(Wire.available()) // slave may send less than requested
{
char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
i++;
}
Serial.println("");
Serial.println(i);
delay(500);
}
Slave
#include <Wire.h>
void setup()
{
Wire.begin(2); // join i2c bus with address #2
Wire.onRequest(requestEvent); // register event
}
void loop()
{
delay(100);
}
// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
Wire.write("hello"); // respond with message of 6 bytes
// as expected by master
}
After runnig this sketches you'll notice that master reader receives 10 bytes per package regardless that the slave sends only 5 (or seems that sends).
I suppose that problem is in hardware, when master receives data, it sets ACK until last expected byte, ACK makes the slave to send byte from 32 byte buffer regardless is there processed data or not. So I think, I need to make slave to ignore ack when there is no data to send and stop sending. Is there a way to do this?
This is strange, I look into the TWI library and it should process length of transmuted data in slave mode.
// transmit first byte from buffer, fall
case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register
TWDR = twi_txBuffer[twi_txBufferIndex++];
// if there is more to send, ack, otherwise nack
if(twi_txBufferIndex < twi_txBufferLength){
twi_reply(1);
}else{
twi_reply(0);
}
Seems slave sender works correct, something strange happens at master reader, I2C interrupt calls the SIGNAL function 10 times (but there is only 5 bytes send)
The requestFrom() method calls twi_readFrom(), which actually performs the I2C read by sending the START condition and waiting for the buffer to be filled as requested. The I2C slave will NACK the read request if you request more bytes than are available, and the requestFrom() method will exit cleanly.
// transmit first byte from buffer, fall
case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register
TWDR = twi_txBuffer[twi_txBufferIndex++];
So that writes to TWDR. According to the datasheet:
Handling of the ACK bit is controlled automatically by the TWI logic, the CPU cannot access the ACK bit directly.
So I am reading that as the sender (the slave in this case) sends a byte and it is up to the receiver (the master) to ACK or NAK it.
Also I read the code as it sending random data after the end of the buffer (twi_txBufferIndex continues to increment) so you cannot rely on the data after the buffer is empty.
Digging into Atmega doc that states (in Slave Transmitter mode)
If the TWEA bit is written to zero during a transfer, the TWI will transmit the last byte of the transfer.
State 0xC0 or state 0xC8 will be entered, depending on whether the Master Receiver
transmits a NACK or ACK after the final byte. The TWI is switched to the not addressed Slave
mode, and will ignore the Master if it continues the transfer. Thus the Master Receiver receives
all “1” as serial data. State 0xC8 is entered if the Master demands additional data bytes (by
transmitting ACK), even though the Slave has transmitted the last byte (TWEA zero and expecting
NACK from the Master).
Master really receives all "1" after Slave sets TWEA to 0, but seems it somehow ignores (or misses) NACK and sends next NAC, so it receives 255 after slave goes off.
Thanks for the reply, so did you try my sketches and do you have the same result?
Is that scope for my sketch ? that shows that there is no nack signal after 5 bytes but after 10 bytes that is produced by master not slave. that may explain the problem.
Yes, seems you'r right. The example sketches drove me wrong way, I'm looking for the decision, how can I make my master reader read exact bytes that is send by slave transmitter.
Of course I can send data length as data's first byte and send whole buffer but this is not good way for me because in this way I waste communication time.
kaor:
Thanks for the reply, so did you try my sketches and do you have the same result?
Is that scope for my sketch ? that shows that there is no nack signal after 5 bytes but after 10 bytes that is produced by master not slave.
Yes, that was what I was attempting to say. That is from your sketches.
kaor:
Yes, seems you'r right. The example sketches drove me wrong way, I'm looking for the decision, how can I make my master reader read exact bytes that is send by slave transmitter.
I read the docs as saying that if one end transmits, the other end ACKs or NAKs. So when the slave is transmitting it can't also send a NAK.
Of course I can send data length as data's first byte and send whole buffer but this is not good way for me because in this way I waste communication time.
Well, design a protocol where you know how many bytes to expect.
Due to hardware problems (too long wire), I have to use low SCL rate, thus I need to optimize the communication time and I'm trying to use all hardware features, it would be great to acknowledge master receiver end of data, else I need to send maximum data package with length in it or send length as another package with slave address in it, both ways takes more time in communication. That is why I was trying to go another way.
I can't change hardware right now, boards are done already.
Anyway, that is interesting for me to know for sure how I2C works. Seems the wire library function available() is absolutely useless after calling requestFrom(a,l) method, because anyway it returns l or error.
I was playing with ack not to be sent from master but it didn't help.
Seems there is no way acknowledge master receiver from slave transmitter end of data.
I'll change my data protocol, but same time I'd appreciate any help to success in way I tried.
Look at my sketch, there is loop in Wire library example
while(Wire.available()) with comment "slave may send less than requested",
the first thing I supposed reading this comment was that if slave send less bytes than master requested, then this loop stops when there is no more bytes received (available() returns false). But my example shows that things aren't going this way, master receiver supposes that it received all bytes requested, regardless they where sent from slave or not, so if you requested 10 bytes, you just can loop through rx buffer 10 times via FOR statement not WHILE, without checking available().
BTW, atmega doc also states that slave transmitter can send less than master expects (my quotation on the previous page), I'm just curious about that, I think there is a way out, just should modify the library functions.
Here is my temporary way out:
Little modifications in Wire and TWI libraries, also I modified my sketch.
In slave sketch - I added data package length in the first byte of the data to send;
in Wire and TWI I added twi_1stByteLen flag that is used in SIGNAL interrupt in MR mode and if flag is set and 1st byte is received, then twi_masterBufferLength is modified regarding length byte received, so in next interrupts master knows real data size coming in. So I transfer only 1 extra byte.
That is not the best way but that is better than asking slave to times for data length and data itself that needs at least 3 more bytes to be transferred.