PM2.5 Sensor Project: Possible Library Conflict

Howdy folks. I’m a first-timer trying to make a PM2.5 sensor and I ran into an issue while using the GXEPD2 library and the Nova Fitness SDS dust sensors library on the Arduino Uno. Upon uploading my sketch, absolutely nothing happened. No debug printouts, no TX or RX LED flashes, nothing. Not even the “setting up…” is printed to the serial monitor. I resolved this bug by using a different library for my smoke sensor, but I don’t know what the original issue was. I’m not sure if it’s worth mentioning, or if this is the right spot in the forum to post about it. If either are not the case, please let me know.

Here’s the code I was trying to run:

/*
   PM2.5 Smoke Concentration Sensor and Display
   Based off of the examples GXEPD2_minimumExample
   from the GXEPD2 library (https://github.com/ZinggJM/GxEPD2) and
   queryReportingMode from the Nova Fitness SDS dust sensors library
   (https://github.com/lewapek/sds-dust-sensors-arduino-library)
   Uses Waveshare 1.54inch E-Paper display, Arduino Uno, and Nova PM SDS011 Air Quality Sensor.
   Last updated 4/9/21
*/

//#define ENABLE_GxEPD2_GFX 0
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#define MAX_DISPLAY_BUFFER_SIZE 800
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
GxEPD2_BW<GxEPD2_154_D67, MAX_HEIGHT(GxEPD2_154_D67)> display(GxEPD2_154_D67(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEH0154D67

#include "SdsDustSensor.h"
SdsDustSensor sds(3, 5);  //rx pin, tx pin



void setup() {

  Serial.begin(9600);
  Serial.println("setting up...");
  delay(1000);

  sds.begin();


  display.init();
  display.fillScreen(GxEPD_WHITE);
  display.fillScreen(GxEPD_BLACK);
  display.fillScreen(GxEPD_WHITE);
  display.setRotation(1);
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);

}

void loop() {

  Serial.println("Waking up sensor");
  sds.wakeup();
  Serial.println("Waiting...");
  delay(30000);
  Serial.println("Getting PM values");
  checkSensor();
  Serial.println("Sensor going back to sleep\n");
  sds.sleep();
  
  delay(60000);

}

void checkSensor() {

  PmResult pm = sds.queryPm();
  
  display.firstPage();
  do
  {
    
    Serial.println("PM2.5 = ");
    Serial.print(pm.pm25);
    
    display.fillScreen(GxEPD_WHITE);
    
    display.setCursor((display.width() - 200) / 2, display.height() / 8);
    display.println("PM2.5 Conc.[µg/m^3]: ");
    display.println(pm.pm25);
  
    display.setCursor(0, display.height() * 1 / 2);
    display.println("Caution:  100% of \nthose who breathe O2 die.\n");
    //^^ this is stand-in:  later I want custom messages for different PM2.5 concentrations
  }
  while (display.nextPage());
  
}

This sketch works if the portions written for the sensor are commented out and the display left to periodically update with dummy values, and it works if the portions written for the display are commented out and the sensor simply prints to the serial monitor. For example, both of the below work.
Commeting out the display code:

/*
//#define ENABLE_GxEPD2_GFX 0
#include 
#include 
#define MAX_DISPLAY_BUFFER_SIZE 800
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
GxEPD2_BW display(GxEPD2_154_D67( SS,  8,  9,  7)); // GDEH0154D67
*/

#include "SdsDustSensor.h"
SdsDustSensor sds(3, 5);  //rx pin, tx pin


void setup() {

  Serial.begin(9600);
  Serial.println("setting up...");
  delay(1000);

  sds.begin();

  /*
  display.init();
  display.fillScreen(GxEPD_WHITE);
  display.fillScreen(GxEPD_BLACK);
  display.fillScreen(GxEPD_WHITE);
  display.setRotation(1);
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);
  */
}



void loop() {

  Serial.println("Waking up sensor");
  sds.wakeup();
  Serial.println("Waiting...");
  delay(30000);
  Serial.println("Getting PM values");
  checkSensor();
  Serial.println("Sensor going back to sleep\n");
  sds.sleep();
  
  delay(60000);

}



void checkSensor() {

  PmResult pm = sds.queryPm();
  Serial.println("PM2.5 = ");
  Serial.println(String(pm.pm25)+"\n");

  /*
  display.firstPage();
  do
  {
    
    Serial.println("PM2.5 = ");
    Serial.print(pm.pm25);
    
    display.fillScreen(GxEPD_WHITE);
    
    display.setCursor((display.width() - 200) / 2, display.height() / 8);
    display.println("PM2.5 Conc.[µg/m^3]: ");
    display.println(pm.pm25);
  
    display.setCursor(0, display.height() * 1 / 2);
    display.println("Caution:  100% of \nthose who breathe O2 die.\n");
    //^^ this is stand-in:  later I want custom messages for different PM2.5 concentrations
  }
  while (display.nextPage());
  */
  
}

Commenting out the sensor code:

//#define ENABLE_GxEPD2_GFX 0
#include 
#include 
#define MAX_DISPLAY_BUFFER_SIZE 800
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
GxEPD2_BW display(GxEPD2_154_D67(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEH0154D67

/*
#include "SdsDustSensor.h"
SdsDustSensor sds(3, 5);  //rx pin, tx pin
*/



void setup() {

  Serial.begin(9600);
  Serial.println("setting up...");
  delay(1000);

  //sds.begin();


  display.init();
  display.fillScreen(GxEPD_WHITE);
  display.fillScreen(GxEPD_BLACK);
  display.fillScreen(GxEPD_WHITE);
  display.setRotation(1);
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);

}

void loop() {

  /*
  Serial.println("Waking up sensor");
  sds.wakeup();
  Serial.println("Waiting...");
  delay(30000);
  Serial.println("Getting PM values");
  checkSensor();
  Serial.println("Sensor going back to sleep\n");
  sds.sleep();
  */
  checkSensor();
  
  //delay(60000);
  delay(1000);

}

void checkSensor() {

  //PmResult pm = sds.queryPm();
  
  display.firstPage();
  do
  {
    
    Serial.println("PM2.5 = ");
    //Serial.print(pm.pm25);
    
    display.fillScreen(GxEPD_WHITE);
    
    display.setCursor((display.width() - 200) / 2, display.height() / 8);
    display.println("PM2.5 Conc.[µg/m^3]: ");
    //display.println(pm.pm25);
  
    display.setCursor(0, display.height() * 1 / 2);
    display.println("Caution:  100% of \nthose who breathe O2 die.\n");
    //^^ this is stand-in:  later I want custom messages for different PM2.5 concentrations
  }
  while (display.nextPage());
  
}

This updated sketch, which uses a different library, also works:

/*
   PM2.5 Smoke Concentration Sensor and Display
   Based off of the examples GXEPD2_minimumExample
   from the GXEPD2 library (https://github.com/ZinggJM/GxEPD2) and
   NovaSDS011 from the Nova_sds011 Sensor Library
   (https://github.com/lewapek/sds-dust-sensors-arduino-library)
   Uses Waveshare 1.54inch E-Paper display, Arduino Uno, and Nova PM SDS011 Air Quality Sensor.
 */
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#define MAX_DISPLAY_BUFFER_SIZE 800
#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8))
GxEPD2_BW<GxEPD2_154_D67, MAX_HEIGHT(GxEPD2_154_D67)> display(GxEPD2_154_D67(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEH0154D67


#include <NovaSDS011.h>
#define SDS_PIN_RX 3
#define SDS_PIN_TX 5
NovaSDS011 sds011;


void setup() {

  Serial.begin(9600);
  Serial.println("setting up...");
  delay(1000);

  sds011.begin(SDS_PIN_RX, SDS_PIN_TX);
  
  sds011.setWorkingMode(WorkingMode::work);
  sds011.setDutyCycle(5);

  display.init();
  display.fillScreen(GxEPD_WHITE);
  display.fillScreen(GxEPD_BLACK);
  display.fillScreen(GxEPD_WHITE);
  display.setRotation(1);
  display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);

}

void loop() {

  float p25, p10;
  if (sds011.queryData(p25, p10) == QuerryError::no_error)
  {
    Serial.println(String(millis() / 1000) + "s:PM2.5=" + String(p25) + ", PM10=" + String(p10));


    display.firstPage();
    do
    {    
      display.fillScreen(GxEPD_WHITE);
      
      display.setCursor((display.width() - 200) / 2, display.height() / 8);
      display.println("PM2.5 Conc.[µg/m^3]: ");
      display.println(String(p25));
    
      display.setCursor(0, display.height() * 1 / 2);
      display.println("Caution:  100% of \nthose who breathe O2 die.\n");
      //^^ this is stand-in:  later I want custom messages for different PM2.5 concentrations
    }
    while (display.nextPage());

    Serial.println("Waiting for 60 seconds...");
    delay(60000);
  }


  

}

void checkSensor() {

  //PmResult pm = sds.queryPm();
  
  display.firstPage();
  do
  {
    
    Serial.println("PM2.5 = ");
    //Serial.print(pm.pm25);
    
    display.fillScreen(GxEPD_WHITE);
    
    display.setCursor((display.width() - 200) / 2, display.height() / 8);
    display.println("PM2.5 Conc.[µg/m^3]: ");
    //display.println(pm.pm25);
  
    display.setCursor(0, display.height() * 1 / 2);
    display.println("Caution:  100% of \nthose who breathe O2 die.\n");
    //^^ this is stand-in:  later I want custom messages for different PM2.5 concentrations
  }
  while (display.nextPage());
  
}

Sounds like you might be running out of memory. Displays can consume a lot of RAM and an Uno doesn’t have a ton to start with…

There are functions available for reporting how much free memory your sketch has if you google for them.

Sounds like you might be running out of memory…

The Arduino IDE prints the following warning when I compile the original sketch:

Sketch uses 23510 bytes (72%) of program storage space. Maximum is 32256 bytes.
Global variables use 1779 bytes (86%) of dynamic memory, leaving 269 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

Which seems like it should be enough to at least run poorly. I’ve certainly uploaded other draft sketches to my arduino that use that amount of memory or more without having similar issues.

You can save a bit of RAM by wrapping all those Serial.print() strings with the F() macro so they stay in PROGMEM and don’t consume RAM

 Serial.println(F("setting up..."));
...

That’s a neat trick. Thank you for the recommendation!

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