Interfacing with A Precision Navigation Vector 2X Compass Module

copyright, Peter H. Anderson and Vance Foster
Dept of Electrical Engineering
Morgan State University, Baltimore, MD 21239
Jan 1, '97

Introduction.

This discussion shows how to interface a Vector 2X Compass Module with a PC Parallel Port. The discussion also shows how to interface the module with the Parallax Basic Stamp (BS1-IC).

My thanks to Mr Vance Foster who undertook this as his Senior Project during the Fall, 96 semester.

The Vector 2X Module is truly an amazing device. Indeed, a year ago, if anyone speculated that such a device could be designed, I would be the first to say, "No way!". Having used a hand compass for most of my life, I know the earth's magnetic field is mighty weak and having fooled with Hall Effect devices I have come to believe that Hall devices require a relatively strong field. But the Vector 2X does indeed work!

A brief description of the module is available on Precision Navigation's Web Page. It is available from Jameco (http://www.jameco.com) for $49.95. This includes a reasonably good 12 page data sheet and some very brief notes on interfacing with various p rocessors.

Jameco also sells a Developer's Kit, but this appears to be simply a demo of the various functions. The small card which interfaces with the parallel port does not even include the $49.95 compass module for later experimentation. I didn't buy it, and y ou might hesitate to spend $99.95 for this. Hopefully, in this discussion, I provide all of the information you need, and in you hacking my code, you have the same thing, are $100 richer (and can afford to buy a Parallel Port Manual) and more importantl y, you understand what you are doing.

The module itself is 1.5" X 1.3" X 0.3". The pins are on standard 0.1 inch spacings. However, 1.3 inch spacing between the rows is too wide to be accommodated on a single panel on a standard solder less bread board. However, I found that I could mount it such that one row of terminals is on one panel and the other on a second panel. When we went to the wire wrap version we used two 20 pin DIP wire wrap sockets, one for each side of the module.

Power is +5 VDC. As the current drain when in the sleep mode is but 1 mA and only 10 mA when active, we used a 9 Volt transistor battery and a 7805 regulator. Aside from the regulator, the unit is self contained; i.e., it can be directly interfaced with the parallel port (or Stamp) with no other components.

Two routines are discussed below.

Compass Bearing.

See Figure 1A.

The general theory of the device is that two perpendicularly mounted sensors detect the magnitude of the magnetic field. Of course, if the unit is mounted upside down, the field is reversed in each sensor. Thus, Precision Navigation has provided two ter minals /XFLIP and YFLIP. For normal operation, /XFLIP is set to logic one and YFLIP to logic zero.

The module may be operated in either a Master or Slave mode. As our intent was to interface this with a processor, we operated in the slave mode, where the processor controls the clocking of the data. Thus input M/S was set to logic zero.

Within the slave mode, there is an option for either the raw data measured by each of the two sensors to be returned in two 16-bit words or for the compass bearing to be returned. As we are considering taking a compass bearing at the moment, the /RAW inp ut is set to logic one. The RAW data mode is treated elsewhere.

The /LO_RES input permits high (logic one) and low resolution. In measuring a compass bearing , we found the low resolution more than adequate.

The /CAL input associated with calibration which is discussed elsewhere. As we are now concerned with making a measurement, this input is high. The CI output is a calibration indicator and is left unconnected in this application.

There is an option for the compass to return the compass bearing either in BCD or natural binary format. In both cases, the bearing consists of 16 bits with the most significant six bits set 0. Thus, in the BCD mode the lower ten bits are a binary code d decimal representation of the compass bearing. In the natural binary mode, only the lower nine bits are used. Consider a compass bearing of 359 degrees;

          BCD      0000 0011 0101 1001 or 0x0359                                     
          binary   0000 0001 0 110 0101 or 0x0165             

In our application, we used the BCD mode and thus the /BCD input was set to logic zero.

Module inputs; /RESET, SCLK, /SS and /PC and outputs SDO and EOC are used to obtain a reading. Please refer to the timing diagram on Figure #1B.

Note that /RESET is normally at logic one. It is brought to a momentary low for a minimum of 10 ms to reset the device.

The /P/C (polled/continuous) input is brought momentarily low for a minimum of 10 ms to initiate the sequence. The module brings EOC (end of conversion) low during the time it is making the conversion and goes high to signal the external processor that t he conversion is complete. Input /SS (slave select) is then brought low and a minimum of 10 msec thereafter, sixteen negative going clock pulses are output to the module, with the data on SDO (serial data out) being read after each of the positive SCLK t ransitions.

This is implemented in the following routine COMPASS1.C.

                                   

/*
** Program COMPASS1.C
**
** This program interfaces the parallel port with the 2X Compass Module. 
** Compass bearings are continually taken and displayed to the terminal. 
**
** Vance Foster, Peter Anderson, MSU, Dec 22, '96
*/

#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <stdlib.h>
#include <process.h>

#define DATA 0x03bc
#define STATUS DATA+1
#define CONTROL DATA+2

