How do I troubleshoot a BMP085?

I found a couple of code samples for using the BMP085 Barometric Pressure Sensor, the simplest and shortest included below. The code is also available from http://www.tinyclr.com/codeshare/entry/178. My problem is, I can’t get any of the code to work and actually read data from the sensor. In the code below, The following line throws the exception.

if (!MyBMP085.Ok) throw new Exception(“Unable to access the BMP085 sensor”);

In BMP085.CS, line 42 returns from the constructor, resulting in a null BMP085, and causes the above exception.

if (BMP085Device.Execute(xActions, 100) != 23) return;

How do I troubleshoot this sensor? How do I figure out if the sensor is bad? At this point, I’m trying to figure out if it’s my code of if the sensor is bad. This is my first time using this sensor and I only have one so I can’t just swap out the sensor.

I’ve tried some other code from the netduino forums and that didn’t work either, resulting in an exception stating “unable to write to device”.

I’m using the Panda II…

Thanks!


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace BMP085_Sample
{
    public class Program
    {
        public static void Main()
        {
            // Blink board LED

            bool ledState = false;

            OutputPort led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, ledState);

            for (int i = 0; i < 10; i++)
            {
                // Sleep for 500 milliseconds
                Thread.Sleep(100);

                // toggle LED state
                ledState = !ledState;
                led.Write(ledState);
            }

            //Use maximum precision (and maximum power use), auto acquire every 10s
            BMP085 MyBMP085 = new BMP085(Oversampling.Level3, 10);
            if (!MyBMP085.Ok) throw new Exception("Unable to access the BMP085 sensor");
            Thread.Sleep(50); // Wait for Sensor to make measurement

            while (true)
            {
                if (MyBMP085.Ok)    // sensor values where read
                {
                    Debug.Print("BMP085 Temperature=" + MyBMP085.Temperature.ToString("F1") + "°C");
                    Debug.Print("BMP085 Pressure=" + MyBMP085.Pressure + "Pa");
                    Debug.Print("BMP085 Altitude=" + MyBMP085.Altitude + "M.");
                }
                else Debug.Print("Unable to access the BMP085 sensor !");
                Thread.Sleep(10000);
            }
        }
    }
}


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

namespace BMP085_Sample
{
    public enum Oversampling : byte
    {
        None = 0,
        Level1,
        Level2,
        Level3,
    }


    public class BMP085
    {
        private I2CDevice BMP085Device;
        private Int16 AC1, AC2, AC3, B1, B2, MB, MC, MD;
        private UInt16 AC4, AC5, AC6;

        public byte OS;         // 0 = low precision & power to 3 = higher both
        public int Refresh = 60; // seconds between mesures
        public bool Ok = false;         // True if sensor responding
        public float Temperature = 0;   // in Celcius
        public int Pressure = 0;   // in Pa
        public int Altitude = 0;    // in meters

        //0 to 3 : 0 = low precision and low power and 20ms, to 3 = higher both and 40ms, refresh=seconds between capture, if 0 : only manual calls to ReadSensor()
        public BMP085(Oversampling OSS = Oversampling.None, int refresh = 60)
        {
            BMP085Device = new I2CDevice(new I2CDevice.Configuration(0x77, 100));
            // Calibration
            I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[2];
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0xAA });
            byte[] RawData = new byte[22];
            xActions[1] = I2CDevice.CreateReadTransaction(RawData);
            if (BMP085Device.Execute(xActions, 100) != 23) return;
            AC1 = (short)((short)(RawData[0] << 8) + (short)(RawData[1]));
            AC2 = (short)((short)(RawData[2] << 8) + (short)(RawData[3]));
            AC3 = (short)((short)(RawData[4] << 8) + (short)(RawData[5]));
            AC4 = (ushort)((ushort)(RawData[6] << 8) + (ushort)(RawData[7]));
            AC5 = (ushort)((ushort)(RawData[8] << 8) + (ushort)(RawData[9]));
            AC6 = (ushort)((ushort)(RawData[10] << 8) + (ushort)(RawData[11]));
            B1 = (short)((short)(RawData[12] << 8) + (short)(RawData[13]));
            B2 = (short)((short)(RawData[14] << 8) + (short)(RawData[15]));
            MB = (short)((short)(RawData[16] << 8) + (short)(RawData[17]));
            MC = (short)((short)(RawData[18] << 8) + (short)(RawData[19]));
            MD = (short)((short)(RawData[20] << 8) + (short)(RawData[21]));
            if (AC1 * AC2 * AC3 * AC4 * AC5 * AC6 * B1 * B2 * MB * MC * MD == 0) return;
            Ok = true;
            OS = (byte)OSS;
            Refresh = refresh;
            if (refresh > 0) new Thread(Capture).Start();
        }

        private void Capture()
        {
            while (true)
            {
                ReadSensor();
                Thread.Sleep(1000 * Refresh);
            }
        }

        public bool ReadSensor() // Might take up to 40ms to get the data if OS=3 or 10ms if OS=0
        {
            Int32 X1, X2, B5, B6, X3, B3, P, UT, UP;
            UInt32 B4, B7;
            // Temperature
            I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[1];
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0xF4, 0x2E });
            if (BMP085Device.Execute(xActions, 100) != 2) { Ok = false; return false; }
            Thread.Sleep(5);
            I2CDevice.I2CTransaction[] xActions2 = new I2CDevice.I2CTransaction[2];
            xActions2[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0xF6 });
            byte[] RawData = new byte[2];
            xActions2[1] = I2CDevice.CreateReadTransaction(RawData);
            if (BMP085Device.Execute(xActions2, 100) != 3) { Ok = false; return false; }
            UT = (Int32)((Int32)(RawData[0] << 8) + (Int32)(RawData[1]));
            // Pressure
            xActions[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0xF4, (byte)((OS << 6) + 0x34) });
            if (BMP085Device.Execute(xActions, 100) != 2) { Ok = false; return false; }
            Thread.Sleep(OS > 0 ? OS * 10 : 5);
            xActions2[0] = I2CDevice.CreateWriteTransaction(new byte[] { 0xF6 });
            byte[] RawData2 = new byte[3];
            xActions2[1] = I2CDevice.CreateReadTransaction(RawData2);
            if (BMP085Device.Execute(xActions2, 100) != 4) { Ok = false; return false; }
            UP = (((Int32)(RawData2[0]) << 16) + ((Int32)(RawData2[1]) << 8) + (Int32)RawData2[2]) >> (8 - OS);
            // Calculus
            X1 = (UT - AC6) * AC5 >> 15;
            X2 = ((Int32)MC << 11) / (X1 + MD);
            B5 = X1 + X2;
            Temperature = ((float)((B5 + 8) >> 4)) / 10;
            B6 = B5 - 4000;
            X1 = (B2 * (B6 * B6 >> 12)) >> 11;
            X2 = AC2 * B6 >> 11;
            X3 = X1 + X2;
            B3 = ((((Int32)AC1 * 4 + X3) << OS) + 2) >> 2;
            X1 = AC3 * B6 >> 13;
            X2 = (B1 * (B6 * B6 >> 12)) >> 16;
            X3 = ((X1 + X2) + 2) >> 2;
            B4 = AC4 * (UInt32)(X3 + 32768) >> 15;
            B7 = ((UInt32)(UP - B3)) * (UInt32)(50000 >> OS);
            P = (B7 < 0x80000000) ? (Int32)((B7 * 2) / B4) : (Int32)((B7 / B4) * 2);
            X1 = (P >> 8) * (P >> 8);
            X1 = (X1 * 3038) >> 16;
            X2 = (-7357 * P) >> 16;
            Pressure = P + ((X1 + X2 + 3791) >> 4);
            //Altitude
            Altitude = (int)System.Math.Round(44330.75 * (1 - System.Math.Pow((double)Pressure / 101325, 0.19029)));
            Ok = true;
            return true;
        }
    }
}

If you check out the I2C wiki entry, http://wiki.tinyclr.com/index.php?title=I2C_-_EEPROM you will see that the return code essentially says i can’t communicate to the device. So first thing to check is your wiring. (the return code of the I2C Execute command is the # of bytes written, check how many were written and my bet is 0, essentially meaning device not detected)

Okay… so I deployed the same code (minus a change to make the onboard LED work) to my netduino plus. It worked right out of the gate. But, it still doesn’t work on the Panda II.

Is there a way to reset the Panda II ? This is not the first bit of weirdness I’ve encountered in the last couple of days with the Panda. I have a project that has been working for weeks and now it won’t POST updates to my web service. I’m thinking I might want to just “push reset” and see what happens but I’m not sure what’s involved in doing that.

check firmware and SDK version match (or mismatch). Erase firmware and reupload.

I updated the firmware. Now using SDK v1.0.19 and the following is from MFDeploy.

ClrInfo.targetFrameworkVersion:         4.1.2821.0
SolutionReleaseInfo.solutionVersion:    4.1.8.0
SolutionReleaseInfo.solutionVendorInfo: GHI Electronics, LLC
SoftwareVersion.BuildDate:              Dec 22 2011
SoftwareVersion.CompilerVersion:        410561

Unfortunately, the code still doesn’t run on the Panda II. Thoughts?

it’s a wiring issue.

What is the return of the execute command? Step debug. and find out more.

The return value from the sensor is 0.

I verified I have 3.3v to sensor. I have a stable 3.309v to the breakout board so it appears I have continuity and stable power to the sensor.

Inserting a voltage meter in series on the GND shows a voltage of 3.04v +/-.

I checked the solder joints on the BMP085 and wires for continuity. They all look good.

BMP085 —> Panda
SDA is connected to A4.
SCL is connected to A5.
VCC is connected to 3V3
GND is connected to GND

The object returned by the constructor, MyBMP085, has most of its properties set to 0. The following are populated with non-zero values; OK = false, Refresh = 60, BMP085Device.Config.Address = 119, and BMP085Device.Config.ClockRateKhz = 100.

SDA = D2
SCL = D3

not A4/A5.

Thanks for all your help, Brett! Changing the pins solved the problem.

Why did A4 and A5 work on the netduino plus but not on my Panda II ? On the netduino plus, A4 and A5 are labeled 'Analog In". The same pins (name and position on board) on the Panda II are labeled “Analog & Digital”. I’m curious about the “why” and “how” of this solution.

If you use the panda DLL then you have all these pins already defined.

I2C needs specific pullups on the specific I2C pins that each platform uses; I suspect the netduino has I2C pullups installed on different pins.

If you check the Panda II silkscreen, you’ll see they’re labelled SDA and SCL explicitly, along with D2, D3.