Sensor Code not Working when put into Header & CPP (Adafruit BME280 & BMP280, Teensy 4.0, Arduino IDE v2.0)

I'm attempting to read from a pair of Adafruit sensors with a Teensy 4.0.
The sensors are the BME280 and the BMP280.
I'm using the Arduino IDE compiler v2.0.0.

I'm a relative begginer with Arduino systems.

Here are some images of my current setup:

The two sensors are connected to the Teensy 4.0 through the SPI protocol, and they are bussed together.

Here's the datasheet for the Teensy 4.0:

And the datasheets for the BME280 and BMP280 sensors respectively:

With this setup, I'm able to properly run & read from the two sensors with the template code that is available in the Arduino IDE examples for the two sensors. I'm even able to combine the sample code together for both sensors, and read them both at once.

I then wanted to fragment my code into a Header (.h) and a C++ (.cpp) file, alongside the main runner code in the INO file. Here's the code setup:

Here's the SENSOR_TESTS.ino file:

#include "Arduino.h"
#include "Sensors.h"

int PIN_SCK = 13;
int PIN_MISO = 12;
int PIN_MOSI = 11;
int PIN_CS_BME = 9;
int PIN_CS_BMP = 10;

float SEALEVELPRESSURE_HPA = 1013.25;
int delayTime = 1000;

bool debugMode = true;

void setup() {
  Serial.begin(9600);

  while (!Serial) {}

  BME280_Init(debugMode);
  BMP280_Init(debugMode);

  Serial.println("SENSOR TESTS\n");
}

void loop() {
  Serial.println("BME280:\n" + String(BME280_ReadData(0)) + "\n");
  Serial.println("BMP280:\n" + String(BMP280_ReadData(0)) + "\n");

  delay(delayTime);
}

Here's the Sensors.h file:

/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor

  Designed specifically to work with the Adafruit BME280 Breakout
  ----> http://www.adafruit.com/products/2650

  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. The device's I2C address is either 0x76 or 0x77.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
  See the LICENSE file for details.
 ***************************************************************************/

#ifndef _Sensors_h_
#define _Sensors_h_

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_BMP280.h>

static Adafruit_BME280 BME280;
static Adafruit_BMP280 BMP280;

float BME280_ReadData(int type);
float BMP280_ReadData(int type);
void BME280_Init(bool debugMode);
void BMP280_Init(bool debugMode);

#endif

And here's the Sensors.cpp file:

#include "Sensors.h"

extern Adafruit_BME280 BME280;
extern Adafruit_BMP280 BMP280;

extern int PIN_SCK;
extern int PIN_MISO;
extern int PIN_MOSI;
extern int PIN_CS_BME;
extern int PIN_CS_BMP;

extern float SEALEVELPRESSURE_HPA;

float BME280_ReadData(int type)
{
  if (type == 0) //Temperature
    return BME280.readTemperature();
  else if (type == 1) //Pressure
    return (BME280.readPressure() / 100.0F);
  else if (type == 2) //Altitude
    return BME280.readAltitude(SEALEVELPRESSURE_HPA);
  else if (type == 3) //Humidity
    return BME280.readHumidity();

  return -6969;
}

float BMP280_ReadData(int type)
{
  if (type == 0) //Temperature
    return BMP280.readTemperature();
  else if (type == 1) //Pressure
    return BMP280.readPressure();
  else if (type == 2) //Altitude
    return BMP280.readAltitude(1013.25);

  return -6969;
}

void BME280_Init(bool debugMode)
{
  if (debugMode)
    Serial.println("SETTING UP BME280...");

  BME280 = Adafruit_BME280(PIN_CS_BME);  // hardware SPI
  //BME280 = Adafruit_BME280(PIN_CS_BME, PIN_MOSI, PIN_MISO, PIN_SCK); // software SPI

  bool status = BME280.begin();

  while (!status) 
  {
    if (debugMode)
    {
      Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
      Serial.print("SensorID was: 0x");
      Serial.println(BME280.sensorID(), 16);
      Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
      Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
      Serial.print("        ID of 0x60 represents a BME 280.\n");
      Serial.print("        ID of 0x61 represents a BME 680.\n");
    }

    delay(1000);
  }

  if (debugMode)
    Serial.println("FINISHED SETTING UP BME280.");
}

void BMP280_Init(bool debugMode)
{
  if (debugMode)
    Serial.println("SETTING UP BMP280...");

  BMP280 = Adafruit_BMP280(PIN_CS_BMP);  // hardware SPI
  //BMP280 = Adafruit_BMP280(PIN_CS_BMP, PIN_MOSI, PIN_MISO, PIN_SCK); // software SPI

  bool status = BMP280.begin();

  while (!status) 
  {
    if (debugMode)
    {
      Serial.println(F("Could not find a valid BMP280 sensor, check wiring or try a different address!"));
      Serial.print("SensorID was: 0x");
      Serial.println(BMP280.sensorID(), 16);
      Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
      Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
      Serial.print("        ID of 0x60 represents a BME 280.\n");
      Serial.print("        ID of 0x61 represents a BME 680.\n");
    }

    delay(1000);
  }

  BMP280.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                    Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                    Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                    Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                    Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */

  if (debugMode)
    Serial.println("FINISHED SETTING UP BMP280.");
}

