Reducing BMP180 Reading Latency/Delay

Hello all,

I have a BMP180, SD Card and MPU6050 hooked up to a Teensy LC. The intent is to make a high frequency (approximately 50 Hz, 20 ms) datalogger. The problem I am encountering is the data retrieval from the registers of the BMP180 is taking incredibly long. This was all measured using the "millis()" function.

MPU6050: Readings take approximately 1 ms in total (negligible)

BMP180: Temperature Readings take 6 ms
BMP180: Pressure Readings take 33 ms

SD Card: Data logging takes 10 ms per cycle.

The pressure readings seem to be the main culprit to the low frequency data logging that I am encountering (approximately 20 Hz). I am unsure whether the structure of the code is the root of the problem, or if my pressure sensor is faulty (bought it off Amazon).

My main inquiry is finding out how to reduce that pressure sensor latency.

Thanks in advance,
Dawn

Is that latency consistent with the values specified in the data sheet?

Surprisingly not. I am currently using the Adafruit library, and I am unsure how to set the modes for accuracy vs. power consumption.

image

The latency is still greater than the max conversion time datasheet of 25.5 ms.

Please provide a link to the library. Also the data sheet, so we don't have to do it.

That is the link to the Adafruit library.

I can attach the code if that would help (although I am unsure as to how that is done)

Not necessary if you used examples verbatim and you can tell us which one you used for testing.

This looks interesting

#define BMP085_ULTRALOWPOWER 0 //!< Ultra low power mode
#define BMP085_STANDARD 1      //!< Standard mode
#define BMP085_HIGHRES 2       //!< High-res mode
#define BMP085_ULTRAHIGHRES 3  //!< Ultra high-res mode
...
  bool begin(uint8_t mode = BMP085_ULTRAHIGHRES, TwoWire *wire = &Wire);

So Ultra High res is the default value in the begin() method. Just pass the one you want in the begin() method.

Thank you very much for your reply, it is indeed appreciated.

Sorry, I am a bit of a beginner but I assume I would write a line in void setup() as:

bool begin(uint8_t mode = BMP085_ULTRALOWPOWER, TwoWire *wire = &Wire);

UPDATE:

I implemented the change suggested.

In the bmp.begin() function, I passed the parameter "ULTRALOWPOWER" and it reduced the latency for the pressure reading from 33ms to 12 ms, a tremendous improvement.

First off, thank you very much for your valuable advice as it has definitely worked.

I had a couple of follow up questions however:

  1. The delay in the datasheet for the selected mode says 4.5 ms. Is there any method to reduce the latency to that level?

  2. Are the accuracies of the modes in the datasheet accurate? (In meters and hPa)?

  3. Is it possible to decrease the temperature reading latency?

  4. I read somewhere online that increasing the clock rate of the I2C Communication from 100 kHz to 400 kHz may somewhat aid in the situation. Is this a likely possibility?

Again, thank you very much!

Dawn

It's hard to guess exactly where the extra milliseconds are going to. You should first rule out any possibility that your own code is doing it. So try it with an absolute minimum sketch first, and work from there.

Temperature reading latency shouldn't matter, unless you are forced to combine temp and pressure readings together (I'm not familiar with the device or library...). I realize that you are trying to maintain the 20Hz update rate, but consider that the temperature can not change that fast. So you will be logging a lot of redundant information. That is something that you should look at, in itself. But if you are forced to combine log records, you could sample temperature only, say, every second. Then buffer it and use the same value for 20 readings. If you do that, you might as well also average them.

Again, I am too busy to look at details myself, but possibly this would free up some processor time, since then most of the time it would only be requesting pressure readings from the device.

It is certainly worth looking into I2C bus rates, it may or may not yield anything but it's worth a try.

Your question 2 is a question for the legal department. :sunglasses:

For the record, I assume this is what you ended up with?

bool begin(BMP085_ULTRALOWPOWER, TeensyWire);

where TeensyWire is whatever Wire instance the Teensy uses, or just

bool begin(BMP085_ULTRALOWPOWER);

?
For future readers of the thread...

One thing the OP can do is switch to a SPI BMP/BME device to get more speed.

Much appreciated @anon57585045

That certainly raises a valid point of the need to record temperature every cycle. I might as well just record once every second or so as temperature will not change that drastically in the time frame I am dealing with (5-10 seconds).

I will try adjusting the rate of the I2C and see if it speeds up the cycle.

The solution that I found in the end was simply adding the required mode in the parameters of the bmp.begin() function, with the "bmp" being the object created from the Adafruit library (I believe that is the correct terminology).

bmp.begin(BMP085_ULTRALOWPOWER);

SPI is a potential solution to increasing cycle speed. However, since I have already created a PCB for this application, it is not possible. This may be a feasible solution in future iterations though.

Thanks for the suggestion!

1 Like

FINAL UPDATE

I figured I would update the situation:

  1. I managed to reduce the pressure reading latency from 33 ms to around 12. This was done by simply passing the parameter "BMP085_ULTRALOWPOWER" (or any other mode), through the function.
bmp.begin(BMP085_ULTRALOWPOWER);

This reduces the accuracy of the reading, but by a very slight amount.

  1. I reduced the frequency of the temperature reading. Instead of taking a temperature reading every cycle, I added an "if" statement that would record data, only on the 50th cycle. This was acceptable for my application, since the temperature does not change significantly.
if(d % 50 = 0){
}

The "d" variable was the increment variable for the "while" loop. I was having trouble with global and local variables and whatnot, but I have managed to solve the issue (let me know if further details are wanted.

  1. The frequency of I2C communication is increased. The normal I2C frequency is 400 kHz, but this can be increased by using the "Wire.setClock()" function:
Wire.setClock(1000000);

I cannot tell if there is a difference between passing "1000000" or "1000000L". (some say to add the L, some don't and some say to add the UL, I have very little idea here)

  1. In addition, I reorganized the structure of my code in such a manner that the SD card file is only opened once, and closed once. This is in contrast to the former set up, where the SD Card was opened and closed with every loop cycle. This shaved off approximately 10 ms from my reading latency.

In summary, I

  • Set the BMP180 mode
  • Stopped taking unnecessary temperature measurements
  • Increased Clock speed (400 kHz to 1 MHz)
  • Restructured code to only open SD Card once

This reduced the latency for the data logging from 50 ms (20 Hz), to approximately 20 ms (50 Hz). Thank you once again to @anon57585045 and @Idahowalker for the suggestions.

-Dawnn

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.