NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Sensors, Actuators, and Robotics » adafruit 10DOF with I2C

April 12, 2015
by scootergarrett
scootergarrett's Avatar

I finally got around to figuring out the adafruit 10DOF board, which forced me to learn I2C. So its a 3 axis accelerometer, 3 axis gyro (rotational velocity), 3 axis magnetometer, and has temperature and barometric pressure. I set it up with the 324p circuit diagram but the code should still work with a 328/168. I wrote functions that set up the I2C then set up the sensors set gains exc. Then I have functions that populate a structure IMURawData_S with space for each measurement. The pressure measurement is the strangest; first all the internal coefficients need to be read and stored from the sensor. Then the raw measurement needs to go through this crazy math just to get the barometric pressure.

I have been able to test the accelerometers and the magnetometer by mounting the sensor on a servo mounting the sensor on a servo motor and slowly rotating it some quic results:

plot

And I tested the pressure measurments by driving up and down hills with it in my car.

bacause of the math required for the pressure using the pow() function I had to switch the make file line from:

    avr-gcc ${GCCFLAGS} ${LINKFLAGS} -o $(ProgramName).o $(ProgramName).c  ${LINKOBJECTS}

to:

    avr-gcc ${GCCFLAGS} -o $(ProgramName).o $(ProgramName).c ${LINKFLAGS} ${LINKOBJECTS}

Here are all the functions I'm using/ developing:

/// How to get data from the Ada fruit 10DOF IMU ///
/// Still need pressure and rotational velocity and temp and structures and nice functions ///

struct IMURawData_S
{
    uint16_t AccelerationX;
    uint16_t AccelerationY;
    uint16_t AccelerationZ;

    uint16_t AngularVelocityX;
    uint16_t AngularVelocityY;
    uint16_t AngularVelocityZ;

    uint16_t MagneticFieldX;
    uint16_t MagneticFieldY;
    uint16_t MagneticFieldZ;

    uint32_t Pressure;
    int16_t Temperature;
};

#define AccelerationSlaveAddress 0x32
#define Acceleration_CTRL_REG1_A_Register 0x20  // Enable and power mode
#define Acceleration_CTRL_REG4_A_Register 0x23  // Mode select and gain
#define Acceleration_OUT_X_L_A_Register   0x28  // X axes acceleration field Low bit
#define Acceleration_OUT_X_H_A_Register   0x29  // X axes acceleration field High bit
#define Acceleration_OUT_Y_L_A_Register   0x2A  // Y axes acceleration field Low bit
#define Acceleration_OUT_Y_H_A_Register   0x2B  // Y axes acceleration field High bit
#define Acceleration_OUT_Z_L_A_Register   0x2C  // Z axes acceleration field Low bit
#define Acceleration_OUT_Z_H_A_Register   0x2D  // Z axes acceleration field High bit

#define AngularVelocitySlaveAddress 0xD6
#define AngularVelocity_WHO_AM_I_Register 0x0F  // Device identification register
#define AngularVelocity_WHO_AM_I_RegisterDefault 0xD7
#define AngularVelocity_CTRL1_Register 0x20     // Enable axis, bandwidth, and output data rate
#define AngularVelocity_OUT_X_L_Register 0x28   // X axes AngularVelocity Low bit
#define AngularVelocity_OUT_X_H_Register 0x29   // X axes AngularVelocity High bit
#define AngularVelocity_OUT_Y_L_Register 0x2A   // Y axes AngularVelocity Low bit
#define AngularVelocity_OUT_Y_H_Register 0x2B   // Y axes AngularVelocity High bit
#define AngularVelocity_OUT_Z_L_Register 0x2C   // Z axes AngularVelocity Low bit
#define AngularVelocity_OUT_Z_H_Register 0x2D   // Z axes AngularVelocity High bit

#define MagneticFieldSlaveAddress 0x3C
#define MagneticFieldS_CRA_REG_M_Register 0x00  // Temperature enable and DataRate
#define MagneticFieldS_CRB_REG_M_Register 0x01  // Gain Register
#define MagneticFieldS_MR_REG_M_Register  0x02  // Mode select
#define MagneticFieldS_OUT_X_H_M_Register  0x03 // X axes magnetic field High bit
#define MagneticFieldS_OUT_X_L_M_Register  0x04 // X axes magnetic field Low bit
#define MagneticFieldS_OUT_Z_H_M_Register  0x05 // Z axes magnetic field High bit
#define MagneticFieldS_OUT_Z_L_M_Register  0x06 // Z axes magnetic field Low bit
#define MagneticFieldS_OUT_Y_H_M_Register  0x07 // Y axes magnetic field High bit
#define MagneticFieldS_OUT_Y_L_M_Register  0x08 // Y axes magnetic field Low bit

