Arduino Beaglebone I2C Communication

Hi. I'm new to I2C with the Arduino and Beaglebone Black. Has anyone used the I2C bus for Beaglebone to/from Arduino communication. I am using several Arduinos to capture sensor data and would like to poll them using a Beaglebone to receive values from the Arduinos. So far the Beaglebone can see the Arduinos using i2cdetec on the Beaglebone. I have written simple C++ code to write/read from the Arduinos. So far when I use ioctl (ioctl(file, I2C_SLAVE, addr) on the Beaglebone the Arduino fires the request interrupt and it sends back a few characters. However, when I write to the Arduino it still fires the request interrupt vice the receive interrupt and if the Arduino checks for wire.available using the wire library there is nothing available but the Aduino can still write back to the Beaglebone and the Beaglebone gets it. I'm sure I am missing something simple but I am quite stuck. I can fire the request interrupt on any of the Arduinos and the correct Arduino answers but it never gets anything from the reads. I have used I2C for Arduino to Arduino comms and that seems to work perfectly. I'm not sure why the Arduinos are not getting the chars from the Beaglebone since they respond to the Beaglebone writes but not in a way that is useful. Any suggestions would be appreciated.

Don

Don, welcome to the forum.

It sounds interesting what you are doing.
I'm wondering which version of Arduino you are using and if you have considered the voltage levels of both boards may be different ?

I use Cubieboards and I am guessing the Beaglebone Black will be quite similar in that they are 3.3Volt boards, while generally, the Arduino boards are 5Volt boards.

Maybe you are using a bi-directional voltage level shifter on the I2C to go from 3.3Volt to 5Volt ?

Another thing, have you checked that both run the same I2C clock rate ?

If you are coding in C/C++ for the Beaglebone, maybe there is a library you can use where you can simply link it into your program to get an API for I2C ?

I'd be interested to know more of what you are doing, in terms of how you process the data on the Beaglebone and what you do with it, if you are willing to tell. I'm also developing a system that may be similar to what you are doing for such boards.


Paul

Hello Paul,

I am using the arduino nano and the beaglebone black. I am also using the SparkFun level converter https://www.sparkfun.com/products/12009. The level converter is working quite well. I haven’t checked the clock rates but the Arduino can send text to the beaglebone via I2C and the beaglebone gets the text fine. I’m not using any library on the beaglebone side. Here is a snippit of the code on the beaglebone.

 int opResult;
  string i2cFile = "/dev/i2c-1";
  int i2cHandle;
  int tenBitAddress = 0;
  char rxBuffer[32];  // receive buffer
  char txBuffer[32];  // transmit buffer

 // opening the bus
  // Create a file descriptor for the I2C bus

 if ((i2cHandle = open(i2cFile.c_str(), O_RDWR)) < 0)
 {
    perror("Failed to open the I2C bus");
    /* ERROR HANDLING; check errno to see what went wrong */
    printf("%s.\n", strerror(errno));
    printf("\n\n");
    exit(1);
 }

  // Tell the I2C peripheral that the device address is (or isn't)
  // a 10-bit value. Most probably won't be.
  opResult = ioctl(i2cHandle, I2C_TENBIT, tenBitAddress);
  if(opResult<0) postError("Error specifying tenBitAddress.");

 // initiating comms

 if ((opResult = ioctl(i2cHandle, I2C_SLAVE, addr)) < 0)
 {
    printf("Failed to acquire bus access and/or talk to slave.\n");
    /* ERROR HANDLING; check errno to see what went wrong */
    printf("%s.\n", strerror(errno));
    printf("\n\n");
    exit(1);
 }

 // reading from the device

 unsigned char buf[80] = {0};
 
  // Using I2C Read
  if (read(i2cHandle, buf, 12) < 2)
  {
    // ERROR HANDLING: I2C read transaction failed
    printf("Failed to read from the I2C bus.\n");
    // ERROR HANDLING; check errno to see what went wrong
    printf("%s.\n", strerror(errno));
    printf("\n\n");
    exit(1);
  }
  else
  {
   //string str(buf);
  //printf("Received: %s\n",str.c_str());
  printf("\nReceived after iotcl: %s\n",buf);
 }

