two way communication between i2c and UART (in a bridge configuration)

Hi all,

I have an i2c based sensor and want to communicate with it using a xbee modue with a UART interface. I tried making a sketch but it doesn't work as expected. What could be the cause? Has anyone does so? Moreover the i2C commands I am sending over the air are ASCii based with the format: S [slave write address] [register] [data_byte] P. I guess I also need to format/parse the command. Please guide me. Thanks!

#include <Wire.h>

void setup() {
  // put your setup code here, to run once:
  Wire.begin(13);
  Wire.onReceive (receiveEvent);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly
  serialEvent();
}

void receiveEvent(int numBytes) {
  while (Wire.available () > 0)
  {
    char b = Wire.read (); //never tested this
    Serial.write(b);
  }  
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    Wire.write(inChar);
  }
}

You will have to design and parse a serial input stream of printable characters, and when a complete command has been received, send the appropriate command to the I2C device (which is very likely to contain byte values that are not printable). In the serial stream, people usually use a human-readable Hex ASCII representation of unprintable data bytes.

It has been done many times and you can even buy dedicated boards. Search for "serial uart to I2C converter"

The serial characters need not be printable. Usually they are, but I've seen devices that just used the byte values directly.

Yes, it would certainly make a beginner's life easier to type unprintable characters on a keyboard.

The onReceive() function is an interrupt service routine. Doing things in an ISR that rely on interrupts being enabled (they are not), such as Serial.write(), is a colossally bad idea.

Having loop() do nothing but call a function that will be called anyway is silly. Ditch the stupid serialEvent() function and just read the serial data in loop().

Hi all,

Thanks a lot for your responses. Well, the parsing of the data is working as expected but forwarding the data over I2C is not working correctly. PaulS, I am really new to Arduino programming so I used some examples snippets and create the code therefore, it might be hacky or wrong. Please guide me how to simultaneously read and write between i2C and UART.

#include <Wire.h>
#include <stdlib.h>

String command = "";
bool startFrame = false;
bool stopFrame = false;

void setup() {
  // put your setup code here, to run once:
  Wire.begin();
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly
  serialEvent();
  receiveEvent();
  

}

void receiveEvent() {
  while (Wire.available () > 0)
  {
    char b = Wire.read ();
    Serial.write(b);
  }  
}

void serialEvent() {
  
  bool IsReadCmd = false;
  
  
  String i2cAddress = "";
  int i2cAddress_num = 13;
  int address;
  String registerAddress = "";
  int registerAddress_num = 0;
  String registerData = "";
  int registerData_num = 0;
  
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    //Serial.println(inChar);
    
    if (inChar == 'S')
    {
      startFrame = true;
    }
    else if (inChar == 'P')
    {
      startFrame = false;
      stopFrame = true;
    }

    if (startFrame)
    {
      if (inChar == ' ' || inChar == '\n')
      {
        // Do nothing
      }
      else
      {
        command += inChar; 
      }
    }
    else if (stopFrame)
    {
      stopFrame = false;
      i2cAddress = command.substring(1,3);
      i2cAddress_num = strtol(i2cAddress.c_str(),NULL,16);
      registerAddress = command.substring(3,5);
      registerAddress_num = strtol(registerAddress.c_str(),NULL,16);
      if ( i2cAddress_num & 0x01 )
      {
        IsReadCmd = true;
        address = i2cAddress_num >> 1;
        Wire.beginTransmission(address);
        Wire.write(registerAddress_num);
        Wire.endTransmission();
        command = "";
      }
      else
      {
        registerData = command.substring(5);
        registerData_num = strtol(registerData.c_str(),NULL,16);
        address = i2cAddress_num >> 1;
        Wire.beginTransmission(address);
        Wire.write(registerAddress_num);
        Wire.write(registerData_num);
        Wire.endTransmission();
        command = "";
      }
      
      
      
      
    }
  }
}

Please guide me how to simultaneously read and write between i2C and UART.

You can't.

You have an interrupt handler that is triggered when there is I2C data to read. In that ISR you read the data and set a flag.

In loop(), you see if that flag is set. If it is, you write the data to the serial port and clear the flag.