Friday, June 4, 2010

Arduino to Arduino I2C

Pokey's "visual cortex" (an Ardweeny interfaced to Game Boy Camera) can detect candles, sure.  But unless Pokey's Orangutan LV168 brain can talk to the Ardweeny, Pokey can't really do diddly-squat with the information.

One could use serial I/O in this instance, but that's reserved for telemetry transmission over Bluetooth. Another option is the ATmega built-in Two-Wire Interface (TWI), Atmel's name for I2C.

For this experiment I used the Arduino IDE not only on the Ardweeny but also on the Orangutan, so that I could use the simple Arduino Wire library on both.

This tutorial on Instructables was a big help in getting the AVRs talking to each other.  The Orangutan is set up as the I2C master and the Ardweeny is the slave.  Pull up resistors on the SDA and SCL lines are 4.7k.

The Slave listens for data in, and sends back a "pong" if the master requests data after sending a "ping".  The Master sends a "ping" to the slave. Then it requests a byte back in response. So far the only way the Slave will accept commands and respond to requests for data is by setting up interrupt handlers.

Here's the Master code.
#include
#include
#include "camCom.h"

int ledPin = 1;                 // LED connected to digital pin 1 (PD1) on Orangutans
OrangutanLCD lcd;

void setup() {
  Wire.begin();
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  lcd.clear();
  lcd.gotoXY(0,0);
  lcd.print("Pokey");
}

void loop() {
  char buf[5];
  boolean timeout;
  unsigned char i;
  unsigned char c;
 
  delay(500);
  // tell the Ardweeny "PING"
  Wire.beginTransmission(TWI_CAMERA);
  Wire.send(CAM_COM_PING);
  Wire.endTransmission();
  // get back the response: "PONG"
  blink(2,200);
  delay(500);
  Wire.requestFrom(TWI_CAMERA, 1);
  timeout = true;
  for (i = 0; i < 10; i++) {
    if (Wire.available() > 0) {
      timeout = false;
      c = Wire.receive();
      lcd.gotoXY(0,1);
      lcd.printHex(c);
      break;
    }
    delay(100);
  }
}

void blink(unsigned char n, int pause) {
  unsigned char i;
 
  for (i = 0; i < n; i++) {
    digitalWrite(ledPin, HIGH);   // sets the LED on 
    delay(pause);                  // waits for a second 
    digitalWrite(ledPin, LOW);    // sets the LED off 
    delay(pause);              
  }
 
  return;
}

Here's the Slave code (excerpts).

int dataIn;
int dataOut;
boolean dataReady;
unsigned char reg;


void setup()
{
   Serial.begin(38400);
   Wire.begin(TWI_CAMERA);
   dataReady = false;
   Wire.onReceive(recvByte);
   Wire.onRequest(sendByte);
   pinMode(ledPin, OUTPUT);
   camInit();
}

void loop()
{
  delay(10);
  if (dataReady) {
    delay(200);
    blink(2,200); // same blink() code as above
    dataReady = false;
    Serial.write(dataIn);
    switch (dataIn) {
      case CAM_COM_PING:
        dataOut = CAM_COM_PONG;
        break;
      default:
        break;
    }

  }

}

void recvByte(int howMany) {
   dataIn = Wire.receive();
   dataReady = true;
}


void sendByte(void) {
   Wire.send(dataOut);
}

The code for the vision system has to be refactored a tad so as to accommodate this strange protocol where the Master tells the slave not only what to do but when to send data back and how much.

No comments:

Post a Comment