#define PressureSlaveAddress 0xEE
#define BMP085_MODE_STANDARD 0x00

#define SCL_CLOCK 100000L

void I2C_INT();
uint8_t SetUpIMU();
uint8_t SendI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t Data);
uint8_t GetI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t *Data);

struct Bosch_Coefficients_S
{
    int16_t AC1;
    int16_t AC2;
    int16_t AC3;
    uint16_t AC4;
    uint16_t AC5;
    uint16_t AC6;
    int16_t B1;
    int16_t B2;
    int16_t MB;
    int16_t MC;
    int16_t MD;

    float BasePressure;
};

void Populate_Bosch_Coefficients(volatile struct Bosch_Coefficients_S *Bosch_Coefficients)
{

    GetI2CData(PressureSlaveAddress, 0xAA, (uint8_t*)&Bosch_Coefficients->AC1 + 1 );
    GetI2CData(PressureSlaveAddress, 0xAB, (uint8_t*)&Bosch_Coefficients->AC1 );

    GetI2CData(PressureSlaveAddress, 0xAC, (uint8_t*)&Bosch_Coefficients->AC2 + 1  );
    GetI2CData(PressureSlaveAddress, 0xAD, (uint8_t*)&Bosch_Coefficients->AC2 );

    GetI2CData(PressureSlaveAddress, 0xAE, (uint8_t*)&Bosch_Coefficients->AC3 + 1 );
    GetI2CData(PressureSlaveAddress, 0xAF, (uint8_t*)&Bosch_Coefficients->AC3 );

    GetI2CData(PressureSlaveAddress, 0xB0, (uint8_t*)&Bosch_Coefficients->AC4 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB1, (uint8_t*)&Bosch_Coefficients->AC4 );

    GetI2CData(PressureSlaveAddress, 0xB2, (uint8_t*)&Bosch_Coefficients->AC5 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB3, (uint8_t*)&Bosch_Coefficients->AC5 );

    GetI2CData(PressureSlaveAddress, 0xB4, (uint8_t*)&Bosch_Coefficients->AC6 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB5, (uint8_t*)&Bosch_Coefficients->AC6 );

    GetI2CData(PressureSlaveAddress, 0xB6, (uint8_t*)&Bosch_Coefficients->B1 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB7, (uint8_t*)&Bosch_Coefficients->B1 );

    GetI2CData(PressureSlaveAddress, 0xB8, (uint8_t*)&Bosch_Coefficients->B2 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB9, (uint8_t*)&Bosch_Coefficients->B2 );

    GetI2CData(PressureSlaveAddress, 0xBA, (uint8_t*)&Bosch_Coefficients->MB + 1 );
    GetI2CData(PressureSlaveAddress, 0xBB, (uint8_t*)&Bosch_Coefficients->MB );

    GetI2CData(PressureSlaveAddress, 0xBC, (uint8_t*)&Bosch_Coefficients->MC + 1 );
    GetI2CData(PressureSlaveAddress, 0xBD, (uint8_t*)&Bosch_Coefficients->MC );

    GetI2CData(PressureSlaveAddress, 0xBE, (uint8_t*)&Bosch_Coefficients->MD + 1 );
    GetI2CData(PressureSlaveAddress, 0xBF, (uint8_t*)&Bosch_Coefficients->MD );

    return;
}

volatile struct Bosch_Coefficients_S Bosch_Coefficients;

/// Sets up the I2C ///
void I2C_INT()
{
    TWBR = ((F_CPU/SCL_CLOCK)-16)/2;                // [Bit rate register] controls signal speed p.232
    TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWINT);     // [Control register] p.232
    TWSR &= ~((1<<TWPS1) | (1<<TWPS0));             // [Status register 0-1] controls signal speed p.234

    return;
}

uint8_t SendI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t Data)
{
    /// Set start ///
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));   // wait
    if ((TWSR & 0xF8) != 0x08)
        return -1;

    /// Send slave address + w ///
    TWDR = SlaveAddress;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x18)
        return -2;

    /// Send sub address ///
    TWDR = Register;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x28)
        return -3;

    /// Send  Data ///
    TWDR = Data;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x28)
        return -4;

    /// Stop bit ///
    TWCR = (1<<TWINT) | (1<<TWSTO);

    return 0;
}

