Arduino UNO hangs while trying to run GY-302 and BME280 on same I2C bus

Hello there,

This is my first post, and trying to comply to the guidelines and best practices, but I may miss something, apologies in advance if so!

The Problem
I am trying to run a very simple loop that reads the values of these two sensors. The BME280 is being read every 15s and the GY-302 ligt sensor, is being read (in single sample mode) every minute. Everything starts normal and successful, but after aprrximately one hour, arduino hangs. I know it hagngs cause I have set a led to blink every second.

Attempts to solve
I have read so many post about arduinos hanging or crashing. No one seems to point me in the direcction of the real cause of my problem. As you will see in the code. I am not using std libreary strings, just plain C-Strings. The code is very simple. I am sampling at very low rates (15s, and 60s) . I2c cable to the devices is just about 10cm long, so no cable impadance issues. Baud rate is low enough (9600) so to prevent high freq noise? I have added pull-up resistors 2kOhm as this is being sugested in many places. Nothing seems to work. The only clue I can provide is that, if I remove the light sensor, the program can run forever no problem (sampling the pressure temp sensor only) . So problems come if I run both or even if I run the light sensor only. I am a Software guy so HW is not my strength, please feel free to correct me if i said something silly.

The code

/*--------------------------------------------------------
 *  Sensors platform
 --------------------------------------------------------*/
#include <Arduino.h>                // arduino types and defs
#include <Adafruit_Sensor.h>        // Generic sensor lib
#include <Adafruit_BME280.h>        // static air data drivers
#include <BH1750.h>                 // light sensor driver... Christph Laws
#include <Wire.h>


//--- Serial
static const unsigned SERIAL_BAUDRATE = 9600;   // 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 76800, 115200, 230400, 250000[baud]
static const byte BUFFER_SIZE = 255;
static const byte LED_PIN   = 2;

//--- tasks schedulling
static byte count60s = 0;
static byte count15s = 0;
static int led_status = HIGH;
static unsigned long count1s = 0;
static char output_buffer[BUFFER_SIZE];
static char straux[25];

//--- light sensor
static BH1750 lt_sensor;
static float lux = ZERO;

//--- baro sensor
//{
static Adafruit_BME280 bme280;             // I2C add 0x76 (118)
static float press = 1013.25f;
static float temp = 15.f, rel_hum = 50.f;
//}

//--- prototypes
static bool validate_value(const float min, const float max, const float update, float &value);
static const char *format_to_float(char *str, float  const x);

//-------------------------------------------------------------------
// Initialisations
//-------------------------------------------------------------------
void setup() 
{
   delay(1000);
   byte count = 0;
   
   //--- Serial setup
   while(count < 150)
   {
      Serial.begin(SERIAL_BAUDRATE);
      if(Serial) break;
      count++;
   }
   
   Serial.println("Initialising");
   
   //--- Pins I/O configuration
   pinMode(LED_PIN  ,  OUTPUT);
   digitalWrite(LED_PIN , HIGH);

   //---- I2C
   Serial.println("Init Wire");
   Wire.begin();
   delay(1000);

   //--- pressure sensor BME280 inits
   Serial.println("Init BME280 sensor");
   if(bme280.begin(0x76, &Wire) == 0)
      Serial.println("BME280 Fault!");
   
   //--- Light Sensor
   Serial.println("Init light sensor");
   lt_sensor.begin(BH1750::ONE_TIME_HIGH_RES_MODE);
   delay(500);
}