The code above compiles successfuly for a 4.0, however the Teensy behaves very weirdly...

Upon uploading the code, the Teensy initializes the BME280 sensors, however upon attempting to initialize the BMP280 sensor, it simply halts and hangs at the BMP280.begin() call inside the
BMP280_Init() function...

I tried to not initialize the BMP280 sensor, only trying to read from the BME280 sensor, however the Teensy then stops and hangs at the BME280_ReadData(0) call in the loop() function in the INO file. After a few seconds the Teensy appears to reset, and it continues in an infite loop...

The output I get upon attempting to run, and right before the Teensy halts & hangs, is as follows:

-> SETTING UP BME280...
-> FINISHED SETTING UP BME280.
-> SETTING UP BMP280...

Even more interestingly, I tried to move all the initialization code to the setup() function in the INO file, and moving all the reading functions to the loop() function, and I'm able to read from both of the sensors again...

I'm also aware that in the code above I'm using the Hardware SPI function calls in order to setup the two sensors, but I've also tried the Software method, and the result is the same.

I'm a bit lost as to why separating the code like this would cause such a critical problem. I've seen people run sensors with separated code before. Moreover, I actually had another recent project that I worked on, where two Teensy's sent data to each other through an Ethernet cable. I also had a very simillar issue there, where if I separated the code into Header and CPP files, the Teensy would stop and hang indefinitely at a random line in the code. It would lead me to think that there may be something that the Arduino compiler doesn't like with the way that header files are included, but I may be wrong. I even tried reverting to & using the previous IDE versions, but to no avail.

Thank you for reading my post, any guidance is appreciated!

Download the code from external resources is not in the tradition of the local community. Please do not force the users follow the links. Insert your code directly to the forum using code tags.

You're right... I apologize, I just edited the post so all the code is integrated in the post.
Thanks for pointing it out, my post looks better now.

I've also added the fact that while I'm currently using the Hardware method of intializing the sensors, I've also tried the Software method and the results are the same.

Here's an update to my problem:

I recieved the suggestion from someone to replace the static keyword in the following two lines of code, in the Sensors.h file, with the extern keyword:

static Adafruit_BME280 BME280;
static Adafruit_BMP280 BMP280;

And to remove the extern keyword from the following two lines of code, in the Sensors.cpp file:

extern Adafruit_BME280 BME280;
extern Adafruit_BMP280 BMP280;

The changes above would fix the supposed issue of the IDE creating two separate instances of the pair of sensor variables, one when the Sensors.h file was included by SENSOR_TESTS.ino, and one when it was included by Sensors.cpp. That made sense to me, however these changes above unfortunately did not help the problem.

Out of curiosity, I tried disabling the "BMP280" sensor, just trying to intialize & read the "BME280" sensor instead, and the Teensy now halts and hangs inside the "BME280_ReadData()" function...

This is the most weird behaviour I've ever seen out of these, they just appear to stop at random points in the code and hang indefinitely, at a slightly different point each time the code is slightly changed...

Here's my code again, with the small few changes:

SENSOR_TESTS.ino:

#include "Arduino.h"
#include "Sensors.h"

int PIN_SCK = 13;
int PIN_MISO = 12;
int PIN_MOSI = 11;
int PIN_CS_BME = 9;
int PIN_CS_BMP = 10;

float SEALEVELPRESSURE_HPA = 1013.25;
int delayTime = 1000;

bool debugMode = true;

void setup() 
{
  if (debugMode)
  {
    Serial.begin(9600);

    while (!Serial) {}
  }

  BME280_Init();
  //BMP280_Init();

  if (debugMode)
    Serial.println("SENSOR TESTS\n");
}

void loop() 
{
  if (debugMode)
    Serial.println("SENSOR DATA:\n");
    
  Serial.println("BME280:\n" + String(BME280_ReadData(0)) + "\n");
  //Serial.println("BMP280:\n" + String(BMP280_ReadData(0)) + "\n");

  delay(delayTime);
}

Sensors.h:

/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor

  Designed specifically to work with the Adafruit BME280 Breakout
  ----> http://www.adafruit.com/products/2650

  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. The device's I2C address is either 0x76 or 0x77.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
  See the LICENSE file for details.
 ***************************************************************************/

#ifndef _Sensors_h_
#define _Sensors_h_

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_BMP280.h>

extern Adafruit_BME280 BME280;
extern Adafruit_BMP280 BMP280;

float BME280_ReadData(int type);
float BMP280_ReadData(int type);
void BME280_Init();
void BMP280_Init();

#endif

Sensors.cpp:

#include "Sensors.h"

Adafruit_BME280 BME280;
Adafruit_BMP280 BMP280;

extern int PIN_SCK;
extern int PIN_MISO;
extern int PIN_MOSI;
extern int PIN_CS_BME;
extern int PIN_CS_BMP;

extern float SEALEVELPRESSURE_HPA;
extern int delayTime;

extern bool debugMode;

float BME280_ReadData(int type)
{
  if (type == 0) //Temperature
    return BME280.readTemperature();
  else if (type == 1) //Pressure
    return (BME280.readPressure() / 100.0F);
  else if (type == 2) //Altitude
    return BME280.readAltitude(SEALEVELPRESSURE_HPA);
  else if (type == 3) //Humidity
    return BME280.readHumidity();

  return -6969;
}

float BMP280_ReadData(int type)
{
  if (type == 0) //Temperature
    return BMP280.readTemperature();
  else if (type == 1) //Pressure
    return BMP280.readPressure();
  else if (type == 2) //Altitude
    return BMP280.readAltitude(1013.25);

  return -6969;
}

void BME280_Init()
{
  if (debugMode)
    Serial.println("SETTING UP BME280...");

  BME280 = Adafruit_BME280(PIN_CS_BME);  // hardware SPI
  //BME280 = Adafruit_BME280(PIN_CS_BME, PIN_MOSI, PIN_MISO, PIN_SCK); // software SPI

  while (!BME280.begin()) 
  {
    if (debugMode)
    {
      Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
      Serial.print("SensorID was: 0x");
      Serial.println(BME280.sensorID(), 16);
      Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
      Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
      Serial.print("        ID of 0x60 represents a BME 280.\n");
      Serial.print("        ID of 0x61 represents a BME 680.\n");
    }

    delay(delayTime);
  }

  if (debugMode)
    Serial.println("FINISHED SETTING UP BME280.");
}

void BMP280_Init()
{
  if (debugMode)
    Serial.println("SETTING UP BMP280...");

  BMP280 = Adafruit_BMP280(PIN_CS_BMP);  // hardware SPI
  //BMP280 = Adafruit_BMP280(PIN_CS_BMP, PIN_MOSI, PIN_MISO, PIN_SCK); // software SPI

  while (!BMP280.begin()) 
  {
    if (debugMode)
    {
      Serial.println("Could not find a valid BMP280 sensor, check wiring or try a different address!");
      Serial.print("SensorID was: 0x");
      Serial.println(BMP280.sensorID(), 16);
      Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
      Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
      Serial.print("        ID of 0x60 represents a BME 280.\n");
      Serial.print("        ID of 0x61 represents a BME 680.\n");
    }

    delay(delayTime);
  }

  BMP280.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                    Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                    Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                    Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                    Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */

  if (debugMode)
    Serial.println("FINISHED SETTING UP BMP280.");
}

Just to be clear, the current output here I'm getting before the Teensy halts & hangs is the following:

-> SETTING UP BME280...
-> FINISHED SETTING UP BME280.
-> SENSOR TESTS
-> 
-> SENSOR DATA:
->

I've verified again that I can run & read from both of the sensors with the sample template code from the Arduino IDE Adafruit Libraries as intended. At this point I'm thinking it may be an internal problem with my Teensy 4.0. I'll try running this code on a Teensy 4.1, and see what the results are. If that doesn't work, I'm at a complete loss unfortunately. :frowning:

After posting about the issue on another forum, I finally found the solution to my issue.

After removing the sensor global variable declarations from the header file, and only doing them in the CPP file, it appears to work!

I'm able to initialize & read both of my sensors, as intended:

-> -- SENSOR DATA --
-> 
-> BME280:
-> Temperature:	12.78 °C
-> Pressure:	        972.61 hPa
-> Altitude:	        458.29 m
-> Humidity:	        47.52 %
-> 
-> BMP280:
-> Temperature:	13.59 °C
-> Pressure:	        98269.79 Pa
-> Altitude:	        457.53 m
->

Here's the current code that is able to successfully run both of these sensors through SPI:

SENSOR_TESTS.ino:

#include "Arduino.h"
#include "Sensors.h"

int PIN_SCK = 13;
int PIN_MISO = 12;
int PIN_MOSI = 11;
int PIN_CS_BME = 9;
int PIN_CS_BMP = 10;

float SEALEVELPRESSURE_HPA = 1013.25;
int delayTime = 1000;

bool debugMode = true;

void setup() 
{
  Serial.begin(9600);

  BME280_Init();
  BMP280_Init();

  if (debugMode)
    Serial.println("---- SENSOR TESTS ----\n");
}

