For a start I had several I2C devices already connected to including DS1307 RTC. I wished to add an arduino as a slave device to existing I2C bus. On master side I didn't change any code, as it was already working perfectly, regarding I2C protocol. On slave I tried to make it behave similar to other slave devices which have addresses and 16bit registers inside I could read and write.
The result is somewhat confusing. Sending data from Master to Slave just works perfectly. But when Request comes from Master, Slave receives first byte which is register pointer and sending fails. No matter what slave sends, Master receives 2 bytes - one is 0 and other is 255. Meanwhile the same routine is working perfectly with other I2C devices.
I2C bus works ok, as other devices are unaffected and sending data from slave to master works.
Code on Master side should be ok as well, as other devices use the same code and work.
code on the slave side looks like this:
#include <MemoryFree.h>
#include <avr/wdt.h>
#include <Wire.h> // include Wire library for I2C
/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.
This example code is in the public domain.
*/
//Global variables defined here
byte datain[9] = {};
long unsigned int lastmillis = 0;
long unsigned int millisnow = 0;
int x = 0;
int blinktime = 200;
byte dataOut = 210;
//Registers for I2C
int I2C_register[8] ={72,9400,20202,-17432,44,-8433,18,777};
boolean dataready = false; // data is not ready for sending
boolean receiveddata = false;
boolean senddata = false;
boolean address_data = false; //if false it means address if true it means data
byte bytes_count = 0; // how many bytes are available?
byte reg_pointer = 0; //register pointer - which register to use for read or write
byte bytes_requested = 0;
void setup() {
wdt_disable();
Wire.begin(9); // Start I2C Bus as a Slave (Device Number 9)
Wire.onRequest(sendRequest); // this is interrupt - code must be extremely small Data must be sent
Wire.onReceive(receiveEvent); // Data must be received.
// initialize the digital pin as an output.
// Pin 13 has an LED connected on most Arduino boards:
pinMode(13, OUTPUT);
Serial.begin(9600);
wdt_enable(WDTO_8S); // set the wdt on 8 sec
Serial.print("freeMemory()=");
Serial.println(freeMemory());
}
void loop() {
ledblink();
data_receive(); //check if there is any data to receive
data_send(); //check if there is any data to send
wdt_reset(); // reset the wdt
}
// There is data received. Interrupt handler
void receiveEvent(int howMany) {
bytes_count = howMany;
receiveddata = true;
}
// There is a request to send data - interrupt handler
void sendRequest()
{
// bytes_requested = howMany;
senddata = true;
}
void ledblink() {
millisnow = millis();
if ((millisnow - lastmillis) > blinktime) {
if (digitalRead(13) == LOW) {
digitalWrite(13, HIGH); // set the LED on
}
else {
digitalWrite(13, LOW); // set the LED off
}
lastmillis = millisnow; //start a new cycle of one second
}
}
void data_send(){
if ((senddata == true) && (address_data == true)) {
uint8_t dataOut[6] = {22,33,44,55,66,77};
dataOut[0] = highByte(I2C_register[reg_pointer]);
dataOut[1] = lowByte(I2C_register[reg_pointer]);
//byte* datapointer = &(dataOut[0]);
Wire.send(dataOut,2);
Serial.print("Bytes requested: ");
Serial.println(int(bytes_requested));
Serial.print("from register: ");
Serial.println(int(reg_pointer));
Serial.print("data sent: ");
Serial.println(I2C_register[reg_pointer]);
Serial.println(int(dataOut[0]));
Serial.println(int(dataOut[1]));
address_data = false;
reg_pointer = 0;
senddata = false;
bytes_requested = 0;
}
}
void data_receive () {
if (receiveddata == true) {
Serial.print("How many: ");
Serial.println(int(bytes_count));
byte i = 0;
while(Wire.available()) //read until buffer is empty
{
datain[i] = Wire.receive(); // write received data to array
i ++;
}
// if one byte is received then it is a address of register, if 3 bytes, then data after first byte
// must be combined into word and written to register pointed to in the first byte
reg_pointer = datain[0]; //write received register pointer
Serial.print("Register chosen: ");
Serial.println(int(reg_pointer)); //show register number
if (bytes_count == 1) { //if incoming data is address, it is written to register pointer
address_data = true; // next byte is data either incoming or outgoing.
}
if (bytes_count == 3) {
I2C_register[reg_pointer] = word(datain[1],datain[2]);
Serial.print(" received and written data: ");
Serial.println(I2C_register[reg_pointer]); //show data received and written to register
reg_pointer = 0; // set register pointer to default after receive is finished
}
bytes_count=0;
receiveddata = false;
}
}
Any suggestions?
Could there be some timing problem on master side?