I2C and Minimu9 - strange behavior

01 Feb 2013

Hey,

i'm trying to comunicate with an Minimu9 from Pololu, but it shows some strange behavior. I use the following code:

#include "mbed.h"
#include "Gyro.h"

using namespace std;
  
Serial pc(USBTX, USBRX);
Gyro gyro(p28, p27);
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
  
int main()
{
    wait(5);
    pc.printf("1\n");
    int status = (int)gyro.readRegister(L3G4200D_WHO_AM_I);
    wait(1);
    pc.printf("Who am i: _%i_ \n", status);
    pc.printf("2\n");
    wait(1);
    status = (int)gyro.readRegister(L3G4200D_STATUS_REG);
    pc.printf("Status: _%i_ \n", status);
    pc.printf("3\n");
    led1 = 1;
    
}

The class Gyro:

#include "Gyro.h"
#include "mbed.h"

Gyro::Gyro(PinName sda, PinName scl): _i2c(sda, scl)
{
    writeRegister(L3G4200D_CTRL_REG1, 0x0F);
}

int Gyro::writeRegister(char regAdresse, char value)
{
    char daten[2] = {regAdresse, value};
    return _i2c.write(GYR_ADDRESS, daten, 2);
}

char Gyro::readRegister(char regAdresse)
{
    char ret[1];
    char Adresse[1] = {regAdresse};
    _i2c.write(GYR_ADDRESS, Adresse, 1, 1);
    _i2c.read(GYR_ADDRESS, ret, 1);
    return ret[0];
}

If i connect it and let the program run, the output is:

Quote:

1 Who am i: _17_ 2 Status: _189_ 3

If i change the code to:

#include "mbed.h"
#include "Gyro.h"

using namespace std;
  
Serial pc(USBTX, USBRX);
Gyro gyro(p28, p27);
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
  
int main()
{
    wait(5);
    pc.printf("100\n");                                                     //<---
    int status = (int)gyro.readRegister(L3G4200D_WHO_AM_I);
    wait(1);
    pc.printf("Who am i: _%i_ \n", status);
    pc.printf("200\n");                                                     //<---
    wait(1);
    status = (int)gyro.readRegister(L3G4200D_STATUS_REG);
    pc.printf("Status: _%i_ \n", status);
    pc.printf("300\n");                                                     //<---
    led1 = 1;
    
}

the output is:

Quote:

100 Who am i: _17_ 200 Status: _201_ 300

I think the reading of the WHO_AM_I register should produce an integer of 211 and not 17.

I have no pullup resistors connected because the imu (if i read the schematics right) has an internal pullup: http://www.pololu.com/file/0J502/MinIMU-9_schematic.pdf

I hope someone could help me, cause im a kind of desperated with this right now, don't know if i destroyed the mbed in some way. The imu is definitely working, i tested it.

01 Feb 2013

I would consider it highly unlikely anything is broken, then it shouldnt return any value. That the status changes depending on a few zeros in your serial output is weird, but since they are just saying if there is new data/old data overwritten it probably can chance quite a bit.

Regarding WhoAmI register, well that indeed shouldn't be 17. Can you post where you define the I2C address and the value for the register definitions? Most obvious guess would be that you got an error there.

01 Feb 2013

Here's the header:

#ifndef GYRO_H
#define GYRO_H

#include "mbed.h"

// --- register addresses ---

#define L3G4200D_WHO_AM_I      0x0F

#define L3G4200D_CTRL_REG1     0x20
#define L3G4200D_CTRL_REG2     0x21
#define L3G4200D_CTRL_REG3     0x22
#define L3G4200D_CTRL_REG4     0x23
#define L3G4200D_CTRL_REG5     0x24
#define L3G4200D_REFERENCE     0x25
#define L3G4200D_OUT_TEMP      0x26
#define L3G4200D_STATUS_REG    0x27

#define L3G4200D_OUT_X_L       0x28
#define L3G4200D_OUT_X_H       0x29
#define L3G4200D_OUT_Y_L       0x2A
#define L3G4200D_OUT_Y_H       0x2B
#define L3G4200D_OUT_Z_L       0x2C
#define L3G4200D_OUT_Z_H       0x2D

#define L3G4200D_FIFO_CTRL_REG 0x2E
#define L3G4200D_FIFO_SRC_REG  0x2F

#define L3G4200D_INT1_CFG      0x30
#define L3G4200D_INT1_SRC      0x31
#define L3G4200D_INT1_THS_XH   0x32
#define L3G4200D_INT1_THS_XL   0x33
#define L3G4200D_INT1_THS_YH   0x34
#define L3G4200D_INT1_THS_YL   0x35
#define L3G4200D_INT1_THS_ZH   0x36
#define L3G4200D_INT1_THS_ZL   0x37
#define L3G4200D_INT1_DURATION 0x38

#define GYR_ADDRESS (0xD2 >> 1)

class Gyro
{
public:
    Gyro(PinName, PinName);
    I2C _i2c;
    int writeRegister(char, char);
    char readRegister(char);
};

#endif

The registers are defined here on page 27:http://www.pololu.com/file/0J491/L3G4200D.pdf

Some important things i forgot to post: before i read the schematics of the imu, i had some pullup resistors connected like in the i2c handbook page mentioned, and also if i had not connected the imu, only the resistors, it produced the same values.

01 Feb 2013

You shift GYR_ADDRESS one to the right. However the mbed library wants 8-bit addresses, so effectively you supplied it with the wrong address, you dont need to do the shift action. (That is btw why it can be an idea when having issues with i2c to just write only the address, and check if it gets an ack, the library will return a value to check that).

That you got anything back at all is probably because the variable was unitialized, so it could be anything.

01 Feb 2013

Yes, thanks very much, that was the fault. Now i get 211 for WhoIAm back (and 255 for status). Such a silly fault :)