void loop() 
{
  if (debugMode)
    Serial.println("-- SENSOR DATA --\n");
    
  Serial.println(ReadAllSensors());

  delay(delayTime);
}

Sensors.h:

/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor

  Designed specifically to work with the Adafruit BME280 Breakout
  ----> http://www.adafruit.com/products/2650

  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. The device's I2C address is either 0x76 or 0x77.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
  See the LICENSE file for details.
 ***************************************************************************/

#ifndef _Sensors_h_
#define _Sensors_h_

#include "Arduino.h"
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_BMP280.h>

String ReadAllSensors();
float BME280_ReadData(int type);
float BMP280_ReadData(int type);
void BME280_Init();
void BMP280_Init();

#endif

Sensors.cpp:

#include "Sensors.h"

extern int PIN_SCK;
extern int PIN_MISO;
extern int PIN_MOSI;
extern int PIN_CS_BME;
extern int PIN_CS_BMP;

extern float SEALEVELPRESSURE_HPA;
extern int delayTime;

extern bool debugMode;

Adafruit_BME280 BME280(PIN_CS_BME);  // hardware SPI
//Adafruit_BME280 BME280(PIN_CS_BME, PIN_MOSI, PIN_MISO, PIN_SCK); // software SPI
Adafruit_BMP280 BMP280(PIN_CS_BMP);  // hardware SPI
//Adafruit_BMP280 BMP280(PIN_CS_BMP, PIN_MOSI, PIN_MISO, PIN_SCK); // software SPI

String ReadAllSensors()
{
  String BME280_data = "";
  String BMP280_data = "";

  BME280_data += "BME280:\n";
  BME280_data += "Temperature:\t"  + String(BME280_ReadData(0)) + " °C\n";
  BME280_data += "Pressure:\t"     + String(BME280_ReadData(1)) + " hPa\n";
  BME280_data += "Altitude:\t"     + String(BME280_ReadData(2)) + " m\n";
  BME280_data += "Humidity:\t"     + String(BME280_ReadData(3)) + " %\n";
  BME280_data += "\n";

  BMP280_data += "BMP280:\n";
  BMP280_data += "Temperature:\t"  + String(BMP280_ReadData(0)) + " °C\n";
  BMP280_data += "Pressure:\t"     + String(BMP280_ReadData(1)) + " Pa\n";
  BMP280_data += "Altitude:\t"     + String(BMP280_ReadData(2)) + " m\n";
  BMP280_data += "\n";

  String data = "";

  data += BME280_data;
  data += BMP280_data;

  return data;
}

float BME280_ReadData(int type)
{
  if (type == 0) //Temperature
    return BME280.readTemperature();
  else if (type == 1) //Pressure
    return (BME280.readPressure() / 100.0F);
  else if (type == 2) //Altitude
    return BME280.readAltitude(SEALEVELPRESSURE_HPA);
  else if (type == 3) //Humidity
    return BME280.readHumidity();

  return -6969;
}

float BMP280_ReadData(int type)
{
  if (type == 0) //Temperature
    return BMP280.readTemperature();
  else if (type == 1) //Pressure
    return BMP280.readPressure();
  else if (type == 2) //Altitude
    return BMP280.readAltitude(1013.25);

  return -6969;
}

void BME280_Init()
{
  if (debugMode)
    Serial.println("SETTING UP BME280...");

  while (!BME280.begin()) 
  {
    if (debugMode)
    {
      Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
      Serial.print("SensorID was: 0x");
      Serial.println(BME280.sensorID(), 16);
      Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
      Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
      Serial.print("        ID of 0x60 represents a BME 280.\n");
      Serial.print("        ID of 0x61 represents a BME 680.\n");
    }

    delay(delayTime);
  }

  if (debugMode)
    Serial.println("FINISHED SETTING UP BME280.");
}

void BMP280_Init()
{
  if (debugMode)
    Serial.println("SETTING UP BMP280...");

  while (!BMP280.begin()) 
  {
    if (debugMode)
    {
      Serial.println("Could not find a valid BMP280 sensor, check wiring or try a different address!");
      Serial.print("SensorID was: 0x");
      Serial.println(BMP280.sensorID(), 16);
      Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
      Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
      Serial.print("        ID of 0x60 represents a BME 280.\n");
      Serial.print("        ID of 0x61 represents a BME 680.\n");
    }

    delay(delayTime);
  }

  BMP280.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                    Adafruit_BMP280::SAMPLING_X2,     /* Temp. oversampling */
                    Adafruit_BMP280::SAMPLING_X16,    /* Pressure oversampling */
                    Adafruit_BMP280::FILTER_X16,      /* Filtering. */
                    Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */

  if (debugMode)
    Serial.println("FINISHED SETTING UP BMP280.");
}

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