Program slowly degrades

Hello,
I’m writing a piece of software that logs some data from various environmental sensors and GPS, and does some basic data processing and SD storage. I have run into some problems (Probably?) regarding memory. after several loops this program’s output degrades as seen in screenshot below. I suspect this may be caused by memory fragmentation and I have tired several ways how to fix it, but I’ve run out of ideas. I’m posting the code with screenshot below, if anyone here could point me to right direction I’d be very grateful…

//=== LIBRARIES ===//
#include <dht.h>
#include <SD.h> //library for SD card
#include <SPI.h> // library for comunication
#include <Wire.h> //virtual wire library
#include <Adafruit_BMP085.h> // BMP180 library
#include <TinyGPS.h> // library for GPS NEO 6M
#include <SoftwareSerial.h> // library for Serial comunication and for using more serial pins

//=== DEFINES ===//
//define for SD card
#define SD_INIT_MAX_RETRY 100
#define CHIP_SELECT
//defines for DHT
#define DHTPIN 2
#define DHTTYPE DHT21   // DHT 21 (AM2301)
#define LOG_FILE_OPEN_MAX_ATTEMPTS 100
//defines for GPS
#define TX 3 //pin 3 where is gps TX wire connected
#define RX 4 // pin 4 where is gps RX wire connected

#define BUTTON_PIN 7

//=== GLOBAL VARIABLES ===//
int loopCounter = 0; //counter

//variables for activating and deactivating function
bool active = false;
int buttonValue;

//=== VOID SETUP ===//
void setup() {
  Serial.begin(9600);
  pinMode(BUTTON_PIN, INPUT);

  // this part is for initialization of the SD card
  for (int i = 0; !SD.begin(CHIP_SELECT) && i < SD_INIT_MAX_RETRY; i++) {
  }
}

//=== MAIN LOOP ===//
void loop() {
  //check for button presses, on press it will pause/unpause main loop to prevent SD card corruption
  buttonValue = digitalRead(BUTTON_PIN);
  if (buttonValue == LOW) {
    active = !active;
  }

  if (!active) {
    Serial.print("Inactive \n");
    delay(1000);
    return;
  } else {
    Serial.print("Active \n");
  }

  processDHT();
  processBMP();
  processGPS();

  loopCounter++;
  delay(1000);
}

void processDHT() {
  dht DHT;

  DHT.read21(DHTPIN);
  logData("Humidity: " + String(DHT.humidity));
  logData("Temperature: " + String(DHT.temperature));
  logData("Dew point: " + String(dewPoint(DHT.temperature, DHT.humidity)));
}

void processBMP() {
  Adafruit_BMP085 bmp180;
  bmp180.begin();

  logData("Press: " + String(bmp180.readPressure()));
}

void processGPS() {
  TinyGPS gps;
  SoftwareSerial swSerial(RX, TX);
  swSerial.begin(9600);

  // after 5 seconds, the data will come from gps
  for (unsigned long start = millis(); millis() - start < 1000;) {
    // control of activity of serial monitor
    while (swSerial.available()) {
      // invoke a variabile for reading data from GPS
      char c = swSerial.read();
      //Serial.write(c); // for displaying data on serial monitor, uncomment this line
      if (gps.encode(c)) { //if this pass, we got meaningfull data
        // if the data are recieved we will invoke an another variabile for cleaning the data :P <-- yeah, after we solve memory issues...
        float latitude, longitude;
        int year;
        byte month, day, hour, minute, second;

        //just log everything
        gps.f_get_position(&latitude, &longitude);
        logData("Lat: " + String(latitude));
        logData("Long: " + String(longitude));
        logData("Alt: " + String(gps.f_altitude()));
        logData("Spd: " + String(gps.f_speed_kmph()));
      }
    }
  }
}

void logData(String data) {
  File dataFile;
  //Serial.print("Trying to open Data File \n");
  for (int i = 0; i < LOG_FILE_OPEN_MAX_ATTEMPTS && !dataFile; i++) {
    //Serial.print("Opening data file \n");
    dataFile = SD.open("datalog.txt", FILE_WRITE);
    if (i == 99) { //comment after
      Serial.print("Max attempts reached");
    }
  }

  if (dataFile) {
    Serial.print("Logging data " + data + "\n");
    dataFile.print("Loop no. " + loopCounter);
    dataFile.println(" | " + data);
    dataFile.close();
  }
}


//
//Celsius to Fahrenheit conversion
double Fahrenheit(double celsius)
{
  return 1.8 * celsius + 32;
}

//Celsius to Kelvin conversion
double Kelvin(double celsius)
{
  return celsius + 273.15;
}

// dewPoint function NOAA
// reference: http://wahiduddin.net/calc/density_algorithms.htm
double dewPoint(double celsius, double humidity)
{
  double A0 = 373.15 / (273.15 + celsius);
  double SUM = -7.90298 * (A0 - 1);
  SUM += 5.02808 * log10(A0);
  SUM += -1.3816e-7 * (pow(10, (11.344 * (1 - 1 / A0))) - 1) ;
  SUM += 8.1328e-3 * (pow(10, (-3.49149 * (A0 - 1))) - 1) ;
  SUM += log10(1013.246);
  double VP = pow(10, SUM - 3) * humidity;
  double T = log(VP / 0.61078); // temp var
  return (241.88 * T) / (17.558 - T);
}

Output degradation from log:


It is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. This can happen after the program has been running perfectly for some time. Just use cstrings - char arrays terminated with '\0' (NULL).

There is a fair probability that the use of the String class is the cause of your problem.

...R

    dataFile.print("Loop no. " + loopCounter);

That's equivalent to:

    char message[] = "Loop no. ";
    dataFile.print(&message[loopCounter]);

What you want to do is:

    dataFile.print("Loop no. ");
    dataFile.print(loopCounter);

johnwasser:

    dataFile.print("Loop no. " + loopCounter);

That's equivalent to:

    char message[] = "Loop no. ";

dataFile.print(&message[loopCounter]);




What you want to do is:


dataFile.print("Loop no. ");
    dataFile.print(loopCounter);

Using pre-allocated buffer to store my data and then printing whole buffer solves my problem actually... Or at last, seems it solved the problem, I'll have to do thorough testing today