#define RESET 0x08
#define SCLK 0x04
#define SS 0x02
#define PC 0x01

int d=0x00;    /* note this is global */

void reset(void);
void set_ss(int state);
void wink_pc_low(void);
void clock(void);
int get_reading_bcd(void);

void main(void)
{
   int n, reading, hunds, tens, units;
   clrscr();
   reset();
   for(n=0; n<50; n++)  /* make 50 readings */
   {
      d=0x07;
      outportb(DATA, d); /* initialize at 1 1 1 1 */
      wink_pc_low();     /* bring /PC momentarily low */
      while (((inportb(STATUS)^0x80) >>7) == 0) 
                                   /* loop while EOC low */ ;     
      delay(50);
      set_ss(0);
      reading = get_reading_bcd() &0x3ff;
      set_ss(1);
      hunds=(reading >> 8) & 0x0f;
      tens= (reading >> 4) & 0x0f;
      units=reading & 0x0f;
      printf("\n%d%d%d\t%x\n", hunds, tens, units, reading);                 sleep(5);
   }
}

void reset(void)
/* brings reset momentarily low - all others high */
{
   d=0x0f;
   outportb(DATA, d);  /* 1 1 1 1 */
   outportb(DATA, d & (~RESET));   /* 0 1 1 1 */
   delay(10);
   outportb(DATA, d | RESET);   /* 1 1 1 1 */
}

void wink_pc_low(void)
{
   d=d&(~PC);
   outportb(DATA, d);
   delay(20);
   d=d|PC;
   outportb(DATA, d);
}

void set_ss(int state)
/* set /ss to indicated state */
{
   if(state == 1)
   {
      d=d|SS;
   }
   else
   {
      d=d&(~SS);
   }
   outportb(DATA, d);
}

int get_reading_bcd(void)
{
   int n, reading=0, bit;

   for(n=15; n>=0; n--)
   {
      clock();
      bit = (((inportb(STATUS)^0x80) >> 6) & 0x01);
/*    printf("%d ", bit); */
      reading = reading | (bit <<n);
   }
   return(reading);
}

void clock(void)
{
   delay(10);
   d=d & (~SCLK);
   outportb(DATA, d);  /* SCLK low */
   delay(10);
   d=d | SCLK;        /* SCLK high */
   outportb(DATA, d);
}                                                                            

A Note on Applications of the Compass Bearing Feature.

When I excitedly showed my wife a working model of this, she dutifully acted impressed, but noted, "do you walk around in the woods with that whole big PC?". I responded walking around in the woods is the obvious application. "Rather, think of a 10 elem ent 2 meter amateur radio beam on the car. The compass senses the direction of travel and the beam is rotated using a stepping motor to continue to point the beam to the desired location." I think she left the conversation hoping I didn't have the energ y to mount such an antenna on the family car. I don't, at least not right now.

In many cases control using the parallel port may make sense. But, in many others, the parallel port may simply be a part of the development process. Get the application going on the parallel port, and then map it over to a 68HC11, PIC or a Stamp.

This application uses four outputs and two inputs. (One might be tempted to scrap the EOC input in favor of a sufficient time delay for completion of the conversion). In using the parallel port, there are four other convenient bits on the Data Port and thus the high nybble of the Data Port might be used to control a stepper using a ULN2803 as discussed elsewhere in Volumes 1 and 2.

But, in using the Stamp, there just are not four spare I/O bits. However, the four signal leads used to control the compass may easily be also used to control a stepper if one additional bit is used to enable and disable the stepper.

Compass Bearing using the Basic Stamp BS1-IC.

Figure 2 illustrates the circuitry and COMPASS1.BAS illustrates the code to perform the same function using the Basic Stamp BS1. '

Program COMPASS1.BAS

'
' Basic Stamp BS1-IC interfaced with Vector 2X Compass Module. 
'
' Makes 256 compass bearing measurements at about 5 second intervals. 
'
' Vector 2X is reset, _PC is brought momentarily low, _SS is brought 
' low and 16 bits of data are read.  Lower 10 bits are displayed in 
' hexadecimal.
'
' The bearing is also converted to natural binary and displayed. 
'
' Peter Anderson, MSU, Dec 31, '96

symbol reading=w0
symbol n=b2
symbol m=b3

symbol base_10= w2

symbol RESET=pin3
symbol SCLK=pin2
symbol _SS=pin1
symbol _PC=pin0

symbol EOC=pin7
symbol DATA=pin6

   dirs=%00001111
   pins=%00001111
 
top:
   for n=0 to 255
      RESET=0       ' reset compass module
      pause 10
      RESET=1
      pause 100
      _PC=0         ' _PC brought momentarily low
      pause 10
      _PC=1

      pause 100
      _SS=0         ' slave select brought low
      
scan:
      if EOC=0 then scan      ' wait until conversion is completed 
      gosub get_reading       ' fetch 16 bit reading
      reading=reading & $3ff  ' only the 10 least sig bits       
      debug $reading          ' display result in base 10
    
      gosub convert_base_10   ' converts reading to base 10       
      debug base_10
     
      _SS=1              ' reading done
      pause 500               ' wait for next measurement
   next
   end