uint8_t GetI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t *Data) { /// Set start /// TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); // wait if ((TWSR & 0xF8) != 0x08) return -1;

/// Send slave address + w ///
TWDR = SlaveAddress;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != 0x18)

// if ((TWSR & 0xF8) != 0x48) return -2;

/// Send  sub address ///
TWDR = Register;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != 0x28)
    return -3;

/// Set repeat start ///
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));   // wait
if ((TWSR & 0xF8) != 0x10)
    return -4;

/// Send slave address + r ///
TWDR = SlaveAddress | 0x01;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));   // wait
if ((TWSR & 0xF8) != 0x40)
    return -5;

/// Get data ///
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));   // wait

/// Stop bit ///
TWCR = (1<<TWINT) | (1<<TWSTO);

*Data = TWDR;

return 0;

}

uint8_t SetUpIMU() { uint8_t RegisterData;

I2C_INT();
delay_ms(10);

/// Set up the Acceleration /// WIP need sensitivity set up
if( SendI2CData(AccelerationSlaveAddress, Acceleration_CTRL_REG1_A_Register, 0x57) )
    return -1;

if( SendI2CData(AccelerationSlaveAddress, Acceleration_CTRL_REG4_A_Register, 0b00000000) )    /// Gain and High res mode????
    return -1;

/// Set up the AngularVelocity /// WIP
if( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_WHO_AM_I_Register,  &RegisterData) )
    return -2;
if( RegisterData != AngularVelocity_WHO_AM_I_RegisterDefault)
    return -2;

if( SendI2CData(AngularVelocitySlaveAddress, AngularVelocity_CTRL1_Register, 0b00001111) )   /// Enable stuff WIP (fast with high cut off freq?)
    return -2;

/// Set up the MagneticField /// WIP need sensitivity set up
if( SendI2CData(MagneticFieldSlaveAddress, MagneticFieldS_MR_REG_M_Register, 0b00000000) )
    return -3;

if( SendI2CData(MagneticFieldSlaveAddress, MagneticFieldS_CRA_REG_M_Register, 0b10011100) )
    return -3;

if( SendI2CData(MagneticFieldSlaveAddress, MagneticFieldS_CRB_REG_M_Register, 0b11100000) )
    return -3;

/// Set up pressure measurements /// WIP
delay_ms(10);
Populate_Bosch_Coefficients(&Bosch_Coefficients);

return 0;

}

uint8_t IMUGetAcceleration(struct IMURawData_S IMURawData) { if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_X_L_A_Register, (uint8_t)&((IMURawData).AccelerationX) ) ) return -1; if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_X_H_A_Register, (uint8_t)&((*IMURawData).AccelerationX) + 1 ) ) return -1;

if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Y_L_A_Register,  (uint8_t*)&((*IMURawData).AccelerationY)  ) )
    return -1;
if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Y_H_A_Register,  (uint8_t*)&((*IMURawData).AccelerationY) + 1  ) )
    return -1;

if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Z_L_A_Register,  (uint8_t*)&((*IMURawData).AccelerationZ)  ) )
    return -1;
if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Z_H_A_Register,  (uint8_t*)&((*IMURawData).AccelerationZ) + 1  ) )
    return -1;

return 0;

}

uint8_t IMUGetMagneticField(struct IMURawData_S *IMURawData) { /// Looks if the data is new /// WIP // if ( GetI2CData(MagneticFieldSlaveAddress, 0x09, &k) ) // return -1; // if(!(k & 0x01)) // continue;

if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_X_H_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldX) + 1  ) )
    return -1;
if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_X_L_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldX)  ) )
    return -1;

if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Z_H_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldZ) + 1  ) )
    return -1;
if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Z_L_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldZ)  ) )
    return -1;

if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Y_H_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldY) + 1  ) )
    return -1;
if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Y_L_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldY)  ) )
    return -1;

return 0;

}

uint8_t IMUGAngularVelocity(struct IMURawData_S *IMURawData) {

if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_X_L_Register,  (uint8_t*)&((*IMURawData).AngularVelocityX) ) )
    return -1;
if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_X_H_Register,  (uint8_t*)&((*IMURawData).AngularVelocityX) + 1  ) )
    return -1;

if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Y_L_Register,  (uint8_t*)&((*IMURawData).AngularVelocityY) ) )
    return -1;
if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Y_H_Register,  (uint8_t*)&((*IMURawData).AngularVelocityY) + 1  ) )
    return -1;

