[SOLVED]Problem on boot with two LPS331AP sensors over I2C

Hello everyone,
I am experiencing the following issue:

I hooked two LPS331AP sensors over I2C, on an Arduino Uno R3. The sensors allow the last bit of its address to be changed - it is internally pulled-up. I wired it to GND to pull it down. The communication - once established, is fine.
But every time I power-on the Arduino it starts to read wrong data from the pulled-down sensor - pressure 760mbar, and the value never changes.
Here is the strange part - if I do the following:

  • power-on Arduino - fails to read correct data;
  • remove GND wire - so the two sensors now have the same address, the Arduino freezes;
  • reboot Arduino (whitout powering it off) - fails to detect sensor;
  • connect GND wire back;
  • reboot Arduino (again no play with the power supply, only reboot from the button on the Arduino board);
    and now the faulty sensor is detected and everything works fine...Until power-off.

Somewhere, I believe from Pololu support forum, I read that the value 760mbar is read when the I2C
wiring was not done properly. And I did see this early on while I was wiring the first time. But the case now is very different. Once I do the mentioned procedure after a fail-start everything works wonderfully!
The code that follows is the part of the setup() that relates to the sensors. It was largely copied from
an example from the <LPS.h> developers.

#include <Wire.h>
#include <LPS.h>
void setup() {
 Serial.begin(9600);
 Wire.begin();
 if (!ps.init(LPS::device_331AP, LPS::sa0_low))
 {
   Serial.println("Failed to autodetect pressure sensor_In!");
 }
 if (!ps.init(LPS::device_331AP, LPS::sa0_high))
 {
   Serial.println("Failed to autodetect pressure sensor_Out!");
 }
 ps.enableDefault();
 ps.init(LPS::device_331AP, LPS::sa0_low);   //address sens_In; [sa0] is the last bit of the I2C address; here Im telling it to look for LPS331AP device with sa0_low;
 
 ps.writeReg(LPS::RES_CONF, 0x7A);           //sets high averg rate
 ps.init(LPS::device_331AP, LPS::sa0_high);   //address sens_Out
 ps.writeReg(LPS::RES_CONF, 0x7A);           //sets high averg rate
}

The hole code is rather large, but I wont post it all unless requiered. I believe the problem lies in the beginning somewhere. Once the Arduino powers up and boots up with the two sensors properly recognized everything works fine!
If someone had expirience with these sensors please respond.

Any reply will be appreciated and thank you very much! You may not know it but
you already helped a lot with this project! :slight_smile:

Do you have pullup resistors on the I2C bus ? Around 4.7k ?

The sensors should not have pullup resistors on the I2C bus, but some do. If these both do, then it could be providing 2.4k, that may be to low.

If you disconnect one sensor, does the other one work ok?

Hi, welcome to the forum.
Please read this : http://forum.arduino.cc/index.php/topic,148850.0.html
Number 7 on that page is about use code tags.

This is the manufacturers page : http://www.st.com/web/catalog/sense_power/FM89/SC1316/PF251601
This is the module at Pololu : Pololu - LPS331AP Pressure/Altitude Sensor Carrier with Voltage Regulator

With an Arduino Uno, connect the 5V pin of the Arduino to the sensor module VIN. Do you have that ?
Never remove the GND wire, it is the most important wire.

Add a delay of half a second with delay(500) ; in setup(). It can happen that something is not ready. I would add it after Wire.begin().

Do you use this library ? https://github.com/pololu/lps-arduino/tree/master/LPS
I'm sorry to say, but that code is bad. I can spot one bug and a few problems at first glance. You are lucky that you can read data with it.
The code line after Wire.requestFrom() is wrong in three places and the way bytes are converted to 32-bit long is questionable.

Oh my..I taught I got it :confused: but no.
@jack wp,
Yes I have the resistors and all. If only one sensor on the I2C bus is used then the resistor is not needed. Currently with 10k, was with 1.8k no difference.

@Peter_n,
I think you misunderstood about the GND wire. The one that I was pulling out is the one that sets bit SA0_ to LOW. Just a wire from pin SDO. This is on the sensor board if you look at the pic you can see pin SDO, between SCL and CS. Changes the last bit of the I2C address of the device, default is 1. The board is powered from the Arduino's 5V trough USB only.

