Arduino-cRIO I2C Communication

Has anybody used I2C to talk to an arduino from the crio (Java)? I would like to do it to control some lights on our robot, and I think I know what the crio side of the code should look like, but I don’t know how to do the arduino side. Does anybody have any suggestions? Has anyone had a good experience with a different method?

you’ll want to use the Wire library, probably. If you are trying to be an I2C slave, worst case you can bit-bang it.

How many different light patterns do you want to display? It may be easier to just use a few I/O between the two as raw signals instead of doing a bus-type interface.

We tried to mimic some Accelerometer code from WPILib since it is also an I2C device. However, we couldn’t really get it to work so it didn’t end up on this year’s robot. I’d recommend looking at the ADXL345_I2C class.

Alex Brinister

Bryce,

What you are trying to do is definately possible as we’ve implemented this on our robot this year, both for LED control as well as gyro and field positioning. There are a couple of bugs you have to watch out for, two on the cRIO side, and one on the Arduino, but once you understand what they are, it works reasonably well. I say, reasonably, because we were having some sporatic communication issues that I think is due to the I2C cable length, but as the robot is bagged, I can’t test it out. Initial bench testing didn’t seem to have this issue. As Branden mentioned, you will want to use the Wire library with the Arduino as the I2C slave. You will need to bit shift the address you use left by 1 for the cRIO as it apparently interprets the LSB (the read/write bit) as part of the address. For example, if you use an address of “2” for the Wire library on the Arduino, you will have to use an address of “4” on the cRIO. Second, there is a bug in the Wire library in the slave “restart” command that will prevent the cRIO from completing a successful write/read transaction with the Arduino. You can get around this by splitting the transaction into two parts, a write only (0 bytes for the read) followed by a read (0 write bytes). Alternately, there is a fix for the Wire library you can find on the net if you search (this is where I found it). Finally, there seems to be a bug in the WPI Library, where if you try to send (write) multiple bytes to the Arduino, it will interpret the individual bytes as “signed integers” and possibly overwrite some bytes with a value of 255 up to the integer 4 byte boundry where it will work again. The easiest way around this is to make sure you never send a value greater than 127 to the Arduino, or ensure that if you do need to do so, it is either the 4th byte or last byte sent. Finally, this brings up the fact that the cRIO limits you to 7 bytes of data communication per transaction each way. If you have any other questions, PM me, and I’ll try to help.

Mike

For reference, the communication failures were resolved by calling:

SetCompatabilityMode(true); 

on the I2C object.

Mike

I am also trying to communicate with an Arduino over i2c. I can’t get anything to be transmitted. I’m using this code on the cRIO:

public static void sendMessage(int message){
        DigitalModule.getInstance(1).getI2C(1).setCompatabilityMode(true);
        DigitalModule.getInstance(1).getI2C(1).write(4, message);
    }

And this code on the Arduino:

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
  Serial.print("Start up");
  pinMode(13, OUTPUT); 
  digitalWrite(13, LOW); 
}

void loop()
{
  delay(100);
}

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

I tried changing the addresses like you said, but saw no effect. Am I doing something stupid? I really feel like I’m making this harder than it should be.