Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 20:17 25 Apr 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : QMC5883L

Author Message
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 11:25am 18 Nov 2021
Copy link to clipboard 
Print this post

I've got a QMC5883L compass incorporated in a GPS module a Matek Neo M9N-5883 which the GPS works beautifully
I cannot however figure out how to get the compass working
Does anyone have any code for this module that I could use?
OR
Can anyone "translate" from Arduino?

I found Arduino code here

With the compass.h here and the compass.cpp here

Example code for direction here  This I believe uses N,W, E and W
where I'd prefer to use 8 points of the compass rather than 4

Anyone able to decipher and translate or have any code for this module?

I did have a go at it myself but completely got lost and couldn't make head nor tail of what I was trying to do

The only thing I can say for definite is it needs to be in continious mode
Continuous Mode Setup Example  
Write Register 0BH by 0x01 (Define Set/Reset period)
Write  Register  09H  by  0x1D  (Define  OSR  =  512,  Full  Scale  Range  =  8  Gauss,  ODR  =  200Hz,  set  continuous
measurement mode)

7.2 Measurement Example  
Check status register 06H[0] ,"1" means ready.
Read data register 00H ~ 05
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 11:20am 20 Nov 2021
Copy link to clipboard 
Print this post

it's a compass ic
 
SimpleSafeName

Senior Member

Joined: 28/07/2019
Location: United States
Posts: 286
Posted: 04:26am 26 Nov 2021
Copy link to clipboard 
Print this post

What platform and language do you plan to run the compass on? Whose compass board are you using?

Taking a quick look at it and it doesn't seem too bad. First off have you seen how to operate it in the Arduino world? https://belchip.by/sitedocs/10882.pdf

Let me know the board and more importantly, the platform that you want to use it on, and I'll give it a shot.


John
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 10:52am 26 Nov 2021
Copy link to clipboard 
Print this post

It's going on a Picomite
it's part of a GPS program, the compass is built into the GPS module
I know nothing about Arduino and I'm pretty cr@p at programming using MM as well
 
SimpleSafeName

Senior Member

Joined: 28/07/2019
Location: United States
Posts: 286
Posted: 01:40pm 26 Nov 2021
Copy link to clipboard 
Print this post

So I took the plunge last night and dropped $7 bucks on a compass module to get the ball rolling. The important thing is that we are using the same chipset.

When it gets here I'll see about programming it to work with a CMM2. That will get you close.
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 03:26pm 26 Nov 2021
Copy link to clipboard 
Print this post

Thanks :)
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3839
Posted: 03:40pm 05 Feb 2022
Copy link to clipboard 
Print this post

I've spent a few hours on this (using the same integrated GPS/Compass Matek Neo module as Lewis) and am stymied. I'm reasonably sure the following should read the raw data:

Option base 0
Option default none
Option explicit on

Const MAG_ADDRESS = &h0D

SetPin GP0, GP1, I2C

I2C OPEN 100, 1000

qmc5883l.init()

Do
 qmc5883l.read()
 Pause 100
Loop

Sub qmc5883l.init()
 qmc5883l.writeReg(&h0A, &h80) ' Reset the chip
 qmc5883l.read()

 qmc5883l.writeReg(&h0B, &h01)
 qmc5883l.read()

 ' Continuous (0x01), 200Hz (0x0C), 8G (0x10), OSR=512 (0x00)
 ' qmc5883l.writeReg(&h09, &h01 Or &h0C Or &h10 Or &h00)
 qmc5883l.writeReg(&h09, &h1D)
 qmc5883l.read()
End Sub

Sub qmc5883l.writeReg(reg%, value%)
 I2C Write MAG_ADDRESS%, 1, 1, reg%
 If MM.I2C Then Error
 I2C Write MAG_ADDRESS%, 0, 1, value%
 If MM.I2C Then Error
End Sub

Sub qmc5883l.read()
 I2C Write MAG_ADDRESS%, 1, 1, &h00
 If MM.I2C Then Error

 Local buf$
 I2C Read MAG_ADDRESS%, 0, 14, buf$
 If MM.I2C Then Error

 Local i%
 For i% = 1 To 14
   Print Asc(Mid$(buf$, i%, 1));
 Next
 Print
End Sub


But all I get when RUNning is:
> RUN
0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0
...


The datasheet describes register &h0C, the one with the '1' as both "Reserved" and a "Status register", but doesn't say what its contents actually means ... presumably a value of 1 means "the monkey is doing it wrong" ?

Does anyone have any ideas before I order a standalone QMC5883L module to try with ... Lewis does it give the same non-result for you ?

Best wishes,

Tom
Edited 2022-02-06 02:09 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 08:48am 06 Feb 2022
Copy link to clipboard 
Print this post

Sorry Tom only just saw this
I get this error
> RUN
[33] If MM.I2C Then Error
Error
>


I did change this SetPin GP4, GP5, I2C after it failed the first time as that's where my i2c pins are

