I2C for HMC5883L compass

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable
        I am trying to use the PSoC as the master to communicate with the compass to get values for x, y and z axis and display them on the LCD screen. I have set the I2C component to master mode as Fixed Function. SDA is connected to P12[5] and SCL to P12[4]. I get the same values 127 32 9 displayed on the screen regardless of the orientation of the compass. The code is as follows: #include        #include          #include            #define SLAVE_ADD 0x1E #define Config_Reg_A 0x00 #define Config_Reg_B 0x01 #define Mode_Reg 0x02 #define X_MSB_Reg 0x03 #define X_LSB_Reg 0x04 #define Z_MSB_Reg 0x05 #define Z_LSB_Reg 0x06 #define Y_MSB_Reg 0x07 #define Y_LSB_Reg 0x08 #define Status_Reg 0x09 #define ID_Reg_A 0x0A #define ID_Reg_B 0x0B #define ID_Reg_C 0x0C void compass_init(); void main() { LCD_Char_1_Start(); I2C_Compass_Start(); /* Send 9 clocks on SCL line in order to unlock any possible freeze of connected devices on the I2C bus */ I2C_Compass_MasterSendStart(0xFF, I2C_Compass_READ_XFER_MODE); I2C_Compass_MasterSendStop(); compass_init(); CyDelay(6); uint8 x=0, y=0, z=0; // 3-axis Magnetometer Raw sensor values while(1){ uint8 send_data[] = {X_MSB_Reg}; uint8 *setup = send_data; I2C_Compass_MasterWriteBuf(SLAVE_ADD, setup, 1u,I2C_Compass_MODE_COMPLETE_XFER); uint8 rec_data[6]; uint8 *read = rec_data; I2C_Compass_MasterReadBuf(SLAVE_ADD, read, 6u, I2C_Compass_MODE_COMPLETE_XFER); LCD_Char_1_PrintInt8(rec_data[0]); x = rec_data[0]<<8 | rec_data[1]; y = rec_data[2]<<8 | rec_data[3]; z = rec_data[4]<<8 | rec_data[5]; LCD_Char_1_PrintNumber(x); LCD_Char_1_PutChar(' '); LCD_Char_1_PrintNumber(y); LCD_Char_1_PutChar(' '); LCD_Char_1_PrintNumber(z); CyDelay(1500); LCD_Char_1_ClearDisplay(); CyDelay(1500); void compass_init() { uint8 send_data[] = {Mode_Reg, Config_Reg_A}; uint8 *setup = send_data; I2C_Compass_MasterWriteBuf(SLAVE_ADD, setup, 2u,I2C_Compass_MODE_COMPLETE_XFER); }              
0 Likes
22 Replies
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Welcome in the forum!

   

Please do not try to post code-snippets but attach a completre project archive, so we all can have a look at all of your settings.  To do so, use
Creator->File->Create Workspace Bundle (minimal)
and attach the resulting file. A link to the datasheet of the compass would be helpful, so we must not search for it.



Bob
 

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable
        Yeah sorry about that. Please find the file attached   
0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You did not enable global interrupts which is requred for the I2C-component to function properly..

   

        uint8 send_data[] = {X_MSB_Reg};
        uint8 *setup = send_data;
        I2C_Compass_MasterWriteBuf(SLAVE_ADD, setup, 1u,I2C_Compass_MODE_COMPLETE_XFER);
This sequence can be done easier, since in C-language an array is a pointer to its data. So you might write

   

        uint8 send_data[] = {X_MSB_Reg};
        I2C_Compass_MasterWriteBuf(SLAVE_ADD, send_data, 1u,I2C_Compass_MODE_COMPLETE_XFER);

   

thus saving an additional variable and its initialization.

   

Sometimes it is requred to address an I2C-slave with a sequence of

   

MasterSendStart();  //Initializing a read register sequence

   

MasterWriteByte(); // Register to read

   

MasterSendRestart(); // Switch to reading now

   

MasterReadByte(); // Get register value, could be repeated, some devices allow for that

   

MasterSendStop(); // End the transmission

   


Happy coding

   

Bob

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

There is a fairly good ap note here and some examples.

   

 

   

www.dropbox.com/s/1s8u0uurlhw0nbs/I2C%20Ap%20Notes.zip

   

 

   

Regrds, Dana.

0 Likes
Anonymous
Not applicable

I have been working with the PSOC for some time. I really like them and find the very useful. The issue I have them is I have always had problems with the I2C. I am trying to use the this same sensor. I have the interrupts enable. I have connected it to a logic analyzer and I can see that when I make the function call MasterSendStart(); It is sending out the data that  I would expect. I am even seeing the Ack. The problem that I am having is with the next line which is I2C_MasterWriteByte(byte); it just hangs up in here and never continues. Any hints?

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Welcome in the forum!

   

Can you post your complete project, so that we all can have a look at all of your settings? To do so, use
Creator->File->Create Workspace Bundle (minimal)
and attach the resulting file.

   

MasterSendStart() returned a value, was it != zero? Same for MasterSendByte(), what was returned.

   

What is your environment? Cypress Kit?? Self-made pcb???

   

I2C terminated correctly? Connections checked twice?

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

I am using the FreeSoC2 Development Board - PSoC5LP https://www.sparkfun.com/products/13229. I can't see what is being returned in the status it doesn't come up in the locals when I am am running it in the debugger. I have checked the connections many of time. It works with an Arduino I set up just to test the sensor. I can also see the data that I expect on a logic analyzer when this line of code is executed: I2C_MasterSendStart(HMC5883L_ADDRESS, I2C_WRITE_XFER_MODE). I have uploaded the file. The main function I have been debugging is HMC5883L_Config(). I do have uart that I was using for debuging. 

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Here is a PSOC 4 solution you could possibly adapt -

   

 

   

https://github.com/EmbeddedSam/PSoC-4-Compass-Sensor

   

 

   

Regards, Dana.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

First I see that the pin connected to sda is not configured correctly. Datasheet states:

   

sda – In/Out
Serial data (SDA) is the I2C data signal. It is a bidirectional data signal used to transmit or receive all bus data. The pin connected to sda should be configured as Open-Drain-Drives-Low.

   

Usually reading from an I2C-device is done in one transaction, in your case like

   

    I2C_MasterSendStart(HMC5883L_ADDRESS, I2C_WRITE_XFER_MODE);
    I2C_MasterWriteByte(array[0]);
    I2C_MasterWriteByte(array[1]);

   

 
    I2C_MasterSendRestart(HMC5883L_ADDRESS, I2C_READ_XFER_MODE);
    array[0] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[1] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[2] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[3] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[4] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[5] = I2C_MasterReadByte(I2C_NAK_DATA); // Signal LAST BYTE to read
    I2C_MasterSendStop();

   

 

   

Additionally I would suggest to check the returned values of SendStart() etc which are ment to indicate any errors occured.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Bob,
I don't know where you saw that configuration but as I am looking at mine it is configured like you said. No I didn't change it. See the screen shot that I have attached

   

   

Other than checking that what you said  I feel I have all ready been work with. In the config function I guess I don't need to stop it and start it again to set up the next set or regs.

   

Thanks,

   

Jorden Luke

   

0 Likes
Anonymous
Not applicable

I have found out that after I do my status = I2C_MasterSendStart(HMC5883L_ADDRESS, I2C_WRITE_XFER_MODE); I get 3 returned. Which I understand to be a the last bite got Nacked. Which means to say that the address got Naked because that is the only thing i sent right?

0 Likes
Anonymous
Not applicable

Ok I looked into the spark fun board was not giving enough output on 3.3v line to make it the sensor work. I had to make some modifications to the board as prescribe on their website and now it isn't nacking. It still doesn't work fully but I think that is to pour choice with pointers I will continue to fix it on my own. Thanks for you help.

   

Jorden Luke

0 Likes
Anonymous
Not applicable

So has anyone solved the problem for the magnetometer. I cannot solve it. Infact I dont Know how to start. Any help would be greatly appreciated. Thanks

0 Likes
Anonymous
Not applicable

So has anyone been able to solve the problem for the compass and I2C. I am currently working on it and i dont know where to start. I read the datasheet but I m still confused. Any help would be greatly appreciated. Thanks

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

What is the state of your project? Pleasee upload a workspace and tell us what works and what does not work.

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi Bob,

   

This is my project. I cannot display any values using termite. So I dont know if it is working.

0 Likes
Anonymous
Not applicable

Also when we connect do we need to use any external resistors.

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

If you look at the Honeywell datasheet the module does not have the

   

I2C pins pulled up internally, so unless the board you are using to drive

   

the Honeywell part has them you need to add the pullups externally.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

Hi Bob

   

I still can't figure out how to work with the compass

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Regard Dana's advice concerning the pull-ups!

   

The datasheet for your device is not quite clear and leads to mis-interpretations (which you did follow)

   

Datasheet tells to send 0x3c or 0x3d. This is not what you should do. 0x3c is the device address 0x1E shifted 1 bit left and padded with the write bit, 0x3D the same, but padded with the read bit. So this is ment to be replaced by

   

I2C_MasterSendStart(HMC5883L_ADDRESS,I2C_WRITE_XFER_MODE); // 0x3c

   

or

   

I2C_MasterSendStart(HMC5883L_ADDRESS,I2C_READ_XFER_MODE); // ßx3d

   

 

   

Reading: do not send the 0x06, they really mean: "read six bytes"

   

Instead set the internal data-pointer to 0x03

   

I2C_MasterSendStart(HMC5883L_ADDRESS,I2C_WRITE_XFER_MODE);

   

    I2C_MasterWriteByte(0x03);
    I2C_MasterSendStop();
    CyDelay(67);

   


Then with a new transaction read the X,Z and Y values

   

    I2C_MasterSendStart(HMC5883L_ADDRESS, I2C_READ_XFER_MODE);
    array[0] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[1] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[2] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[3] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[4] = I2C_MasterReadByte(I2C_ACK_DATA);
    array[5] = I2C_MasterReadByte(I2C_NAK_DATA); //*** Mind the NAK !!!
    I2C_MasterSendStop();

   

To get the desired values you will have to combine two of the array[] values to form a 16-bit number.

   

 

   

Happy coding

   

 

   

Bob

0 Likes
lock attach
Attachments are accessible only for community members.
Anonymous
Not applicable

Hi BOB

   

Here are my connections, board and my project. I have followed your instruction and I still cannot make it work. Most probably I m making a mistake somewhere. Any help is appreciated. Thanks.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Not sure what goes wrong, any symptoms? What I can see is your conversion going wrong:

   

    x_com = (array[0] << 😎 | array[1];

   

Since array are uint8 the term array[0] << 8 will result in zero. better use

   

(int16)array[0] << 8

   

your expected result is type int, so you have to cast the expression accordingly

   

 

   

    x_com = ((int16)array[0] << 😎 | (uint16)array[1];

   

 

   

Bob

0 Likes