if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Z_L_Register,  (uint8_t*)&((*IMURawData).AngularVelocityZ) ) )
    return -1;
if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Z_H_Register,  (uint8_t*)&((*IMURawData).AngularVelocityZ) + 1  ) )
    return -1;

return 0;

}

uint8_t IMUPressure(struct IMURawData_S *IMURawData) { int32_t UT = 0, UP = 0, X1 = 0, X2 = 0, B5 = 0, B6 = 0, X3 = 0, B3 = 0, p = 0; uint32_t B4 = 0, B7 = 0; uint8_t MSB, LSB, XLSB;

/// Get the Raw temperature ///
SendI2CData(PressureSlaveAddress, 0xF4, 0x2E);
delay_ms(5);
GetI2CData(PressureSlaveAddress, 0xF6, (uint8_t*)&UT + 1 );
GetI2CData(PressureSlaveAddress, 0xF7, (uint8_t*)&UT );

/// Get the raw pressure //
SendI2CData(PressureSlaveAddress, 0xF4, 0x34 + (BMP085_MODE_STANDARD<<6) );
delay_ms(30);
GetI2CData(PressureSlaveAddress, 0xF6, &MSB);
GetI2CData(PressureSlaveAddress, 0xF7, &LSB);
GetI2CData(PressureSlaveAddress, 0xF8, &XLSB);
UP = ( (((int32_t)MSB)<<16) + (((uint32_t)LSB)<<8) + XLSB) >> (8-BMP085_MODE_STANDARD);

/// Calculate the temperatur ///
X1 = (UT - Bosch_Coefficients.AC6)*Bosch_Coefficients.AC5 / 32768L;
X2 = ((int32_t)Bosch_Coefficients.MC << 11) / (X1 + (int32_t)Bosch_Coefficients.MD);
B5 = X1 + X2;
IMURawData->Temperature = (float)((B5 + 8) >> 4);

/// Calculate the pressure ///
B6 = B5 - 4000;
X1 = (Bosch_Coefficients.B2 * ((B6 * B6) >> 12)) >> 11;
X2 = (Bosch_Coefficients.AC2 * B6) >> 11;
X3 = X1 + X2;
B3 = ((((int32_t)Bosch_Coefficients.AC1 * 4 + X3) << BMP085_MODE_STANDARD) + 2) >> 2;
X1 = (Bosch_Coefficients.AC3 * B6) >> 13;
X2 = (Bosch_Coefficients.B1 * ((B6 * B6) >> 12)) >> 16;
X3 = ((X1 + X2) + 2) >> 2;
B4 = (Bosch_Coefficients.AC4 * (uint32_t) (X3 + 32768)) >> 15;
B7 = ( ((uint32_t)UP - B3) * (uint32_t)(50000 >> BMP085_MODE_STANDARD));
if (B7 < 0x80000000)
    p = (B7 << 1) / B4;
else
    p = (B7 / B4) << 1;
X1 = (p >> 8) * (p >> 8);
X1 = (X1 * 3038) >> 16;
X2 = (-7357 * p) >> 16;
IMURawData->Pressure = p + ((X1 + X2 + 3791) >> 4);

return 0;

}

float CalculateAltitude(uint32_t Pressure) { float Alt;

// Alt = 44330 * ( 1- pow( (float)Pressure/101325.0 , 0.190294957183635 ) ); Alt = 44330 * ( 1- pow( (float)Pressure/Bosch_Coefficients.BasePressure , 0.190294957183635 ) );

return Alt;

}

void CalSeaLevelPressure(uint16_t Starting_Elevation) { struct IMURawData_S IMURawData;

IMUPressure(&IMURawData);
Bosch_Coefficients.BasePressure = IMURawData.Pressure / pow(1.0 - (Starting_Elevation/44330.0), 5.255);

return;

}

and here is a quick code that shows current pressure on the LCD:

#define TestPin A,0

int main()
{
    struct IMURawData_S IMURawData;
    int8_t k = 0;
    float Altitude;
    OUTPUT(TestPin);

    lcd_init();
    fdev_setup_stream(&lcd_stream, lcd_putchar, 0, _FDEV_SETUP_WRITE);
    lcd_clear_and_home();

    uart_init();
    if(SetUpIMU())
        goto error;

    while(true)
    {

        IMUPressure(&IMURawData);

        lcd_line_one();
        fprintf_P(&lcd_stream, PSTR("P: %li  "), IMURawData.Pressure);
        lcd_line_two();
        fprintf_P(&lcd_stream, PSTR("T: %.1f  "), (float)IMURawData.Temperature/10);

        delay_ms(1000);
    }

    error:
    fprintf_P(&lcd_stream, PSTR("ERROR"));
    lcd_line_two();
    fprintf_P(&lcd_stream, PSTR("TWSR & 0xF8: %X  "), TWSR & 0xF8 );
    lcd_line_three();
    fprintf_P(&lcd_stream, PSTR("k: %i  "), k);

    while(1)
    {
        TOGGLE(TestPin);
        delay_ms(100);
    }

    return 0;
}

