Search code examples
c++linuxarduinoraspberry-pii2c

Raspberry Pi I2C


I have multiple arduino's that talk back and forth using I2C. The master write two bytes and then reads 1 byte response back. Everything worked great and horray. But now I've been working on switching my master to a Raspberry Pi. The code that I have written works with no problems but 1 in every 200 read/write, it returns an occasional wrong reading which would be a huge set back on the system's reliability. I'm attaching my code just in case someone see anything that I am doing wrong or if anyone else have ran into similar issue before.

RPi C++ Code:

#include <iostream>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include "../HaMiD_Lib/StopWatch.h"

using namespace std;

int file_i2c;
int length;
uint8_t buffer[2] = {0};

int timingLoopFreq = 500;       
int timingLoopMicroSeconds = 1000000 / timingLoopFreq;      //500 us
StopWatch loopTime(timingLoopMicroSeconds);                 // My own stopwatch livrary
uint8_t addr = 0x11;

using namespace std;

int main(void)
{
         //-------------- OPEN THE I2C BUS--------------------------
        char *filename = (char*)"/dev/i2c-1";
        if((file_i2c = open(filename, O_RDWR))< 0 ){
                //ERROR HANDLING: you can check errno to see what went wrong;
                cout << "Failed to open the i2c bus" << endl;
                return 0;
        }

        while(1){
                if (loopTime.check()) {
                        loopTime.reset();

                        if (ioctl(file_i2c, I2C_SLAVE, addr) < 0){
                                cout << "Failed to acquire bus access and/or talk to slave" << endl;
                                //ERROR HANDLING: you can check errno to see what went wrong;
                        }

                        // ------------- WRITE BYTES -------------
                        buffer[0] = 4;
                        buffer[1] = 0;
                        length = 2;                 //<<<<< Number of bytes to write
                        if (write(file_i2c, buffer, length) != length){                    // write() returns the number of bytes actually written, if it doesn't match then an error occurred (e.g. no response from the device)
                        // ERROR HANDLING: i2c transaction failed
                                cout << "Failed to write to the i2c bus " << endl;
                        } else {
                                    // ------------ READ BYTES -------
                                    length = 1;
                                    if (read(file_i2c, buffer, length) != length){              // read() returns the number of bytes actually read, if it doesn't match then an error occurred (e.g. no response from the device)
                                        //ERROR HANDLING: i2c transaction failed
                                        cout <<"Failed to read from the i2c bus" << endl;
                                    } else {
                                            cout << "Data read:" << buffer[0] << endl;
                                }
                        }
                }
        }
        cout << "exiting" << endl;
        return 0;
}

Arduino I2C Snippet:

//I2C functions
void receiveEvent(int byteCount) {
    while (Wire.available()) {
        I2C_cmd_1st = Wire.read(); // 1 byte (maximum 256 commands)
        I2C_cmd_2nd = Wire.read(); // 1 byte (maximum 256 commands)
    }
}

void slavesRespond() {
    byte returnValue = 0;

    switch (I2C_cmd_1st) {
    case status_cmd:   // 40
        returnValue = module;
        if (module == DONE) {
            module = STOP;                  //reset the machine
        }
        break;
    case test_cmd:
        returnValue = ID;
        break;
    }
    Wire.write(returnValue);          // return response to last command
}

And here is a small section of the output from cout. The Data read should always return 2 but once a while (1 in 100) it fails to read or write from i2c bus and sometimes (1 in 500) it returns a wrong value (in below example it should return 2 but it sometimes return 3 by accident or it could be 97 or etc).

Data read:2
Data read:3    //This is wrong!
Data read:2
Failed to read from the i2c bus
Failed to read from the i2c bus
Data read:3    //This is wrong!
Data read:2

Any help would be appreciated. Has anyone else seen something similar with RPi and Arduino? The wiring is pretty straight forward cause RPi is the master.


Solution

  • Have you tried to read at receive event only as my data as it was actually available. Code takes into account that byteCount in receiveEvent is divisible by 2.