Hard Fault SOS after reboot - Electron

I am using an Electron and am experiencing a hard fault SOS loop when rebooting as described below. The loop that I am experiencing is solid white, blinking green, blinking cyan, then breathing cyan very briefly before giving the hard fault SOS. Then it will restart and do the same thing.

When flashing my code, it will work continuously without any problems, but when I turn the power off to the device then turn it back on, it enters this SOS loop and will not exit.

I am able to exit out of the loop by flashing tinker in DFU mode, then re-flash my code to the device and it will work as expected until I try to reboot the device again.

I was wondering what can cause this loop to happen as I want to be able to turn the device off and on. My code is quite long to be applied to this thread, but I can update as needed, but mainly looking for possible causes that I can go search for.

Thanks,
Jeff

Is that an SOS+1 “hard fault”? Quoting this thread:

“The most common reason for hard faults are due to code violating buffer/variable boundaries or memory leaks.”

If using the WebIDE, you can always use the “Share this Revision” button and post the link here instead of posting the raw code.

Yes that is correct, it is the SOS+1 “hard fault”.

According to the thread, a possibility of the fault occurring is accessing “buggy” data in the EEPROM. I am not storing any data, instead I am just reading data of multiple sensors and pushing them to particle cloud. Here is a rundown of what I am doing:

Setting up my sensors:

std::vector<Sensor*> sensorVector;

sensorVector.push_back(new firstSensor("pipe1","pipe2","pipe3",4));
sensorVector.push_back(new firstSensor("pipe1","pipe2","pipe3",5));
sensorVector.push_back(new bme("Temp","Hmdty", bme));
…

Parent Sensor class:

#ifndef SENSOR_H
#define SENSOR_H

#include "map"
#include "application.h"

//Size of averageing array
const int SIZE = 60;

class Sensor {

private:

  //Collection of data values
  std::map<String, String> rawData;
  std::map<String, String> avgData;
    
  //Flag for Sensor state
  int flag = -1;

public:

  //Abstract method to read sensor data
  virtual void readSensor() = 0;

  //Abstract method to calculate average
  virtual void calculateAvg() = 0;

  //Getters
  int getFlag() { return flag; };
  std::map<String, String> getRawData() { return rawData; };
  std::map<String, String> getAvgData() { return avgData; };

  //Setters
  void setFlag(int newFlag) { flag = newFlag; }
  void setRawDataValue(String name, String value) { rawData[name] = value; };
  void setAvgDataValue(String name, String value) { avgData[name] = value; };

  //Insert
  void insertRawData(String name, String value) { rawData.insert({name, value}); };
  void insertAvgData(String name, String value) { avgData.insert({name, value}); };

};

#endif

Here is the class for bme, firstSensor follows similar but with different communication

#ifndef BME_h
#define BME_h

#include "Sensor.h"
#include "application.h"
#include "Adafruit_BME280.h"

class Bme: public Sensor {
  
  private:
  
    //Name of JSON objects
    String temperature, humidity;

    //BME object
    Adafruit_BME280* bme;
  
  public:

    //Constructor for BME sensor
    Bme(String temp, String hmdty, Adafruit_BME280* bmeSensor);
    
    //Read BME sensor
    virtual void readSensor();
    
    //Calculate average for BME sensor
    virtual void calculateAvg();
    
};

#endif

I didn’t include the .cpp files as I have these working in different code without any errors that I am experiencing in this code.

In my loop() function, I have:

currentSecond = Time.second();

//Iterate through Sensors
for (std::vector<Sensor*>::iterator it = sensorVector.begin(); it != sensorVector.end(); ++it) {
    
  //Run particle process
  Particle.process();

  //Obtain sensor values
  (*it)->readSensor();

  //Run particle process
  Particle.process();

  //Obtain sensor average
  (*it)->calculateAvg();

}

//Run particle process
  Particle.process();

if (currentSecond == 0) {
  createMessage();
  bool success = Particle.publish("Data", message);
}

//Run particle process
Particle.process();

Where my createMessage() function is:

//Create message from sensors
void createMessage() {

  //Get all sensor data into a single string
  String preMessage = "{";

  //Create time JSON object
  preMessage += String("\"Time\":\"") + String((const char*)Time.format("%FT%TZ"));

  //Grab data from sensors
  for (auto sensor : sensorVector) {
    for (auto data : sensor->getAvgData()) {
      preMessage = preMessage + String(",\"") + data.first + String("\":") + data.second;
    }
  }

  //Close message
  preMessage += String("}");

  //Format string to c-style string to be sent
  strcpy(message, preMessage.c_str());

}

with message being declared as char[256]

I am not using the WebIDE, I am using particle workbench.

Don’t get caught up on the use of EEPROM in that post. I think the takeaway is that you have to be extremely careful about data boundaries in C++.

I have only worked with a vector of Strings once… and from what I recall, I started getting into hard-fault problems as well. First think I would do is change the size of the “message” variable to larger than 256… try 1000 or something very large to rule out you aren’t copying too much data into a small buffer. Also, you’ll find that the use of String causes heap fragmentation over time. It may very well be contributing to your hard fault problem. You might consider switching to c-style strings in place of String.

Second, are you sure this iterator is working properly and not trying to call data past the end of the vector boundry?

for (std::vector<Sensor*>::iterator it = sensorVector.begin(); it != sensorVector.end(); ++it) {
 

Why are there less arguments on the third line? Should they not all have an identical quantity of parameters?

1 Like

Thank you for the fast reply, I will take these points into consideration and modify the code. I will respond if these points fixes this problem or if I am still having trouble.

I believe the iterator is working properly as I did extensive amount of testing with it, but I may have missed something so I will do some more testing with it.

For the last point, each sensor has different quantities of data that it measures and because I need to set each parameter to a unique name, each sensor will need different amount of parameters. This is mainly due to the possibility of having multiple of the same sensors on a single unit for correlation purposes.