I2C - Write as Slave

I’m trying to network my Arduino with the Surveyor Corporation SRV-1. I have no problem configuring my Arduino as a slave and recieving Data from the SRV-1 which is the master. But when the SRV-1 request’s data from the Arduino I recieve the byte containing the address on the Arduino, which I’m assuming is a request for the data at the specific register. How do I write as a Slave?

My current Code

#include <Wire.h>

#define I2cLocalDeviceID 42 // My local device ID is 42

void setup() 
{                
  Serial.begin(9600);
  Wire.begin(I2cLocalDeviceID); // Initialize I2C as slave with LocalDeviceID
  Wire.onReceive(ReceiveEvent);
}

void loop() 
{

}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void ReceiveEvent(int howMany)
{
  Serial.println("I2C Receive Event");
  Serial.println(howMany);
  word myWord = 1234;
          
  if(howMany == 1)  // Recieve Request
  {
    byte Register = Wire.read();
    switch(Register)
    {
      case 128:
         Serial.println("AHH 128");
         Wire.write(0x35);
      break;
      case 129:
       Serial.println("AHH 129");
      break;
      case 130:
        Serial.println("AHH 130");
      break;
      default:
       Serial.println("Default");
    }
  }
 
  if(howMany == 3)  // Recieve Data
  {
    byte Register = Wire.read();
    
    switch(Register)
    {
      case 0:
         Serial.println("Address 0");
         
      break;
      case 1:
       Serial.println("Address 1");
      break;
      case 2:
        Serial.println("Address 2");
      break;
      default:
       Serial.println("Default");
    }
    
    for (int i=0; i<howMany; i++)
    {
      Serial.println(int(Wire.read()));
    }

  }
}

If I use Wire.write(0x35); nothing happens, and If i do this:

Wire.beginTransmission();
Wire.write(0x35);
Wire.endTransmission();

Both the Arduino and the SRV-1 crash.

Any help or ideas will be apreciated

You have to implement the "onReceive()" handler to handle incoming messages from the Master and the "onRequest()" handler which gets called when the Master does a requestFrom().

Hi John,

At first I implemented both "onReceive()" and "onRequest()". For some unknown reason "onRequest" never happens, when I send a request from the Master for some reason "onReceive" gets a single byte (the register address I requested from the master). I'm guessing I can't simply do Wire.write(0x35); in "onReceive()" because nothing happens.

I'm receiving messages on my arduino sent from the Master.

Does the arduino use a non standard I2C "onRequest"? Because my SRV-1 works fine with I2C sensors. Is there a request byte I can perhaps send the Arduino?

There are some devices that are expecting ACK pulses which the Wire library doesn't provide. There is a TWI (Two Wire Interface) library somewhere that provides more granularity. Perhaps you will need to read the device datasheet to find out what signals it is expecting.

I've emailed the manufacturers for more information regarding their I2C settings. But if my arduino recieves the correct data, the settings should be correct, right?

I have removed all time critical code and made it so that it would simply turn on a LED if "onRequest()" occurs and that still does nothing.

The question that I still have is: Why would the Arduino execute "onRecieve()" instead of "onRequest()" when I send a request? I just recieve a single byte (the register address) in "onRecieve".

Thanks

Marco

If I were going to attempt this, this is what I'd try:
{code]
#include <Wire.h>

const int I2cLocalDeviceID = 42;  // My local device ID is 42

unsigned char RequestedRegister;

void setup() 
{                
  Serial.begin(9600);
  Wire.begin(I2cLocalDeviceID); // Initialize I2C as slave with LocalDeviceID
  Wire.onReceive(ReceiveEvent);
  Wire.onRequest(RequestEvent);
}

void loop() 
{
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void ReceiveEvent(int howMany)
{
  Serial.println("ReceiveEvent: howMany=");
  Serial.println(howMany);

  if(howMany == 1)  // Read register
  {
    RequestedRegister = Wire.read();
    Serial.print("command = Read Register #");
    Serial.println(RequestedRegister);
  }
  else
    if (howMany == 3)  // Write register
    {
      RequestedRegister = Wire.read();
      Serial.print("command = Write Register #");
      Serial.println(RequestedRegister);
      unsigned int value = Wire.read() << 8 | Wire.read();  // Get two byte value
      switch(RequestedRegister)
      {
      case 0:
        Serial.print("Register 0 = 0x");
        Serial.println(value, HEX);
        break;
      case 1:
        Serial.print("Register 1 = 0x");
        Serial.println(value, HEX);
        break;
      case 2:
        Serial.print("Register 2 = 0x");
        Serial.println(value, HEX);
        break;
      default:
        Serial.println("Write unknown register!");
      }
    }
    else // empty the receive buffer
    for (int i=0; i<howMany; i++)
      Wire.read();
}

void RequestEvent()
{
  Serial.println("RequestEvent");

  switch(RequestedRegister)
  {
  case 128:
    Serial.println("AHH 128");
    Wire.write(0x35);
    break;
  case 129:
    Serial.println("AHH 129");
    Wire.write(0x35);
    break;
  case 130:
    Serial.println("AHH 130");
    Wire.write(0x35);
    break;
  default:
    Serial.println("Read unknown register");
  }
}

Thanks for that.

“onRequest()” still does not execute, I recieve the requests in “onReceive()”. Also for some reason the code you sent causes my arduino to crash when I send a command, which aslo causes my other MCU to crash. I don’t even know how thats possible.

I worked off of the Wire examples to build this code and also get the same result where “onRequest()” does not execute and “onReceive()” will execute instead when I send a request. When I just send a command it goes through “onReceive()” and the correct data makes it to the Arduino.

#include <Wire.h>

void setup()
{
  Wire.begin(42);                // join i2c bus with address #42
  Wire.onRequest(requestEvent); // register event
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
  Serial.println("I2C Test");
}

void loop()
{
  delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
    Serial.println("Request Recieved");
    Wire.send("AB"); // respond with message of 6 bytes
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  Serial.println("Command Recieved");
 
  int x = Wire.receive();    // receive byte as an integer
  Serial.println(x);         // print the integer
  while(0 < Wire.available()) // loop through all but the last
  {
    char c = Wire.receive(); // receive byte as a character
    Serial.print(c);         // print the character
  }
  Serial.println();

Question: In your opinion is it possible that I might have problems with the physical connections? My Arduino is connected to a logic level converter by sparkfun, it has 10k pull up resistors so I haven’t connected any pull up resistors. All my grounds are connected together, however I’m using the 3.3V supply from the arduino to power the logic level converter not from the 3.3V supply of the other MCU. Could that be a problem?