Problem calibrating CMPS03 via i2c comms

westaust55

Moderator
Hi all,

I am having problems calibrating a CMPS03 compass module using the i2c method (using the manual/switch method tonight works) but want so try and sort out what is wrong in the/my i2c method.

The program to calibrate first correctly reads the firmware revision and heading so the basic i2c comms is working. :)

To calibrate, one has to write the value 255 to register 15 once for each of the four cardinal points with the compass alighed to each of the 4 directions.

The value in register is supposed to be cleared in a fraction of a second but appears to be locking / holding as 255.

I tried writing a different value but it still read back 255 suggest no actual response from the register.

Before I write to the register 15, I DO read back a value of zero (0) from register 15 suggesting the i2c comms is working and can see the register.
I see this value change from 0 to 255 on read back after writing a value to register 15.

Extracted below are some of the pertinent lines from the PICAXEcode I am using.

Code:
SYMBOL cmps03_0 = %11000000  ; CMPS03 COMPASS MODULE address = $C0
; many other SYMBOL statements here are omitted 

Main:  HI2CSETUP  i2cmaster, cmps03_0, i2cslow, i2cbyte
           PAUSE 100
           HI2CIN 0, (b9,b10, b19,b18)  ; reads revision, 1-byte and 2-byte values correctly

           SEROUT lcd_data, N2400, ("Revision ", #b9)   ; all the read data is displayed correctly
           PAUSE 10
           SEROUT lcd_data, N2400, (lcdcmand,lcdline3)
           PAUSE 10
           SEROUT lcd_data, N2400, ("angle ", #b10)
           PAUSE 10
           SEROUT lcd_data, N2400, (lcdcmand,lcdline4)
           PAUSE 10
           SEROUT lcd_data, N2400, ("angle ", #w9)       ; w9 = b19 (msb) and b18 (lsb)
           PAUSE 2000

          HI2CIN 15, (b9)   ; read value in register 15 into b9 : it does shows up as zero (0) here at power up
         debug                 ; displays all the PICAXE variables on PC screen
        :
        :
        :
       DO                       ; keypad is read by interrupt routine which is working
          PAUSE 10
       LOOP WHILE keyval =0     ; wait for a keypress on keypad  - this is one
 of 4 such loops, to handle the four cardinal directions for calibration
       pause 5
      
       HI2COUT 15, (255)              ; write a calibration command/action to CMPS03 register 15
       pause 100

                                            ' on the CMPS03, pin 5 should go low but stays high = no calibration started
       
       HI2CIN 15, (b9)                  ; read back the value in register 15 =   always comes back
                                              ; with 255    even if a value like 170 written to register 15. 
                                              ; (suggesting that I am not getting response back on i2c )
                                              ; but seems to read value from reg. 15 correctly at start
        debug
       pause 1000
     END
Its getting late here and maybe I am overlooking something obvious.
Any help would be greatly appreciated.
 

BCJKiwi

Senior Member
The documentation indicats that the same value - 255 - should be written to register 15 for each cardinal. So where does 170 come from?

Which rev do you have? Earlier Revs (7 thru 13) allow you to read register 14 to see what was there. Revs prior to 7 have different procedures.
 

westaust55

Moderator
The documentation indicats that the same value - 255 - should be written to register 15 for each cardinal. So where does 170 come from?

Which rev do you have? Earlier Revs (7 thru 13) allow you to read register 14 to see what was there. Revs prior to 7 have different procedures.
Hi BCJ,

Q. Which firmware revison:
A. I have Rev 16 firmware.

Q. Where does the value of 170 come from:
A. Yes, you are correct and should be using the value of 255 entered into register 15 at each cardinal point.

Having noted that after power up I can read a value of 0 at register 15,
when I write the value of 255 ($FF) to register 15, I then see 255 in register 15. The register 15 should clear (and pin 5 go low at the first write) but this does not happen (for me) in i2c calibration mode.

After several failed attempts, with a fresh power up I tried as an experiment to write 170 (=$AA = an arbitary value) into register 15 to see what I might read back. Before the write I can read a value of zero but after a write of 170, I still read back a value of 255. Again, the register never clears which it is supposed to do after writing for each cardinal point.

If it were not for the fact that I can read the Revision number (16) and heading data (as 1-byte and 2-byte values) correctly and initially see a value of zero (0) in register 15, I would tend to think that the i2c comms was not reading register 15.

With respect to Register 14, for normal operation the current CMPS03 manual states:
14 Unused - Read as Undefined

And for calibration the current combined CMPS01 / CMPS03 manual states:
14 Calibration Done Flag - Zero in calibrate mode when un-calibrated, 255 otherwise - unused in Rev 7 software & CMPS03

I note that the calibration instruction is for both the CMPS01 rev 7 AND the CMPS03.

I have been using pin 5 as a means of detecting whether the calibration has commenced. This pin is normally high and changes to low when the calibration process starts. When the 4 calibration steps are completed, pin 5 returns high.

I have managed to calibrate using a swtch on pin 6 so the onboard microcontroller is working (at least in the main if not totally). The issue is i2c mode is not perfoming a calibration. :mad:
 

BCJKiwi

Senior Member
With revs post 14 then my reading of the process is that you need to send 255 to each of the cardinal points in turn. I doubt the process will work if you try to do anything other than write each of the cardinals in turn.

I would suggest that the described procedure be followed to the letter - i.e. know the cardinal points in a disturbance free level place, send 255 to each point in turn while slowly turning the device.
Then test it in use by reading bearings from it at each of the cardinal points.

The manual does say;
"One point which must be emphasized. The calibration must be done in exactly four steps, once for
each of the four major compass points North, East, South and West. Previous versions performed
part of the calibration at each step and you could actually go back and do a point again, taking 5 or
more steps. Only the most recent reading from each point was used. Rev 14 onwards works
differently. The 1st step (pulling pin 6 low or writing 255 to register 15) initializes internal
construction registers and collects the 1st data set. The remaining steps only collect data. After the
final 4th step, multiple processing stages generate and store in EEPROM a number of internal calibration values. When you perform the 1st step, Pin 5 will go low. After the 4th step it will go
high again. You can connect an LED from pin 5 to 5v via a 390ohm resistor to indicate calibration is
in progress. It should be high (Led off) before you start. "

After all, the i2c setting process emulates the pin process - set each cardinal in turn without anything else going on in between.

If you want to monitor if it is working, monitor pin5, as described in the manual, it will go low after the first 255, and not come high again until after the 4th 255 when the four points are processed. Reads in between will probably upset the process.

I should add that I have only recalibrated by the pin method myself - after all, you only need to do it once and with the minimum of other stuff around - so a couple of batteries to power it and some jumpers on a small breadboard and you can do this outside well clear of interference if you wish.
 
Last edited:

westaust55

Moderator
Hi BCJ,

Yes I have done everything several times as per the exactly as per the manual. What you write is also my understanding.

Trying to write another value was only a test to try and see what might be happening when I realised the CMPS03 was not calibrating via i2c. Shortly after I had a go with the manula/switch method and it worked first time.

If you want to monitor if it is working, monitor pin5, as described in the manual, it will go low after the first 255, and not come high again until after the 4th 255 when the four points are processed. Reads in between will probably upset the process.
Yes that is exactly what I was doing.

I should add that I have only recalibrated by the pin method myself - after all, you only need to do it once and with the minimum of other stuff around - so a couple of batteries to power it and some jumpers on a small breadboard and you can do this outside well clear of interference if you wish.
Initially my CMPS03 module was spot on. Did some trials and put is aside for a while. Then came to install it in a small plastic box and connect it up more permanently and found the headings were all over the place as if it had lost all calibration.

Also agree about making sure the area is free of magnetic influences as much as possible. I was using an old analogue meter to monitor pin 5 and while moving my conventional compass around discovered the magnet for the analogue movement was strong enough to obviously influence readings at around 400mm distant.

I believe the problem is purely to do with the CMPS03 not starting a calibration when first intiated over the i2c comms bus. The data (255) is written to Register 15 for the first position, but the CMPS03 does not appear to react to the command so pin 5 does not go low and nothing else happens.


Thanks for your review of the situation and suggestions.



Would still be keen to hear from anyone with a CMPS03 module who has managed to achieve calibration using the i2c comms method.
 
Last edited:

BCJKiwi

Senior Member
The code posted at the beginning and the notes appeared to suggest that you were writing 255 then reading to check before the next 255 was written. Perhaps I have misunderstood but if you do reads between writes while trying to calibrate I figure it would not work.
 

westaust55

Moderator
Problem calibrating CMPS03 via i2c

Maybe my description has confused people.

When I first tried the calibration via i2c my code flow as:
1. Message to say point north and press a key
2. wait for a key press (this is the DO...Until loop - my keypad is interrupt driven so comes back into the loop with a value)
3 write 255 to register 15
4. Message to say point east and press a key
5. wait for a key press
6 write 255 to register 15
7. Message to say point south and press a key
8. wait for a key press
9 write 255 to register 15
10. Message to say point west and press a key
11. wait for a key press
12. write 255 to register 15
13 Message to say all done.

When after several attempts entirely as per the manual/calibration notes and no sign of improvement (ie no calibration) taking place I added a test after step 3, as the manual says register 15 will be cleared. Never came out of the loop waiting for register 15 to clear so I delved further as per first posting to see that register 15 was changing from 0 to 255 but never being cleared AND the signal at pin 5 never went from high to low state.
 
Last edited:

BCJKiwi

Senior Member
I suggest you email gerry @ robot-electronics.co.uk for further clarification, maybe the procedure has changed again for FW ver16!
 
Last edited by a moderator:

westaust55

Moderator
Thanks for the suggestion.

Tried that approach in parallel over the last couple of days as another avenue.

Gerry states that it is possible to program via i2c and asked if I had another i2c device using address $C0 (which I do not).

But after frustation and no progress with the i2c mode over a few days, as soon as I indicated that I had tried and managed to calibrate the CMPS03 using the manual/switch method, all was fine to him and seems to have lost interest.

The fact that the CMPS03 had initially lost calibration for no apparent reason and that mine seemingly cannot be calibrated via i2c was not a worry.

Edit:
If no-one can spot an obvious error in my calibration code (below)
then think I need to try and find someone who has tried/used the i2c method and look at their code if they were successful.

(Dont worry about lots of SYMBOL statements - part of my default programming template. Only a few are used here)

Oh Oh - Add I have just found that there is a 10,000 character limit in a post :D

Code:
;
; - - - DIGITAL INPUT PINS  - - -
SYMBOL key_data = 0        ; keypad serial data input
;intrpt val_data =1            ; keypad valid data signal
SYMBOL tempsens = 2       ; DS18B20 temp sensor 
SYMBOL irdetect = 3         ; infrared detector 
;
; - - - DIGITAL OUTPUT PINS - - -
SYMBOL speaker  = 0         ; piezo speaker output;
SYMBOL lcd_data = 1         ; LCD serial display
SYMBOL ir_outpt = 2         ; infrared LED output

;
; - - - ANALOGUE INPUT PINS  - - -
SYMBOL adc_pot = 5          ; potentiometer
SYMBOL adc_ldr  = 6          ; light dependant resistor
SYMBOL adc_mag = 7         ; hall effect magnetic field sensor
;
; -----[ i2c Device Addressing ]---------------------
; 24LC256 EEPROM's   %1010 = EPROM
SYMBOL eeprom_0 = %10100000
SYMBOL eeprom_1 = %10100010
SYMBOL eeprom_2 = %10100100
SYMBOL eeprom_3 = %10100110
SYMBOL eeprom_4 = %10101000
SYMBOL eeprom_5 = %10101010
SYMBOL eeprom_6 = %10101100
SYMBOL eeprom_7 = %10101110
;
; PCF8574 8-BIT IO EXPANDERS
SYMBOL expand_0 = %01000000  ; For row of 8 Red LED's
SYMBOL expand_1 = %01000010  ; For Keypad Shift LED
SYMBOL expand_2 = %01000010  ; For Compass Indication Right half
SYMBOL expand_3 = %01000010  ; For Compass Indication Left half
;
; DS1338 REAL TIME CLOCK with 56 bytes of RAM
SYMBOL rtc1338  = %11010000
;
; CMPS03 COMPASS MODULE
SYMBOL cmps03_0 = %11000000 
; 
; SRF008 ULTRA SONIC RANGE FINDER
SYMBOL srf008_0 = %11100000
;
; SPE030 TEXT TO SPEECH SYNTHESIS MODULE
SYMBOL spe030_0 = %11000100
;
; -----[ Constants ]--------------------------------
SYMBOL shiftkey = 64           ; value returned by keypad for shift key
SYMBOL NoLEDs   = 8           ; No of LEDs in the bar graph
;
; 4 x 20 char LCD commands
SYMBOL lcd_bs   = $08         ; back space
SYMBOL lcd_lf    = $0A         ; line feed
SYMBOL lcd_ff   = $0C          ; form feed
SYMBOL lcd_cr   = $0D         ; carriage return
; 
SYMBOL lcdcmand = $FE        ; = 254 - send this before following commands
SYMBOL lcdclear = $01          ; clear screen and cursor to home position
SYMBOL lcdhome  = $02        ; move cursor to home position
SYMBOL lcdnocur = $0C         ; display on with no cursor
SYMBOL lcdcuron = $0E         ; display on with visible cursor
SYMBOL lcdcblnk = $0F         ; display on with blinking cursor
SYMBOL lcdline1 = $80         ; move to start of 1st line
SYMBOL lcdline2 = $C0         ; move to start of 2nd line
SYMBOL lcdline3 = $94         ; move to start of 3rd line
SYMBOL lcdline4 = $D4         ; move to start of 4th line
SYMBOL lcdlitof = $FC          ; turn backlight off
SYMBOL lcdLiton = $FD         ; turn backlight on
;
; CMPS03 Compass Module
SYMBOL cmps03_sr = 0         ; read register 0 for software revision
SYMBOL cmps03_lr = 1         ; read bearing as 8-bit (0-255 for 0-359deg)
SYMBOL cmps03_hb = 2         ; read bearing high byte (16-bit value 0-3599)
SYMBOL cmps03_lb = 3         ; read bearing low  byte (for 0.0 - 359.9 deg)
;
; -----[ Variables ]------------------------------------------------------
;
SYMBOL keypad    = b27       ; Value returned from keypad (0-63)
SYMBOL keyval     = b26       ; Add\justed value from keypad keypd+1 (1-64)
SYMBOL shflock    = b25       ; Flag to indicate if shiftlock is ON/OFF
SYMBOL keychar   = b24       ; ASCII character value for keypad key press
SYMBOL pattern    = b23       ; 8 bit pattern to be sent to the 8 x LED's
SYMBOL rearlite    = b22       ; Light level on rear detector on i2c SRF08
SYMBOL loop_cnt  = b21       ; temp value used for For-Next Loop counter
SYMBOL val2graph = b20       ; input value to be presented on bar graph
SYMBOL directn   = b19       ; 0 = right to left, >0 = left to right
SYMBOL indtype   = b18       ; 0 = bar graph, 1= for lower ‘level’ dot posn
SYMBOL scaledadc = w8        ; =b17 + b16 scaled value used for bar graph function
; 
; -----[ EEPROM Data ]-------------------------------------------------
;
; -----[ Initialization ]--------------------------------------------------
;
Init:  pattern = 0           ; Set to clear all 8 red LED's
       GOSUB Pattn2led
       shflock = 0           ; Set the SHIFTLOCK green LED to OFF
       GOSUB Shlok2led
       PAUSE 1000            ; wait for LCD to initialise
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 10
       SEROUT lcd_data, N2400, (lcdcmand,lcdnocur)
       PAUSE 5
       SEROUT lcd_data, N2400, (lcdcmand,lcdLiton)
       PAUSE 5
       SEROUT lcd_data, N2400, ("WELCOME TO MY PICAXE")
       PAUSE 5
       SEROUT lcd_data, N2400, (lcdcmand,lcdline2)
       PAUSE 5
       SEROUT lcd_data, N2400, (" EXPERIMENTER'S BOX ")
       PAUSE 1000
       
       directn = 0
       indtype = 0
;
       SETINT %00000000, %00000010  ; set polled interrupt to act on a change to 0 on input 1       
;
   
;
;
; -----[ Program Code ]------------------------------------------------
;
Main:  HI2CSETUP  i2cmaster, cmps03_0, i2cslow, i2cbyte

        PAUSE 100
        HI2CIN 0, (b9,b10, b19,b18)
        

        PAUSE 10
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 5
       SEROUT lcd_data, N2400, (lcdcmand,lcdLiton)
       PAUSE 5
       
       SEROUT lcd_data, N2400, (lcdcmand,lcdline2)
       PAUSE 1
       SEROUT lcd_data, N2400, ("Revision ", #b9)
       PAUSE 1
       SEROUT lcd_data, N2400, (lcdcmand,lcdline3)
       PAUSE 1
       SEROUT lcd_data, N2400, ("angle ", #b10)
       PAUSE 1
       SEROUT lcd_data, N2400, (lcdcmand,lcdline4)
       PAUSE 1
       SEROUT lcd_data, N2400, ("angle ", #w9)
       pause 2000
       HI2CIN 15, (b9)
       debug                     ; this indicates value of zero initially in Reg 15
       
       
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 5
       SEROUT lcd_data, N2400, ("Ready 4 Calibration")
       PAUSE 2000
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 5      
       SEROUT lcd_data, N2400, ("Set 2 North & press")
       DO
         PAUSE 10
       LOOP WHILE keyval =0   
       pause 5
       HI2COUT 15, (255)       
       keyval =0
       
              
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 5
       SEROUT lcd_data, N2400, ("Set 2 East & press")
       DO
         PAUSE 10
       LOOP WHILE keyval =0   
       pause 5
       HI2COUT 15, (255)
       keyval =0
      
      
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 5
       SEROUT lcd_data, N2400, ("Set 2 South & press")
       DO
         PAUSE 10
       LOOP WHILE keyval =0   
       pause 5
       HI2COUT 15, (255)
       keyval =0
       
       
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 5
       SEROUT lcd_data, N2400, ("Set 2 West & press")
       DO
         PAUSE 10
       LOOP WHILE keyval =0   
       pause 5
       HI2COUT 15, (255)
       keyval =0
       
       pause 5
       SEROUT lcd_data, N2400, (lcdcmand,lcdclear)
       pause 5
       SEROUT lcd_data, N2400, ("Calibration done  ")
       
       end
;
; -----[ Subroutines ]-----------------------------------------------
;
pattn2led: HI2CSETUP  i2cmaster, expand_0, i2cslow, i2cbyte
           HI2COUT (pattern)
           RETURN
;
shlok2led: HI2CSETUP  i2cmaster, expand_1, i2cslow, i2cbyte
           IF shflock = 0 THEN
             HI2COUT (0)
           ELSE
             HI2COUT (1)
           ENDIF
           RETURN


;           RETURN
; =================================================
;      THE END
; =================================================
Interrupt: SERIN key_data, T2400, keypad            ; here when a key is pressed
           keyval = keypad +1                       ; change 0 to 63 to 1 to 64 (easier for maths)
	     
           IF keyval = shiftkey THEN                ; If it was shift key Then . . .
	        shflock = shflock ^ keyval            ; exclusive OR to toggle state of shift lock flag
              GOSUB Shlok2led                       ; update the SHIFT LED
	     ENDIF

	     keyval = keyval + shflock                ; 1 to 63 for lower, 65 to 127 for upper/shifted
           
           HI2CSETUP i2cmaster, EEPROM_0, i2cslow, i2cword
           HI2CIN keyval, (keychar)                 ; fetch the equivalent character from EEPROM table
	     
	     SETINT %00000000, %00000010              ; restore the interrupt scheme and return to main program
	     RETURN
 
Last edited:

BCJKiwi

Senior Member
I managed to stuff one of these completely by inadvertently applying a low power signal to one of the other pins (pin4 I think) when it was on the breadboard. I wish that not all the pins were soldered into the card as that would have avoided this sort of problem. Maybe something similar may have happened to upset the calibration routine. However in my case even the pin calibration method no longer worked and it does for you.
 
Top