The above snippit works OK. The ioctl causes an onRequest interrupt to fire on the arduino and it sends text back. Here is the arduino code.

#include <Wire.h>

const int addr = 0x33;

byte count = 0;
int n = 0;

void setup()
{
  // join i2c bus as a slave device
  Wire.begin(addr);

  // register request event
  Wire.onRequest(requestEvent);
  
  // register receive event
  Wire.onReceive(receiveEvent);
}

void loop()
{
    delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
  
  // receive a byte
  while(Wire.available()>0)
  {
    char c = Wire.read();
    Wire.write("I am Nano-x.");
    return;
  }
  
  if(n==0)
  {
    Wire.write("I am Nano-0.");
    n++;
  }
  else if (n==1)
  {
    Wire.write("I am Nano-1.");
    n++;
  }
  else if (n==2)
  {
    Wire.write("I am Nano-2.");
    n++;
  }
  else
  {
    Wire.write("I am Nano-*.");
    n=0;
  }
}

// function that executes whenever data is received
// this function is registered as an event, see setup()
void receiveEvent(int numberOfBytesReceived)
{
  // receive a byte
  while(Wire.available()>0)
  {
    char c = Wire.read();
    Wire.write("I am Nano-?.");
  }
}

Note the Wire.available is always zero. If I then use the following code the arduino still fires the onRequest interrupt and not the onReceive interrupt.

 char buffer[3]={0x01,0x3F,0x67}; // char ?
 int num;
  num=write(i2cHandle,buffer,sizeof(buffer));               
  if(num < 1)
  {                 
   printf("Failed to write byte to device.\n");
    printf("%s.\n", strerror(errno));
    printf("\n\n");
    exit(1);
  }

 // Using I2C Read
  if (read(i2cHandle,buf,12) < 2)
  {
    // ERROR HANDLING: I2C read transaction failed
    printf("Failed to read from the I2C bus.\n");
    // ERROR HANDLING; check errno to see what went wrong
    printf("%s.\n", strerror(errno));
    printf("\n\n");
    exit(1);
  }
  else
  {
   //string str(buf);
  //printf("Received: %s\n",str.c_str());
  printf("Received after write: %s\n",buf);
 }

Note the code is simple test code.

Bottom line is the arduino never gets an onReceive interrupt even after I write to it via I2C from the beaglebone and its Wire.available is always zero.

Once I solve this problem I will be happy to share my code and what I am doing. In a nutshell I am building a robot with sonic and IR sensors as well as motor quadrature sensors. I want the processing power of the beaglebone so it can control the robot via the arduino nanos.

Don

drdon:
Hello Paul,

I am using the arduino nano and the beaglebone black. I am also using the SparkFun level converter https://www.sparkfun.com/products/12009. The level converter is working quite well. I haven’t checked the clock rates but the Arduino can send text to the beaglebone via I2C and the beaglebone gets the text fine. I’m not using any library on the beaglebone side. Here is a snippit of the code on the beaglebone.

 int opResult;

string i2cFile = “/dev/i2c-1”;
 int i2cHandle;
 int tenBitAddress = 0;
 char rxBuffer[32];  // receive buffer
 char txBuffer[32];  // transmit buffer

// opening the bus
 // Create a file descriptor for the I2C bus

if ((i2cHandle = open(i2cFile.c_str(), O_RDWR)) < 0)
{
   perror(“Failed to open the I2C bus”);
   /* ERROR HANDLING; check errno to see what went wrong */
   printf("%s.\n", strerror(errno));
   printf("\n\n");
   exit(1);
}

// Tell the I2C peripheral that the device address is (or isn’t)
 // a 10-bit value. Most probably won’t be.
 opResult = ioctl(i2cHandle, I2C_TENBIT, tenBitAddress);
 if(opResult<0) postError(“Error specifying tenBitAddress.”);

// initiating comms

if ((opResult = ioctl(i2cHandle, I2C_SLAVE, addr)) < 0)
{
   printf(“Failed to acquire bus access and/or talk to slave.\n”);
   /* ERROR HANDLING; check errno to see what went wrong */
   printf("%s.\n", strerror(errno));
   printf("\n\n");
   exit(1);
}

// reading from the device

unsigned char buf[80] = {0};

// Using I2C Read
 if (read(i2cHandle, buf, 12) < 2)
 {
   // ERROR HANDLING: I2C read transaction failed
   printf(“Failed to read from the I2C bus.\n”);
   // ERROR HANDLING; check errno to see what went wrong
   printf("%s.\n", strerror(errno));
   printf("\n\n");
   exit(1);
 }
 else
 {
  //string str(buf);
 //printf(“Received: %s\n”,str.c_str());
 printf("\nReceived after iotcl: %s\n",buf);
}





The above snippit works OK. The ioctl causes an onRequest interrupt to fire on the arduino and it sends text back. Here is the arduino code.



#include <Wire.h>

const int addr = 0x33;

byte count = 0;
int n = 0;

void setup()
{
 // join i2c bus as a slave device
 Wire.begin(addr);

// register request event
 Wire.onRequest(requestEvent);
 
 // register receive event
 Wire.onReceive(receiveEvent);
}

void loop()
{
   delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent()
{
 
 // receive a byte
 while(Wire.available()>0)
 {
   char c = Wire.read();
   Wire.write(“I am Nano-x.”);
   return;
 }
 
 if(n==0)
 {
   Wire.write(“I am Nano-0.”);
   n++;
 }
 else if (n==1)
 {
   Wire.write(“I am Nano-1.”);
   n++;
 }
 else if (n==2)
 {
   Wire.write(“I am Nano-2.”);
   n++;
 }
 else
 {
   Wire.write(“I am Nano-*.”);
   n=0;
 }
}

// function that executes whenever data is received
// this function is registered as an event, see setup()
void receiveEvent(int numberOfBytesReceived)
{
 // receive a byte
 while(Wire.available()>0)
 {
   char c = Wire.read();
   Wire.write(“I am Nano-?.”);
 }
}




Note the Wire.available is always zero. If I then use the following code the arduino still fires the onRequest interrupt and not the onReceive interrupt.



char buffer[3]={0x01,0x3F,0x67}; // char ?
int num;
 num=write(i2cHandle,buffer,sizeof(buffer));              
 if(num < 1)
 {                
  printf(“Failed to write byte to device.\n”);
   printf("%s.\n", strerror(errno));
   printf("\n\n");
   exit(1);
 }

// Using I2C Read
 if (read(i2cHandle,buf,12) < 2)
 {
   // ERROR HANDLING: I2C read transaction failed
   printf(“Failed to read from the I2C bus.\n”);
   // ERROR HANDLING; check errno to see what went wrong
   printf("%s.\n", strerror(errno));
   printf("\n\n");
   exit(1);
 }
 else
 {
  //string str(buf);
 //printf(“Received: %s\n”,str.c_str());
 printf(“Received after write: %s\n”,buf);
}




Note the code is simple test code.

Bottom line is the arduino never gets an onReceive interrupt even after I write to it via I2C from the beaglebone and its Wire.available is always zero.

Once I solve this problem I will be happy to share my code and what I am doing. In a nutshell I am building a robot with sonic and IR sensors as well as motor quadrature sensors. I want the processing power of the beaglebone so it can control the robot via the arduino nanos.

Don

Heck of a longshot, but did you figure out a successful I2C communication between Beaglebone and Arduino? I am running into the same issue and would love to see how your code developed!