Pages: [1]   Go Down
Author Topic: HMC6352 digital compass - memory / register map?  (Read 690 times)
0 Members and 1 Guest are viewing this topic.
Canada
Offline Offline
Jr. Member
**
Karma: 1
Posts: 81
Frequently Befuddled
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm working with this Honeywell HMC6352 digital compass and I've been trying to find if they list a memory map or register map anywhere but have been coming up with nothing.

The datasheet does list the EEPROM map, and it provides functions for reading (and writing) to RAM, but it does not give a list of RAM addresses. Two addresses are mentioned in the text but nothing beyond those two.

If there's no published information on the memory map, would there be a way to go about poking around and figuring it out?

Would it be safe to just issue read commands to addresses to see what comes back? Eg. read every byte from address 0x00 to 0xff and see what comes back?

I'm looking to learn all the ins and outs of this part but it's about $30 so I don't want to kill it in the process.

Thanks!
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Did quite some tests with the compass and wrote a library for it last year but never had time to finish and test it. Other tasks got priority smiley

disclaimer: This library is BETA, only tested partially and not thoroughly. So no guarantees, use at own risk, all disclaimers apply

besides the EEPROM dump I have several other small test apps. (worked under IDE 22 IIRC).
Code:
//
//    FILE: dumpEEPROM.pde
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: test app HMC6352 library for Arduino
//
// Released to the public domain
//

#include <Wire.h>
#include <hmc6352.h>

hmc6352 Compass(0x21);

void setup()
{
  Serial.begin(115200);
  Serial.println("demo HMC6352: dumpEEPROM");
  Serial.println(HMC_LIB_VERSION);
}

void loop()
{
  Compass.wakeUp();
  Serial.println();
  int x = 0; //Compass.direction();
  Serial.print("DEGREE: ");
  Serial.println(x);

  Serial.println("EEPROM: (decimal values)");
  Serial.print("       I2C ADDRESS: 0x00 :  ");
  Serial.println(Compass.getI2CAddress(), DEC);
  Serial.print(" MAGN X OFFSET MSB: 0x01 :  ");
  Serial.println(Compass.readEEPROM(1), DEC);
  Serial.print(" MAGN X OFFSET LSB: 0x02 :  ");
  Serial.println(Compass.readEEPROM(2), DEC);
  Serial.print(" MAGN Y OFFSET MSB: 0x03 :  ");
  Serial.println(Compass.readEEPROM(3), DEC);
  Serial.print(" MAGN Y OFFSET LSB: 0x04 :  ");
  Serial.println(Compass.readEEPROM(4), DEC);
  Serial.print("        Time Delay: 0x05 :  ");
  Serial.println(Compass.getTimeDelay(), DEC);
  Serial.print("   Measurement Sum: 0x06 :  ");
  Serial.println(Compass.getMeasurementSumming(), DEC);
  Serial.print("  Software Version: 0x07 :  ");
  Serial.println(Compass.readEEPROM(7), DEC);
  Serial.print("   Operation Mode: 0x08 :  ");
  Serial.println(Compass.readEEPROM(8), DEC);

  Serial.println("REGISTERS RAM");
  Serial.print(" Operational Mode Control Byte: 0x74 :  ");
  Serial.println(Compass.readRAM(0x74), BIN);
  Serial.print(" Output Data Mode: 0x4E :  ");
  Serial.println(Compass.getOutputModus(), BIN);

  Compass.sleep();
  delay(1000);
}


hmc6352.h
Code:
//
//    FILE: hmc6352.h
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.03
// PURPOSE: HMC6352 library for Arduino
//
// DETAILS: see cpp file
//
// Released to the public domain
//

//#ifndef hmc6352_h
//#define hmc6352_h

#include "Wprogram.h"

#define HMC_LIB_VERSION "0.1.01"

#define HMC_GET_DATA 0x41
#define HMC_WAKE 0x57
#define HMC_SLEEP 0x53
#define HMC_SAVE_OP_MODE 0x4C
#define HMC_CALLIBRATE_ON 0x43
#define HMC_CALLIBRATE_OFF 0x45
#define HMC_UPDATE_OFFSETS 0x4F
#define HMC_WRITE_RAM 0x47
#define HMC_READ_RAM 0x67
#define HMC_WRITE_EEPROM 0x77
#define HMC_READ_EEPROM 0x72

enum hmcMode { STANDBY=0, QUERY=1, CONT=2, ERROR};

class hmc6352
{
public:
    hmc6352(uint8_t device);

// BASIC CALLS FOR STANDBY MODE
int getHeading(void); // just a merge of ask & read
    int askHeading(void);
    int readHeading(void);

    int wakeUp(void);
    int sleep(void);

// EXPERT CALLS
int factoryReset();

int setOperationalModus(hmcMode m, uint8_t freq, bool periodicReset);
int getOperationalModus();

int setOutputModus(uint8_t om);
int getOutputModus();

int callibrationOn(void);
int callibrationOff(void);

int setI2CAddress(uint8_t address);
int getI2CAddress();

int writeEEPROM(uint8_t address, uint8_t data);
int readEEPROM(uint8_t address);

int writeRAM(uint8_t address, uint8_t data);
int readRAM(uint8_t address);


// NOT TESTED / UNKNOWN
int setTimeDelay(uint8_t msec);
int getTimeDelay();
int setMeasurementSumming(uint8_t ms);
int getMeasurementSumming();
int saveOpMode(void);  
int updateOffsets(void);



  private:
int cmd(uint8_t c);
int readCmd(uint8_t c, uint8_t address);
int writeCmd(uint8_t c, uint8_t address, uint8_t data);

uint8_t _device;
};

//#endif
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

hmc6352.cpp
Code:
//
//    FILE: hmc6352.cpp
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.03
// PURPOSE: HMC6352 library for Arduino
//
// HISTORY:
// 0.1.00 - 2011-04-07 initial version
// 0.1.01 - 2011-04-09 quite a complete redo
// 0.1.02 - 2011-04-12 added timing, fixed a bug
// 0.1.03 - 2011-04-13 fixed small things; added getHeading()
//
// Released to the public domain
//

#include <hmc6352.h>
#include <Wire.h>
#include "WProgram.h"

/* ERROR CODES ALL FUNCTIONS
//
// * twi_writeTo codes (== endTransmission  commands)
//   0 .. OK
//  -1 .. length to long for buffer
//  -2 .. address send, NACK received
//  -3 .. data send, NACK received
//  -4 .. other twi error (lost bus arbitration, bus error, ..)
//
// * requestFrom
// -10 .. not enough values returned
//
// * function calls
//   0 .. OK
// -20 .. error param1
// -21 .. error param2
// -22 .. error param3
//
//
*/

hmc6352::hmc6352(uint8_t device)
{
Wire.begin();
_device = constrain(device, 0x10, 0xF6);
}

int hmc6352::getHeading()
{
int rv = askHeading();
if (rv != 0) return rv;
return readHeading();
}

// Ask the device to make a new reading
int hmc6352::askHeading()
{
int rv = cmd(HMC_GET_DATA);
if (rv != 0) return -rv;   // problem with handshake
delay(6); // see datasheet, p8
return rv;
}

// read the last value from the
int hmc6352::readHeading()
{
int rv = Wire.requestFrom(_device, (uint8_t)2);  // remove ambiguity
if (rv != 2) return -10;
rv = Wire.receive() * 256;  // MSB
rv += Wire.receive();       // LSB
return rv;
}

// wake up from energy saving modus
int hmc6352::wakeUp()
{
int rv =  cmd(HMC_WAKE);
delayMicroseconds(100);
return rv;
}

// go into energy saving modus
int hmc6352::sleep()
{
int rv = cmd(HMC_SLEEP);
delayMicroseconds(10);
return rv;
}

