Go Down

Topic: Buffering BME280 sensor reads using ISR (Read 725 times) previous topic - next topic

WeaSiL

Hi all,  my first time posting here.  Chances are I'm making a simple mistake, but been staring at the screen for a while and not figuring it out.

I want to read altitude from a BME280 sensor (eventually I'd like to read temp and log the relative time of the readings as well) and write it to an SD card.  The research I've done leads me to think that taking my readings with an ISR and buffering them is the way to go.  Even when I strip all the buffering and SD related code out I can't even seem to get a simple ISR to return a reading.  The sensor is confirmed working by using the same code in my 'void loop ()' so I know it's something else.

I'm using an Arduino Pro Mini 3.3V 8MHz

Code: [Select]
#include "SparkFunBME280.h"
#include <Wire.h>
#include <SD.h>
#include <TimerOne.h>

#define buffSize 16
#define buffCount 2

//buffer related variables
volatile float writeBuffer [buffSize][buffCount];     //array to buffer sensor readings for write to SD
volatile float alt;                                   //temp variable to check if interrupt function working properly
volatile byte bufferID = 0;                           //array of elements 1 or 2
//volatile unsigned long sensorTime;                  //future use to write time of sensor read to SD 
volatile byte bufferCount = 0;                        //which array element is being indexed
volatile bool bufferFull = false;                     //trigger the main loop to write buffer to SD

//sensor related variables
BME280 sensor;
//float alt, temp;

// SD write related variables
File myFile;
int once=0;
String FileName = "";
String FileExt = ".csv";
String FilePre = "test";
int inc = 0;

//time related variables
long unsigned timer = 0;
int Delay = 50;

void setup()
{
  sensor.settings.commInterface = I2C_MODE;           //sensor setup calls
  sensor.settings.I2CAddress = 0x76;
  sensor.settings.runMode = 3;
  sensor.settings.tStandby = 4;
  sensor.settings.filter = 0;
  sensor.settings.tempOverSample = 1;
  sensor.settings.pressOverSample = 1;

  delay(1000);
  sensor.begin();                                     //make sure sensor has adequate time to come online
  delay(1000);

  Serial.begin(57600);
  Serial.println("Begin");
  Serial.print("Starting BME280....");

  //if(!SD.begin(4))                                  //check for SD communication
  //{
  //  Serial.println("Initialization failed.");
  //  return;
  //}
  Serial.println("Initialization done.");

  //FileName = FilePre + inc + FileExt;               //routine to determine filename, numbered sequentially from one run to the next
  //while (SD.exists(FileName))                       //disabled all SD functions to try and troubleshoot ISR
  //{
  //  inc++;
  //  FileName + "";
  //  FileName = FilePre + inc + FileExt;
  //}
  //myFile = SD.open(FileName, FILE_WRITE);
  //if (myFile)
  //{
  //  Serial.println("File Open");
  //  myFile.println("time, alt, temp");
  //  myFile.close();
  //} else
  //{
  //  Serial.println("Error opening file.");
  //}
  Serial.println("time, alt, temp");

  Timer1.initialize(500000);
  Timer1.attachInterrupt(readSensor);
}

void loop()
{
  if (bufferFull = true)                             //check if one of the buffers is full
  {
    for (int i = 0; i < buffSize; i++)
    {
      //Serial.println (writeBuffer[i][bufferID]);  //write buffer values to screen, eventually will change to SD write
    }
    bufferFull = false;                             //reset buffer trigger
  }
}

void readSensor()                                   //ISR to read sensor values
{
  Serial.print("Reading sensor value.... :");       //on screen notification
  alt=sensor.readFloatAltitudeFeet();               //read sesnor value to temp variable
  Serial.print(alt);                                //write to screen
  /*if (bufferCount = buffSize)                     //check if buffer is full and increment to next element
  {
    if (bufferID = 0)
    {
      bufferID = 1;
      bufferCount = 0;
      bufferFull = true;                            //set buffer full trigger
    }
    else
    {
      bufferID = 0;
      bufferCount = 1;
      bufferFull = true;
    }
  }
  else
  {
    bufferCount++;                                  //increment buffer element counter
    writeBuffer[bufferCount][bufferID]=sensor.readFloatAltitudeFeet();  //write sensor reading to buffer element
    Serial.println(alt);
  }
  */
 
}


The serial monitor window gets cut off part way through writing the initialisation messages, I'm assuming my ISR is being called?

Any help would be greatly appreciated.


Thanks,
Scott

PaulS

Code: [Select]
  if (bufferFull = true)                             //check if one of the buffers is full
That is NOT what the code does. == is the comparison operator. = is the assignment operator. HUGE difference.

The art of getting good answers lies in asking good questions.

WeaSiL

lol .... I knew it.  Always something simple.  I'll make the appropriate change tonight and see where it gets me.

However, even with that portion commented out, it should be outputting the sensor reading every time the ISR is called should it not?  Or can I not use a Serial.println in my ISR function?

PaulS

Quote
Or can I not use a Serial.println in my ISR function?
Serial output uses interrupts. Interrupts are disabled during an ISR.

To overcome the issue, the print() method invokes the same function that the interrupt service routine does, as many times as needed to make room in the buffer. That WILL slow your ISR down. So, while you can (using relative recent versions of the IDE) get away with using Serial.print() in an ISR, you should not be doing that.

If you MUST, print as little as possible in the ISR.

You also need to make SURE that the functions you are calling from the ISR do not use delay() or rely on interrupts being enabled.

Which BME280 library are you using? Adafruit's and Sparkfun's libraries both use interrupts to read from the sensor.
The art of getting good answers lies in asking good questions.

WeaSiL

I'm using Sparkfun's library for the BME280.  Can you recommend a library that doesn't use interrupts?

Thanks,
Scott

PaulS

Quote
Can you recommend a library that doesn't use interrupts?
As far as I can tell, that device is an I2C device, which means that it's read from/written to using the Wire library, which is all about interrupts. So, no.

Why do you need to read the device in an ISR? The blink without delay philosophy should be sufficient to allow you to read the device at regular intervals without using timer interrupts.
The art of getting good answers lies in asking good questions.

WeaSiL

I'm not familiar with the Blink without delay approach.... It looks like I will be looking into it.

The problem is that I want a regular sensor reading (50ms or so), and to write that to a .csv file on an SD card.  It seems this cannot be done in a strictly linear fashion as the SD writes can take a lot of time.  So some reading pointed me towards the buffer idea, which got me looking into ISR's somehow.

The end goal is an altimeter for model rockets.  I want to sample barometric pressure, and temperature at regular intervals and write them all to an SD card.


WeaSiL

My limited understanding tells me that it's simply not possible to continuously read my sensor every 50ms and at the same time write buffered readings to SD.  If at times the SD writes can take as much as 200+ms I will be missing sensor readings won't I?

If there is a way to do it, I am totally open to enlightenment.

Thanks,
Scott

Go Up