Compass HMC6352 in Continous Mode anyone who got it working?

I have not seen anyone who has got the HMC6352 to work in continous mode.

Getting it to run in in Query Mode where you first initiate a reading with the "A" command was fairly easy.
(After some initial TWI issues)

I try to initiate the compass as follows:

Wire.beginTransmission(COMPASS_1_WRITE_ADDRESS);
Wire.send(CMD_WRITE_TO_RAM_REGISTER);
Wire.send(RAM_ADRESS_OPERATIONAL_MODE);
Wire.send(CMD_CONTINOUS_10HZ_NORES);
Wire.endTransmission();

with the following defines:
#define COMPASS_1_WRITE_ADDRESS 0x21
#define COMPASS_1_READ_ADDRESS 0x21
#define CMD_WRITE_TO_RAM_REGISTER 'G'
#define CMD_CONTINOUS_20HZ 0x72
#define CMD_CONTINOUS_10HZ 0x52
#define CMD_CONTINOUS_10HZ_NORES 0x42
#define RAM_ADRESS_OPERATIONAL_MODE 0x74

Anyone who can share code working for continous mode?
thanks/Fred

PLease post your whole code so people with such a sensor can help.
and please use the # button to tag code appropiate.

Here comes the code.

Again...Getting my data by sending "A" and then ask for the result works fine.
Now I just want to step it up a bit and let the compass sample so all I have to do is ask for the result.
The idea is to have a compass sending data via the Arduino 2560 board autonomously on Serial1 which goes to my PC. On the PC I run my robot SW which is done in C#.
(I know .... probably overkill to have the 2560 to do this simple task but thats how it is done today :slight_smile: )

#include <avr/io.h>
#include <MsTimer2.h>
#include <Wire.h>

//General 
#define __AVR_ATmega2560__
#define F_CPU 16000000UL
#define UBRR1H  // Used for Serial1 routines

//COMPASS 
#define COMPASS_1_WRITE_ADDRESS 0x21 // The addess is normally 0x42 but shifted >> 1 to get right format for wire lib
#define COMPASS_1_READ_ADDRESS 0x21   // The addess is normally 0x43 bin 0100 0011 but shifted >> 1 -> 0010 0001 also 0x21 ???? to get right format for wire lib
#define CMD_WRITE_TO_EEPROM     			  'w'
#define CMD_READ_FROM_EEPROM     			  'r'
#define CMD_WRITE_TO_RAM_REGISTER			  'G'
#define CMD_READ_FROM_RAM_REGISTER            'g'
#define CMD_ENTER_SLEEP_MODE     			  'S'
#define CMD_EXIT_SLEEP_MODE     			  'W'
#define CMD_UPDATE_BRIDGE_OFFSETS			  'O'
#define CMD_ENTER_USER_CALIBRATION_MODE	      'C'
#define CMD_EXIT_USER_CALIBRATION_MODE        'E'
#define CMD_SAVE_OP_MODE_TO_EEPROM            'L'
#define CMD_GET_DATA_COMPENSATE_AND_CALCULATE_NEW_HEADING  'A'
#define CMD_CONTINOUS_20HZ 0x72
#define CMD_CONTINOUS_10HZ 0x52
#define CMD_CONTINOUS_10HZ_NORES 0x42

#define RAM_ADRESS_OPERATIONAL_MODE     0x7F //0x74
#define RAM_ADRESS_OUTPUT_MODE          0x4E

//OPERATIONAL_MODE = MEASUREMENT_RATE || OP_MODE
const byte MEASUREMENT_RATE_1HZ   = 0x00;
const byte MEASUREMENT_RATE_5HZ   = 0x20;
const byte MEASUREMENT_RATE_10HZ  = 0x40;
const byte MEASUREMENT_RATE_20HZ  = 0x60;

const byte PERIOD_RESET_SET_ON     = 0x10;
const byte PERIOD_RESET_SET_OFF    = 0x00;

const byte OP_MODE_STANDBY         = 0x00;
const byte OP_MODE_QUERY           = 0x01;
const byte OP_MODE_CONTINUOUS      = 0x02;
const byte OP_MODE_NOT_ALLOWED     = 0x03;