// values obtained from dump
int hmc6352::factoryReset()
{
writeRAM(0x74, 0x50); // is needed !!
writeCmd(HMC_WRITE_EEPROM, 0, 66);
writeCmd(HMC_WRITE_EEPROM, 1, 0);
writeCmd(HMC_WRITE_EEPROM, 2, 0);
writeCmd(HMC_WRITE_EEPROM, 3, 0);
writeCmd(HMC_WRITE_EEPROM, 4, 0);
writeCmd(HMC_WRITE_EEPROM, 5, 1);
writeCmd(HMC_WRITE_EEPROM, 6, 4);
writeCmd(HMC_WRITE_EEPROM, 7, 6);
writeCmd(HMC_WRITE_EEPROM, 8, 0x50);
cmd(HMC_SAVE_OP_MODE);
delayMicroseconds(125);
return 0;
}

// HANDLE WITH CARE - RESTART NECESSARY
// Returns Operational Mode Config Byte
int hmc6352::setOperationalModus(hmcMode m, uint8_t freq, bool periodicReset)
{
byte omcb = 0;  // Operational Mode Control Byte
switch(freq)
{
case 1: break;
case 5: omcb |= 0x20; break;
case 10: omcb |= 0x40; break;
case 20: omcb |= 0x60; break;
default: return -21;
}

if (periodicReset) omcb |= 0x10;

switch(m)
{
case STANDBY: break;  // omcb |= 0x00;
case QUERY: omcb |= 0x01; break;
case CONT: omcb |= 0x02; break;
default: return -20;
}

writeCmd(HMC_WRITE_RAM, 0x74, omcb);
cmd(HMC_SAVE_OP_MODE);
delayMicroseconds(125);
return omcb;
}

// read the Operational Modus as byte from EEPROM
// TODO: split into 3 items
//
int hmc6352::getOperationalModus()
{
// datasheet state that at startup the OM is copied from EEPROM
// and that after writing to RAM a reboot is needed to enable new settings
// my interpretation ==> EEPROM is leading
return readCmd(HMC_READ_RAM, 0x74);
//return readCmd(HMC_READ_EEPROM, 0x08);
}

// Switch between normal heading and raw modes
// default = 0 ==> normal headings
// Note: after a reboot the output modus will be 0 again.
int hmc6352::setOutputModus(uint8_t om)
{
if (om > 4) return -20;
return writeCmd(HMC_WRITE_RAM, 0x4E, om);
}

// Read the output modus from RAM
int hmc6352::getOutputModus()
{
return readCmd(HMC_READ_RAM, 0x4E);
}

// NOT TESTED
int hmc6352::callibrationOn()
{
int rv = cmd(HMC_CALLIBRATE_ON);
delayMicroseconds(10);
return rv;
}

// NOT TESTED
int hmc6352::callibrationOff()
{
int rv = cmd(HMC_CALLIBRATE_OFF);
delay(15);
return rv;
}

// NOT TESTED
int hmc6352::setI2CAddress(uint8_t address)
{
if (address < 0x10 || address > 0xF6 ) return -20;
return writeCmd(HMC_WRITE_EEPROM, 0, address);
}

// returns current I2C address
int hmc6352::getI2CAddress()
{
return readCmd(HMC_READ_EEPROM, 0);
}

// NOT TESTED
// meaning time delay unknown
// therefore removed from lib for now
int hmc6352::setTimeDelay(uint8_t msec)
{
return writeCmd(HMC_WRITE_EEPROM, 5, msec);
}

int hmc6352::getTimeDelay()
{
return readCmd(HMC_READ_EEPROM, 5);
}

// NOT TESTED
// meaning measurement summing unknown
// therefore removed from lib for now
int hmc6352::setMeasurementSumming(uint8_t ms)
{
if (ms > 16 ) ms = 16;
return writeCmd(HMC_WRITE_EEPROM, 6, ms);
}

