PDA

View Full Version : I2C Comm with Digital Compass HMC6352



jihlein
- 13th March 2008, 03:50
This is my first post to the group.

I'm designing a heading hold autopilot for a free flight glider. I'm basing it on a PIC16F88, and using an HMC6352 digital compass (http://www.sparkfun.com/datasheets/Components/HMC6352.pdf).

I've never played with I2C before, and figured that I would try something simple first, like reading an EEPROM register in the compass module. My problem is that no matter what I do, I seem to always read back a value that is exactly 1/2 of what it should be.

So then I tried writting a value to a RAM address and reading it back. Again, same issue, the value read back is 1/2 the value written.

I'm using PIC BASIC PRO, on a LABX18 development board. Here's the code I'm using for the EEPROM read, which is modified from some of the example programs:


Define LCD_DREG PORTA
Define LCD_DBIT 0
Define LCD_RSREG PORTB
Define LCD_RSBIT 6
Define LCD_EREG PORTB
Define LCD_EBIT 3

' Define I2C Interface

SDA Var PORTB.1 ' Data pin
SCL Var PORTB.4 ' Clock pin

cmd Var Byte
addr Var Byte
cont Var Byte

ANSEL = 0 ' PORTA is digital
CMCON = 7 ' PORTA is digital

Pause 100 ' Wait for LCD to start up

loop1:
pauseus 1000
cmd = $72 ' Read from compass EEPROM
addr= $00 ' EPROM address $00
I2CWRITE SDA, SCL, $42, [cmd, addr], nowrite

pauseus 1000
I2CREAD SDA, SCL, $42, [cont], noread
Lcdout $fe, 1, "Data: ", cont

goto loop1

End

nowrite:
Lcdout $fe, 1, "Write Err"
goto nowrite

noread:
Lcdout $fe, 1, "Read Err"
goto noread


If anyone can point me to the error of my ways, it would be greatly appreciated.

John Ihlein
Albuqueruqe, NM

skimask
- 13th March 2008, 14:36
I'm fairly you don't have the I2C command syntax's correct.
Double check the PBP manual and see what you come up with.

jihlein
- 13th March 2008, 17:08
Skimask,

The manual shows the addr parameter as option. Since this isn't an EEPROM, and from looking at the HMC6352 data sheet, I figured that the commands should be sent as data arguements.

I can try sending what I'm calling cmd as the address argument:

I2CWRITE SDA, SCL, $42, [cmd, addr], nowrite

becomes

I2CWRITE, SDA, SCL, $42, cmd, [addr], nowrite

later today. It does seem like my write commands are somewhat working, however. If I change the commands to write and read RAM rather than just read EEPROM, I can see the RAM data change with the read command, it's just off by 1/2.

Looking at how the module responds to commands, I'm not sure how I would restructure the I2CREAD command. Maybe it needs a dummy addr argument??

At the moment I can't tell if the issue is on the write or the read side, but since I've tried to read known values from EEPROM and they are off by 1/2, I tend to think the read side is where my problem lies. I'm wondering if it's a data type issue, although the documentation says the data will be transmitted in bytes.

Thanks,

John

skimask
- 13th March 2008, 17:17
The manual shows the addr parameter as option. Since this isn't an EEPROM, and from looking at the HMC6352 data sheet, I figured that the commands should be sent as data arguements.
Yep, I got that.
But I still don't think they're right for what you want.
And is the module getting the 70uSec delay it requires after requesting the data from the eeprom?

JD123
- 13th March 2008, 18:18
Values that come in as 1/2 what they should have been shifted right one bit. You are loosing the LSB somewhere? I don't know the in's and out's of exactly what PBP does when shifting in I2C, but it might be that PBP is expecting one more bit. Does that compass send out 8 bits... or does it send out 7? Maybe it's sending out 9?

Anywho, it's a byte shifted right... some where, some how.

Does this from the datsheet have anything to do with your problem?

"Negative binary values will be in two’s complement form"

skimask
- 13th March 2008, 18:47
Values that come in as 1/2 what they should have been shifted right one bit.
Or maybe...
North 360 / 2 = 180 South ..... 1/2 the value
Are those values always exactly 1/2? Or are they just close to 1/2...

jihlein
- 13th March 2008, 18:54
It sure does look like a byte shift. For reading EEPROM/RAM locations, I believe it is just sending back an 8 bit byte. If you choose to read raw magnetometer data rather than computed heading, that's where the 2's complement comes into play. I haven't got that far yet, and FWIW, plan to read computed heading. Thought it would be a good simple test to just try to read an write some simple values to the unit before trying to take measurements....

The delay I put in is consdierbaly longer than the delays mentioned in the data sheet. From my understanding og the I2C protocol, the extra wait time should not be a factor. Whether or not it "bugs" the compass processing I can't see. Can reduce the wait time to the recommended 70 usecs and see if that changes anything.

If else fails, I'll take it to work and watch the transaction on a digital storage scope and see what's occuring.

jihlein
- 13th March 2008, 19:15
The values are exactly half.

Got a couple of quick posts here -

Haven't tried taking measurements yet, figured if I can't write and read simple bytes correctly, I wouldn't be able to set the operating mode and read data correctly. Baby steps.

When reading out a computed heading, it's a 2 byte read. The combined value will be 0 to 3599.

jihlein
- 14th March 2008, 03:12
Success!

The code as written works fine if you add the following define at the beginning:

Define I2C_HOLD 1

I added this line, made the delays the appropriate times, and could read EEPROM correctly.

Took the next step and could write RAM and read it back correctly.

Finally, put the device in standby mode, commanded it to compute heading, and all works as it should.

On to the control law (the "easy" part!!)

John

Andy Baker
- 9th April 2008, 17:51
The documentation in the Picbasic manual isn't so good for I2C commands. I've been screwing around with LOTS of I2c for the past 5 weeks, and I can tell you that all the commands that are shown in the green Picbasic book are for Eprom, and are confusing.

Here's my version...


I2CWrite Datapin, Clockpin, Deviceaddress, data,data, data,data, [data with stop bit, optional]

Now here's the deal...

The chip address is whatever you set, or whatever the chip is default set to. The first 7 bits are the address. The last bit is whether you're reading or writing.

A chip with an address of 1100111 would have to have it's address followed by a 0 if you were using an I2CWrite, and a 1 if you were reading. Hence

I2CWrite Dpin,Cpin, %11001110, [single byte of data]
I2CRead Dpin,Cpin, %11001111, [single byte of data]

This MIGHT be dependant on the device, so check your datasheet. I'm using a Phillips chip, and since they invented the protocol, I'll guess that it's relatively standard.

OK.. Now about those brackets... Those denote the Acknowledge bit. In sending, say your chip wants to get 8 bytes in sequence...


I2CWrite Dpin,Cpin, %11001110, Byte1, Byte2,Byte3,Byte4,Byte5,Byte6,Byte7,[Byte8]

OR (this would work but it's stupid and would eat up code space)

I2CWrite Dpin,Cpin, %11001110, Byte1, Byte2,Byte3,Byte4,
I2CWrite Dpin,Cpin, %11001110, Byte5,Byte6,Byte7
I2CWrite Dpin,Cpin, %11001110, [Byte8]

The bracket sends the Acknowledge bit. It's kinda like the "End Of Transmission" signal.

I've found that if you're doing a lot of I2C, it's best to make a subroutine with ONE I2C command in it that sends from variables. Set the variables, then call your sub. In this one program I'm working on, with individual I2CWrite lines, sending a single I2C byte took 17 words of data. Sending 14 bytes of data ate up 56 words. Probably not a bad figure considering that it's bit banging, but still, worth looking in to doing in hardware, plus the fact that it'll cut back my CPU time.

I'm off to learn assembly.

Andy

JD123
- 9th April 2008, 23:25
Good to see you’re figuring it out Andy. I too have jumped ship on PBP's I2C functions for my current project and have written my own. Like you said, it's easy to send out wrong addresses since the byte contains the address and is not in itself the address. If a data sheet says its address is xyz, then you have to format it to the device control byte by left-shifting it one place. If it says send xyz in the device address, then use that literally.

So, your I2C bus does not expect the receiving device to send an ack after each byte is received? That's odd. I thought that was only for slave to master reads after the last byte needed was read.

My needs were more about speed and open-ended read/write functions. It would be nice if PBP had better ways to deal with I2C. I think I understand why it's done the way they do it, but for some of us placing a bit more demand on us to follow a bit more rigid format, it could have a ton of time. For the average basic language programmer, it seems they are too far removed from what's going on in order to make it easy. I guess I'm just spoiled by CCS-C I2C functions.

You can see an example of my I2C code here:http://www.picbasic.co.uk/forum/attachment.php?attachmentid=2448&d=1206738334

Again, my goals were speed because I'm clocking at 1mhz and I want to leave the I2C bus open while I go do other things and come back to a bus that's just waiting for the next byte.