Monday, February 1, 2016

I2C Communication Update


Fault in our stars: I2C Crashing either the sensor or master (SHADOW) controllers.


When working with the Sensor controllers, I believe I have swapped the wires out at least 4 times now.  Either swapping for better shielding, gauge or just plain different wire to combat issues with the I2C channels simply crashing either the MEGA or the NANO CPUs.

What I was doing was setting up the arduino nano's which were on sleds or shields that the CPU plugs into. and was connecting to I2C and common grnd/pwr from the arduino mega in the body.

The design



I2C was setup in a MASTER MASTER configuration where every device had an address on the channel.

REVISION 1: Force it down the throat

The code was using interrupts on the mega to simply listen and when something came across the wire it would listen and store the next variables into an array of bytes.
simple right? riiiight.

What would happen is the nanos would basically flood the shadow controller until all of a sudden it would lock up when trying to use the BLUETOOTH controller or it was in the middle of something else.

Many re-writes, pull up configurations as well as wiring scenarios...

Some of the outcomes were very poor or simply unresponsive sabertooth controller response (like delayed by several seconds) this was probably due to the mega having to stop what it was doing every 3 secs and listen on wire.

REVISION 2: Ask and you shall receive

The code now incorporates the mega participating still in a MASTER MASTER scenario BUT it asks only when I am doing collision avoidance from each of the foot controllers.
This appears to be more stable, after roughly 2-3 minutes though depending upon where the arduino is in the code it will then lock.  Only the SHADOW controller will lock though as the nanos keep pinging away!

Here is the code used and differences:
On each SENSOR device I have the following definitions to help me remember what address is what as well as for the system to use these addresses as needed.
// ==========================================// This function determines I2C addressing // ==========================================#define I2C_ADDRESS_SHADOW  0x1#define I2C_ADDRESS_LEFT    0x2#define I2C_ADDRESS_RIGHT   0x3#define I2C_ADDRESS_DOME    0x4#define I2C_ADDRESS_CENTER  0x5#define I2C_ADDRESS_VOICE   0x6#define I2C_ADDRESS_BODY    0x7#define I2C_ADDRESS_TCAADDR 0x70 adafruit multiplexer

Then I simply within SETUP()

  #ifdef LEFTFOOT // If this is the leftfoot sensor slave
    Wire.begin(I2C_ADDRESS_LEFT);
    Wire.onRequest (requestSensorData);  // interrupt
    partnum=1;
    #ifdef PIRSENSOR
      pinMode(DS1P, INPUT);
      delay(2000); // calibrate for about 2 seconds
    #endif
  #endif

Configure this for each foot and voice controller, when you uncomment comment variables this tells the compiled code which device it is controlling.

LEFTFOOT, RIGHTFOOT and VOICE are all I use currently.

What the above does is when a request from SHADOW is made, it will call the function requestSensorData which is below:

void requestSensorData()
{
  uint8_t Buffer[4];
  Buffer[0]=cm[0];  // Send the IR Sensor from front
  Buffer[1]=cm[1];  // Send the IR Sensor from side
  Buffer[2]=cm[2];  // Send the IR Sensor from back
  Buffer[3]= pir;   // Send the PIR Sensor from ankle
  Wire.write(Buffer,4); 
}

The above basically reads in each sensor from the CM array as well as PIR state of HIGH or LOW and sends it across the I2C channel when asked.

This has prevented a lot of the issues BUT there are still lockups that occur.

on the SHADOW, there is similar setup to assign SHADOW an address but here is the code for it to ask.

void getFootSensorData()
{
  if (isR2Automation)
  {
    currentTime = millis();
    int sensortable[]={0,0,0,0};
    if ((currentTime - lastDecisionTime) >= PingWaitInterval) // Wait for PingWaitInterval and then send results
    {
      lastDecisionTime = millis();
      Wire.requestFrom(I2C_ADDRESS_LEFT, 4);    // request 4 bytes from slave device I2C_ADDRESS_LEFT
      for(int i=0;i<4;i++)
      { 
        int c = Wire.read(); // receive a byte as character
        sensortable[i]=c;
      }
        leftfront =  sensortable[0];
        leftside  =  sensortable[1];
        leftback  =  sensortable[2];
        leftpir   =  sensortable[3];
      #ifdef SHADOW_SENSOR
        Serial.print("\n");
        Serial.print("Left Foot Sensors: ");
        Serial.print(sensortable[0]);
        Serial.print('\t'); 
        Serial.print(sensortable[1]);
        Serial.print('\t'); 
        Serial.print(sensortable[2]);
        Serial.print('\t'); 
        Serial.print(sensortable[3]);
        Serial.print('\n');
      #endif
      Wire.requestFrom(I2C_ADDRESS_RIGHT, 4);    // request 4 bytes from slave device I2C_ADDRESS_LEFT
      for(int i=0;i<4;i++)
      { 
        int c = Wire.read(); // receive a byte as character
        sensortable[i]=c;
      }
        rightfront =  sensortable[0];
        rightside  =  sensortable[1];
        rightback  =  sensortable[2];
        rightpir   =  sensortable[3];
      #ifdef SHADOW_SENSOR
        Serial.print('\n');
        Serial.print("Right Foot Sensors: ");
        Serial.print(sensortable[0]);
        Serial.print('\t'); 
        Serial.print(sensortable[1]);
        Serial.print('\t'); 
        Serial.print(sensortable[2]);
        Serial.print('\t'); 
        Serial.print(sensortable[3]);
        Serial.print('\n');
      #endif
    }
  }


}

No comments:

Post a Comment