get_reading:
' reads each of 16 bits from SDO, most significant bit first    
   reading=0
   for m=0 to 15
      pause 20   ' negative going clock pulses
      SCLK=0
      pause 20
      SCLK=1   ' DATA is read after positive clock
      reading=reading * 2 + DATA  ' shift left and add new bit   
   next
   return 

convert_base_10:
' convert BCD to natural binary   
   base_10 = reading / 256 * 100      ' hundreds
   reading = reading // 256
   base_10 =  reading / 16 * 10 + base_10 ' tens 
   reading = reading // 16
   base_10 = reading + base_10          ' units
   return

Raw Data.

The principle of the compass is to measure the magnitude of the magnetic field in the two sensors which are mounted perpendicular to one another. In determining the bearing, the 2X Compass Module measures the field intensity at each sensor and then does the necessary trigonometric calculations to translate this into a direction.

Precision Navigation thoughtfully provided a means to access this raw data. Note that in Figure #1A, input /RAW was tied to logic one. To obtain the raw data, tie this to logic zero.

The raw data is then fetched as two 16 bit words as illustrated in program COMPASS2.C. Note that I have only shown the main and get_reading_16 in the following as these are the only changes from the COMPASS1.C program.

/*
** Program COMPASS2.C
**
** This program interfaces the parallel port with the 2X Compass Module. **
** Measures raw data on each of the two sensors.
**
** Vance Foster, Peter Anderson, MSU, Dec 28, '96
*/


#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <stdlib.h>
#include <process.h>

#define DATA 0x03bc
#define STATUS DATA+1
#define CONTROL DATA+2

#define RESET 0x08
#define SCLK 0x04
#define SS 0x02
#define PC 0x01

int d=0x00;    /* note this is global */

void reset(void);
void set_ss(int state);
void wink_pc_low(void);
void clock(void);
int get_reading_16(void);

void main(void)
{
   int n, X_reading, Y_reading;
   clrscr();
   reset();
   for(n=0; n<50; n++)  /* make 50 readings */
   {
      d=0x0f;
      outportb(DATA, d); /* initialize at 1 1 1 1 */
      wink_pc_low();     /* bring /PC momentarily low */
      while (((inportb(STATUS)^0x80) >>7) == 0) 
                         /* loop while EOC low */ ;     
      delay(50);
      set_ss(0);
      X_reading = get_reading_16();
      Y_reading = get_reading_16();
      set_ss(1);
      printf("\nX:%d Y:%d\n", X_reading, Y_reading);
      sleep(5);
   }
}

int get_reading_16(void)
{
   int n, reading=0, bit;

   for(n=15; n>=0; n--)
   {
      clock();
      bit = (((inportb(STATUS)^0x80) >> 6) & 0x01);
      printf("%d ", bit);
      reading = reading | (bit << n);
   }
   printf("\n");
   return(reading);
}

The results are interesting. When rotating by 90 degrees, I saw the interchange of magnetic field between the X and Y sensors. In rotating by 180 degrees, the sign of the fields reversed.

I didn't repeat this exercise using the Stamp. However, you should be able to quickly modify program COMPASS1.BAS to make raw data measurements.

Non-obtrusive DC Current Sensor.

I then wondered how well the device would perform as a non-obtrusive DC current detector and built the simple arrangement shown in Figure #3A. Note that I positioned a wire directly above and perpendicular to the X sensor and varied the amount of DC cur rent.

The data is plotted in Figure #3B. Note that the magnetic field is the sum of the earth's magnetic field and the magnetic field caused by the current. Thus, in plotting the data in Figure #3B, the contribution due to the earth's magnetic field was first subtracted. For example, with no current, my reading on the X sensors was -24. This was normalized to 0. At 30 mA, the reading was -3. This was normalized to 21.

Note that this data was obtained using the low resolution option and even then, one can readily detect the field associated with as little as 10 mA..

This capability is worthy of note. In addition to measuring DC current, the Vector 2X Compass Module may well have applications in electromagnetics. My experience in undergraduate education is that students do not like electromagnetics in part because t hey are never shown any applications and this might be an inexpensive tool for various laboratory experiments.

Calibration.

Precision Navigation provides a capability to calibrate the module. Calibration may be necessary if the module is located near iron as would be the case if the unit were mounted in a vehicle. We did not try this.

However, from the data sheet, it appears the following sequence may be used;

1.  RESET=1, SCLK=1, /SS=1, /PC=1, /CAL=1

2.  Reset by momentarily bringing RESET low for a minimum of 10 ms. 

3.  Initiate calibration by momentarily bringing /CAL low for a minimum 
of 10 ms.  This causes the CI output to go high.  Rotate the module 
through 180 degrees. 

4.  Stop the calibration by again momentarily bringing /CAL low for a 
minimum of 10 ms. 

It is worthy of note that this calibration is stored in RAM on the compass module and if power is lost, the calibration is also lost.