To be honest I am very new at this thing, like 2 weeks young, and this is my first project besides the examples, which I did the fist evening, and the second day started this. I have limited experience with programming and I am still learning how to Wire() :slight_smile:

Peter_n:
....
This is the manufacturers page : http://www.st.com/web/catalog/sense_power/FM89/SC1316/PF251601
This is the module at Pololu : Pololu - LPS331AP Pressure/Altitude Sensor Carrier with Voltage Regulator
Do you use this library ? https://github.com/pololu/lps-arduino/tree/master/LPS
I'm sorry to say, but that code is bad. I can spot one bug and a few problems at first glance. You are lucky that you can read data with it.
The code line after Wire.requestFrom() is wrong in three places and the way bytes are converted to 32-bit long is questionable.

Yes, this is the library. But I don't understand the part with the Wire.requestFrom() - I dont see where I wrote that. Please point me to the wrong places so I can look and read on to that. I was all over these three pages for the last week. And that's what I made of it.

UPDATE:
Tried setting delay() between almost every line in setup(), tried moving sp.enableDefault() up and down. Only more of a weird stuff, so hear that now:
If I power down the Arduino, in order to get it running I need to have this code:

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ps.init(LPS::device_331AP, LPS::sa0_low);
  ps.init(LPS::device_331AP, LPS::sa0_high);
  ps.enableDefault();
}

ps.init() replaces the long check if(!ps.init()) and serves as to address the sensors before/after ps.enableDefault(). And it turns out it matters, because if ps.enableDefault() was before ps.init() the procedure described in my first post does not return the system to normal behaviour.

This following code will NOT return to normal operation once disturbed and will output 760mbar and 42.5 C on the sensor with bit sa0_low

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ps.enableDefault();
  ps.init(LPS::device_331AP, LPS::sa0_low);
  ps.init(LPS::device_331AP, LPS::sa0_high);
}

If I start and set up the Arduino to get correct data (by means of the method described in my first post), I can then reupload this code and all works fine:

void setup() {
  Serial.begin(9600);
  Wire.begin();
  ps.enableDefault();
}

One workaround is if I add external supply then, of course, the chip wont stop working, and I wont lose
I2C communication, but this is unacceptable for standalone operation - the reset operation after power-down / battery fail is quite extraordinary. :slight_smile:

According to the schematic, the SDO/SA0 is default pulled high to the onboard 3.3V. You can connect it to GND if you want to.

Your Arduino Uno is powered via the USB cable. So far so good.
But the LPS331AP module should be powered with the pin of the Arduino Uno called "5V". That's what I ment with the Arduino 5V pin to module VIN.
Can you confirm that you have that ?
You can make a photo of it.

Run the i2c_scanner for a while : Arduino Playground - I2cScanner
It should run without any problem.
You need a new sketch for that, but it is normal to have a number of test sketches when developing a project.

I don't know what to think about the library and the functions and how you use them in setup().

Have you copied the library files into your project ? or did you install the library via the zip-file ? or did you copy the library into the Arduino system files (that's bad).

Could you fix that library ?
Find "LPS.cpp", remove line 103 : "Wire.endTransmission() ;".
https://github.com/pololu/lps-arduino/blob/master/LPS/LPS.cpp

The other problems that I spotted at first glance don't cause trouble, but I wonder what else could be wrong with that code.

How about that delay ? Starting the I2C and immediate start a I2C transmission might be too much for these chips that combine SPI and I2C and address selection.

void setup() {
  Serial.begin(9600);
  Wire.begin();
  delay(500);    // SDA and SCL are now high and idle, let it settle for a while.
  ...
}

Hello,
@Peter_n,
Yes, I got it all according to the manufacturer datasheet. VIN:5V; resistors at SCL and SDA, SDO pin pulled down on one of the sensors.
Adding delay() does not help. I tried adding delay() after each line in setup() one by one, and even tried adding delay() after every line at one time. The problem persists.

I ran the I2C scanner before even starting to write my sketch, just to see if I changed the sa0_ bit.

Everything worked fine, anyway I did the scanning now, with the current problem in mind, and the sensor behaves normally. Both sensors are properly recognized after power-down when I run the I2C scanner sketch.
The library was added trough Arduino IDE's "Add .ZIP library.." Could a improper installation of the library lead to such a weird bug? I taught it wont work at all? Or at least have much bigger problems with reading the sensors.

So, by elimination, I am led to believe that the problem is in the library or the way I use it. I will remove the line at row 103 in LPS.ccp, and do further testings and will report about that.
I will look further into the library's files and see if something pops out there. As I said I am new to arduino, I used to study some programming in high school but that was long time ago and back then we studied PASCAL (that's way I consider myself total n00b). :slight_smile: So to say, I may need some time but I can find my way along a code as long as I understand the functions of the code in the first place. So if the gods of home education are with me maybe I'll spot the troublemaker.