I did see in the manual that it says I2C WRITE addr, option, sendlen, senddata [,sendata ....]
but you have I2C Write MAG_ADDRESS%, 1, 1, reg%

I see that MAG_ADDRESS% is &h0D but I can't find what reg% or value% actually are?
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3839
Posted: 01:01pm 06 Feb 2022
Copy link to clipboard 
Print this post

  lew247 said  Sorry Tom only just saw this


No worries.

  lew247 said  I get this error
> RUN
[33] If MM.I2C Then Error
Error
>


Interesting.

Anyway, I think I have it working now, try the code below instead.

  lew247 said  I did change this SetPin GP4, GP5, I2C after it failed the first time as that's where my i2c pins are


Yes, I temporarily removed your PCB from the equation and just wired directly to the first available SDA and SCL pins, GP0 & GP1.

Working (?) code - the output is just raw for the moment, no post-processing at all, but it seems to behave appropriately when I mess with the module orientation, not sure about the temperature reading though, perhaps needs calibrating ?

Option base 0
Option default none
Option explicit on

Const qmc5883l.I2C_ADDR% = &h0D

SetPin GP4, GP5, I2C
I2C OPEN 100, 1000

Dim mag_x%, mag_y%, mag_z%, temp%

Print "Initialising..."
qmc5883l.init()

Print "Running..."
Do
'  qmc5883l.read_all()
 qmc5883l.read(mag_x%, mag_y%, mag_z%, temp%)
 Print mag_x%, mag_y%, mag_z%, temp%
 Pause 1000
Loop

' Initialises the QMC5883L.
Sub qmc5883l.init()

 ' Reset the chip.
 qmc5883l.write_register(&h0A, &h80)
 qmc5883l.read_all()

 qmc5883l.write_register(&h0B, &h01)
 qmc5883l.read_all()

 ' Continuous (0x01), 200Hz (0x0C), 8G (0x10), OSR=512 (0x00)
 ' qmc5883l.write_register(&h09, &h01 Or &h0C Or &h10 Or &h00)
 qmc5883l.write_register(&h09, &h1D)
 qmc5883l.read_all()
End Sub

' Writes value to a QMC5883L register.
Sub qmc5883l.write_register(register%, value%)
 ' Address the slave and write two bytes, the register and the value.
 I2C Write qmc5883l.I2C_ADDR%, 0, 2, register%, value%
 If MM.I2C Then Error qmc5883l.get_i2c_error$()
End Sub

' Gets string corresponding to MM.I2C error code.
Function qmc5883l.get_i2c_error$()
 Select Case MM.I2C
   Case 0    : qmc5883l.get_i2c_error$ = "None"
   Case 1    : qmc5883l.get_i2c_error$ = "NACK"
   Case 2    : qmc5883l.get_i2c_error$ = "Timeout"
   Case Else : qmc5883l.get_i2c_error$ = "Unexpected error: " + Str$(MM.I2C)
 End Select
End Function

' Reads X, Y, Z from the magnetic sensor and also the temperature.
Sub qmc5883l.read(mag_x%, mag_y%, mag_z%, temp%)
 ' TODO: should probably check if data ready bit/register is set.

 ' Address the slave and send the first register address to read (0x00).
 I2C Write qmc5883l.I2C_ADDR%, 1, 1, &h00
 If MM.I2C Then Error qmc5883l.get_i2c_error$()

 ' Read 8 registers/bytes (0x00 .. 0x07).
 Local buf$
 I2C Read qmc5883l.I2C_ADDR%, 0, 8, buf$
 If MM.I2C Then Error qmc5883l.get_i2c_error$()

 mag_x% = Peek(Var buf$, 1) Or (Peek(Var buf$, 2) << 8)
 mag_y% = Peek(Var buf$, 3) Or (Peek(Var buf$, 4) << 8)
 mag_z% = Peek(Var buf$, 5) Or (Peek(Var buf$, 6) << 8)
 temp%  = Peek(Var buf$, 8) Or (Peek(Var buf$, 9) << 8)
End Sub

' Reads and dumps the contents of all 14 QMC5883L registers.
Sub qmc5883l.read_all()
 ' Address the slave and send the first register address to read (0x00).
 I2C Write qmc5883l.I2C_ADDR%, 1, 1, &h00
 If MM.I2C Then Error qmc5883l.get_i2c_error$()

 ' Read 14 registers/bytes (0x00 .. 0x0D).
 Local buf$
 I2C Read qmc5883l.I2C_ADDR%, 0, 14, buf$
 If MM.I2C Then Error qmc5883l.get_i2c_error$()

 Local i%
 For i% = 1 To 14
'    Print Hex$(Asc(Mid$(buf$, i%, 1)), 2) " ";
   Print Asc(Mid$(buf$, i%, 1));
 Next
 Print
End Sub

Edited 2022-02-06 23:02 by thwill
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
DaveJacko
Regular Member

