HMC6352 Library

Revision:
0:78e66010e47b
Child:
1:1f500fa755c8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HMC6352.cpp	Thu Feb 11 12:18:33 2010 +0000
@@ -0,0 +1,317 @@
+// 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)
+{
+    // Send the enter calibrate command.
+    _buffer[0] = HMC6352_START_CAL;
+    _i2c.write(this->address(), _buffer, 1);
+    // Enter takes 10us.
+    wait_us(10);
+    
+    // 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);
+    
+    // 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);
+}