MAG3110 - I2C 3-axes sensitive magnetometer

ThierryP

New Member
Example program connecting a MAG3110 3-axis magnetometer to a Picaxe 08M2.
The Mag3110:
  • has an I2C interface
  • is very sensitive (0,1uT resolution, while the Earth's magnetic field is 50uT strong around here (and pointing almost straight down, about 65-70 degrees downwards, didn't realise that)
  • it's speed is OK (max 80 3D readings per second)
  • is very small, you need a breakout board to use it, but these are not too expensive, see: www.sparkfun.com or www.olimex.com
  • runs on 3.3V, so don't connect it to 5V, it will be fried:eek:
The example program uses a AXE133Y OLED 16x2 module to display the X, Y, Z values of the magnetic field in real time. Due to the space restrictions on the LCD panel only 4 last digits and the sign of the value in each direction X, Y, Z are displayed
A critical parameter for a meaningfull measurement is the offset in each direction X, Y, and Z. To estimate these values have the program run with all 3 Offsets set at $0000, while turning and twisting the Mag3110 in all directions. Note down the max en min values for X, Y and Z. The midpoint between X-max and X-min is the estimate for the X Offset, same for Y, Z (you need to convert them to their two's-complements values in the program below).

Enjoy

Thierry
Code:
;Testprogram for MAG3110 3-axis Magnetometer
;  -Uses MAG3110 (Mag) I2C interface
;  -Reads XYZ values from Mag
;  -Applies XYZ Offset values in program (instead of in-chip)
;  -Displays XYZ values on LCD module (AXE133)
;  -Currently runs at approx 180ms per loop, measurements + displays
;   Most of this is display time to Serial LCD
;   Should be possible to run it close at max speed of less than 20ms per loop, without slow display
;  v1  ThierryP, April 2012

#picaxe 08M2

;Connections 08M2
;--Pin--Name----Function--------Remark
;  1	+V	Supply Voltage	IMPORTANT! USE 3.3V, 5V WILL FRY THE MAG3110!!
;  2	C.5	Serial In		Programming Interface Rx
;  3	C.4   Out			Serial Tx Interface to LCD Panel AXE133 (I use idle=hi levels in AXE133, "T2400", can be changed)
;  4         C.3   In			Irq from Mag (not used in this test)
;  5  C.2   hi2c SDA		I2C SDA interface with Mag, with 4k7 Pull-Up
;  6  C.1   hi2c SCL		I2C SCL interface with Mag, with 4k7 Pull-Up
;  7	C.0	Serial Out		Programming Interface Tx
;  8  0V   	Ground		              Again, use 3.3V as +!!
;-------------------------------

symbol RawX=  w0 ;Raw X value of Magnetic Field,       b1-b0
symbol RawY=  w1 ;Raw Y value of Magnetic Field,       b3-b2
symbol RawZ=  w2 ;Raw Z value of Magnetic Field,       b5-b4

symbol MagnX= w3 ;Converted X value of Magnetic Field, b7-b6
symbol MagnY= w4 ;Converted Y value of Magnetic Field, b9-b8
symbol MagnZ= w5 ;Converted Z value of Magnetic Field, b11-b10

symbol OffsX= w6 ;X Offset value of Magnetic Field,    b13-b12
symbol OffsY= w7 ;Y Offset value of Magnetic Field,    b15-b14
symbol OffsZ= w8 ;Z Offset value of Magnetic Field,    b17-b16

symbol SignX= b18 ;Sign of Converted X value
symbol SignY= b19 ;Sign of Converted Y value
symbol SignZ= b20 ;Sign of Converted Z value

symbol SignBit = b26 'temp variable
symbol CntConv = b27 'to check the speed of loops

symbol K4D = b21 'ten-thousand in readout
symbol K3D = b22 'thousand in readout
symbol K2D = b23 'hundred in readout
symbol K1D = b24 'ten in readout
symbol K0D = b25 'units in readout

symbol SerLCD = C.4
symbol baud = T2400_16

;Change these Offset values for each Mag (Calibration)
;Initially set all offsets at $0000 and check range extremes of the Raw XYZ values
;Then the Offsets are the means of Max and Min XYZ values 
;########################################
let OffsX = $0CD2  '2-complement of +3282
let OffsY = $F778  '2-complement of -2183
let OffsZ = $F591  '2-complement of -2670
;########################################
CntConv=0

setfreq m16

serout SerLCD, baud, (254,1) ;Clear LCD Display
pause 300

hi2csetup i2cmaster, %00011100, i2cfast_16, i2cbyte 
;MAG3110 Address is $0E. In bits 7-1 that becomes: %000 1110 x  
hi2cin $07, (b0)   ;Test presence of Mag if needed: ID=$C4, ignored here
hi2cout $11, ($80) ;Init Mag Ctrl_reg2: operation mode, RESET
hi2cout $10, ($01) ;Init Mag Ctrl_reg1: operation mode, ACTIVE

main:
;---Measure XYZ------------
hi2cin 1,(b1, b0, b3, b2, b5, b4)  	;read 6 raw bytes from address 1, 2-complement

;---Calc X------------------------------
let RawX = RawX - OffsX			;substract X-offset, 2-complement
SignX = "+"
MagnX = RawX
SignBit = RawX / 256 / 128
if SignBit=1 then
	SignX="-"
	MagnX= RawX ^ $FFFF + 1   	;Convert 2-complement negative to normal binary
endif
;---Display X on 16x2 display, top line - Left
bintoascii MagnX, b21,b22,b23,b24,b25
serout SerLCD, baud, (254,128)
serout SerLCD, baud, ("X=", SignX, b22,b23,b24,b25, "  ")  ; 10k's suppressed, display will overflow with strong fields

'---Calc YX------------------------------
let RawY = RawY - OffsY
SignY = "+"
MagnY = RawY
SignBit = RawY / 256 / 128
if SignBit=1 then
	SignY="-"
	MagnY= RawY ^ $FFFF + 1   	;Convert 2-complement negative to normal binary
endif
'---Display Y on 16x2 display, top line - Right
bintoascii MagnY, b21,b22,b23,b24,b25
serout SerLCD, baud, ("Y=", SignY, b22,b23,b24,b25)
'---Calc Z------------------------------
let RawZ = RawZ - OffsZ
SignZ = "+"
MagnZ = RawZ
SignBit = RawZ / 256 / 128
if SignBit=1 then
	SignZ="-"
	MagnZ= RawZ ^ $FFFF + 1   	;Convert 2-complement negative to normal binary
endif
'---Display Z on 16x2 display, 2nd line - Left
bintoascii MagnZ, b21,b22,b23,b24,b25
serout SerLCD, baud, (254,192)
serout SerLCD, baud, ("Z=", SignZ, b22,b23,b24,b25, "  ")
CntConv=CntConv+1
bintoascii CntConv, b21, b22, b23
serout SerLCD, baud, ("Cnt=", b21,b22,b23)
'debug

goto main
 
Top