I am wondering if I don't use the LPS.h library but try to config the sensors trough Wire(), and use Wire() commands only - It's the longest, hardest way - for me - but if it is a viable alternative I will try to do that. Another question popped just now - if I don't use LPS.h, but config manually in the code and use only Wire() - Am I going to save some memory space. In other words - does the library add unnecessary bits of data? Or the compiler gets of the library just what is needed for the functions used in the code?

Just to make it clear here, as it got clear to me now. The sensors, I2C protocol and all test sketches work fine - the I2C scanner finds both sensors even after power-down. Here is a screenshot for no particular reason, just to show that without the LPS.h library the sensors are recognized correctly:

*The screenshot was taken after:

  • I uploaded the I2C scanner to Arduino;
  • Power down Arduino;
  • Power up Arduino;
  • Open serial monitor and made the screenshot;

If I do the same procedure, but with my sketch which includes LPS.h, it fails to config the sensors on power-up and reads wrong data from the sensor with sa0_low; Then if I do the procedure in my first post, the sensor is properly recognized and works. The procedure for getting the sensors to work after fail-start is(like in the first post, just changed GND with GREEN to match the photos so you can make sens of it, sorry for misleading, I should choose my words better):

  • power-on Arduino - fails to read correct data;
  • remove GREEN wire - so the two sensors now have the same address, the Arduino freezes;
  • reboot Arduino (whitout powering it off, just press the reset button on the Arduino board) - fails to detect sensor;
  • connect GREEN wire back to GND;
  • reboot Arduino (again no play with the power supply, only reboot from the button on the Arduino board);

I remember reading something like "If there is a conflict in the I2C bus the sensor may read constant pressure at 760mbar." It gets blurry in my mind as I went back and forth trough the documents and I can't remember what it said actually. I dismissed it as it related to when you can't get correct data at all, but I get correct data(once the system boots up correctly) I will try to find the exact text and see what is all that about.

Here are pics, so we can rule out wrong wiring:
I did some color-coding of the wires for your ease of read.

  • yellow - SCL;
  • orange - SDA;
  • red - +5V;
  • black - GND;
  • green - pulls down bit sa0_ on one of the sensors.

UPDATE: Deleting line 103 in LPS.cpp does not change anything. It was a quick check to see if the problem persists - and it does. I did not go any further into looking in the library as I have to get out now. I will try to gain more understanding in the way the configuration of the sensors is done in the library and will try to modify some bits to see if that gets me somewhere. If you saw something in the library that may relate to the problem please point me to that row so I can do research on that. I am going out now and will resume testing tonight. I will report if something new pops up.

Close .. but no cigar. For now. Thank you very much for your effort!
Best regards,
Stoyo

You are correct in that init should come befor enable. I'm not quite sure how the library handles the two sensors, but perhaps you could try setting up two instances like

#include <Wire.h>
#include <LPS.h>

LPS ps1;
LPS ps2;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  ps1.init(LPS::device_331AP, LPS::sa0_low);
  ps2.init(LPS::device_331AP, LPS::sa0_high);
  ps1.enableDefault();
  ps2.enableDefault();
}

  

void loop()
{}

Then in your code, all additional calls should be for either ps1 or ps2.

If you can't figure out how to get the library to play well with two sensors, is should be relatively easy to write the direct wire library code with the explicit address to do what is done in the library.

Thanks for the photos.
stoyo, this is not your fault. It turns out that Pololu doesn't know what I2C is and it seems that no one else has written code for the LPS331.

Pullups
The Pololu module has already two 4k7 pullup resistors (on both side of the level shifter on the sensor module). That is not normal, the value is rather low, since 10k is mostly used.
So you might have a combined pullup that has too low impedance.
The I2C bus is specified to pull SDA or SCL down by maximum of 3mA. When "Wire.begin()" is called, the Arduino turns the SDA and SCL pins into pins according the I2C specifications with a maximum of 3mA pull down current.