Joined: 25/07/2019
Location: United Kingdom
Posts: 52
Posted: 10:41pm 06 Feb 2022
Copy link to clipboard 
Print this post

This seemed to work for me,
The Text commands are for the old LCD micromite backpack.
Change to 'print' for other platforms.
hope this is informative..


' test code for Q not H =QMC5883L
' 3 axis digital Magnetometer
' DPJ 2020

addr  = &h0D
'mfr says 3C=write 3D=read ie 1E
Dim buf(6) As integer
bit15=&h8000
k6=65536
CLS 'LCD stuff
Font 1,2 '16x32
Colour RGB(0,255,255),0
rd=RGB(255,0,0)
Text 0,0,"mag fld demo DPJ 2020",,,1

I2C OPEN 100,100,PU  'speed kHz,timeout ms,pullup

' ----  init hmc5883 see pdf

I2C write addr,0,2,&h09,&h1D 'sensitivity etc
I2C write addr,0,2,&h0B,&h01 'needed
Pause 100


mlp:

I2C write addr,0,1,&h00 'select reg 0
I2C read addr,0,6,buf() 'read datas

xm=buf(0)+256*buf(1)
If xm And bit15 Then xm=xm-k6
ym=buf(2)+256*buf(3)
If ym And bit15 Then ym=ym-k6
zm=buf(4)+256*buf(5)
If ym And bit15 Then zm=zm-k6

Text 0,20,Str$(xm)
Text 0,60,Str$(ym)
Text 0,100,Str$(zm)

Pause 1000
GoTo mlp




Function atn2(y,x)
If x > 0 Then
atn2 = Atn(y/x)
ElseIf y >= 0 And x < 0 Then
atn2 = Pi + Atn(y/x)
ElseIf y < 0 And x < 0 Then
atn2 = Atn(y/x) - Pi
ElseIf y > 0 And x = 0 Then
atn2 = Pi / 2
ElseIf y < 0 And x = 0 Then
atn2 = Pi / -2
EndIf
If atn2 < 0 Then
atn2 = atn2 + 2 * Pi
EndIf

End Function
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1676
Posted: 05:30pm 07 Feb 2022
Copy link to clipboard 
Print this post

Just to confirm both sets of codes work
I had to alter the 2nd slightly to match the Pico but it does work
Now to read the datasheet and find out what the numbers actually mean :)
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3839
Posted: 05:36pm 07 Feb 2022
Copy link to clipboard 
Print this post

Great.

Note that @DaveJacko's code accounts for the fact that the returned 16-bit numbers (pairs of bytes) may be -ve (in 2's complement), I didn't handle that in what I posted.

The Arduino code you linked to in your original post shows how to translate the numbers into compass directions.

Best wishes,

Tom
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
Bill.b

Senior Member

Joined: 25/06/2011
Location: Australia
Posts: 225
Posted: 08:44pm 07 Feb 2022
Copy link to clipboard 
Print this post

Hi all

I used a compass in my robot car using picaxe to decode the 5 bytes of data received.
this picaxe code mite help in decoding the data.


serin CompassSerialIn, cmpbaud, b14, b15, b50, b51, b52, b53, b54, b55


dspdir:  '****************** Display Commpass Readings ***************


serout OLED,Baud,(254,128)
serout OLED,Baud,("     Heading    " )
serout OLED,Baud,(254,192)
if b50 = 30 then
     serout OLED,Baud,("     ", b51, b52, b53, b54, 210," ")
Else
     serout OLED,Baud,("    ",b50, b51, b52, b53, b54, 210," ")
endif
heading = b50 - 48 * 10 + b51 - 48 * 10 + b52 - 48

select case heading
     case 0 to 10
      serout OLED,Baud,("N    ")
     case 11 to 32
      serout OLED,Baud,("NNE  ")
     case 33 to 55
      serout OLED,Baud,("NE   ")
     case 56 to 80
      serout OLED,Baud,("ENE  ")
     case 81 to 101
      serout OLED,Baud,("E    ")
     case 102 to 122
      serout OLED,Baud,("ESE  ")
     case 123 to 149
      serout OLED,Baud,("SE   ")
     case 150 to 170
      serout OLED,Baud,("SSE  ")
     case 171 to 190
      serout OLED,Baud,("S    ")
     case 191 to 212  
      serout OLED,Baud,("SSW  ")
     case 213 to 235
      serout OLED,Baud,("SW   ")
     case 236 to 258
      serout OLED,Baud,("WSW  ")
     case 259 to 280
      serout OLED,Baud,("W    ")
     case 281 to 302
      serout OLED,Baud,("WNW  ")
     case 303 to 325  
      serout OLED,Baud,("NW   ")
     case 336 to 347
      serout OLED,Baud,("NNW  ")
     case 348 to 360
      serout OLED,Baud,("N    ")
END SELECT
     
return


Bill
Edited 2022-02-08 06:48 by Bill.b
In the interests of the environment, this post has been constructed entirely from recycled electrons.
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024