Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

HMC6343 Tilt Compensated Compass


  • Please log in to reply
16 replies to this topic

#1 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 31 August 2010 - 03:35 PM

Ok - so here's a quick class I wrote to handle reading from a HMC6343 digital tilt compensated compass. It uses I2C (the most annoying bus ever if you ask me). These compasses are very accurate, if a little sensitive to magnetic fields around them unless hard-iron compensated.

Regardless, in case it's useful to someone, go ahead and use it. This is NOT optimized in any way and I'm sure there are more elegant ways of getting it done but it's a start.

// HMC6343 Digital Tilt-Compensated Driver
// Written by Greg Oberfield
// Feel free to use, modify or distribute this code for non-commercial use
// This header must remain intact - if you make changes, please add your name
//
// 2010-08-30: Greg Oberfield: Initial Build

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace HMC6343
{
    public class Compass : IDisposable
    {
        const ushort HMC6343_ADDRESS = 0x32 >> 1;
        const int CLOCK_FREQ = 100;
        const int DELAY = 100;

        //Write buffer
        byte[] headingCommand = new byte[] { 0x50 }; // Read bearing command

        //Read buffer
        private byte[] inBuffer = new byte[6]; // Six bytes, MSB followed by LSB for each heading, pitch and roll

        public float realHeading = 0.0f;
        public float realPitch = 0.0f;
        public float realRoll = 0.0f;

        //Create Read & Write transactions
        I2CDevice compass;
        I2CDevice.I2CTransaction[] bearingTrans;
        I2CDevice.I2CTransaction[] readTrans;

        /// <summary>
        /// Initializes a new instance of the <see cref="HMC6343"/> class.
        /// </summary>
        public Compass()
        {
            Thread.Sleep(500); // As per spec sheet, give the compass 500ms to warm up - doing it here guarantees it
                               // is done only once on object creation
            compass = new I2CDevice(new I2CDevice.Configuration((ushort)HMC6343_ADDRESS, CLOCK_FREQ));
            bearingTrans = new I2CDevice.I2CTransaction[] { I2CDevice.CreateWriteTransaction(headingCommand) };
            readTrans = new I2CDevice.I2CTransaction[] { I2CDevice.CreateReadTransaction(inBuffer) };
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        public void Dispose()
        {
            compass.Dispose();
            bearingTrans = null;
            readTrans = null;
        }

        /// <summary>
        /// Reads heading, pitch and roll and converts to usable degrees.
        /// </summary>
        public void ReadBearings()
        {
            compass.Execute(bearingTrans, DELAY);
            Thread.Sleep(1);  // Give the compass the requested 1ms delay before reading
            compass.Execute(readTrans, DELAY);

            int heading = (int)(((ushort)inBuffer[0]) << 8 | (ushort)inBuffer[1]);
            int pitch = (int)(((ushort)inBuffer[2]) << 8 | (ushort)inBuffer[3]);
            int roll = (int)(((ushort)inBuffer[4]) << 8 | (ushort)inBuffer[5]);
            realHeading = heading / 10.0f;
            realPitch = (float)pitch / 10.0f;
            if (realPitch > 6400)
                realPitch = (realPitch - 6400 - 155);
            realRoll = (float)roll / 10.0f;
            if (realRoll > 6400)
                realRoll = (realRoll - 6400 - 155);
        }

    }
}

Edit: Quick edit to delete some unneeded variables and such

Edited by greg, 31 August 2010 - 04:06 PM.


#2 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 31 August 2010 - 06:44 PM

Chris - as a followup - I'm having trouble with my own code now. This code works flawlessly on the Fez Domino. I made sure I'm not doing anything Fez'ish in the code but when I try to deploy it onto my Netduino I consistently get "An error has occurred: please check your hardware". Resetting the Netduino doesn't help. Erasing doesn't help. I can deploy a little blinky app just fine though (and it works). Any ideas?

#3 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 31 August 2010 - 07:15 PM

greg, Just to verify...this code ran fine on the Netduino--but now you can't run it again? Did you change something and redeploy it? It's quite possible that you've added an assembly specific to another .NET Micro Framework platform or something of the sort. Can you e-mail me a reproducible test case (or post it here) and we can look at it for you? Chris

#4 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 31 August 2010 - 07:19 PM

greg,

Just to verify...this code ran fine on the Netduino--but now you can't run it again?

Did you change something and redeploy it?

It's quite possible that you've added an assembly specific to another .NET Micro Framework platform or something of the sort. Can you e-mail me a reproducible test case (or post it here) and we can look at it for you?

Chris


Sure - btu I actually created a brand new Netduino project then just added the class file so it's a plain vanilla solution.

I'll post the entire solution (see attached).

Attached Files



#5 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 31 August 2010 - 07:29 PM

Sure - btu I actually created a brand new Netduino project then just added the class file so it's a plain vanilla solution.

I'll post the entire solution (see attached).


greg,

For some reason your project is set to deploy to transport "USB" and device "". Go into the project deployment settings (Project Properties > .NET Micro Framework) and change transport type to SERIAL and then back to USB--and then close that tab in Visual Studio. This will force Visual Studio to save the setting.

Does that fix things for you?

Chris

#6 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 31 August 2010 - 07:36 PM

greg,

For some reason your project is set to deploy to transport "USB" and device "". Go into the project deployment settings (Project Properties > .NET Micro Framework) and change transport type to SERIAL and then back to USB--and then close that tab in Visual Studio. This will force Visual Studio to save the setting.

Does that fix things for you?

Chris


That fixed it. Weird - I checked to make sure it was set to USB and showed "Netduino_Netduino" in the device and it had - but I didn't change the property to serial and back again.

#7 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 31 August 2010 - 07:42 PM

Chris, So it all deploys but the Netduino gets no reading back from the HMC6343 but the Domino reads it just fine. I'm assuming that I don't need to do anything special to Analog pins 4 & 5 to support the I2C bus, right? I've got SDA in A4 and SCL in A5.

#8 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 01 September 2010 - 02:48 AM

So considering the code works fine on the Domino and now deploys properly to the Netduino it should "just work" right - assuming that I've wired SDA and SCL properly since the Netduino uses A4 and A5 and the Fez uses D2 and D3.

#9 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 01 September 2010 - 02:51 AM

So considering the code works fine on the Domino and now deploys properly to the Netduino it should "just work" right - assuming that I've wired SDA and SCL properly since the Netduino uses A4 and A5 and the Fez uses D2 and D3.


Do you have a set of pull-up resistors wired in your I2C circuit?

Both Arduino and Netduino use external pull-up resistors (so that you're not limited to 3.3V vs. 5V or a certain number of I2C devices).

Chris

#10 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 01 September 2010 - 03:06 AM

Do you have a set of pull-up resistors wired in your I2C circuit?

Both Arduino and Netduino use external pull-up resistors (so that you're not limited to 3.3V vs. 5V or a certain number of I2C devices).

Chris


External, no - guess I'll throw a couple in. Ah - that would explain it - the Domino has I2C on the digital with internal pullup. Duh. I'll wire a couple in and let you know but I bet that's it.

I'll figure this electronics crap out sooner or later.

#11 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 15 September 2010 - 07:49 PM

So considering the code works fine on the Domino and now deploys properly to the Netduino it should "just work" right

Greg, have you managed to get the I2C code working on Netduino? I am now playing with a different I2C device and I too cannot get reading back from it - I may have an idea, why it does not work, but I would like to have some confirmation first.

#12 greg

greg

    Advanced Member

  • Members
  • PipPipPip
  • 169 posts
  • LocationChicago, IL

Posted 15 September 2010 - 10:51 PM

Greg, have you managed to get the I2C code working on Netduino? I am now playing with a different I2C device and I too cannot get reading back from it - I may have an idea, why it does not work, but I would like to have some confirmation first.


No - I tried with a 4.7k resistor as a pullup but no dice - I'm sure I'm doing something stupid somewhere.

#13 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 16 September 2010 - 06:16 AM

No - I tried with a 4.7k resistor as a pullup but no dice - I'm sure I'm doing something stupid somewhere.

Well, it seems the problem on Netduino is caused by missing support for repeated start bit during I2C communication. Unfortunately, I don't have HMC6343 to verify that, but my device Melexis MLX90614 IR Thermometer does not acknowledge the second read transaction (I use the same write address read buffer transaction sequence). I have found in the firmware source code that repeated start bit functionality is not implemented for AT91 family (see AT91__I2C.cpp), because "At91 I2C do not support repeated start". Fortunately, this is not completely true (more below), but it explains why the I2C communication fails on Netduino while it works correctly on FEZ boards - the feature is implemented in their firmware, as the NXP LPC microprocessors support it.

Repeated start bit on AT91SAM7X: As stated in the official datasheet (pdf), the repeated start bit is supported only in Master Receiver mode when internal addressing (IADR) is used (p.281). This means that the "write address read buffer" transactions has to be replaced with a single "read buffer with IADR=address" transaction, which issues the repeated start bit (p. 286).

I will look at the firmware source to see how hard it would be to fix this, either by modifying the existing code or adding a new transaction type; I am going to create a new ticked on .NET MF CodePlex Issue Tracker if it appears to be too complex.

#14 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 16 September 2010 - 06:53 AM

CW2, The I2C drivers for the Atmel chips are new in .NET MF 4.1. If there's a possible I2C improvement in the Atmel drivers, we'd be happy to help champion the cause... Chris

#15 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 16 September 2010 - 09:36 PM

The I2C drivers for the Atmel chips are new in .NET MF 4.1. If there's a possible I2C improvement in the Atmel drivers, we'd be happy to help champion the cause...

This would be really great, thanks Chris. I have successfully hacked the I2C driver to get the temperature reading from Melexis sensor, I have published my findings and some ideas in I2C Driver Improvement post.

#16 Spike

Spike

    Member

  • Members
  • PipPip
  • 24 posts

Posted 26 September 2010 - 08:58 PM

So is this the case will all I2C devices? As I am having trouble reading from a an I2C device and wonder if this might be the problem, before I dig any deeper into it.

#17 DrJaymz

DrJaymz

    Advanced Member

  • Members
  • PipPipPip
  • 42 posts

Posted 30 December 2011 - 02:40 PM

Has anyone got this working yet? I am using a Melexis MLX90614 IR Thermometer and I cannot get it to respond to a read from 0x07. I don't understand what the internal address register and size fields mean in this context. I have other devices on the I2C bus responding correctly, and I have pullups etc. I just cannot get a bean out of the MLX90614. I'm running 4.2.0.0 RC3. With the other devices I wrote to the device telling it what I wanted then do a read. Can I do only a read transaction? I'm about to give up on this.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.