HMC6352 Library

HMC6352.cpp

Committer:
richardparker
Date:
2010-04-29
Revision:
2:dc4867624d5a
Parent:
1:1f500fa755c8

File content as of revision 2:dc4867624d5a:

// Copyright 2009 Richard Parker

#include "mbed.h"
#include "HMC6352.h"

// Misc defines.
#define HMC6352_DEFAULT_ADDRESS    0x42

// Masks.
#define HMC6352_OP_MODE_MASK        0x03
#define HMC6352_OP_FREQ_MASK        0x60
#define HMC6352_OP_AUTO_MASK        0x10

// Register addresses.
#define HMC6352_ADDRESS_ADDRESS    0x00
#define HMC6352_XO_MSB_ADDRESS     0x01
#define HMC6352_XO_LSB_ADDRESS     0x02
#define HMC6352_YO_MSB_ADDRESS     0x03
#define HMC6352_YO_LSB_ADDRESS     0x04
#define HMC6352_TIME_DELAY_ADDRESS 0x05
#define HMC6352_SUMMING_ADDRESS    0x06
#define HMC6352_VERSION_ADDRESS    0x07
#define HMC6352_OPERATION_ADDRESS  0x08

#define HMC6352_OUTPUT_REGISTER    0x4E
#define HMC6352_OPERATION_REGISTER 0x74

// Commands for HMC6352.
#define HMC6352_WRITE_EEPROM       0x77 // 'w'
#define HMC6352_READ_EEPROM        0x72 // 'r'
#define HMC6352_WRITE_RAM          0x47 // 'G'
#define HMC6352_READ_RAM           0x67 // 'g'
#define HMC6352_WAKE_UP            0x57 // 'W'
#define HMC6352_SLEEP              0x53 // 'S'
#define HMC6352_RESET              0x4F // 'O'
#define HMC6352_START_CAL          0x43 // 'C'
#define HMC6352_END_CAL            0x45 // 'E'
#define HMC6352_SAVE_OPERATION     0x4C // 'L'
#define HMC6352_RETRIEVE_HEADING   0x41 // 'A'

HMC6352::HMC6352(PinName sda, PinName scl)
:   _i2c(sda, scl),
    _address(HMC6352_DEFAULT_ADDRESS)
{
    // Set the frequency of the transfers in Hz for HMC6352 is 100000 Hz.
    _i2c.frequency(100000);   
}

HMC6352::~HMC6352()
{
}

char HMC6352::getVersion()
{
    // Read the version number of the chip will be above 0x00 if it 
    // is a production chip.
    _readFromMemory(HMC6352_VERSION_ADDRESS, true);  
    return _buffer[0];
}

void HMC6352::setVersion(const char version)
{
    // Write the version number to the chip.
    _writeToMemory(HMC6352_VERSION_ADDRESS, version, true);  
}

char HMC6352::getTimeDelay()
{
    // Read the time delay
    _readFromMemory(HMC6352_TIME_DELAY_ADDRESS, true);  
    return _buffer[0];
}

void HMC6352::setTimeDelay(const char delay)
{
    // Write the time delay to the chip.
    _writeToMemory(HMC6352_TIME_DELAY_ADDRESS, delay, true);  
}

char HMC6352::getSumming()
{
    // Read the number of summing samples.
    _readFromMemory(HMC6352_SUMMING_ADDRESS, true);  
    return _buffer[0];
}

void HMC6352::setSumming(const char samples)
{
    // Write the number of summing samples to the chip.
    _writeToMemory(HMC6352_SUMMING_ADDRESS, samples, true);  
}

float HMC6352::getHeading()
{
    // Send the retrieve heading command.
    _buffer[0] = HMC6352_RETRIEVE_HEADING;
    _i2c.write(this->address(), _buffer, 1);
    // Retrieve takes 6000us.
    wait_us(6000);
    
    // As soon as the rerieve command has been sent read the result read 
    // commands only return 2 bytes.
    _clearBuffer();
    _i2c.read(this->address(), _buffer, 2);
    
    return _bufferToHeading();
}

HMC6352::Mode HMC6352::getMode()
{
    // Read the operation mode.
    _readFromMemory(HMC6352_OPERATION_REGISTER, false);
    
    // Buffer now contains the op mode register, mask to get values.
   int opmode = _buffer[0];
   opmode = opmode & HMC6352_OP_MODE_MASK;
   
   // Convert the value into the mode.
   switch (opmode)
   {
       case 0x0:
           return HMC6352::Standby;
       case 0x1:
           return HMC6352::Query;
       case 0x2:
           return HMC6352::Continuous;
       default:
           return HMC6352::None;
   }
}

void HMC6352::setMode(HMC6352::Mode mode)
{
    _readFromMemory(HMC6352_OPERATION_REGISTER, false);

    switch (mode)
    {
        case HMC6352::Standby:
            _writeToMemory(HMC6352_OPERATION_REGISTER, (_buffer[0] & 0xFC) | 0x0, false);
        break;
        case HMC6352::Query:
            _writeToMemory(HMC6352_OPERATION_REGISTER, (_buffer[0] & 0xFC) | 0x1, false);
        break;
        case HMC6352::Continuous:
            _writeToMemory(HMC6352_OPERATION_REGISTER, (_buffer[0] & 0xFC) | 0x2, false);
        break;
        default:
            return;
    }
}

HMC6352::Output HMC6352::getOutput()
{
    // Read the output mode from RAM
    _readFromMemory(HMC6352_OUTPUT_REGISTER, false);
    
    // Buffer now contains the output register.
   int output = _buffer[0];
   
   // Convert the value into the mode.
   switch (output)
   {
       case 0x0:
           return HMC6352::Heading;
       case 0x1:
           return HMC6352::RawX;
       case 0x2:
           return HMC6352::RawY;
       case 0x3:
           return HMC6352::X;
       case 0x4:
           return HMC6352::Y;
       default:
           return HMC6352::Unknown;
   }
}

void HMC6352::setOutput(HMC6352::Output output)
{
    switch (output)
    {
        case HMC6352::Heading:
            _writeToMemory(HMC6352_OUTPUT_REGISTER, 0x0, false);
        break;
        case HMC6352::RawX:
            _writeToMemory(HMC6352_OUTPUT_REGISTER, 0x1, false);
        break;
        case HMC6352::RawY:
            _writeToMemory(HMC6352_OUTPUT_REGISTER, 0x2, false);
        break;
        case HMC6352::X:
            _writeToMemory(HMC6352_OUTPUT_REGISTER, 0x3, false);
        break;
        case HMC6352::Y:
            _writeToMemory(HMC6352_OUTPUT_REGISTER, 0x4, false);
        break;
        default:
            return;
    }
}

void HMC6352::calibrate(int delay)
{
    startCalibrate();
        
    // Now wait an optimal 20s in which two full turns should be 
    // made of the compass to gather enough data, see page 7 of 
    // the data sheet.
    wait(delay);

    endCalibrate();    
}

void HMC6352::startCalibrate()
{
    // Send the enter calibrate command.
    _buffer[0] = HMC6352_START_CAL;
    _i2c.write(this->address(), _buffer, 1);
    // Enter takes 10us.
    wait_us(10);
}

void HMC6352::endCalibrate()
{
    // Send the exit calibrate command.
    _buffer[0] = HMC6352_END_CAL;
    _i2c.write(this->address(), _buffer, 1);
    // Enter takes 14000us.
    wait_us(14000);  
}

void HMC6352::saveOperation()
{
    // Send the enter calibrate command.
    _buffer[0] = HMC6352_SAVE_OPERATION;
    _i2c.write(this->address(), _buffer, 1);
    // Save takes 125us.
    wait_us(125);  
}

void HMC6352::reset()
{
    // Send the reset command.
    _buffer[0] = HMC6352_RESET;
    _i2c.write(this->address(), _buffer, 1);
    // Reset takes 6000us.
    wait_us(6000);
}

void HMC6352::wakeUp()
{
    // Send the wakeup command.
    _buffer[0] = HMC6352_WAKE_UP;
    _i2c.write(this->address(), _buffer, 1);   
    wait_us(100);
}

void HMC6352::goToSleep()
{
    // Send the reset command.
    _buffer[0] = HMC6352_SLEEP;
    _i2c.write(this->address(), _buffer, 1);   
    wait_us(10);
}

void HMC6352::_readFromMemory(const char address, const bool eeprom)
{
    char command;

    // Decide what the command should be (either read from eeprom or 
    // currently loaded memory).
    if (eeprom == true)
    {
        command = HMC6352_READ_EEPROM;
    } else {
        command = HMC6352_READ_RAM;
    }
    
    // Send the read command to the current address (commands are always 
    // two bytes long).
    _buffer[0] = command;
    _buffer[1] = address;
    _i2c.write(this->address(), _buffer, 2);
    wait_us(70);    
    
    // As soon as the read command has been sent read the result read 
    // commands only return 1 byte.
    _clearBuffer();
    _i2c.read(this->address(), _buffer, 1);
}

void HMC6352::_writeToMemory(const char address, const char data, const bool eeprom)
{
    char command;

    // Decide what the command should be (either write to eeprom or 
    // currently loaded memory).
    if (eeprom == true)
    {
        command = HMC6352_WRITE_EEPROM;
    } else {
        command = HMC6352_WRITE_RAM;
    }
    
    // Send the write data to the current address (commands are always 
    // three bytes long).
    _buffer[0] = command;
    _buffer[1] = address;
    _buffer[2] = data;
    _i2c.write(this->address(), _buffer, 3);   
    wait_us(70);
}

void HMC6352::_clearBuffer()
{
    // Set both buffer bytes to null.
    _buffer[0] = 0x0;
    _buffer[1] = 0x0;
    _buffer[2] = 0x0;
}

float HMC6352::_bufferToHeading()
{
    // The heading is returned as a 16 bit number with the msb in the first 
    // byte and the lsb in the next byte.
    return (((_buffer[0] << 8) + _buffer[1])/10.0);
}