HMC6352 Library
Diff: HMC6352.cpp
- 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); +}