#define MAX_NO_OF_READINGS_IN_FILTER  50

// GLOBAL VARIABLES
static boolean COMPASSTIME,COMPASSDATAVALID;
unsigned int GlobCompassData[4]={0x55,00,00,00}; //Startbyte always 55 , 2 data bytes and a checksum is added when data is read.

// Init Compass1 to a mode where it sends data at TBDHz
void InitCompass1()
{
  
 Wire.beginTransmission(COMPASS_1_WRITE_ADDRESS); 
 Wire.send(CMD_WRITE_TO_RAM_REGISTER);            
 Wire.send(RAM_ADRESS_OPERATIONAL_MODE);			

//Only one of the two below is used
  Wire.send(CMD_CONTINOUS_10HZ_NORES);					
//  Wire.send(MEASUREMENT_RATE_1HZ || PERIOD_RESET_SET_ON || OP_MODE_CONTINUOUS);


  Wire.endTransmission();
}

void GetCompass1Dir()
{

byte val = 0;
byte data[2];
int deg, j, frac, compassdatavalid, checksum;

 
  //Wire.beginTransmission(COMPASS_1_WRITE_ADDRESS);
  //Wire.send(CMD_GET_DATA_COMPENSATE_AND_CALCULATE_NEW_HEADING);
  //Wire.endTransmission();
  //delay(70);

  Wire.requestFrom(COMPASS_1_READ_ADDRESS, 2);
  j = 0;
  COMPASSDATAVALID=false;
  while(Wire.available())
  {
	char c = Wire.receive();
    Serial.println(c,HEX);
    data[j] = c;
    GlobCompassData[j+1]=c;
    j++;
    COMPASSDATAVALID=true;
	}
  Wire.endTransmission();
  Serial.print("Total Byte count");
    Serial.println(j,HEX);
// ADD checksum at the end
checksum = GlobCompassData[0];
for(j = 1; j < 3; j++){
   checksum ^= GlobCompassData[j];
}
GlobCompassData[3]=checksum;
  
  
  if (COMPASSDATAVALID)
  {
    Serial.print(" DataByte One: ");
	Serial.print(GlobCompassData[1], HEX);
	Serial.print("    DataByte two: ");
	Serial.println(GlobCompassData[2], HEX);
    Serial.print(" heading = ");
	frac = data[0]*256 + data[1];
	deg = frac / 10;
	frac = frac - deg * 10;
	Serial.print(deg);
	Serial.print(".");
	Serial.println(frac);
  }
  else
  {
	Serial.println("NO DATA RECIEVED");
  }
}

// Timer2int called at 10HZ
void Timer2interrupt() 
{
  static boolean output = HIGH;
  digitalWrite(13, output);
  output = !output;
  COMPASSTIME=true;   
}

void setup() 
{
  
  pinMode(13, OUTPUT);
  MsTimer2::set(500,Timer2interrupt); // 200ms period gives a call at 2Hz to get the compass direction. The compass is internally sampled at 10Hz and average
  MsTimer2::start();
  Serial.begin(19200);
  Serial1.begin(19200);
  Wire.begin();
  delay(100);
  InitCompass1;			// Set up the compass for automode  
  
}

void loop() 
{
   if (COMPASSTIME)
   {
     GetCompass1Dir();
     Serial1.print("Compass data: Command Byte:");
     Serial1.print(GlobCompassData[0], HEX);
     Serial1.print("  First Byte: ");
     Serial1.print(GlobCompassData[1], HEX);
     Serial1.print("  Second Byte: ");
     Serial1.print(GlobCompassData[2], HEX);
     Serial1.print("   Checksum:");
     Serial1.println(GlobCompassData[3], HEX);
	COMPASSTIME=false;    
   }
}

Last Edit ..jus removed some swedish out of the code...

Thats a lot of code (even without the Swedish :slight_smile:

A quick scan revealed in setup():

InitCompass1;

that should be

InitCompass1();

as it is a function call.

If you press CTRL-T in the IDE the autoformatter re-indents the code, makes it more readable (for me)

Well... I just gave up on this.
I have looked at the oscillsocope screen over and over and cannot figure out why I cant read out the values after initiating the compass.
I am starting to believe that I must write som more commands when initating the compass.....but I have no idea which...

Instead I am now using my oscilloscope to trim and run the Command "A" and read data at 20Hz.
Then I will do the Low Pass filtering on my PC instead.....

Simple ....Yes.... but it works :slight_smile:
/Fred

Well... I just gave up on this.
I have looked at the oscillsocope screen over and over and cannot figure out why I cant read out the values after initiating the compass.

Did you read robtillart's comment about the compass not being intialised?
I think your test program is too complicated - I'd simplify, forget the timer.

This is how I got mine to work when I first got it.

#include <Wire.h>
int HMC6352Address = 0x42;
// This is calculated in the setup() function
int slaveAddress;
int ledPin = 13;
boolean ledState = false;
byte headingData[2];
int i, headingValue;
void setup()
{
// Shift the device's documented slave address (0x42) 1 bit right
// This compensates for how the TWI library only wants the
// 7 most significant bits (with the high bit padded with 0)
slaveAddress = HMC6352Address >> 1;   // This results in 0x21 as the address to pass to TWI
Serial.begin(57600);
pinMode(ledPin, OUTPUT);      // Set the LED pin as output
Wire.begin();
}
void loop()
{
  // Flash the LED on pin 13 just to show that something is happening
  // Also serves as an indication that we're not "stuck" waiting for TWI data
  ledState = !ledState;
  if (ledState) {
    digitalWrite(ledPin,HIGH);
  }
  else
  {
    digitalWrite(ledPin,LOW);
  }
  // Send a "A" command to the HMC6352
  // This requests the current heading data
  Wire.beginTransmission(slaveAddress);
  Wire.send("A");              // The "Get Data" command
  Wire.endTransmission();
  delay(10);                   // The HMC6352 needs at least a 70us (microsecond) delay
  // after this command.  Using 10ms just makes it safe
  // Read the 2 heading bytes, MSB first
  // The resulting 16bit word is the compass heading in 10th's of a degree
  // For example: a heading of 1345 would be 134.5 degrees
  Wire.requestFrom(slaveAddress, 2);        // Request the 2 byte heading (MSB comes first)
  i = 0;
  while(Wire.available() && i < 2)
  { 
    headingData[i] = Wire.receive();
    i++;
  }
  headingValue = headingData[0]*256 + headingData[1];  // Put the MSB and LSB together
  Serial.print("Current heading: ");
  Serial.print(int (headingValue / 10));     // The whole number part of the heading
  Serial.print(".");
  Serial.print(int (headingValue % 10));     // The fractional part of the heading
  Serial.println(" degrees");
  delay(500);
}

Basically it's just the example code modified to work on a mega.

Then I got my RTC, MPL115A1, SparkFun huge LCD with serial back pack.
I added a keypad as well, but the finished unit probably wont use it.
It works but the big LCD is proving to be a hassle to house/mount.

Imgur
Imgur
Imgur

If you have a look at the LCD closely you can see the barometer output is bogus! It wasn't hooked up.

How the hell do I put photo's here or circuits or drawings?

tricorder_V1.pde (15.7 KB)

use the button under the italic button to get [ img] and [ /img] tags (without spaces) and

place the URL to the image in between. The URL must end with a real image file I guess, that could cause the flickr files to fail.

@Fred
Got my hmc6352 sensor last week, wrote a library for it which is still in Beta. Also made a simple config sketch to set modes and do a EEPROM dump etc. However when put the hmc in continuous mode it "got mad" values in EEPROM and RAM completely made no sense anymore and I could not reset it for two days. It was working in continuous mode as I could get (uncallibrated) readings at 20 times per second.

I finally got it back to standby mode by a separate sketch that kept on writing to EEPROM the right value and then I pulled the 5V plug.

If you are interested in a "continuous" experiment please send me a PM than I will mail the BETA version. I have to do more tests before publishing the library (but some other projects scream for attention :slight_smile: Let me know.

Do you know that that sensor is a 3.3v part do you?

From datatsheet - Low Voltage Operation (2.7 to 5.2V) - so the Arduino 5V should not harm it ...