bmp180 reading of values

Discussion about Z-Uno product. Visit http://z-uno.z-wave.me for more details.
A.Harrenberg
Posts: 201
Joined: 05 Sep 2016 22:27

Re: bmp180 reading of values

Post by A.Harrenberg »

Hi,

I think I found the problem... :idea:

The library tries to read two registers at once performing a "read16()", but the chip seems not to support that. The second register ist always return as 0xff.

I figured that out when I analyzed the data without oversampling, there the lsb was always 0xff. When using ultrahighres oversampling (default) then there is a shift with 3 bits that makes it difficult to see that directly...

The same applies to the reading for the temperature (which had in my case a resolution of approx. 1C).

I have replaced the read16() with two read8() commands and some additional shifting and will test it further. If anyone would like to test it also, the changed ZUNO_BMP180.cpp is below.

Regards,
Andreas.

Code: Select all

/*************************************************** 
  This is a library for the Adafruit BMP085/BMP180 Barometric Pressure + Temp sensor

  Designed specifically to work with the Adafruit BMP085 or BMP180 Breakout 
  ----> http://www.adafruit.com/products/391
  ----> http://www.adafruit.com/products/1603

  These displays use I2C to communicate, 2 pins are required to  
  interface
  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include "ZUNO_BMP180.h"
#include "Wire.h"


//#define BMP085_DEBUG 1


#define _delay_ms(d) delay(d)

ZUNO_BMP180::ZUNO_BMP180() {
}


boolean ZUNO_BMP180::begin(uint8_t mode) {
  if (mode > BMP085_ULTRAHIGHRES) 
    mode = BMP085_ULTRAHIGHRES;
  oversampling = mode;

  Wire.begin();

  if (read8(0xD0) != 0x55) return false;

  /* read calibration data */
  ac1 = read16(BMP085_CAL_AC1);
  ac2 = read16(BMP085_CAL_AC2);
  ac3 = read16(BMP085_CAL_AC3);
  ac4 = read16(BMP085_CAL_AC4);
  ac5 = read16(BMP085_CAL_AC5);
  ac6 = read16(BMP085_CAL_AC6);

  b1 = read16(BMP085_CAL_B1);
  b2 = read16(BMP085_CAL_B2);

  mb = read16(BMP085_CAL_MB);
  mc = read16(BMP085_CAL_MC);
  md = read16(BMP085_CAL_MD);

}
void     ZUNO_BMP180::dumpInternal()
{
  Serial.print("ac1 = "); Serial.println(ac1, DEC);
  Serial.print("ac2 = "); Serial.println(ac2, DEC);
  Serial.print("ac3 = "); Serial.println(ac3, DEC);
  Serial.print("ac4 = "); Serial.println(ac4, DEC);
  Serial.print("ac5 = "); Serial.println(ac5, DEC);
  Serial.print("ac6 = "); Serial.println(ac6, DEC);

  Serial.print("b1 = "); Serial.println(b1, DEC);
  Serial.print("b2 = "); Serial.println(b2, DEC);

  Serial.print("mb = "); Serial.println(mb, DEC);
  
  Serial.print("mc = "); Serial.println(mc, DEC);
  Serial.print("md = "); Serial.println(md, DEC);
}
uint16_t ZUNO_BMP180::readRawTemperature(void) {
  uint16_t t;
  
  write8(BMP085_CONTROL, BMP085_READTEMPCMD);
  _delay_ms(5);
  
  t = read8(BMP085_TEMPDATA);
  t <<= 8;
  t |= read8(BMP085_TEMPDATA+1);
  
  return t;
}

uint32_t ZUNO_BMP180::readRawPressure(void) {
  uint32_t raw;

  write8(BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6));

  if (oversampling == BMP085_ULTRALOWPOWER) 
    _delay_ms(5);
  else if (oversampling == BMP085_STANDARD) 
    _delay_ms(8);
  else if (oversampling == BMP085_HIGHRES) 
    _delay_ms(14);
  else 
    _delay_ms(26);

  raw = read8(BMP085_PRESSUREDATA);
  raw <<= 8;

  raw |= read8(BMP085_PRESSUREDATA+1);
  raw <<= 8;
  
  raw |= read8(BMP085_PRESSUREDATA+2);
  raw >>= (8 - oversampling);
 
  return raw;
}