I'm not using the interrupt based I2C yet maybe I will try that as some point, but it doesn’t seem to take that much processing time to take measurements

April 12, 2015
by scootergarrett
scootergarrett's Avatar

I don't know why the code got all broken up there I will try again

/// How to get data from the Ada fruit 10DOF IMU ///
/// Still need pressure and rotational velocity and temp and structures and nice functions ///

struct IMURawData_S
{
    uint16_t AccelerationX;
    uint16_t AccelerationY;
    uint16_t AccelerationZ;

    uint16_t AngularVelocityX;
    uint16_t AngularVelocityY;
    uint16_t AngularVelocityZ;

    uint16_t MagneticFieldX;
    uint16_t MagneticFieldY;
    uint16_t MagneticFieldZ;

    uint32_t Pressure;
    int16_t Temperature;
};

#define AccelerationSlaveAddress 0x32
#define Acceleration_CTRL_REG1_A_Register 0x20  // Enable and power mode
#define Acceleration_CTRL_REG4_A_Register 0x23  // Mode select and gain
#define Acceleration_OUT_X_L_A_Register   0x28  // X axes acceleration field Low bit
#define Acceleration_OUT_X_H_A_Register   0x29  // X axes acceleration field High bit
#define Acceleration_OUT_Y_L_A_Register   0x2A  // Y axes acceleration field Low bit
#define Acceleration_OUT_Y_H_A_Register   0x2B  // Y axes acceleration field High bit
#define Acceleration_OUT_Z_L_A_Register   0x2C  // Z axes acceleration field Low bit
#define Acceleration_OUT_Z_H_A_Register   0x2D  // Z axes acceleration field High bit

#define AngularVelocitySlaveAddress 0xD6
#define AngularVelocity_WHO_AM_I_Register 0x0F  // Device identification register
#define AngularVelocity_WHO_AM_I_RegisterDefault 0xD7
#define AngularVelocity_CTRL1_Register 0x20     // Enable axis, bandwidth, and output data rate
#define AngularVelocity_OUT_X_L_Register 0x28   // X axes AngularVelocity Low bit
#define AngularVelocity_OUT_X_H_Register 0x29   // X axes AngularVelocity High bit
#define AngularVelocity_OUT_Y_L_Register 0x2A   // Y axes AngularVelocity Low bit
#define AngularVelocity_OUT_Y_H_Register 0x2B   // Y axes AngularVelocity High bit
#define AngularVelocity_OUT_Z_L_Register 0x2C   // Z axes AngularVelocity Low bit
#define AngularVelocity_OUT_Z_H_Register 0x2D   // Z axes AngularVelocity High bit

#define MagneticFieldSlaveAddress 0x3C
#define MagneticFieldS_CRA_REG_M_Register 0x00  // Temperature enable and DataRate
#define MagneticFieldS_CRB_REG_M_Register 0x01  // Gain Register
#define MagneticFieldS_MR_REG_M_Register  0x02  // Mode select
#define MagneticFieldS_OUT_X_H_M_Register  0x03 // X axes magnetic field High bit
#define MagneticFieldS_OUT_X_L_M_Register  0x04 // X axes magnetic field Low bit
#define MagneticFieldS_OUT_Z_H_M_Register  0x05 // Z axes magnetic field High bit
#define MagneticFieldS_OUT_Z_L_M_Register  0x06 // Z axes magnetic field Low bit
#define MagneticFieldS_OUT_Y_H_M_Register  0x07 // Y axes magnetic field High bit
#define MagneticFieldS_OUT_Y_L_M_Register  0x08 // Y axes magnetic field Low bit

#define PressureSlaveAddress 0xEE
#define BMP085_MODE_STANDARD 0x00

#define SCL_CLOCK 100000L

void I2C_INT();
uint8_t SetUpIMU();
uint8_t SendI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t Data);
uint8_t GetI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t *Data);

