Go Down

Topic: [SOLVED] Writing to specific register of I2C device (Read 1 time) previous topic - next topic

cjdavies

Aug 07, 2012, 01:48 pm Last Edit: Aug 07, 2012, 06:09 pm by cjdavies Reason: 1
How does one specify a particular register of an I2C device to write to?

I have an HMC6343 tilt-compensated magnetometer & a number of its features require me to write values to specific registers (eg to alter the variation angle you write to registers 0x0D & 0x0C). But how do I do this with the Wire library? The documentation for Wire doesn't mention anything about this.

PaulS

Quote
I have an HMC6343 tilt-compensated magnetometer

23 posts and still no link.

Quote
a number of its features require me to write values to specific registers (eg to alter the variation angle you write to registers 0x0D & 0x0C).

You write what to these registers? What command causes it to know that the data is for a specific register?

Quote
The documentation for Wire doesn't mention anything about this.

Of course not, because WHAT to send depends entirely on what you are sending data to.

cjdavies


What command causes it to know that the data is for a specific register?

This was precisely my question. I've worked it out now, after re-reading the datasheet for the HMC6343 again. Turns out you send 0xF1 (which the HMC6343 interprets as the 'Write to EEPROM' command), followed by the address of the register you want to write, followed by the data you want to write to it.

I presume this is pretty standard fair for I2C devices & it would be nice if the Arduino.cc page on the Wire library had a bit more explanation - atm it doesn't really say anything that isn't obvious from the method names & I would be surprised if writing to specific registers of I2C devices wasn't a very common requirement for people using the Wire library.

PaulS

Quote
I would be surprised if writing to specific registers of I2C devices wasn't a very common requirement for people using the Wire library.

It might be, but so is the need to understand what Wire is doing, and what Wire is communicating with.

The Wire documentation could be expanded a thousand-fold, and still wouldn't cover half the devices that I2C can be used to communicate with.

cjdavies


Quote
I would be surprised if writing to specific registers of I2C devices wasn't a very common requirement for people using the Wire library.

The Wire documentation could be expanded a thousand-fold, and still wouldn't cover half the devices that I2C can be used to communicate with.

I wouldn't expect the Wire doc to cover specific devices, but I would expect it to at least cover some of the most common functionality of the I2C paradigm.

Anyway, in case Googlers come across this thread, here's some example code that sets some registers to do useful things;
Code: [Select]
#include <Wire.h>

#define HMC6343_ADDRESS 0x19

//==================================================================================== 
void setup() {
  Wire.begin();
  Serial.begin(115200);
 
  /*
   * Set the 'variation angle correction' (magnetic declination), see p8 in datasheet.
   * At the cathedral in St Andrews on 07/08/2012 this was 3 degrees 16 seconds West
   * which is -3.2667 decimal degrees, or -33 tenths of a degree, so MSB/LSB in two's
   * complement is 11111111/11011111. This is written to EEPROM so technically doesn't
   * need to be done every time if the device isn't moving to a drastically new
   * location inbetween use.
   */
  byte deviationMSB = B11111111;
  Wire.beginTransmission(HMC6343_ADDRESS);
  Wire.write(0xF1);                          // 'Write to EEPROM' command
  Wire.write(0x0D);                          // EEPROM address of deviation angle MSB
  Wire.write(deviationMSB);
  Wire.endTransmission();
 
  byte deviationLSB = B11011111;
  Wire.beginTransmission(HMC6343_ADDRESS);
  Wire.write(0xF1);
  Wire.write(0x0C);                          // EEPROM address of deviation angle LSB
  Wire.write(deviationLSB);
  Wire.endTransmission();
 
  /*
   * Set the measurement rate to 10Hz (0x02) from default of 5Hz (0x01).
   * Again this is EEPROM so shouldn't need re-doing unless it is explicitly reset
   * at some point.
   */
  Wire.beginTransmission(HMC6343_ADDRESS);
  Wire.write(0xF1);
  Wire.write(0x05);                        // EEPROM address of Operational Mode Register 2
  Wire.write(0x02);                        // (OM2_1 = 1 && OM2_0 = 0) == 10Hz operation
  Wire.endTransmission();
   
  /*
   * Set the Heading Infinite Impulse Response (IIR) filter from its default of 0
   * to something a bit more than 0. Again, this is EEPROM so shouldn't need re-doing
   * unless it is explicitly reset at some point.
   */
  Wire.beginTransmission(HMC6343_ADDRESS);
  Wire.write(0xF1);
  Wire.write(0x14);                        // EEPROM address of the Heading IIR filter LSB
  Wire.write(0x00);                        // 0 is no filtering, 15 is filtered with 15 previous readings
  Wire.endTransmission();
   
  /*
   * Set the HMC6343 to 'upright front' orientation. This is temporary, but can be
   * written to an EEPROM register if required.
   */
  Wire.beginTransmission(HMC6343_ADDRESS);
  Wire.write(0x74);
  Wire.endTransmission();
 
}
//==================================================================================== 
void loop() {
 
  /*
   * Set the HMC6343 to return the information that we want (HeadMSB, HeadLSB,
   * PitchMSB, PitchLSB, RollMSB, RollLSB).
   */
  Wire.beginTransmission(HMC6343_ADDRESS);
  Wire.write(0x50);                        // Command to return the data we want
  Wire.endTransmission();
 
  byte MSByte, LSByte;
 
  Wire.requestFrom(HMC6343_ADDRESS, 6);  // request 6 bytes (see command 0x50)
  while(Wire.available() < 1);           // busy wait while no bytes to receive
 
  MSByte = Wire.read();
  LSByte = Wire.read();
  float heading = ((MSByte << 8) + LSByte) / 10.0; // the heading in degrees
 
  MSByte = Wire.read();
  LSByte = Wire.read();
  float pitch = ((MSByte << 8) + LSByte) / 10.0;   // the pitch in degrees
 
  MSByte = Wire.read();
  LSByte = Wire.read();
  float roll = ((MSByte << 8) + LSByte) / 10.0;     // the roll in degrees
 
  Serial.print(heading);
  Serial.print(" ");
  Serial.print(pitch);
  Serial.print(" ");
  Serial.println(roll);
 
  delay(100);
}
//==================================================================================== 

Go Up