Arduino Uno : 50k (or 70k) at 5V = 0.1mA
Pololu module : 4k7 at 5V and 4k7 at 3.3V = 1.76mA
One Arduino Uno and two Pololu modules : 3.6mA
You have too much pullup :stuck_out_tongue_closed_eyes:
There must be pullup resistors on both sides of the level shifters, or else the level shifter won't work.

The best you can do is to remove the 4k7 resistors at the 5V side on both modules. That is R1 and R2 and they go from VIN to SDA and from VIN to SCL. That should be enough to make the I2C bus work. Do not add extra resistors. If that makes it unreliable you can add 10k pullup resistors from 5V to SDA and from 5V to SCL.

Library
Adding a library zip-file via the Arduino IDE is perfect :slight_smile:
You did already find that library ?
It is often at /Documents/Arduino
One of those folders is called "libraries", that is where the libraries are (and the file LPS.cpp).
I did not check the code of the library better.

What you should have done
Buy your modules at Adafruit.
Use a common sensor, for example a Bosch sensor like the BMP180.
Buy an Arduino.cc board instead of an Arduino.org board :o

Test
Remove your own pullup resistor.
Remove the two 4k7 resistors on the modules as I wrote above.
Use only one sensor module.
Test the library with that single sensor module. I can't find an other library :frowning:

[ADDED]
cattledog is right, sorry I missed that :-[

Test the library with that single sensor module.

I agree with Peter_n here. The fact that the i2c scanner works correctly and identifies both modules is a good sign.

Use one module at time (one module with sa0 wired to ground and the other one with sa0 pulled high by the module) and the standard example code provided with the library.

If both sensors alone work, you can now investigate whether or not the issue is the combined pullup resistance of both modules on the i2c bus or something with how the library, or your use of it, is handling the two sensors.

You guys rock!

UPDATE: Whoaa .. solved in less than a minute :slight_smile:

Here is the code that runs smoothly:

#include <LPS.h>
#include <Wire.h>

LPS ps1;       //Separate instance should be set up for each sensor
LPS ps2;       //

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  ps1.init(LPS::device_331AP, LPS::sa0_low);    
  ps2.init(LPS::device_331AP, LPS::sa0_high);
  ps1.enableDefault();
  ps2.enableDefault();
}
// the code in loop() just prints the values every 1 sec.
void loop() {
  if (timeElapsed > 1000) {
    timeElapsed = 0;
    p1 = ps1.readPressureMillibars();
    t1 = ps1.readTemperatureC();
    p2 = ps2.readPressureMillibars();
    t2 = ps2.readTemperatureC();
    Serial.print("p1: "); Serial.print(p1);
    Serial.print("  "); Serial.print("p2: "); Serial.println(p2);
    Serial.print("t1: "); Serial.print(t1);
    Serial.print("  "); Serial.print("t2: "); Serial.println(t2);
  }
}

Basically what @cattledog wrote.

@cattledog,
Thank you for your reply. Creating two instances for the sensors did the job. It was so quick and easy fix I taught I forgot what the actual bug was, but I just cant make them read bad data after power-up now. Tried it several times and Arduino powers-up properly and boots with two sensors recognized and transmitting proper data over I2C.

@Peter_n,
Thank you very much for your comments. You bring up a lot of valid points on which I should improve on!

Peter_n, leaving programming aside, I can not agree more with you about the choice of sources for parts...

Peter_n:
Pullups
The Pololu module has ...

I will be revising this in the next days and will definitely keep your post in mind, because I will need one of the sensors extended about 1 meter and i believe I will run in to some problems there, as I read that twisted pairs are good for up to 50cm over I2C and maybe I'll have to buy some I2C transmitter of some sort for longer distances - I did see that somewhere just can't remember the proper name for the part. As I said before I'm pretty new, so excuse me for my layman terms. :slight_smile: But I wont try to remove any soldered part of the sensors as they are smd's of the smallest caliber and I don't have the eyesight (or the nerves) .. If they turn out to be useless for my project I'll find a replacer. But they do run nicely so far. I removed the resistors I added before and all works fine - no difference with or without them in the range 1.2k - 10k.

Peter_n:
What you should have done
Buy your modules at Adafruit.
Use a common sensor, for example a Bosch sensor like the BMP180.
Buy an Arduino.cc board instead of an Arduino.org board :o

To be honest I don't know the difference between both manufacturers(ard.org or ard.cc). I did see this just now!
There is no difference other than www.arduino.org printet on the edge, and different print on the back, but very look-a-like style. Made in Italy is there, the gold plated part next to the USB is there... Just a really good clone I guess. But then again ..!! I ordered this part from a supplier listed on the www.arduino.cc as a distributor: Distributors — Arduino Official Store
The seller is from Bulgaria - Erelement
I guess they tricked me!? If arduino.org is an unauthorized manufacturer then I will be more than happy to report the supplier so the guys from www.arduino.cc are informed about that.
Regarding the Boch sensor - I wanted that really bad, most of all It works better and was credited on some forums as to have more stable output compared to others in the same price range. But it has only one I2C adress, and I need 2 sensors because I need the real pressure outside for calculating real-time-pressure-difference.

The project is about a climate control for а greenhouse. My father is a retired firefighter and he build a greenhouse as he is a general handyman and likes farming. I taught it would be a great touch to add some automation to his greenhouse so he can extend the grow period from as early in the spring to as lately in the autumn as possible. I will control an exhaust fan with 2 speeds based on t_In, I will use the pressure difference to control an air intake check valve (flap) I don't know the English word for that - it's a air valve with a diameter of 200mm and spring(lightly) loaded flaps that are closed by default and I open them with a servo. The pressure difference here gives me a better precision because in combination with the air valve I can always maintain around 0 difference and the outTake fan will work at optimum conditions and I wont have to worry about cold air getting in from elsewhere except from the air intake valve. I plant to elaborate the logic based on t_Out and to change the air inside faster when tOut is close to tIn, or slower when tOut is much lower than tIn. I may add a heater on the intake for the coldest nights, but that is optional because when the temps are so low usually the daylight is pretty low too and no matter how hot I keep that greenhouse nothing will be growing, except mushrooms. :slight_smile:

@jack wp, @Peter_n and @cattledog,
Thank you very much for your time. It was going to take me days just to wrap my head around the library code to figure that by myself. I guess creating two instances was an obvious option for a solution for you guys. I really need to read some basic stuff about programming. It will be a nice finale for me if somebody links e-books or lectures on the basics.( or tell the names I'll google them). You see, I had trouble figuring out I need two instances for two sensors - sounds like basic stuff now! :slight_smile: And yes - I am trying to make good use of the resources available on www.arduino.cc and elsewhere on the web, but my searches are often quite off, simply because I don't know the proper nomenclature.

The Arduino.org board is not a trick, but the Arduino.cc is the "real" Arduino. No wait, Arduino.org is the real one and Arduino.cc is even more real ? No, that's not right, let's bring in Genuino. Now everything is a lot more clear. But Arduino.cc boards are not sold everywhere, so the Metro board might also be a good option.
At Arduino.org they don't have a forum, so they rely on Arduino.cc to spend money to keep the forum running so users can ask questions here in this forum. What !?
Arduino.org has made nice a Arduino M0 board, but I'm a Arduino.cc fan, what should I do ?
When I search for "arduino.org" at Bing.com, the "Arduino.cc" is on top.
(turning green and slamming my head against the keyboard).

So Arduino.cc and Arduino.org are having a lawsuit and are spending their money on lawyers instead of open source electronics and software.

Oh..oh yes, I got it now. It got clear now.. hahah
As it turns out these guys at Erelement (my suppliers) are also listed as distributor at ard.org, so I guess, technically, they did not do anything wrong. But sill .. they don't mention it anywhere, and are giving whatever they have in hand at the moment of purchase. Classy act. I chose this one because it has a socket for the chip and when the programming is done I want to make a separate dedicated circuit board.
This way the project becomes not just intro to programming but rather intro to making dedicated controllers - which is nice for me. I expect a lot more pitfalls along the way, but that's where the excitement is, right!?

This thread got it's complete answer so I guess it's best to leave it already.
I will just post some tags here in hopes that search engines will help others with similar problem.
Anyways, I got some insight into dealing with the LPS331AP and it's library, so anybody else (any other noob) experiencing problems with that sensor may ask me other questions, I'll do my best.

Tags: LPS331AP, sensors, LPS.h, ps.enableDefault, "LPS::device_331AP", "LPS::sa0_low", "LPS::sa0_high", "two LPS331AP", I2C

Thank you, once again, and have a good day! :slight_smile: