.net, Raspberry Pi 3

How to use the CMPS10 tilt compensated compass with C# and the Raspberry Pi 3 with Windows 10 IoT Core

I’m continuing with my series of writing C# code for I2C devices on the Raspberry Pi 3 – this time, I’m showing some code for the CMPS10 tilt compensated compass.

This compass is interesting in a couple of different ways:

  • It gives bearings in a couple of different formats – as a byte (0 – 255 for a full circle), or as a double byte (0 – 3599 for a full circle).
  • Also, this compass can be calibrated.

Getting started

I’ve uploaded my code to GitHub with some sample code on how to use the CMPS10 compass with a Windows 10 UWP app and the Raspberry Pi 3. This uses the Magellanic.I2C NuGet package, which simplifies the code.

Another interesting thing about this device is that the I2C slave address is published as being 0xC0 – which translates to 192 in decimal. I2C devices usually have slave addresses with only 7-bits (a max of 128). I ran the static I2CDiagnostics.DetectI2cDevicesAsync() tool from the Magellanic.I2C package to detect what slave address was identified by the Raspberry Pi 3 – it returned the value 0x60 (which is 96 in decimal), which is what I find to be to slave address that actually works with the Raspberry Pi.

It might be coincidence, but 0xC0 >> 1 = 0x60 (i.e. bit shifted by one place to the right).

Connect the device chip using the following pins:

  • 5v to Pin 4
  • Ground to Pin 6
  • SCL (serial clock) to Pin 5
  • SDA (serial data) to Pin 3

The relevant information returned from the compass device is in register addresses from 0x00 to 0x05. This contains the software version, the bearing information, and the pitch and roll angles. There’s lots more information at this link. I designed a custom class to manage this data.

public class RawCompassData
{
    public RawCompassData(byte[] rawDeviceData)
    {
        this.SoftwareVersion = rawDeviceData[0];
 
        this.BearingAsByte = rawDeviceData[1];
 
        this.BearingAsWord = rawDeviceData[2<< 8 | rawDeviceData[3];
 
        this.PitchAngle = rawDeviceData[4];
 
        this.RollAngle = rawDeviceData[5];
    }
 
    public byte SoftwareVersion { getprivate set; }
 
    public byte BearingAsByte { getprivate set; }
 
    public int BearingAsWord { getprivate set; }
 
    public byte PitchAngle { getprivate set; }
 
    public byte RollAngle { getprivate set; }
}

This easily translates the bytes returned from the device into a useful format.

public RawCompassData GetCompassData()
{
    byte[] readBuffer = new byte[6];    
 
    this.Slave.WriteRead(new byte[] { 0x00 }, readBuffer);
 
    return new RawCompassData(readBuffer);
}

So calling the code (which is available here) is very straightforward.

var compass = new CMPS10();
 
await compass.Initialize();
            
while (true)
{
    var compassData = compass.GetCompassData();
 
    // Writes the bearing in degrees (from 0 - 359.9)
    Debug.WriteLine(((float)compassData.BearingAsWord)/10);
                
    Task.Delay(1000).Wait();
}