Altimeter, the bug hunt

The PCB is ready, and so is the code —almost—, but as…

Computers are good at following instructions, but not at reading your mind —Donald Knuth.

… now it’s time for debugging. Is there a problem, officer? I’m afraid so; the PIC18LF14K50 does not support in-chip debugging. So I have two alternatives:

  1. Print out the variables I want to check.
  2. Test the code on a PIC18F4520.

So far I evaluated the two approaches with similar results.

Figure 1. The BMP085 barometric pressure sensor, a RF module, a protoboard and the mighty PIC18F4520

Figure 1. The BMP085 barometric pressure sensor, a RF module, a protoboard and the mighty PIC18F4520 for debugging purposes.

The first thing I noticed was that the sensor’s address was not the correct one. I was using the libraries from Adafruit, slightly modified to adjust the code for using it in Microchip’s C18 compiler —I think software engineers call that refactoring. The Adafruit library defines the sensor’s address as


#define BMP085_I2CADDR 0x77

and that is one I took for granted. But there was something wrong because I was always getting 0xFFFF when reading from the sensor. And that’s not good. I haven’t looked into the Wire.h library to see how it works, but I am guessing that it gets the 7 bits of the address and adds and eighth bit for write/read. Why? Because the my code is essentially the same…

Adafruit’s piece of code:


uint16_t Adafruit_BMP085::read16(uint8_t a) {
uint16_t ret;

Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
#if (ARDUINO >= 100)
Wire.write(a); // sends register address to read from
#else
Wire.send(a); // sends register address to read from
#endif
Wire.endTransmission(); // end transmission

Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read
#if (ARDUINO >= 100)
ret = Wire.read(); // receive DATA
ret <<= 8;
ret |= Wire.read(); // receive DATA
#else
ret = Wire.receive(); // receive DATA
ret <<= 8;
ret |= Wire.receive(); // receive DATA
#endif
Wire.endTransmission(); // end transmission

return ret;
}

Refactored code:


unsigned int read16(unsigned char a) {
unsigned char string[2];
unsigned int ret;

StartI2C();
WriteI2C(BMP085_I2CADDR);
WriteI2C(a);
RestartI2C();
WriteI2C(BMP085_I2CADDR|0x01);
getsI2C(string,2);
NotAckI2C();
StopI2C();
ret = (string[0]<<8) + string[1];

return ret;
}

… and besause it was quite odd to check —by looking for in the datasheet— that the sensor’s actual address is 0xEF (read) and 0xEE (write). If we look at the numbers,


0x77 == 0111 0111
0xEE == 1110 1110 == 0x77<<1
0xEF == 1110 1111 == (0x77<<1) + 1

we can see that, effectively, my suspicions were right. My fault.

That’s one problem solved. The next one is that I am getting pressure readings of the order of 710 hPa at sea level —that’s equivalent to about 2200 m. The BMP085 requires a lot of bit shift operations to get from readings —raw values— to true pressure and true temperature; and I think that the C18 compiler does not get all along very well with it. But that’s work for tomorrow.