struct Bosch_Coefficients_S
{
    int16_t AC1;
    int16_t AC2;
    int16_t AC3;
    uint16_t AC4;
    uint16_t AC5;
    uint16_t AC6;
    int16_t B1;
    int16_t B2;
    int16_t MB;
    int16_t MC;
    int16_t MD;

    float BasePressure;
};

void Populate_Bosch_Coefficients(volatile struct Bosch_Coefficients_S *Bosch_Coefficients)
{

    GetI2CData(PressureSlaveAddress, 0xAA, (uint8_t*)&Bosch_Coefficients->AC1 + 1 );
    GetI2CData(PressureSlaveAddress, 0xAB, (uint8_t*)&Bosch_Coefficients->AC1 );

    GetI2CData(PressureSlaveAddress, 0xAC, (uint8_t*)&Bosch_Coefficients->AC2 + 1  );
    GetI2CData(PressureSlaveAddress, 0xAD, (uint8_t*)&Bosch_Coefficients->AC2 );

    GetI2CData(PressureSlaveAddress, 0xAE, (uint8_t*)&Bosch_Coefficients->AC3 + 1 );
    GetI2CData(PressureSlaveAddress, 0xAF, (uint8_t*)&Bosch_Coefficients->AC3 );

    GetI2CData(PressureSlaveAddress, 0xB0, (uint8_t*)&Bosch_Coefficients->AC4 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB1, (uint8_t*)&Bosch_Coefficients->AC4 );

    GetI2CData(PressureSlaveAddress, 0xB2, (uint8_t*)&Bosch_Coefficients->AC5 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB3, (uint8_t*)&Bosch_Coefficients->AC5 );

    GetI2CData(PressureSlaveAddress, 0xB4, (uint8_t*)&Bosch_Coefficients->AC6 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB5, (uint8_t*)&Bosch_Coefficients->AC6 );

    GetI2CData(PressureSlaveAddress, 0xB6, (uint8_t*)&Bosch_Coefficients->B1 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB7, (uint8_t*)&Bosch_Coefficients->B1 );

    GetI2CData(PressureSlaveAddress, 0xB8, (uint8_t*)&Bosch_Coefficients->B2 + 1 );
    GetI2CData(PressureSlaveAddress, 0xB9, (uint8_t*)&Bosch_Coefficients->B2 );

    GetI2CData(PressureSlaveAddress, 0xBA, (uint8_t*)&Bosch_Coefficients->MB + 1 );
    GetI2CData(PressureSlaveAddress, 0xBB, (uint8_t*)&Bosch_Coefficients->MB );

    GetI2CData(PressureSlaveAddress, 0xBC, (uint8_t*)&Bosch_Coefficients->MC + 1 );
    GetI2CData(PressureSlaveAddress, 0xBD, (uint8_t*)&Bosch_Coefficients->MC );

    GetI2CData(PressureSlaveAddress, 0xBE, (uint8_t*)&Bosch_Coefficients->MD + 1 );
    GetI2CData(PressureSlaveAddress, 0xBF, (uint8_t*)&Bosch_Coefficients->MD );

    return;
}

volatile struct Bosch_Coefficients_S Bosch_Coefficients;

/// Sets up the I2C ///
void I2C_INT()
{
    TWBR = ((F_CPU/SCL_CLOCK)-16)/2;                // [Bit rate register] controls signal speed p.232
    TWCR |= (1<<TWEA) | (1<<TWEN) | (1<<TWINT);     // [Control register] p.232
    TWSR &= ~((1<<TWPS1) | (1<<TWPS0));             // [Status register 0-1] controls signal speed p.234

    return;
}

uint8_t SendI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t Data)
{
    /// Set start ///
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));   // wait
    if ((TWSR & 0xF8) != 0x08)
        return -1;

    /// Send slave address + w ///
    TWDR = SlaveAddress;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x18)
        return -2;

    /// Send sub address ///
    TWDR = Register;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x28)
        return -3;

    /// Send  Data ///
    TWDR = Data;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x28)
        return -4;

    /// Stop bit ///
    TWCR = (1<<TWINT) | (1<<TWSTO);

    return 0;
}

uint8_t GetI2CData(uint8_t SlaveAddress, uint8_t Register, uint8_t *Data)
{
    /// Set start ///
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));   // wait
    if ((TWSR & 0xF8) != 0x08)
        return -1;

    /// Send slave address + w ///
    TWDR = SlaveAddress;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x18)
//    if ((TWSR & 0xF8) != 0x48)
        return -2;

    /// Send  sub address ///
    TWDR = Register;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
    if ((TWSR & 0xF8) != 0x28)
        return -3;

    /// Set repeat start ///
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));   // wait
    if ((TWSR & 0xF8) != 0x10)
        return -4;

    /// Send slave address + r ///
    TWDR = SlaveAddress | 0x01;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));   // wait
    if ((TWSR & 0xF8) != 0x40)
        return -5;

    /// Get data ///
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));   // wait

    /// Stop bit ///
    TWCR = (1<<TWINT) | (1<<TWSTO);

    *Data = TWDR;

    return 0;
}

uint8_t SetUpIMU()
{
    uint8_t RegisterData;

    I2C_INT();
    delay_ms(10);

    /// Set up the Acceleration /// WIP need sensitivity set up
    if( SendI2CData(AccelerationSlaveAddress, Acceleration_CTRL_REG1_A_Register, 0x57) )
        return -1;

    if( SendI2CData(AccelerationSlaveAddress, Acceleration_CTRL_REG4_A_Register, 0b00000000) )    /// Gain and High res mode????
        return -1;

    /// Set up the AngularVelocity /// WIP
    if( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_WHO_AM_I_Register,  &RegisterData) )
        return -2;
    if( RegisterData != AngularVelocity_WHO_AM_I_RegisterDefault)
        return -2;

    if( SendI2CData(AngularVelocitySlaveAddress, AngularVelocity_CTRL1_Register, 0b00001111) )   /// Enable stuff WIP (fast with high cut off freq?)
        return -2;

    /// Set up the MagneticField /// WIP need sensitivity set up
    if( SendI2CData(MagneticFieldSlaveAddress, MagneticFieldS_MR_REG_M_Register, 0b00000000) )
        return -3;

    if( SendI2CData(MagneticFieldSlaveAddress, MagneticFieldS_CRA_REG_M_Register, 0b10011100) )
        return -3;

    if( SendI2CData(MagneticFieldSlaveAddress, MagneticFieldS_CRB_REG_M_Register, 0b11100000) )
        return -3;

    /// Set up pressure measurements /// WIP
    delay_ms(10);
    Populate_Bosch_Coefficients(&Bosch_Coefficients);

    return 0;
}

uint8_t IMUGetAcceleration(struct IMURawData_S *IMURawData)
{
    if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_X_L_A_Register,  (uint8_t*)&((*IMURawData).AccelerationX)  ) )
        return -1;
    if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_X_H_A_Register,  (uint8_t*)&((*IMURawData).AccelerationX) + 1  ) )
        return -1;

    if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Y_L_A_Register,  (uint8_t*)&((*IMURawData).AccelerationY)  ) )
        return -1;
    if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Y_H_A_Register,  (uint8_t*)&((*IMURawData).AccelerationY) + 1  ) )
        return -1;

    if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Z_L_A_Register,  (uint8_t*)&((*IMURawData).AccelerationZ)  ) )
        return -1;
    if ( GetI2CData(AccelerationSlaveAddress, Acceleration_OUT_Z_H_A_Register,  (uint8_t*)&((*IMURawData).AccelerationZ) + 1  ) )
        return -1;

    return 0;
}

uint8_t IMUGetMagneticField(struct IMURawData_S *IMURawData)
{
    /// Looks if the data is new /// WIP
//    if ( GetI2CData(MagneticFieldSlaveAddress, 0x09, &k) )
//        return -1;
//    if(!(k & 0x01))
//        continue;

    if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_X_H_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldX) + 1  ) )
        return -1;
    if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_X_L_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldX)  ) )
        return -1;

    if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Z_H_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldZ) + 1  ) )
        return -1;
    if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Z_L_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldZ)  ) )
        return -1;

    if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Y_H_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldY) + 1  ) )
        return -1;
    if ( GetI2CData(MagneticFieldSlaveAddress, MagneticFieldS_OUT_Y_L_M_Register,  (uint8_t*)&((*IMURawData).MagneticFieldY)  ) )
        return -1;

    return 0;
}

uint8_t IMUGAngularVelocity(struct IMURawData_S *IMURawData)
{

    if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_X_L_Register,  (uint8_t*)&((*IMURawData).AngularVelocityX) ) )
        return -1;
    if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_X_H_Register,  (uint8_t*)&((*IMURawData).AngularVelocityX) + 1  ) )
        return -1;

    if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Y_L_Register,  (uint8_t*)&((*IMURawData).AngularVelocityY) ) )
        return -1;
    if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Y_H_Register,  (uint8_t*)&((*IMURawData).AngularVelocityY) + 1  ) )
        return -1;

    if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Z_L_Register,  (uint8_t*)&((*IMURawData).AngularVelocityZ) ) )
        return -1;
    if ( GetI2CData(AngularVelocitySlaveAddress, AngularVelocity_OUT_Z_H_Register,  (uint8_t*)&((*IMURawData).AngularVelocityZ) + 1  ) )
        return -1;

    return 0;
}

