Uno to Uno I2C communication not working

Hi,

I am having some difficulty with getting I2C communication between two Arduino Uno Rev3s to work. I am relatively new to this stuff, so I’m not sure if I’m having hardware or software issues, or just don’t really understand how I2C works fully.

They are set up in the typical “master-slave” configuration. The master arduino has an Adafruit LCD Shield attached to it, and is used to display constantly updating information about the testing procedure being performed (this is for an industrial automation application). The slave arduino is has an Adafruit Motor Shield V2 attached, driving two stepper motors along with an electrically controlled pneumatic solenoid. The two arduinos are connected directly, with common grounds, A4->A4, and A5->A5.

There seems to be a problem when I connect the slave arduino up to the master. The master is running a simple menu system that has the user select the type of test that they will be running. Based off of the selection by the user, it sends either a 1 or a 2 to tell the slave arduino which test to run. I have gotten the menu system working fine by itself, and have it serial printing this value that will be sent to the slave. Similarly, I have the slave arduino sending a count to the master so that it can be displayed on the LCD.

However, once I connect the slave to the master, the master seems to “freeze up”. What the master does depends on the order that I connect the components together.

  • If I power on the master first, allow the program to intialize, and then hook up the slave, the master menu program seems to freeze (I can no longer move the cursor or use any of the buttons onboard the shield, and therefore can’t send the required data for the slave to do it’s job.
  • Additionally, if I power on the slave first and connect the master, the LCD on the master lights up and displays blocks of white characters, then eventually a blinking cursor appears. But the menu program that I wrote does not appear to even start.

The code that I’m is provided at the bottom, any help would be much appreciated!
Thanks in advance.

LCD_Menu_Script.ino (10.8 KB)

Slave_Arduino_Script.ino (3.9 KB)

theMoenator:
Hi,

I am having some difficulty with getting I2C communication between two Arduino Uno Rev3s to work. I am relatively new to this stuff, so I’m not sure if I’m having hardware or software issues, or just don’t really understand how I2C works fully.

They are set up in the typical “master-slave” configuration. The master arduino has an Adafruit LCD Shield attached to it, and is used to display constantly updating information about the testing procedure being performed (this is for an industrial automation application). The slave arduino is has an Adafruit Motor Shield V2 attached, driving two stepper motors along with an electrically controlled pneumatic solenoid. The two arduinos are connected directly, with common grounds, A4->A4, and A5->A5.

There seems to be a problem when I connect the slave arduino up to the master. The master is running a simple menu system that has the user select the type of test that they will be running. Based off of the selection by the user, it sends either a 1 or a 2 to tell the slave arduino which test to run. I have gotten the menu system working fine by itself, and have it serial printing this value that will be sent to the slave. Similarly, I have the slave arduino sending a count to the master so that it can be displayed on the LCD.

However, once I connect the slave to the master, the master seems to “freeze up”. What the master does depends on the order that I connect the components together.

  • If I power on the master first, allow the program to intialize, and then hook up the slave, the master menu program seems to freeze (I can no longer move the cursor or use any of the buttons onboard the shield, and therefore can’t send the required data for the slave to do it’s job.
  • Additionally, if I power on the slave first and connect the master, the LCD on the master lights up and displays blocks of white characters, then eventually a blinking cursor appears. But the menu program that I wrote does not appear to even start.

The code that I’m is provided at the bottom, any help would be much appreciated!
Thanks in advance.

Your slave onRequestEvent(); is wrong.

Your code:

void requestEvent() {
  Wire.beginTransmission(0x20);
  Wire.write(shotCount);  //  Transmit shot count when requested by master arduino
  Wire.endTransmission();
}

The Wire.beginTransmission(); and Wire.endTransmission(); are only used in I2C master Mode to Send data to an I2C slave. When a slave has received a request for data, the master is in control. Your onRequestEvent() just needs to return the data.

Correct code:

void requestEvent(){
Wire.write(highByte(shotCount)); // first the MSB (Most Significant Byte)
Wire.write(lowByte(shotCount)); // second the LSB (Least Significant Byte)
}

Also, since you are accessing/changing the values of:

int shotCount;
int releaseType;

from inside an interrupt callback, you need to change the declaration to volatile.

volatile int shotCount;
volatile int releaseType;

The reason for this change, is that the compiler tries to optimize your program. When you declare a variable, you assume the compiler assigns a memory location which contains the current value of the variable, But, (this is the important part) if the compiler can temporarily store the value in one of the CPU’s registers it is faster to access. This means the current value in memory may not be the ‘actual’ value. The RAM (memory) value is only updated when the compiler needs to use the ‘temporary register’ for something else. Your interrupt service routines assume (ass U me) that the ‘memory’ value is current. They don’t know the current value is actually stored in one of the CPU registers.

When you declare a variable volatile you force the compiler to reload the value from RAM every time it is accessed. Also, since the interrupt can happen at any time I would atomize your increment operations.

And, I would not use your for() loop. and you are double incrementing shotCount. once manually:
shotCount++;
and once in the for() loop.

// for (shotCount = 0; shotCount < shotLimit + 1; shotCount++) {
noInterrupts(); // disable interrupts so that shotCount will always contain a valid value
shotCount=0;
interrupts();     // reenable interrupts so that I2C events are serviced, also Serial()
// shotLimit is valid from 1..32767 (integer value range)

while(shotCount<shotLimit){

// your code here

  noInterrupts();
  shotCount++; // increment 
  interrupts();      
  }

Your master I2C code needs a little adjustment also:

      case BUTTON_SELECT: //This case exectutes when the "select" button is pressed
        Serial.print("Select button is pressed");
        Wire.beginTransmission(i2cAddress);
        Wire.write(releaseType);
        Wire.endTransmission();
        Serial.print(releaseType);
          Wire.requestFrom(i2cAddress, 4); // Requests 4 bits from slave arduino (Since max # of shots is 5000)
          while (Wire.available()) {  //  Slave may send less than requested
            shotCount = Wire.read();
            }
          lcd.clear();
          lcd.print("# Shots:");  // Shows continously updated shot count and runtime (Shot count is pulled from slave arduino, runtime is from master)
          lcd.setCursor(8, 0);
          lcd.print(shotCount);
          lcd.setCursor(0, 1);
          lcd.print("Run Time:");
          lcd.setCursor(9, 1);
          lcd.print(millis()/1000);
        break;

the Wire.requestFrom(); needs to change to this:

          Wire.requestFrom(i2cAddress, 2); // Request 2 bytes, this needs to match the Slaves onRequestEvent() (Since max # of shots is 5000)
          if(Wire.available()==2){ // only expected 2 bytes
// now we have to build an int from two bytes
            shotCount = Wire.read(); // first byte, actually the highByte
            shotCount = shotCount *256; // correctly scale it
            shotCount = shotCount + Wire.read(); // add the second byte, lowByte
// now shotCount contains the correct value
            } // end of if()

Chuck.

Chuck,

Thanks for the quick and detailed reply, your suggestions helped unlock the I2C bus and it now functions as it should. Another slightly daft issue that I was having the slave join the i2c bus with the wrong address. I was using the one for the motor shield instead... oh well!

Thanks again!

Kris

theMoenator:
Chuck,

Thanks for the quick and detailed reply, your suggestions helped unlock the I2C bus and it now functions as it should. Another slightly daft issue that I was having the slave join the i2c bus with the wrong address. I was using the one for the motor shield instead… oh well!

Thanks again!

Kris

If you are still having problems, load this I2C_Scan sketch into your ‘master’ let it show you all devices on the I2C bus.

Chuck.

I2C_Scan_only.ino (2.21 KB)