//-------------------------------------------------------------------
// Main loop
//-------------------------------------------------------------------
void loop() 
{
   //--- 1s base sampling
   if(millis() < count1s) return;

   //--- 1s tasks
   led_status = (led_status == HIGH)? LOW : HIGH;
   digitalWrite(LED_PIN, led_status);

   //--- 15s tasks
   //. Sample BME280 sensor
   //. Broadcast to PMCU: press, temp, RH, lux
   
   if(count15s >= 15)
   {
      count15s = 1;
      float aux = press;
      
      //--- NAN filter
      validate_value(-15.f  , 50.f    , bme280.readTemperature(), temp);   // [C]  greenhouse temperature
      validate_value(89000.f, 110000.f, bme280.readPressure(), aux);       // [Pa] static pressure
      validate_value(0.f    , 100.f   , bme280.readHumidity(), rel_hum);   // [%]  uncalibrated greenhouse relative humidity
      
      press = aux; 

      char *wr_pt = output_buffer;
      format_to_float(straux, press * 0.01f);
      snprintf(wr_pt, BUFFER_SIZE, "$%s", straux);   // press
      
      byte len = strlen(output_buffer);
      wr_pt = output_buffer + len;
      format_to_float(straux, temp);
      snprintf(wr_pt, BUFFER_SIZE, ",%s", straux);    // temp
      
      len = strlen(output_buffer);
      wr_pt = output_buffer + len;
      format_to_float(straux, rel_hum);
      snprintf(wr_pt, BUFFER_SIZE, ",%s", straux);    // RH
      
      len = strlen(output_buffer);
      wr_pt = output_buffer + len;
      format_to_float(straux, lux);
      snprintf(wr_pt, BUFFER_SIZE, ",%s\n", straux);   // lux
      
      Serial.print(output_buffer);  // data stream
      
   }
   else
      count15s++;
   
   //---1min tasks
   //. Sample light sensor
   if(count60s >= 60)
   {
      count60s  = 1;
      
      //--- Light sensor - Xistoph Laws library version
      if(lt_sensor.measurementReady(true))
      {
         float lumens = lt_sensor.readLightLevel();
         
         //--- self calibration as per library example)
         bool ltsen_error = false; 
         
         if (lumens > 40000.f)   // reduce measurement time - needed in direct sun light  
            ltsen_error = !lt_sensor.setMTreg(32);
         else
         {
            if (lumens > 10.f)   // typical light environment
               ltsen_error = !lt_sensor.setMTreg(69);
            else
               ltsen_error = !lt_sensor.setMTreg(138);
         }
         
         // perform some fault handling using ltsen_error
         // TODO
         
         //--- sample
         lt_sensor.configure(BH1750::ONE_TIME_HIGH_RES_MODE);
         ltsen_error = !validate_value(0., 100000.f, lumens, lux);   //E: read the result
         
         if(ltsen_error)
            Serial.println("Invalid Light Sample");
      }
   }
   else
      count60s++;

   count1s = millis() + 1000;
}


////////////////////////////////////////////////////////////////////////////
static const char *format_to_float(char *str, float  const x)
{
   int intg = (int)x, 
       cent = abs((int)((x - intg)* 100.f));
       
   sprintf(str, "%d.%d", intg, cent);
   return str;
}

//------------------------------------------
// Valid number checker
//------------------------------------------
static bool validate_value(const float min,const  float max, const float update, float &value)
{
   if(isnan(update)) return false;
   
   if((update < min) || (update > max)) return false;
   
   value = update; 
   return true;
}

Sounds more like a issue in code.
At least verify if that after x time is always the same.

no, the time is variable. can range from 40 min to 2 hrs. If it was the code, it would crash when running on the BME280 only, would'n it?

Not necessarily in case of some overflow.
Anyway if it's variable, hardware issue becomes probable.
Try with 4k7 pullups.
Control your wires carefully, also solder joints.
Overheating somewhere? On voltage regulator for example.

Not always a good thing to do. Usually, the modules for the sensors have pull-ups built-in. When you have multiple modules each with pull-ups, and the Arduino uses it's own internal pull-ups and you add external pull-ups also, these pull-ups combine and can become too strong, which can prevent the i2c bus from working.

But I guess you already tried without external pull-ups and the result was the same.

Indeed :frowning: i tried a lot before adding the pull-ups. One thing to mention... the arduino board is not arduino official but from some other provider... could this put in to question the quality of the HW?

I did put a lot of atention on no overflowing allocated memory, I don't think there is an issue here. The buffer I am ussing to write the data stream is 255 bytes long... more than enough!I No overheating that I have seen. . will try with the 4k7 pull ups then, txs!