int32_t ZUNO_BMP180::readPressure(void) {

  int16_t UT = readRawTemperature();
  long    UP = readRawPressure();


  long X1 = UT - ac6;
  long X2 = mc;

  X1 *= ac5;
  X1 >>= 15;
  X2 <<= 11;
  X2 /= (X1 + md);
  //1) => B5 => B6 
  long B6 = (X1 + X2) - 4000;

  //2) X1
  // X1 = (B2*(B6*B6)/2^12)/2^11
  X2 = X1 = B6;
  X1 *= B6;
  X1 >>= 12;
  uint16_t koef1 = X1;
  X1 *= b2;
  X1 >>= 11;
  //3) 
  // X2 = ac2*b6/2^11
  X2 *= ac2;
  X2 >>= 11;
  // 4
  // B3 = ((4*ac1 + X1 + X2)*2^(oversampling) + 2) / 4
  long B3 = ac1;
  B3 <<= 2;
  B3 += X1 + X2;
  B3 <<= oversampling;
  B3 >>= 2;
  B3 = UP-B3; // B7
  B3 *= (50000 >> oversampling); 
  // 5)
  // X1 = AC3*B6/2^13
  X1 = ac3;
  X1 *= B6;
  X1 >>= 13;
  // 6)
  // X2 = (b1*b6*b6/2^12)/2^16
  X2 = b1;
  X2 *= koef1;
  X2 >>= 16;
  // 
  X1 += X2 + 2;
  X1 >>= 2;

  // B4....
  unsigned long B4 = X1;
  B4 += 32768;
  B4 *= ac4;
  B4 >>= 15;

  long p = B3 < 0x80000000 ? (B3 << 1) / B4 : (B3/B4) << 1;
  X1 = p >> 8;
  X1 *= X1;
  X1 *= 3038;
  X1 >>= 16;
  X2 = p;
  X2 *= -7357;
  X2 >>= 16;
  X1 += X2 + 3791;
  X1 >>= 4;

  p += X1; 

  return p;
}


int16_t ZUNO_BMP180::readTemperatureC10(void) {

 
  int16_t UT = readRawTemperature();
  //Serial.print("UT=");
  //Serial.println(UT);
  long X1 = UT - ac6;
  long X2 = mc;

  X1 *= ac5;
  X1 >>= 15;
  X2 <<= 11;
  X2 /= (X1 + md);
  X1 += X2 + 8;
  X1 >>= 4;

  return  (int16_t) X1;
}

float  ZUNO_BMP180::readTemperature(void)
{
    return readTemperatureC10() / 10.0;
}
float ZUNO_BMP180::readAltitude(float sealevelPressure) {
  float altitude;

  float pressure = readPressure();

  altitude = 44330 * (1.0 - pow(pressure /sealevelPressure,0.1903));

  return altitude;
}


/*********************************************************************/

uint8_t ZUNO_BMP180::read8(uint8_t a) {
  uint8_t ret;

  Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.write(a); // sends register address to read from
  Wire.endTransmission(); // end transmission
  
  //Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read
  ret = Wire.read(); // receive DATA
  //Wire.endTransmission(); // end transmission

  return ret;
}

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

  Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.write(a); // sends register address to read from
  Wire.endTransmission(); // end transmission
  
  //Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read
  ret = Wire.read(); // receive DATA
  ret <<= 8;
  ret |= Wire.read(); // receive DATA
  //Wire.endTransmission(); // end transmission

  return ret;
}

void ZUNO_BMP180::write8(uint8_t a, uint8_t d) {
  Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.write(a); // sends register address to read from
  Wire.write(d);  // write data
  Wire.endTransmission(); // end transmission
}
fhem.de - ZWave development support
michap
Posts: 442
Joined: 26 Mar 2013 10:35
Contact:

Re: bmp180 reading of values

Post by michap »

A.Harrenberg wrote:The library tries to read two registers at once performing a "read16()", but the chip seems not to support that.
I'm not sure about that.

uint16_t Adafruit_BMP085::read16(uint8_t a) is a definition - and this function will do the same as you - calling two times the read8().

I have seen such (for me) unclear strokes ("==>>") - and do some experiments too.
(Wire.endTransmission - then Wire.request should not work - I thought so...)

Code: Select all

  Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
  Wire.write(a); // sends register address to read from
  Wire.endTransmission(); // end transmission
 
==>>  //Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device
  Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read
Will publish later

Michael
A.Harrenberg
Posts: 201
Joined: 05 Sep 2016 22:27

Re: bmp180 reading of values

Post by A.Harrenberg »

Hi MIchael,

we are talking about the BMP180 library here, in this library the read16() directly tries to read 2 bytes with Wire.requestFrom(BMP085_I2CADDR, 2):

Code: Select all

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

  Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.write(a); // sends register address to read from
  Wire.endTransmission(); // end transmission
  
  //Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read
  ret = Wire.read(); // receive DATA
  ret <<= 8;
  ret |= Wire.read(); // receive DATA
  //Wire.endTransmission(); // end transmission

  return ret;
}
I have not checked further in the code for wire, but I can state that changing the read16() call into 2 read8() call with the respective shift/Or solved the issue for me.

