Help with I2C

22 May 2010

I am trying to communicate with an HMC5843 magnetometer. I am new to I2C, so I am having issues. Right now, I get a series of 9 numbers repeated, that varies alot. Datasheet:

http://www.magneticsensors.com/datasheets/HMC5843.pdf

Code:

#include "mbed.h"
#include "TextLCD.h"
TextLCD lcd(p21, p22, p23, p24, p25, p26, p29,16,2);
I2C i2c(p9, p10);        // sda, scl
Serial pc(USBTX, USBRX); // tx, rx

const int addr = 0x3C; // define the I2C Address
char cmd[3];
char read[8];
float x;
float y;
float z;
float echo;


int main() {
    cmd[0] = 0x3C;
    cmd[1] = 0x02;
    cmd[2] = 0x00;
    i2c.write(addr, cmd, 3);
    wait(1);
    while (1) {
        lcd.cls();

        i2c.read(addr, read, 8);
        echo =((read[0] << 8)|read[1]);
        x = echo;

        echo =((read[2] << 8)|read[3]);
        y = echo;

        echo =((read[4] << 8)|read[5]);
       z = echo;

        lcd.printf("%.1f %.1f\n%.1f",x,y,z);
       pc.printf("%.1f %.1f %.1f\n",x,y,z);
        wait(1);
    }

}

22 May 2010

I think you don't need to send 0x3C as the address is already specified in the write() call. Another thing is that you might need to sign-extend the read value. I would probably do it like this:

// use a signed 16-bit type so that compiler automatically sign-extends the value when copying it into a bigger type
int16_t val = (read[0]<<8) | read[1];
int x = val; // sign-extended

22 May 2010

Hey,

That changed the values, but It still doesn't look right. Now it has negative numbers (which looks right).

Output:

1533.0 -17409.0 28159.0
773.0 -581.0 -147.0
-253.0 1533.0 -17409.0
28159.0 773.0 -581.0
-147.0 -253.0 1533.0
-17409.0 28159.0 773.0
-581.0 -147.0 -253.0
1533.0 -17409.0 28159.0
773.0 -581.0 -147.0
-253.0 1533.0 -17409.0
28159.0 773.0 -581.0
-147.0 -253.0 1533.0
-17409.0 28159.0 773.0
-581.0 -147.0 -253.0
1533.0 -17409.0 28159.0

02 Aug 2010 . Edited: 02 Aug 2010

Hi Rp181, did you get it working?

I used the following code for mine:

 

#include "main.h"

I2C i2c_2(p28, p27);

int high, low;

const int address = 0x3C; // i2c address - read/write will set lsb as appropriate

//const int CTRL_REGA = 0x00;
//const int CTRL_REGB = 0x01;

const int MODE_REG = 0x02;

const int XOUT_H = 0x03;    //x
const int XOUT_L = 0x04;

const int YOUT_H = 0x05;    //y
const int YOUT_L = 0x06;

const int ZOUT_H = 0x07;    //z
const int ZOUT_L = 0x08;

//--------------- magnetometer ---------------

// write value into register regno, return success
bool write_reg_mag(int regno, int value) {

    char data[2] = {regno, value}; 
    
    return i2c_2.write(address, data, 2) == 0;
    
}

// read value from register regno, return success
bool read_reg_mag(int regno, int *value) {

    char data = regno; 
    
    if (i2c_2.write(address, &data, 1) == 0 && i2c_2.read(address, &data, 1) == 0){
        *value = data;
        return true;
    }
    return false;
    
}

// read from the x axis
int read_x_mag(){
    
    if (read_reg_mag(XOUT_H, &high) && read_reg_mag(XOUT_L, &low) ){
        int16_t val = (high<<8) | low;
        return (int) val;
    } else {
        return -1;
    }
}

// read from the y axis
int read_y_mag(){

    if (read_reg_mag(YOUT_H, &high) && read_reg_mag(YOUT_L, &low) ){
        int16_t val = (high<<8) | low;
        return (int) val;
    } else {
        return -1;
    }
}

// read from the z axis
int read_z_mag(){

    if (read_reg_mag(ZOUT_H, &high) && read_reg_mag(ZOUT_L, &low)){
        int16_t val = (high<<8) | low;
        return (int) val;
    } else {
        return -1;
    }
}

void mag_start(){
    
    write_reg_mag(MODE_REG, 0); //continuous mode
    //write_reg_mag(CTRL_REGA, '0x10'); // 00010000 - 000 100 (10 hz) 00 (normal config mode)
    //write_reg_mag(CTRL_REGB, '0x20'); // 00100000 - 001 (+/- 1.0 Ga gain, default) 00000
    
}

xyz mag_get() {

    xyz data;
    
    data.x = read_x_mag();
    data.y = read_y_mag();
    data.z = read_z_mag();
    
    return data;

}

void mag_sleep(){

    write_reg_mag(MODE_REG, 0x03); //sleep mode 

}

void mag_idle(){

    write_reg_mag(MODE_REG, 0x02); //idle mode

}

main.h:

struct xyz
{
    double x;
    double y;
    double z;
};

void mag_start();
xyz mag_get();
void mag_sleep();
void mag_idle();
int read_x_mag();

02 Aug 2010

Thanks!

I actually moved to the XMOS platform, but this will be alot of help!