Last comment: I read somewhere that some times, two sensors just don't get along, and that's it. Could it be the case?

After an hour or two? They get tired of each other... :grinning:
Also, interferences or corrupted signals don't crash arduino if correctly coded and they wouldn't give initial success of that long.
Only thing matching with these 1-2hours is temperature issue or some overflow.

Edit:
You wrote hangs, not crash..
Control also that your code doesn't hang even if sensor gives corrupted data.

:smiley: :smiley: :smiley: LOL! it happens with humans also! well, in that case I perform an extra x-check of the writing to char arrays and stuff like that. It is true that the format_to_float function is not checking the limits of the array (straux var) and may be at some point i get a number with loads of decimal figures and off we go. I will let you know.

Possibly. Most clone Arduino boards use genuine ATMEL AVR chips. If your clone is one of those, then it is probably fine. However, a small number of clone providers use non-ATMEL chips, and these have caused some problems and incompatibilities in the past.

1 Like

This could mean a faulty light sensor.

When you say "run the light sensor only" I guess you must mean that you remove/comment out the parts of the code that relate to the BME280. But was the BME280 still connected for that test?

If not, try physically removing the BME280 sensor in addition to removing its code.

If it still hangs after 40m~2hr, try running an example sketch from the BH1750 library for > 2hrs.

Also, run an example sketch for the BME280 with only the BME280 connected for > 2hr. If this does not hang, you can be pretty sure there is no problem with the BME280 or the Arduino.

1 Like

Yes, when I tried the light sensor alone, I removed the sensor physically and commented out the code. It crashed anyway. Whereas the bme280 (tested in the same fashion, alone) was running for several hours no problem. I will check with the examples of the BH1750 then!

Hello!
Well I have had the board running tests on the sketch and the sensor non stop. I removed all variables allocated tothe stack and made them globals (this is very drmatic, but, worth trying). Also, another thing I realised (actually, it was a suggestion from ChatGPT) is that the output buffer of the Serial.print() for arduino UNO is only 64 bytes long! (and I was allocating an array of 255 bytes to be sentif required!) This was defenitely a mistake. I made sure any printing is done with low frequency (one log every 10s approx). Having said that, I managed to run 10 hours no crash! but eventually it did freeze again :frowning: So as a last resource, I added a watchdog with 8 sec timeout in order to reset the board if required (this was suggested by ChatGPT as well). I have to say I did not try the 4k7 pullup resistors, may be this was something yet to try. For the time being I will go with the watchdog.
Thanks to all for your help!
E

Have you given up ? But you have not yet started to make a serious project.
What is ZERO ?

Possible hardware issues: Voltage conflict on the I2C bus (the Arduino Uno board is a 5V board with a I2C bus that has 5V levels and both sensors are 3.3V sensors that work best with 3.3V levels on the I2C bus), voltage regulator on a sensor module gives too low voltage to the sensor, SDA should not be next to SCL, counterfeit BME280.
Software issues: Use of millis() timer, snprintf() has no safety once the pointer starts moving along the buffer, dtostrf(), the led is no indicator because there is a return before the led, the while for a timeout of Serial has no fixed timing, 9600 is really slow try 115200, instead of building a string in a buffer we often use many Serial.print() to just send it out.

And this is only at first glance.

Did you know that all ino files are bundled together by the Arduino pre-processor and then presented to the compiler ? That is why we don't use 'static' as being "local".

In the Arduino world, it is better to write simple and basic code. I tell that to software engineers that are used to a certain style of writing software. Don't worry, you get used to it.
There are cheap sensor modules on AliExpress/Amazon/Ebay/TEMU, but you should expect trouble. Good sellers are the Arduino shop, Adafruit, Sparkfun, Pololu.

Yes you are right in many things:

  • the issue with snprintf you are riight, that is something I corrected in the code and forgot to mention in my last post. I move the write pointer fwd but then shorten the max size to print. Having said that, it is true it would be as easy to use many Serial.prints... I don't know why I did it like that here, for I have done it the other way in other projects.
  • ZERO = 0.f the code you see here is asimplified version so not toofuscate the whole things with loads of include files and stuff.
  • I have my sensors connected to the 3v3 output. should that agree with your comment?
  • I don't understand when you say SCL shold not be close to SCL. you mean topologically? physically? don't know.
  • I use 9600 baud , cause... I dont really need that much speed, I read once per minute and the light sensor, and once every 15s the BME280. From what I know, higher freqs are more prone to erros, and noise.
  • The led: is after the 1000 ms check. If the led was right onthe main loop, it would be blinking at nearly 1KHz, makes sense?
  • I just try to start serial before 150 attempts. Is not a timeout. I dont check it again once on the main loop.
  • I did not know about the preprocessor of arduino compiler! thanks for that bit of info! I allways thought , this setup() and loop() where part of a wrapper, may be some higher hierarchy class. And it is so common for proggrammers to use same names allways, that is why I was using static variables allways. Now that you say that i will change my strategy :slight_smile:
  • Is there still the possibility of a faulty sensor in thsi case? I should by a clone to test that :s

Things are different in the Arduino world. They are.

It depends on your sensor module if it should be powered with 5V or 3.3V. We need links to all your modules and board and a photo with the wiring and a schematic/circuit (you can draw it on a piece of paper) that shows the wiring.

Explanation: The Arduino Uno expects at least 3.5V on the I2C bus to see it as a "high". A 3.3V sensor can not give that. It will work, but the noise margin is gone. Pullup resistors to 5V can leak 5V into the sensor (via SDA and SCL) and lift the VCC of the sensor towards 5V. Some sensors are sensitive for that.

Explanation more: When a module is powered with 3.3V and there is a voltage regulator on that module, then the sensor might get 2.3V.

The I2C bus can not deal with cross-talk between SDA and SCL. They should definitely not be next to each other in flat ribbon cable. They are weak digital signals.

The cable between your computer and the Arduino board is a USB cable. The Arduino baudrate is not on that cable. The baudrate in the sketch is just between the microcontroller and the usb-serial chip on the Uno board.

Explanation: When you want to send a lot of text to the Serial Monitor, and the 64 bytes TX buffer inside the Serial library is full, then the Serial.print() waits for a free spot. That means that a sketch can get 100 times slower with a full TX buffer. Therefor 115200 should be default and 9600 is something from the 1980s.

Blinking a led can be done with a millis-timer. This is how to use it: https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay/

For the Arduino Uno, there is no need to check if Serial.begin() was successful. Never. For a Arduino Uno it just works.

I forgot to add to my list: Timeout for Wire library: https://www.arduino.cc/reference/en/language/functions/communication/wire/setwiretimeout/

Are you reading all of this ? I have told almost everything by now. There is not much more :wink:


Thanks very mucho for your comments !! Sorry I've been bussy with other things. I will be answering little by little as I still have some doubts on your comments. Thanks!!
So this is basically my setup

What are your doubts ?

I really need to know the sensor modules to say something about the voltages.
The "GY-302" has a voltage regulator but no I2C level shifters. It is not suitable for a 3.3V board and it is not suitable for a 5V board.
In case you think that it can't be wrong if everyone is selling it, but you have to trust me :innocent: It is wrong. It will work (sometimes) when it is the only sensor on the I2C bus and that is exactly the problem that you have.
The "BH1750" works best with 3.3V power and a I2C bus with 3.3V signals at its SDA and SCL pins.

Are RX and TX connected to a Due ? But the Due is a 3.3V board. The Arduino Uno can push up to 40mA out with the TX pin, and the input clamping diodes of the ATSAM processor on the Due have to deal with that.

We often recommend to use a single Arduino board and add extra hardware for more I/O pins. What is your project about ?

1 Like

I would definitely go with demo code like proposed on post11. Result of that would give indication if issue is code or hw related.

Do you think testing the example on another board like , arduino r4 minima would be a valid test? I intend to test the example as you suggest