It is not a general problem with read16() as the reading for the calibration seems to be working with read16()! It might be worth digging deeper into the code for wire (or read the specification of the I2C for the BMP180 very carefully, as there might be some hint what is going wrong...)

It might also work that way with the BMP085, but with the actual libraries it is definitely not working with the BMP180. If you have a BMP180, just see what the read16() returns.

As the attachment quota for the board is reached, I can't attach anything, but you can find a new picture of my temperature and pressure data here: https://drive.google.com/open?id=0B-Qev ... Vh4eEFWdlk

There are some spikes in the graphs, they come from resetting the Z-Uno and some testing where i screwed up some code... But you can clearly see that from ~20:00 onwards the signals for the BMP180 look much better.

My actual version of the library is here: https://drive.google.com/open?id=0B-Qev ... lZJYm4zMlk

Regards,
Andreas.
fhem.de - ZWave development support
michap
Posts: 442
Joined: 26 Mar 2013 10:35
Contact:

Re: bmp180 reading of values

Post by michap »

Hi Andreas,
I came out to the same result ;)

It seems something wrong in the wire.lib.

Have modified the function - and all is working fine now:

Code: Select all

uint16_t ZUNO_BMP180::read16(uint8_t a) {
  uint16_t ret;
  uint16_t ret2;

  Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
  Wire.write(a); // sends register address to read from
  Wire.endTransmission(); // end transmission
  
  Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 
//  Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read
  Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read
  ret = Wire.read(); // receive DATA
  ret <<= 8;
  Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read
  ret |= Wire.read(); // receive DATA
  Wire.endTransmission(); // end transmission

  return ret;
Michael
A.Harrenberg
Posts: 201
Joined: 05 Sep 2016 22:27

Re: bmp180 reading of values

Post by A.Harrenberg »

Hi michap,

Ok, thank you for the confirmation and the update of the code, I saw that the code in the repository was already updated. Putting the fix in the read16() function itself is smarter than my solution ,-)

If I have some more time I will have a look at the wire library to see if there is something obvious or suspicious in the code.

Kind regards,
Andreas.
fhem.de - ZWave development support
A.Harrenberg
Posts: 201
Joined: 05 Sep 2016 22:27

Re: bmp180 reading of values

Post by A.Harrenberg »

Hi,
A.Harrenberg wrote:Hi michap,
Ok, thank you for the confirmation and the update of the code, I saw that the code in the repository was already updated. Putting the fix in the read16() function itself is smarter than my solution ,-)
I didn't look good enough, the repository is still the old code...

Regards,
Andreas.
fhem.de - ZWave development support
A.Harrenberg
Posts: 201
Joined: 05 Sep 2016 22:27

Re: bmp180 reading of values

Post by A.Harrenberg »

Hi PoltoS,

I made two recordings with my simple Saleae Logic Analyzer with the original lib (1x read16) and with the fix (2x read8).

I have uploaded the results here: https://drive.google.com/open?id=0B-Qev ... DVkejUxbVE
There are .txt and .csv files that are created with a I2C analyzer from the Saleae software and there are also the recordings in the format from the Saleae software. You can import these recordings into the software w/o having the hardware (with CTRL-O or under "Options"). The software can be found here:
https://www.saleae.com/downloads

I haven't looked in detail to the recordings, my last experiments with I2C was approximately 10 years ago, but I noticed a few NO ACK with the original lib.

I have also an OLED connected to the I2C, but for the measurements I disabled all the related code, so there should be no interference.

If you need more / other measurements, please let me know. I have received my second Z-Uno and will set it up with just I2C so I can unplug the BMP180 from my normal sketch, put it to the other Z-Uno and make measurements if needed.

Regards,
Andreas.
fhem.de - ZWave development support
User avatar
PoltoS
Posts: 7649
Joined: 26 Jan 2011 19:36

Re: bmp180 reading of values

Post by PoltoS »

Thanks a lot. We will look on it tomorrow
p0lyg0n1
Posts: 242
Joined: 04 Aug 2016 07:14

Re: bmp180 reading of values

Post by p0lyg0n1 »

You are right, Wire was broken when I moved it from firmware to "s_pins". Found problems with ack/nack during reading and problems with stop sequence in the middle of transmission. Fix this. Now I am testing math code of bmp180. I will publish fixes tomorrow. Thank you for help with that. The problems are not evident and the community helps to find them in the most simple way.
A.Harrenberg
Posts: 201
Joined: 05 Sep 2016 22:27

Re: bmp180 reading of values

Post by A.Harrenberg »

Thanks for the fast checking and the positive reply that you already found the root cause. I will wait for the fixes and test them then.
fhem.de - ZWave development support
Post Reply