HMC6352+TWI = EEEK!! HELP!

I’m trying to interface with a HMC6352 using a mega128 with WinAVR. And I am getting blown away trying to hook this thing up. I don’t have very much experience with TWI, so reading through the mega128 and HMC6352 datasheets trying to understand how to do this is like reading through something in a different language.

If anyone has any experience with this sensor, or with using TWI on the AVR and could give me some tips or point me in the right direction, it’d be greatly appriciated. Thanks!!

I’ve gotten the HMC6352 working on Arduino ATmega168, both using the TWI hardware, and with a software “bit-banging” routine. The HMC6352 does something that defeats some of the software routines, but it is easy to make it work.

The HMC6352 holds the SCL line low when it needs more time, so the TWI master software needs to set the SCL line for input, then wait for the slave to quit holding SCL low and let the pullup resistor do it’s thing before continuing.

You need to have pullup resistors from the SDA line and the SCL line to +Vcc (about 5K is good).

The TWI interaction with the sensor goes like this:

Twi.start();

Twi.sendbyte(0x42); // slave address for HMC6352/WRITE

Twi.sendbyte(0x41); // Get Heading command

Twi.stop();

delay(70); //70 ms delay

Twi.start();

Twi.sendbyte(0x43); //slave address for HMC6352/READ

dhi = Twi.recvbyte(0x01); // high order byte, send ack

dlo = Twi.recvbyte(0x00); // low order byte, no ack for last byte read…

Twi.stop();

There are other modes you can put the HMC6352, this example is the simplest.

I’m happy to share my Twi library, but it is ported to Arduino and will need to be changed. If you want to use the AVR TWI hardware, there is code in AVRLIB that will work without messing around.

D.

Wow thanks a lot!! A friend gave me some TWI init/start functions, and with your help I got it working on the FIRST TRY! Thanks!

Hi, I just got one of these units a bit back and finally got around to interfacing it. I am not getting very good results from it. The measured value seems to be jumping around and there seems to be a lot of noise on it. Also, as I pick up the sensor unit to turn it, the noise increases…

Seems alsmost like a faulty unit? Does anyone have any ideas? Is there a way I can test this to see if its me or the board?

I am using an atmega128.

Hi mooreaa,

My HMC6352 gives very stable heading numbers. If it is sitting on the bench, it stays within a few tenths of a degree. If I rotate it while still sitting flat on the bench, the heading changes smoothly.

The only downside for this sensor is it is really sensitive to tilt, any off-level tilt really affects the heading a lot.

Can you verify that you are getting good I2C transfers? Are you using pullup resistors? I have heard of problems if using only the AVR internal pullups.

Make sure your power supply is stable, and if its on really long leads, add a cap near the sensor.

Also, since its a compass, it’ll be very sensitive to nearby ferrous metals, or worse, magnetic field [like that from a motor].

Cheers,

–David Carne

Hi, I am curious about the properties of this sensor. It is mentioned that any tilt hurts readings, but this is expected since it is a 2axis device, and most of the magnetic component in many areas is downward.

I am also wondering, if you align it with a heading of 0, then turn it exactly 90

degrees, does it read exactly 90? I have been using the 3-axis micromag, and I will normally get results reading 80, but then 180 if I rotate it 90 more degrees. Of course with the 3 axis mag, there is no problem with tilt.

What about indoor readings… I have had a lot of problems taking readings near

anything metal.

I have been told that using a 4 axis mag (imagine axis going through the corners

of a cube) It is possible to correct for iron distortions and have accurate readings

even indoors. Does anyone have information on this? How do you calibrate your

mag?

Thanks

Hi, The HMC has an internal calibration routine you can activate that requires rotating it two full revolutions.

That helps in a lot of cases.

Regarding the 80 degree issue, sounds almost exactly like what I’ve seen when taking a reading too close to something magnetic / ferrous.

Cheers,

–David Carne

I’ve been having problems with the HMC6352 calibration. I can calibrate the IC once, but if I cycle power to the chip, it might lose the calibration data. Has anyone else seen this problem?

Thanks

nutmegzzzz:
I’ve been having problems with the HMC6352 calibration. I can calibrate the IC once, but if I cycle power to the chip, it might lose the calibration data. Has anyone else seen this problem?

Thanks

After the calibration (starts with a “C” command and ends with a “E” command), are you issuing a “L” command to save the operation modes in RAM to the EEPROM?

No I wasn’t doing that, didn’t realize that calibration would be part of the Operation Mode.

This is my code now for the calibration (using CCS PCW) and it seams to be working… Thanks a lot!

i2c_start();

i2c_write(0x42); //talk to compass

i2c_write(0x43); //start calibration

i2c_stop();

delay_ms (20000); //Delay of 20 seconds

i2c_start();

i2c_write(0x42);

i2c_write(0x45);

i2c_stop();

i2c_start();

i2c_write(0x42);

i2c_write(0x4C);

i2c_stop();

“No I wasn’t doing that, didn’t realize that calibration would be part of the Operation Mode”

what u means…u not save the operation mode?..

are your program success and the compass reading accurate?

i’ve make the calibration once,but the compass reading not accurate…i’ve no idea about it…

any can help me…plezz

I am not having any luck with my ATMEGA32 and the HMC6352 compass. It will ACK it’s way all the way through this program, even the read request, but the compass will never write anything to the data bus. I have also tried reading from a RAM register with the same results. Lot’s of ACKs but never any data on the data bus. If anyone has any ideas I would be very grateful.

Russ

#include <util/delay.h>

#include <stdlib.h>

#include <stdio.h>

#include <avr/io.h>

unsigned char read=0x43,write=0x42;

unsigned char recvd_data;

#define Start() TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(0<<TWSTO) //Send START signal

#define Wait() while (!(TWCR & (1<<TWINT))) //Wait for TW hardware to send data

void address_write(unsigned char address)

{

TWDR=address;

TWCR|=(1<<TWINT)|(1<<TWEN);

while(!(TWCR & (1<<TWINT))); //Wait for TWI hardware to do it’s job

while((TWSR & 0xF8)!=0x18); //Wait for address received and ACKed

}

void data_write(unsigned char data)

{

TWDR=data;

TWCR=(1<<TWINT)|(1<<TWEN);

while(!(TWCR & (1<<TWINT))); //Wait for TWI hardware to do it’s job

while((TWSR & 0xF8)!=0x28); //Wait for data received and ACKed

}

void repeat_start(void)

{

TWCR|=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

while(!(TWCR & (1<<TWSTA)));

while((TWSR & 0xF8)!=0x10);

}

void address_read(unsigned char address)

{

TWDR=address;

TWCR|=(1<<TWINT)|(1<<TWEN);

while(!(TWCR & (1<<TWINT)));

while((TWSR & 0xF8)!=0x40);

recvd_data=TWDR;

}

void read_data(void)

{

TWCR=(1<<TWINT)|(1<<TWEN);

while(!(TWCR & (1<<TWINT)));

while((TWSR & 0xF8)!=0x58);

recvd_data=TWDR;

}

int main(){

TWBR = 2; //Set bit rate to 100Khz with 2 Mhz clock prescalar = 0

Start(); //Initialize communication with compass

Wait();

address_write(0x42); //address of compass to command 42 hex

data_write(‘G’); // Write to RAM register

data_write(‘t’); //Op Mode register address

data_write(0x52); //10Hz update rate,periodic set/reset on,continous mode

data_write(0x41); //Get compass data

repeat_start();

address_read(0x43);

}//end of main