I'm using the BME280 temperature and humidity sensor in a project. I have tried every library available and would like to use the one with the least resource usage as my processor is limited. ATMega324AP.
My results of testing with minimal code are:
Library FLASH RAM
Sparkfun 12286 613
Adafruit 15216 871
Bluedot 14204 469
Tyler Glenn BME280 12284 697
Jochem van Kranenburg 08730 525
Grove/seeed 10444 513
Tiny by fabyte 09650 555
SimpleBME280 by Riva 08640 483
Sparkfun and Simple are my preferred libraries, some of the others had constants that conflicted with my SEEED CAN library.
My issue is I cannot make them fail safe. If the sensor becomes disconnected the loop won't run after a board reset.
Can someone help with a reason and a solution?
That would extremely difficult to do, especially with Arduino I2C-based projects. You would have to anticipate and write code to get around a great variety of failure modes.
In particular, the I2C (Wire) library is very primitive and does not trap most errors. It often hangs with illegal or unexpected bus conditions and would require extensive modifications.
In your particular case, it might be possible to detect the absence of the BME280, and avoid all future references to it, but that depends on the BME280 library. Take a look at the library code to see if, for example, there are any useful return values in the beginI2C() method(*).
(*)Edit: I checked, and it does. Try:
if (!bme280.beginI2C()) take_corrective_action(); //no BME280 detected
My guess: your I2C transactions are incomplete.
Example: you do
bme280.beginI2C();
and
int rhOut = bme280.readFloatHumidity();
But I have seen I2C code where I2C.startTransmission() and I2C.endTransmission() is used (and needed).
I could imagine, your external BME280 does not see completed I2C transactions: use a scope and check if every transaction has a correct START and STOP bit.
If a STOP bit is missing - even a MCU reset will not recover: a new I2C transaction - the BME280 might take it as a RE-START.
My suggestions:
a) check how to do a complete I2C transaction (START, STOP bit, end.transmission() ...)
b) check with a scope if the I2C looks complete and reasonable
I tried Wire.beginTransmission(0x76);
And read error = Wire.endTransmission();
It works if ground, SDA or SCL are broken, but it still gives the correct response with no supply wire.
bme280.beginI2C(); locks up the cpu with no supply.
It's for a sensor mounted at the front of a vehicle. I'm beginning to think the only reliable answer is to go back to the DHT22 I've used previously.
I recently worked on a similar situation, where the code would stop if I did not connect the I2C sensor board (with built-in 4k7 pull-up resistors). In my case I could mitigate by adding extra pull-up resistors, close to the MCU, so that when the sensor became disconnected the pull-up resistors would still be on the I2C line.
I also used the watchdog timer to force a reset if my code would hang somewhere else than during the I2C initialization.
It sounds to me, the the I2C driver code does not act on "all" potential error conditions.
Few examples: bus is allocated, e.g. no pull-ups and signals "hang" low. Or: an ACK is expected, but a NACK comes (e.g. slave address wrong).
I guess, the biggest issue might be "clock stretching": if the own generated clock cannot be seen, e.g. no pull-ups and it hangs low - the master might "think": "oh, the slave has initiated a clock stretching". If this feature is enabled - you might hang forever there.
My five cents:
understand all the conditions which can happen, think about if this is realized and handled in your "driver" and: test all these conditions (hard to force or simulate some of them, e.g. "clock stretching"). At least: check which features your "driver" would enable (and would get vulnerable for issues).
Often, the bug is not in the source code - it is in the "use case" (a not coded functionality).