0

I'm a beginner at I2C communication and I am trying to hook up communication with an I2C device a (mpu6050) using librobotcontrol http://strawsondesign.com/docs/librobotcontrol/group___i2_c.html i2c library in C. The code Excluding stuff not I2C related I have:

#define I2C_ADDRESS 0x68
#define I2C_BUS 1

void setupMPU();
float recordAccelRegisters();

int main(){

    float ax = 0;
    while(1){
        ax = recordAccelRegisters()
    }

    float recordAccelRegisters(){
        float Xg = 0;
        float Xa = 0, Ya, Za;
        unsigned char data;

        printf("Recording Accel Data\n");

        rc_i2c_init (I2C_BUS,I2C_ADDRESS);
        rc_i2c_read_bytes(I2C_BUS, 0x3B, 6, data);
        rc_i2c_close(I2C_BUS);

        //Xa = 8 << data;
        //Xa = (float)Xa;
        //Xg = Xa/16384.0;
        return Xg;
        }

    void setupMPU(){
        printf("Initalizing Mpu\n");

        // init I2C Bus
        rc_i2c_init (I2C_BUS,I2C_ADDRESS);

        //Wake up setup
        rc_i2c_write_byte(I2C_BUS, 0x6B, 0x00);
        rc_i2c_close(I2C_BUS);

        printf("Configuring Accelerometer\n");
        printf("Initalizing Mpu\n");

        //Accel Config
        rc_i2c_init (I2C_BUS,I2C_ADDRESS);
        rc_i2c_write_byte(I2C_BUS, 0x1C, 0x00);

        printf("Done with Accel Config\n");
        rc_i2c_close(I2C_BUS);
        }
   }

I am trying to figure out if I need to close and reopen the port every time like in an Arduino using wire library or if I can just initialize it once. I have tried many different types of code configurations. For instance only initializing the communication only once, using send words instead of send bytes, sending only 1 byte at a time ect... but I am still unable to get data from the device. I am also struggling with weather or not to use read words or read bytes. It keeps returning a -1 bytes as seen by this error message when using

read bytes:

ERROR: in rc_i2c_read_bytes, received -1 bytes from device, expected 1

and this error when using read words:

ERROR: Segmentation Fault
Fault address: (nil)
Address not mapped.
Segmentation fault

Any help on this will be much appreciated.

Chaz
  • 11
  • 2

1 Answers1

0

According to the documentation you linked, the function rc_i2c_read_bytes takes a pointer where it will store the bytes read:

int rc_i2c_read_bytes (int bus, uint8_t regAddr, size_t count, uint8_t *data);
Reads multiple bytes from a device register

Thus, in your recordAccelRegisters function, you should define an array to store the bytes:

float recordAccelRegisters(){
        float Xg = 0;
        float Xa = 0, Ya, Za;
        unsigned char data[6];

        printf("Recording Accel Data\n");

        rc_i2c_init (I2C_BUS,I2C_ADDRESS);
        rc_i2c_read_bytes(I2C_BUS, 0x3B, 6, data);
        rc_i2c_close(I2C_BUS);

        //Xa = 8 << data;
        //Xa = (float)Xa;
        //Xg = Xa/16384.0;
        return Xg;
}

Same applies if you use rc_i2c_read_word, it also requires a pointer (to a uint16_t):

float recordAccelRegisters(){
        float Xg = 0;
        float Xa = 0, Ya, Za;
        uint16_t data;

        printf("Recording Accel Data\n");

        rc_i2c_init (I2C_BUS,I2C_ADDRESS);
        rc_i2c_read_word(I2C_BUS, 0x3B, &data);
        rc_i2c_close(I2C_BUS);

        //Xa = 8 << data;
        //Xa = (float)Xa;
        //Xg = Xa/16384.0;
        return Xg;
}

Omar
  • 943
  • 6
  • 9
  • Thank you for your help. Changing the unsigned char data to unsigned char data['large buffer size'] has gotten out the errors and warnings!! However, now I am stuck trying to see if any data is being written. – Chaz Feb 23 '22 at 05:20
  • Update. So I think data is coming through but if anyone sees this. I'm looking for a way to store the data into sub bytes of 8 so Xa = bits 1-16, Ya = bits 17 - 32, and Za = bits 33 - 48. – Chaz Feb 23 '22 at 06:18
  • @Chaz In which order are the bits sent by the device? If the lowest bits are in data[0], you can use: `Xa = (data[1] << 8) | data[0]; Ya = (data[3] << 8) | data[2]; Za = (data[4] << 8) | data[3];` – Omar Feb 23 '22 at 06:40
  • Thank you for this!. This helps a lot I was able to put the data into its own settings . I'm not sure what you mean by order. In the data sheet it says that the values for Xa_H are bits [15-8] which are the MSB's and bits [7-0] are LSB. While some data is coming out it seems to be garbage. My expected values are in the ball park of ax,ay,az = 0,0,9.81. However i'm getting [ax: 1.690 | ay: 2.002 | az: 3.127]. When reading in bytes if I choose 6 bytes am I reading in registers 0x3B,3C,3D ect... or just 0x3B? – Chaz Feb 24 '22 at 01:53
  • [This might help](https://gyazo.com/f503cf41fcae8d139300b779625d3553) – Chaz Feb 24 '22 at 02:18
  • @Chaz Thank for linking this part of the datasheet. You can see that address 0x3B contains MSB, whereas 0x3C contains LSB, thus, this is big-endian. In that case, in order to retrieve the data you need, use: `Xa = (data[0] << 8) | data[1]; Ya = (data[2] << 8) | data[3]; Za = (data[4] << 8) | data[5];` – Omar Feb 24 '22 at 09:29
  • 1
    I think I finally have it working. Switching the bits to be read in the way you said has fixed the garbage issue!! After dividing by the calibration and multiplying by gravity, I think its finally working. Its reading X,Y,Z = ~~ 0.2, 0.2, 9.84 on a flat surface. It will occasionally read something ridiculous like 39, 39, 0.3 so I might need to add a filter to it. However as of right now I think its working. Thanks again!! – Chaz Feb 26 '22 at 03:58