int hmc6352::getMeasurementSumming()
{
return readCmd(HMC_READ_EEPROM, 6);
}

// Makes only sense in setOperationalModus()
// therefore removed from lib for now
int hmc6352::saveOpMode()
{
int rv = cmd(HMC_SAVE_OP_MODE);
delayMicroseconds(125);
return rv;
}


// NOT TESTED
// meaning UpdateOffsets unknown
// therefore removed from lib for now
int hmc6352::updateOffsets()
{
int rv = cmd(HMC_UPDATE_OFFSETS);
delay(6);
return rv;
}

// idem
// use at own risk ...
int hmc6352::writeEEPROM(uint8_t address, uint8_t data)
{
return writeCmd(HMC_WRITE_EEPROM, address, data);
}

// idem
int hmc6352::readEEPROM(uint8_t address)
{
return readCmd(HMC_READ_EEPROM, address);
}


// idem
// Most RAM locations have an unknown meaning
// use at own risk ...
int hmc6352::writeRAM(uint8_t address, uint8_t data)
{
return writeCmd(HMC_WRITE_RAM, address, data);
}
// idem
int hmc6352::readRAM(uint8_t address)
{
return readCmd(HMC_READ_RAM, address);
}

/* PRIVATE FUNCTIONS
   mostly to remove redundancy in functions above
*/
int hmc6352::cmd(uint8_t c)
{
Wire.beginTransmission(_device);
Wire.send(c);
int rv = Wire.endTransmission();
delay(10);
return rv;
}

int hmc6352::readCmd(uint8_t c, uint8_t address)
{
Wire.beginTransmission(_device);
Wire.send(c);
Wire.send(address);
int rv = Wire.endTransmission();
if (rv != 0) return -rv;

delayMicroseconds(70);

rv = Wire.requestFrom(_device, (uint8_t)1);
if (rv != 1) return -10;
rv = Wire.receive();
return rv;
}

int hmc6352::writeCmd(uint8_t c, uint8_t address, uint8_t data)
{
Wire.beginTransmission(_device);
Wire.send(c);
Wire.send(address);
Wire.send(data);
int rv = Wire.endTransmission();
delayMicroseconds(70);
return rv;
}
« Last Edit: October 26, 2012, 09:55:11 am by robtillaart » Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
//
//    FILE: querymode.pde
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: test app HMC6352 library for Arduino
//
// Released to the public domain
//

#include <Wire.h>
#include <hmc6352.h>

hmc6352 Compass(0x21);

void setup()
{
  Serial.begin(115200);
  Serial.println("demo HMC6352: query mode");
  Serial.println(HMC_LIB_VERSION);
 
  Compass.setOperationalModus(QUERY, 20, false);
 
  Serial.println(Compass.getOperationalModus());
  Compass.direction();  // first time
}

void loop()
{
  int x = Compass.qry();
  Serial.print("DEGREE: ");
  Serial.println(x);

  delay(500);
}
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Canada
Offline Offline
Jr. Member
**
Karma: 1
Posts: 81
Frequently Befuddled
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the info! Your library looks much more thorough than others I've seen and tried.

For your implementation of the RAM read and write functions you have the comment // Most RAM locations have an unknown meaning. Did you actually try dumping all the RAM yourself?

Cheers!
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 211
Posts: 13478
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Thanks for the info! Your library looks much more thorough than others I've seen and tried.
Still, all disclaimers apply smiley-wink
If you find errors / bugs e.g. - http://en.wikipedia.org/wiki/Heisenbug - or improvements let me know so I can include it into the lib.


Quote
For your implementation of the RAM read and write functions you have the comment // Most RAM locations have an unknown meaning. Did you actually try dumping all the RAM yourself?
Yes, but as it was more than a year ago I do not remember details other than those noted in the source code.
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Pages: [1]   Go Up
Jump to: