# HMC5883L magnetometer

#### MFB

##### Senior Member
Just received the new low cost 3-axis magnetometer board from Sparkfun (http://www.sparkfun.com/products/10530) and it seems to work with the following 28X2 code...

hi2csetup i2cmaster, \$3C, i2cslow_16, i2cbyte 'Setup I2C
hi2cout \$00, (\$70) 'Set requister A, for 8-average, 15Hz, normal measurement
hi2cout \$01, (\$A0) 'Set requister B, for gain = 5

start:
hi2cout \$02, (\$01) 'Request single measurement
pause 1000
hi2cin \$03, (b0,b1,b2,b3,b4,b5) 'Read the six output requisters (but documantation said use \$06?)
sertxd (#w0,",",#w1,",",#w2,cr) 'Combine into three data words and send to PC
goto start 'Next three measurements

However, please can anyone help with additional code to convert the 16-bit 2's compliment outputs to decimal?

#### hippy

##### Technical Support
Staff member
From the datasheet (table 2) the X, Y and Z registers seem to be from \$03 onwards so ...

Code:
``````Symbol x     = w0
Symbol x.lsb = b0
Symbol x.msb = b1

[i]Similar for Y and Z[/i]

HI2cIn \$03, (x.mb, x.lsb, z.msb, z.lsb, y.msb, y.lsb )

If x >= \$8000 Then
x = -x
SerTxd( "X= -", #x )
Else
SerTxd( "X= +", #x )
End If

[i]Similar for Y and Z[/i]``````
Edit : Check out page 11, "Register Access". Reading from location \$03 may not be as simple as shown above.

Last edited:

#### MFB

##### Senior Member
Thanks hippy for the help with the 2's compliment conversion.

The raw output seems to work using \$03 as the start address (Data Out X MSB Register) shown on page 11 of the Honeywell data sheet. However, I'm a bit confused
because the example "single-measurement mode" example shown at the foot of page 18 gives \$06 as the start address but (according to page 11 again) this would be
part way through the data output registers at Z LSB. Any guidance would be welcome here.

The raw data looks promising but adding the decimal conversion will give me a better idea.

BTW, Rather than buying Sparkfun products direct, I now get them via Active Robots in the UK. Don't be put off by their very limited cataloque because they are happy
to obtain other products from the SparkFun range. The price is about the same as buying direct from the states, when VAT and postage is included.

#### MFB

##### Senior Member
The following code includes hippy's 2's compliment conversion to give +/- decimal output. This is great for initial tests but can anyone please suggest best way to convert 2's compliment to StampPlot format (e.g. 0 to 4094)?

Filename:MagTest 2
; Date: 23-7-2011
; File Version: 0.2
; Written by: MFB
; Function:Sets up HMC5883L, converts data from 2's compliment to +/- decimal and send to PC
; Last Revision:
; Target: PICAXE:28X2 with 16MHz crystal
' Status: Outputs seems to relate to changes in attitude and test magnet, but real-time plot would help confirm

; *******************************

Symbol x = w0
Symbol x.lsb = b0
Symbol x.msb = b1

Symbol y = w1
Symbol y.lsb = b2
Symbol y.msb = b3

Symbol z = w2
Symbol z.lsb = b4
Symbol z.msb = b5

hi2csetup i2cmaster, \$3C, i2cslow_16, i2cbyte 'Setup PICAXE I2C port
hi2cout \$00, (\$18) 'Set mag req A for non-average,75Hz,normal measurement
hi2cout \$01, (\$00) 'Set mag req B for range of +/- 0.88Ga (Earth = +/-0.5Ga)

start:
hi2cout \$02, (\$01) 'Request single measurement
pause 500 'Allow time for measurement and display
HI2cIn \$03, (x.msb, x.lsb, z.msb, z.lsb, y.msb, y.lsb)'Read six bytes of 2's compliment data

If x >= \$8000 Then 'Convert X to +/- decimal and send to PC *
x = -x
SerTxd( " X -", #x )
Else
SerTxd( " X +", #x )
End If

If y >= \$8000 Then 'Convert Y to +/- decimal and send to PC *
y = -y
SerTxd( " Y -", #y )
Else
SerTxd( " Y +", #y )
End If

If z >= \$8000 Then 'Convert Z to +/- decimal and send to PC *
z = -z
SerTxd( " Z -", #z )
Else
SerTxd( " Z +", #z )
End If

sertxd (cr)

goto start 'Next measurements

'* Output range \$F800 to \$07FF (-2048 to +2047)

#### hippy

##### Technical Support
Staff member
can anyone please suggest best way to convert 2's compliment to StampPlot format (e.g. 0 to 4094)?
I'm not familiar with StampPlot so if we had values from the magnetometer of -2, -1, 0, +1 and +2, what values would you want sending to StampPlot ?

It should be easy enough, just depends on what that mapping is.

#### MFB

##### Senior Member
Thanks hippy. The default format for StampPlot Pro is comma separated decimal values terminated by a carriage return. A three channel example would be sertxd (#w0,",",#w1,",",#w2,cr) with each values start at zero and increasing to a maximum of 4096.

#### marks

##### Senior Member
try something like this

Symbol x = w0
Symbol x.lsb = b0
Symbol x.msb = b1

Symbol y = w1
Symbol y.lsb = b2
Symbol y.msb = b3

Symbol z = w2
Symbol z.lsb = b4
Symbol z.msb = b5

hi2csetup i2cmaster, \$3C, i2cslow_16, i2cbyte 'Setup PICAXE I2C port
hi2cout \$00, (\$18) 'Set mag req A for non-average,75Hz,normal measurement
hi2cout \$01, (\$00) 'Set mag req B for range of +/- 0.88Ga (Earth = +/-0.5Ga)

start:
hi2cout \$02, (\$01) 'Request single measurement
pause 500 'Allow time for measurement and display
HI2cIn \$03, (x.msb, x.lsb, z.msb, z.lsb, y.msb, y.lsb)

x = x+2048

y = y+2048

z = z+2048

sertxd (#w0,",",#w1,",",#w2,cr)
goto start 'Next measurements

#### MFB

##### Senior Member
Marks, thanks that works fine!
I can certainly recommend this new magnetometer from Honeywell. I had been using the basic HMC1053, which needed a significant amount of analog circuitry (FETs for reset and an instrumentation amp per axis) to interface to a microcontroller. Not only does the 5883 have integral signal conditioning but it's much cheaper at less than £10.

#### julianE

##### Senior Member
Gents,
I've been struggling to get the HMC5883L module to work for many days and am ready to throw in the towel.
I tried it with a 28X2, 18M2 and the trusty 20X2. To verify the Picaxe I tried it with a 24LC256 and it works fine.
To test the HMC5883L module I attached it to the 'duino and it works like a champ.
i tried all the sample codes mentioned in the post other then Hippy's skeleton code.
The one thing I have not tried is using an external crystal, is that absolutely necessary?
Must it be run at 16Mhz, I would think it should work at 8.

As always any help would be appreciated.

#### MPep

##### Senior Member
Did you adjust the commands to reflect you are using 8MHz? ie "hi2csetup i2cmaster, \$3C, i2cslow_16, i2cbyte" --> "hi2csetup i2cmaster, \$3C, i2cslow_8, i2cbyte"

Also, please remember the [ code ] [ /code ] tags as this makes the post much easier to read.

#### julianE

##### Senior Member
Did you adjust the commands to reflect you are using 8MHz? ie "hi2csetup i2cmaster, \$3C, i2cslow_16, i2cbyte" --> "hi2csetup i2cmaster, \$3C, i2cslow_8, i2cbyte"
Yes, I tried i2cslow_8
No luck.

#### MFB

##### Senior Member
Crystal will not make much difference when using I2C. Are you running the magnetometer from 3.3V and what value pullup resistors are you using?

#### julianE

##### Senior Member
Crystal will not make much difference when using I2C. Are you running the magnetometer from 3.3V and what value pullup resistors are you using?
yes, i am running it at 3.3 V and the board comes with it's own pull up resistor. The schematic does not show the resistor value. I guess i can measure it.
http://dlnmh9ip6v2uc.cloudfront.net/datasheets/BreakoutBoards/HMC5883L_Breakout-v11.pdf

as a precaution, I went and added my own pull ups in addition, 47K, which would end up lowering whatever value sparkfun used.

to further experiment i used a sure electronics, compass module with I2C and it worked right away.

The one thing i noticed in the 'duino program is that they check the ready line, i think register 6 to verify that the module has made a reading, but i need to check on that.

#### MFB

##### Senior Member
I'll double check my setup and get back to you if I find anything else worth trying.

#### crowland

##### Member
The Sparkfun circuit shows a couple of pull ups but they aren't fitted.

I am using 10k pull ups with this and it works very well.

I don't have the exact code to hand but with an 08M2 running at the default 4MHz I've had no problem. I set it to the sleep mode then when I want to read do something like this:
Code:
``````readCompass:
hi2cout 2,(\$01)	; single conversion
pause 10			; wait
hi2cin 3, (XH,XL, ZH,ZL, YH,YL)	; read
; check for a valid conversion
if X = \$F000 or Y = \$F000 or z = \$F000 then
dataValid = 0
else
dataValid = 1
endif
return``````
Chris

#### MFB

##### Senior Member
Yes, crowland has found the problem. I checked my circuit and found that it was necessary to add two 3.3K pull up resistors at the PICAXE end. My be your Arduino test setup already had pull ups.

#### julianE

##### Senior Member
I will try your suggestion first chance I get. I have an 8M2 handy so I will try the code as well. I looked at the board and there are pull ups on it but then again they may not be hooked up.
Thanks for all the effort, I will reply as soon as I test it.

#### julianE

##### Senior Member
Hello MFB and Crowland I tested and all is well. I also measured the breakout board and sure enough there are no pull up resistors. There are resistors on the board but they must not be used. I used 8K resistors for pull ups. I know I tried using external resistors before but probably missed something else, juggling too many variables.

Thanks very much for all the help.

#### klyball

##### New Member
Hi I am trying to use the hmc5883l as a compass for a project I am using the code below i believe the data is broken into 4 quadrants 315-45, 45-135, 135-225, 225-315

when i run the code i get a accurate reading from 315-45 but before or after that the results are wrong, i have been trying to understand the math ,but can't get my head around it, i believe i need to add to this section highlighted to have the results be corrected , if someone can explain or point me in the right direction that would be a great help.

Code:
``````symbol x = w0 ' x coord
symbol ax = w0 ' absolute x (same word as x)
symbol y = w1 ' y coord
symbol bias = w2 ' angle bias
symbol sign = w3 ' sign, 1 or -1
symbol temp = w4 ' temporary var for calculations
symbol r = w5 ' temporary var for approximation
symbol angle = w6 ' result
symbol scale = 8 ' scale (tenths of a degree), needed for fixed point arithmetic
symbol scsq = scale * scale ' scale squared
symbol pi14 = 45 * scale ' (360 degs + 45 degs) * scale
symbol pi34 = 135 * scale ' (360 degs + 135 degs) * scale
symbol neg = 32768 ' negative numbers start here
symbol pos = 32767 ' positive numbers end here
symbol neg1 = 65535 ' negative one
symbol fact1 = 11 * scale ' factor 1 for approximation: 11.247 * scale
symbol fact2 = 56 * scale ' factor 2 for approximation: 56.247 * scale
symbol circle = 360 * scale ' 360 degs * scale

atan2:

atan2init:
' determine final sign
[COLOR="#FF0000"]sign = 1
if x > pos then : sign = 65535 : ax = -x : endif

temp = ax + y
r = y - ax
bias = pi14
if y > pos then : temp = ax - y : r = y + ax : bias = pi34 : endif[/COLOR]

' remember that with picaxes operations are performed in the order they are written!!!
approx:
if r < neg then : r = r * scsq / temp : else r = -r : r = r * scsq / temp : r = -r : endif
angle = fact1 * r / scsq * r / scsq - fact2 * r
if angle < neg then : angle = angle / scsq : else angle = -angle : angle = angle / scsq : angle = -angle : endif
angle = angle + bias * sign + circle % circle * 10 / scale
sertxd ("Angle:",#angle,13,10) ' note the *10 above - answer is returned in 5ths of a degree``````

Last edited:

#### AllyCat

##### Senior Member
Hi,

I haven't examined your code in great detail, but two items look rather "suspicious". Also, my PE (5.5.6) didn't seem to like the variable "neg" so I changed it (to negx). When I changed "scale = 8" to "scale = 10", the simulator produced a different result. That suggets a mistake, for example that the scale factor has been omitted from one of the expressions. Also, "....+ circle % circle ...." doesn't do anything useful, similar to adding zero (I had to use the manual to look up the meaning of %, personally I prefer // for the remainder from a division).

However, the main issue is probably that the calculation needs to be divided into eight octants (or sectors), to cover all permutations of the sign of X the sign of Y, and whether X>Y or Y>X (to avoid overflows, due to division by small numbers or zero).

By chance, I needed an ARCTAN routine just a few weeks ago which I was planning to eventually submit to the "code snippets" section of the forum, but I think it can be improved first. However, I estimated that using only two "piecewise linear" sections produces a maximum error of one degree (around 17 and 38 degrees), so I only calculated wth byte variables and predominantly integer degrees (good enough for my needs). Here's a "preview" of my first attempt:

Code:
``````#picaxe 20m2        ; or probably any other
#no_data

symbol negx = 128
symbol deltx= b10
symbol delty= b11
symbol sect = b0 				; Sector number from 0 (0 - 45 degs) to 7 (315 - 360 degs) MUST BE b0
symbol vect  = w12

deltx = 50     ; test values
delty = 86     ;
arctan:
if deltx < negx then
sect = 0
else
sect = 7
deltx = - deltx
endif
if delty > negx then
sect = sect xor 3
delty = - delty
endif
if deltx > delty then
sect = sect xor 1
swap deltx, delty						; swap uses 12 - 14 bytes of codespace!
endif
vect = 256 * deltx / delty and 255  	; Calc ATAN from fractional byte (0-255) [AND patches 0/0]
if vect < 129  then						; ATAN 0.5 = 26 degrees
vect = vect * 26 / 128					; Sector from 0 to 26 degrees
else
vect = vect - 128 * 19 / 128 + 27	; Second line section from 0.5 to 1 (26 - 45 degrees)
endif
b0 = sect
if bit0 = 1 then
vect = 45 - vect						; Reverse the sector from 90 to 45 degrees
endif
vect = sect * 45 + vect
sertxd(#vect)``````
Cheers, Alan.

Last edited:

##### Senior Member
Symbol x = w0
Symbol x.lsb = b0
Symbol x.msb = b1

Symbol y = w1
Symbol y.lsb = b2
Symbol y.msb = b3

Symbol z = w2
Symbol z.lsb = b4
Symbol z.msb = b5

hi2csetup i2cmaster, \$3C, i2cslow_16, i2cbyte 'Setup PICAXE I2C port
hi2cout \$00, (\$18) 'Set mag req A for non-average,75Hz,normal measurement
hi2cout \$01, (\$00) 'Set mag req B for range of +/- 0.88Ga (Earth = +/-0.5Ga)

start:
hi2cout \$02, (\$01) 'Request single measurement
pause 500 'Allow time for measurement and display
HI2cIn \$03, (x.msb, x.lsb, z.msb, z.lsb, y.msb, y.lsb)

x = x+2048

y = y+2048

z = z+2048

sertxd (#w0,",",#w1,",",#w2,cr)
goto start 'Next measurements
I've just got three of these from China Ebay and I hope to hook them up to an 08M2. This listing checks Ok with an 08M2 as the processor, so I guess I just hook up pins C.1 and C.2 as per the PCB markings, plus power supply. I'm using these http://www.ebay.co.uk/itm/390654140041?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1439.l2649
It looks like they have pull-ups fitted, but I'll check with a magnifier and multi-meter. If it works the next step is to make it talk to an LCD via serial and in degrees.

#### techElder

##### Well-known member
Would these magnetometers be sensitive enough to detect a "vehicle", such as in a driveway "vehicle" detector using Earth magnetic field?

The specs say, "Measuring range: ± 1.3-8 Gauss"

##### Senior Member
'Probably' if they can sense the earths magnetic field and essentially tiny changes in it, then they should detect variations in it caused by a large metallic object. Need to get it connected first

#### AllyCat

##### Senior Member
Hi,

Assuming that the "vehicle" is made of steel (and not wood, carbon fibre or aluminium/aluminum, etc) then I would expect to be able to detect it passing over a (buried) sensor but probably not passing any significant distance "beside" it.

However, I believe that most vehicle sensors use (buried) induction loop principles (rather like an inverted treasure seeker's metal detector) where the resonance of a tuned circuit (the loop) is "modified" (in frequency or Q) by the presence of the vehicle.

Cheers, Alan.

#### Haku

##### Senior Member
Glad this thread got resurrected, a few days ago I received two of the same modules from the same seller radiogareth got his from and I notice the price as dropped during the weeks they took to arrive!

These ones have a 3.3v regulator onboard capable of delivering 250mA, so you can run your Picaxe from the 3.3v pin, but the regulator can only take 6v maximum input voltage.

When the christmas frenzy has settled down I'll be getting stuck into this and some other boards I haven't yet tinkered with, including a GPS module, Nokia 5110 screens, rain sensor & sound sensors.

#### Colinpc

##### New Member
See my update to my project at link above.

Freddagg