arduino-libraries / Arduino_LPS22HB

LPS22HB Library for Arduino
GNU Lesser General Public License v2.1
6 stars 19 forks source link

LPS22HB pressure sensor reading function crashes the programm after several loops (Nano BLE Sense 33) #5

Open Haoyu-R opened 3 years ago

Haoyu-R commented 3 years ago

Hi guys,

I lost several hours to solve this strange bug. The board I am using is Arduino Nano BLE Sense 33.

In short, I use sprintf to format sensor readings before Serial.print() in loop(). At the start, the program works perfectly. However, after many iterations of loop() the system hangs.

After I checked the program carefully, I found It's pressure sensor reading function causing the crash.

pressure = BARO.readPressure();

If I comment out this function, or simply replace this line with:

pressure = 5;

The program will not crash anymore.

Why I found the pressure sensor cause the froze:

I changed the code like this:

Serial.println("test1");
pressure = BARO.readPressure();
Serial.println(pressure);
Serial.println("test2");

After several loops, the program freezes after the serial port outputs "test1". No output and No error printed in serial port afterward.

What weird is that, if I comment out all the other sensor reading functions except the pressure sensor, the program can run further. (At least for 20 minutes. I don't know if it will crash after a longer period)

Well the code crashes here in the library: https://github.com/arduino-libraries/Arduino_LPS22HB/blob/d3d6bacb12cd4e8519494e3a440a1f7c29e9cfc3/src/BARO.cpp#L60-L63

Here is my sketch: simply read some sensor value, format them and print to the serial port.

Serial.println("test1");
  // pressure = BARO.readPressure();
  pressure = 5;
  Serial.println("test2");#include <Arduino_APDS9960.h>
#include <Arduino_LSM9DS1.h>
#include <Arduino_LPS22HB.h>
#include <Arduino_HTS221.h>
#include <PDM.h>

// Parameters for Microphone
#define MICROPHONE_BUFFER_SIZE_IN_WORDS (256U)
#define MICROPHONE_BUFFER_SIZE_IN_BYTES (MICROPHONE_BUFFER_SIZE_IN_WORDS * sizeof(int16_t))

/* MP34DT05 Microphone data buffer with a bit depth of 16. Also a variable for the RMS value */
int16_t microphoneBuffer[MICROPHONE_BUFFER_SIZE_IN_WORDS];
int16_t microphoneRMSValue;
// /* Used as a simple flag to know when microphone buffer is full and RMS value
//  * can be computed. */
bool microphoneBufferReadyFlag = false;

void Microphone_availablePDMDataCallback()
{
  // query the number of bytes available
  int bytesAvailable = PDM.available();

  if(bytesAvailable == MICROPHONE_BUFFER_SIZE_IN_BYTES)
  {
    PDM.read(microphoneBuffer, bytesAvailable);
    microphoneBufferReadyFlag = true;
  }
}

float Micophone_computeRMSValue()
{
  float rms = 0;
  // Square difference between each set of elements
  for (int i = 0; i < MICROPHONE_BUFFER_SIZE_IN_WORDS; i++) {
    rms += microphoneBuffer[i] * microphoneBuffer[i];
  }
  return sqrt((float)rms/MICROPHONE_BUFFER_SIZE_IN_WORDS);
}

void setup() {
  Serial.begin(9600);
  while (!Serial); // Wait for serial monitor to open

  if (!APDS.begin()) {
    Serial.println("Error initializing APDS9960 sensor.");
    while (true); // Stop forever
  }

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  if (!BARO.begin()) {
    Serial.println("Failed to initialize pressure sensor!");
    while (1);
  }

  if (!HTS.begin()) {
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }

    /* PDM setup for MP34DT05 microphone */
  /* configure the data receive callback to transfer data to local buffer */
  PDM.onReceive(Microphone_availablePDMDataCallback);
  /* Initialise single PDM channel with a 16KHz sample rate (only 16kHz or 44.1kHz available */
  if (!PDM.begin(1, 16000))
  {
    Serial.println("Failed to start PDM!");
    /* Hacky way of stopping program executation in event of failure. */
    while(1);
  }
  else
  {
    /* Gain values can be from 0 to 80 (around 38db). Check out nrf_pdm.h
     * from the nRF528x-mbedos core to confirm this. */
    /* This has to be done after PDM.begin() is called as begin() always
     *  sets the gain as the default PDM.h value (20).
     */
    PDM.setGain(50);
  }

}

int proximity = 0;
int r = 0, g = 0, b = 0;
unsigned long lastUpdate = 0;
float x1, y, z1, x2, y2, z2, x3, y3, z3, pressure, temperature, humidity, sound;
const int size = 50;
char event[size];

void loop() {

  // check if a gesture reading is available
  if (APDS.gestureAvailable()) {
    int gesture = APDS.readGesture();
    lastUpdate = millis();
    switch (gesture) {
      case GESTURE_UP:
        snprintf_P(event, size, PSTR("UP[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, 1);
        Serial.println(event);
        break;

      case GESTURE_DOWN:
        snprintf_P(event, size, PSTR("DOWN[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, 1);
        Serial.println(event);
        break;

      case GESTURE_LEFT:
        snprintf_P(event, size, PSTR("LEFT[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, 1);
        Serial.println(event);
        break;

      case GESTURE_RIGHT:
        snprintf_P(event, size, PSTR("RIGHT[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, 1);
        Serial.println(event);
        break;

      default:
        // ignore
        break;
    }
    delay(1000);
  }

  // Check if a proximity reading is available.
  if (APDS.proximityAvailable()) {
    proximity = APDS.readProximity();
  }

  // check if a color reading is available
  if (APDS.colorAvailable()) {
    APDS.readColor(r, g, b);
  }

  if(IMU.accelerationAvailable()){
      IMU.readAcceleration(x1, y, z1);
  }

  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(x2, y2, z2);
  }

  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(x3, y3, z3);
  }

  if(microphoneBufferReadyFlag)
  {
    sound = Micophone_computeRMSValue();
    microphoneBufferReadyFlag = false;
  }

  pressure = BARO.readPressure();
  temperature = HTS.readTemperature();
  humidity    = HTS.readHumidity();

  // Print updates every 200ms
  if (millis() - lastUpdate > 200) {
    lastUpdate = millis();

    snprintf_P(event, size, PSTR("proximity[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, proximity);
    Serial.println(event);

    snprintf_P(event, size, PSTR("pressure[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, (int)pressure);
    Serial.println(event);

    snprintf_P(event, size, PSTR("temperature[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, (int)temperature);
    Serial.println(event);

    snprintf_P(event, size, PSTR("humidity[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, (int)humidity);
    Serial.println(event);

    snprintf_P(event, size, PSTR("RMS_Sound[%013lu,%013lu](%i)$"), lastUpdate, lastUpdate, (int)sound);
    Serial.println(event);
    Serial.println();

    Serial.print("rgb=");
    Serial.print(r);
    Serial.print(",");
    Serial.print(g);
    Serial.print(",");
    Serial.println(b);

    Serial.print("Vibration=");
    Serial.print(x1);
    Serial.print(",");
    Serial.print(y);
    Serial.print(",");
    Serial.println(z1);

    Serial.print("Gyroscope=");
    Serial.print(x2);
    Serial.print(",");
    Serial.print(y2);
    Serial.print(",");
    Serial.println(z2);

    Serial.print("MagneticField=");
    Serial.print(x3);
    Serial.print(",");
    Serial.print(y3);
    Serial.print(",");
    Serial.println(z3);

    Serial.println();
    Serial.println();
  }
}
ChrisKretschmer commented 3 years ago

I got the same problem.

void Sensors::Loop(SystemState &state) {
  if(DEBUG) Serial.println("BEGIN Sensors::Loop()");

  long currentMillis = millis();
  if(currentMillis - previousMillis >= SAVE_INTERVAL) {  
    float temperature = ReadTemperature();
    Serial.flush();
    float pressure = ReadPressure();
    Serial.flush();
    float humidity = ReadHumidity();
    Serial.flush();
    float acc_x, acc_y, acc_z;
    ReadAcceleration(acc_x, acc_y, acc_z);
    Serial.flush();
    float g_x, g_y, g_z;
    ReadGyroscope(g_x, g_y, g_z);
    Serial.flush();
    float m_x, m_y, m_z;
    ReadMagneticField(m_x, m_y, m_z);
    Serial.flush();
    DataPoint newItem = {state.VehicleState, millis(), pressure, temperature, acc_x, acc_y, acc_z, g_x, g_y, g_z, m_x, m_y, m_z};
    Serial.flush();
    state.CurrentDataPoint = newItem;    
    Serial.flush();

    previousMillis = currentMillis;
  }
  if(DEBUG) Serial.println("END Sensors::Loop()");
}

float Sensors::ReadPressure() {
  if(DEBUG) Serial.println("BEGIN Sensors::ReadPressure()");
  return BARO.readPressure();
}

The print statements are obviously for debugging purposes...

Serial output:

(...)
BEGIN Sensors::Loop()
BEGIN Sensors::ReadTemperature()
BEGIN Sensors::ReadPressure()

The SAVE_INTERVAL is 50ms. If I replace the ReadPressure() with 0.0, the sketch doesn't crash...

ChrisKretschmer commented 3 years ago

This library seems to work:

https://github.com/pilotak/LPS35HW

If you want to try it, don't forget to Init it with !lps.begin(&Wire1)

ChrisKretschmer commented 3 years ago

FYI:

I created a topic in the Arduino forum. Maybe the issues are related: https://forum.arduino.cc/t/sensor-readings-slow-down-after-a-couple-of-minutes/869046/7