uint8_t IMUPressure(struct IMURawData_S *IMURawData)
{
    int32_t UT = 0, UP = 0, X1 = 0, X2 = 0, B5 = 0, B6 = 0, X3 = 0, B3 = 0, p = 0;
    uint32_t B4 = 0, B7 = 0;
    uint8_t MSB, LSB, XLSB;

    /// Get the Raw temperature ///
    SendI2CData(PressureSlaveAddress, 0xF4, 0x2E);
    delay_ms(5);
    GetI2CData(PressureSlaveAddress, 0xF6, (uint8_t*)&UT + 1 );
    GetI2CData(PressureSlaveAddress, 0xF7, (uint8_t*)&UT );

    /// Get the raw pressure //
    SendI2CData(PressureSlaveAddress, 0xF4, 0x34 + (BMP085_MODE_STANDARD<<6) );
    delay_ms(30);
    GetI2CData(PressureSlaveAddress, 0xF6, &MSB);
    GetI2CData(PressureSlaveAddress, 0xF7, &LSB);
    GetI2CData(PressureSlaveAddress, 0xF8, &XLSB);
    UP = ( (((int32_t)MSB)<<16) + (((uint32_t)LSB)<<8) + XLSB) >> (8-BMP085_MODE_STANDARD);

    /// Calculate the temperatur ///
    X1 = (UT - Bosch_Coefficients.AC6)*Bosch_Coefficients.AC5 / 32768L;
    X2 = ((int32_t)Bosch_Coefficients.MC << 11) / (X1 + (int32_t)Bosch_Coefficients.MD);
    B5 = X1 + X2;
    IMURawData->Temperature = (float)((B5 + 8) >> 4);

    /// Calculate the pressure ///
    B6 = B5 - 4000;
    X1 = (Bosch_Coefficients.B2 * ((B6 * B6) >> 12)) >> 11;
    X2 = (Bosch_Coefficients.AC2 * B6) >> 11;
    X3 = X1 + X2;
    B3 = ((((int32_t)Bosch_Coefficients.AC1 * 4 + X3) << BMP085_MODE_STANDARD) + 2) >> 2;
    X1 = (Bosch_Coefficients.AC3 * B6) >> 13;
    X2 = (Bosch_Coefficients.B1 * ((B6 * B6) >> 12)) >> 16;
    X3 = ((X1 + X2) + 2) >> 2;
    B4 = (Bosch_Coefficients.AC4 * (uint32_t) (X3 + 32768)) >> 15;
    B7 = ( ((uint32_t)UP - B3) * (uint32_t)(50000 >> BMP085_MODE_STANDARD));
    if (B7 < 0x80000000)
        p = (B7 << 1) / B4;
    else
        p = (B7 / B4) << 1;
    X1 = (p >> 8) * (p >> 8);
    X1 = (X1 * 3038) >> 16;
    X2 = (-7357 * p) >> 16;
    IMURawData->Pressure = p + ((X1 + X2 + 3791) >> 4);

    return 0;
}

float CalculateAltitude(uint32_t Pressure)
{
    float Alt;

  //  Alt = 44330 * ( 1- pow( (float)Pressure/101325.0 , 0.190294957183635 ) );
    Alt = 44330 * ( 1- pow( (float)Pressure/Bosch_Coefficients.BasePressure  , 0.190294957183635 ) );

    return Alt;
}

void CalSeaLevelPressure(uint16_t Starting_Elevation)
{
    struct IMURawData_S IMURawData;

    IMUPressure(&IMURawData);
    Bosch_Coefficients.BasePressure = IMURawData.Pressure / pow(1.0 - (Starting_Elevation/44330.0), 5.255);

    return;
}
April 25, 2015
by Ralphxyz
Ralphxyz's Avatar

Scooter, how are you doing with this project?

I have found the BMP180 sensor for $2.98.

I would also like to add this to my Weather Station project.

I have found code for LUA and for Arduino

LUA is the scrip used for programing the ESP8266

The ESP8266 is a low cost WiFi module so your sensor data can be seen on the internet!!

Post a Reply

Please log in to post a reply.

Did you know that SPDT stands for "Single Pole, Double Throw"? Learn more...