OpenLog Qwiic - Data Storage on MicroSD not working without opening Serial Monitor

Hi everyone,

I am doing a project with the RedBoard, an IMU, and an OpenLog with micro SD, connected with Qwiic cables. To start off, I wanted to try out example1 WritingLog and example2 AppendFile from the library. Both work perfectly when opening the serial monitor. It displays the right things in the serial monitor and saves a file with the right content on the micro SD.

However, when running the script without opening the serial monitor, or when powering the system with a 9V battery, it does not save anything on the micro SD, or sometimes an empty file without content. I have tried some different things, but as this is a fairly new device and library, there is not much that I did come up with. The SPI commands from older projects do not work with this library.

Please let me know, if anyone has some ideas how to trouble shoot or what the solution might be.

Thanks,

Patrick

I have new information on this topic: When writing into the default log file, it even creates the file - on battery power, without serial monitor - but the file is empty. When trying to create a file with append, that does not work at all on battery power.

It sounds like the sketch is hanging because it’s waiting for a serial connection that isn’t present.

Try commenting out all the likes that have “Serial.” in them and upload that sketch and see if that gets things moving. :slight_smile:

/*
  An I2C based datalogger - Like the OpenLog but for I2C
  By: Nathan Seidle
  SparkFun Electronics
  Date: February 2nd, 2018
  License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).

  This example shows how to record various text and variables to Qwiic OpenLog

  To Use:
    Insert a formatted SD card into Qwiic OpenLog
    Attach Qwiic OpenLog to a RedBoard or Uno with a Qwiic cable
    Load this sketch onto the RedBoard
    Open a terminal window to see the Serial.print statements
    Then insert the SD card into a computer view the log file contents
*/

#include <Wire.h>
#include "SparkFun_Qwiic_OpenLog_Arduino_Library.h"
OpenLog myLog; //Create instance

int ledPin = 13; //Status LED connected to digital pin 13

void setup()
{
  pinMode(ledPin, OUTPUT);

  Wire.begin(); //Initialize I2C
  myLog.begin(); //Open connection to OpenLog (no pun intended)

//  Serial.begin(9600); //9600bps is used for debug statements
//  Serial.println("OpenLog Write File Test");
  
  //Record something to the default log
  myLog.println("This goes to the log file");
 // Serial.println("This goes to the terminal");

  float batteryVoltage = 3.4;
  myLog.println("Batt voltage: " + String(batteryVoltage));

  batteryVoltage = batteryVoltage + 0.71;

  myLog.println("Batt voltage: " + String(batteryVoltage));
  myLog.syncFile();

//Serial.println(F("Done!"));
}

void loop()
{
  //Blink the Status LED because we're done!
  digitalWrite(ledPin, HIGH);
  delay(100);
  digitalWrite(ledPin, LOW);
  delay(1000);
}

Thanks for the reply! I actually tried that already, and it did not solve the problem. Just to make sure, I tried it again now. When the serial monitor is open (obviously without output), it saves the right stuff on the micro sd. When I do not open the serial monitor or I power with a battery, it creates an empty txt file, but without the stuff it should save in the file. :confused:

Not sure what might be causing this then.

Opening the serial monitor will reset the RedBoard.

Have you tried battery operation and then pressing the reset button once to simulate the serial monitor being opened?

Hi Chris,

Thanks, that solved the problem. When I click the reset button in the beginning, it works on battery mode. I also figured out that when using the code that you just posted here, I have to click the reset button. Same goes with the append example.

I am doing this for a project with the IMU, so I basically combined the append example with the IMU qwiic example like this:

/****************************************************************
 * LogIMU - using "Example2_AppendFile" of the SparkFun OpenLog library together
 * with the "Example1_Basics" from the SparkFun IMU library
 * ICM 20948 Arduino Library Demo 
 * Use the default configuration to stream 9-axis IMU data
 * Owen Lyke @ SparkFun Electronics
 * Original Creation Date: April 17 2019
 * 
 * This code is beerware; if you see me (or any other SparkFun employee) at the
 * local, and you've found our code helpful, please buy us a round!
 * 
 * Distributed as-is; no warranty is given.
 ***************************************************************/
#include "ICM_20948.h"  // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU

//#define USE_SPI       // Uncomment this to use SPI


//#define SERIAL_PORT Serial

#define SPI_PORT SPI    // Your desired SPI port.       Used only when "USE_SPI" is defined
#define CS_PIN 2        // Which pin you connect CS to. Used only when "USE_SPI" is defined

#define WIRE_PORT Wire  // Your desired Wire port.      Used when "USE_SPI" is not defined
#define AD0_VAL   1     // The value of the last bit of the I2C address. 
                        // On the SparkFun 9DoF IMU breakout the default is 1, and when 
                        // the ADR jumper is closed the value becomes 0

#ifdef USE_SPI
  ICM_20948_SPI myICM;  // If using SPI create an ICM_20948_SPI object
#else
  ICM_20948_I2C myICM;  // Otherwise create an ICM_20948_I2C object
#endif

//*** added these lines from AppendFile
#include <Wire.h>
#include "SparkFun_Qwiic_OpenLog_Arduino_Library.h"
OpenLog myLog; //Create instance
//***

void setup() {
  //SERIAL_PORT.begin(115200);
 //*** added these lines from AppendFile
  Wire.begin();
  myLog.begin(); //Open connection to OpenLog (no pun intended)
  myLog.append("IMUdata.txt"); // change to your own file nameexample
 // ***

#ifdef USE_SPI
    SPI_PORT.begin();
#else
    WIRE_PORT.begin();
    WIRE_PORT.setClock(400000);
#endif
  
  bool initialized = false;
  while( !initialized ){

#ifdef USE_SPI
    myICM.begin( CS_PIN, SPI_PORT ); 
#else
    myICM.begin( WIRE_PORT, AD0_VAL );
#endif
    myLog.append("IMUdata.txt");
    myLog.print( F("Initialization of the sensor returned: ") );
    myLog.println( myICM.statusString() );
    //SERIAL_PORT.print( F("Initialization of the sensor returned: ") );
    //SERIAL_PORT.println( myICM.statusString() );
    if( myICM.status != ICM_20948_Stat_Ok ){
      myLog.println( "Trying again..." );
      //SERIAL_PORT.println( "Trying again..." );
      delay(500);
    }else{
      initialized = true;
    }
  }
}

void loop() {

  if( myICM.dataReady() ){
    myICM.getAGMT();                // The values are only updated when you call 'getAGMT'
//    printRawAGMT( myICM.agmt );     // Uncomment this to see the raw values, taken directly from the agmt structure
    printScaledAGMT( myICM.agmt);   // This function takes into account the sclae settings from when the measurement was made to calculate the values with units
    delay(30);
  }else{
    myLog.append("IMUdata.txt");
    myLog.println("Waiting for data");
    //Serial.println("Waiting for data");
    delay(500);
  }
  
}


// Below here are some helper functions to print the data nicely!

void printPaddedInt16b( int16_t val ){
  myLog.append("IMUdata.txt");
  // ** change the SERIAL_PORT.print calls to myLog.print calls. 
  // It will now save the data on your SD card
  if(val > 0){     
    myLog.print(" "); 
    if(val < 10000){ myLog.print("0"); }
    if(val < 1000 ){ myLog.print("0"); }
    if(val < 100  ){ myLog.print("0"); }
    if(val < 10   ){ myLog.print("0"); }
  }else{
    myLog.print("-");
    //SERIAL_PORT.print("-");
    if(abs(val) < 10000){ myLog.print("0"); }
    if(abs(val) < 1000 ){ myLog.print("0"); }
    if(abs(val) < 100  ){ myLog.print("0"); }
    if(abs(val) < 10   ){ myLog.print("0"); }
    // *** 
  }
   myLog.print(abs(val));
  //SERIAL_PORT.print(abs(val));
}

void printRawAGMT( ICM_20948_AGMT_t agmt){
  myLog.append("IMUdata.txt");
  // ** change the SERIAL_PORT.print calls to myLog.print calls. 
  // It will now save the data on your SD card
  //SERIAL_PORT.print("RAW. Acc [ ");
  myLog.print("RAW. Acc [ ");
  printPaddedInt16b( agmt.acc.axes.x );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printPaddedInt16b( agmt.acc.axes.y );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printPaddedInt16b( agmt.acc.axes.z );
  //SERIAL_PORT.print(" ], Gyr [ ");
  myLog.print(" ], Gyr [ ");
  printPaddedInt16b( agmt.gyr.axes.x );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printPaddedInt16b( agmt.gyr.axes.y );
  //SERIAL_PORT.print(", ");
   myLog.print(", ");
  printPaddedInt16b( agmt.gyr.axes.z );
  //SERIAL_PORT.print(" ], Mag [ ");
  myLog.print(" ], Mag [ ");
  printPaddedInt16b( agmt.mag.axes.x );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printPaddedInt16b( agmt.mag.axes.y );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printPaddedInt16b( agmt.mag.axes.z );
  //SERIAL_PORT.print(" ], Tmp [ ");
  myLog.print(" ], Tmp [ ");
  printPaddedInt16b( agmt.tmp.val );
  //SERIAL_PORT.print(" ]");
  //SERIAL_PORT.println();
  myLog.print(" ]");
  myLog.println();
  // *** 
}


void printFormattedFloat(float val, uint8_t leading, uint8_t decimals){
  myLog.append("IMUdata.txt");
  // ** change the SERIAL_PORT.print calls to myLog.print calls. 
  // It will now save the data on your SD card
  float aval = abs(val);
  if(val < 0){
   // SERIAL_PORT.print("-");
    myLog.print("-");
  }else{
    //SERIAL_PORT.print(" ");
    myLog.print(" ");
  }
  for( uint8_t indi = 0; indi < leading; indi++ ){
    uint32_t tenpow = 0;
    if( indi < (leading-1) ){
      tenpow = 1;
    }
    for(uint8_t c = 0; c < (leading-1-indi); c++){
      tenpow *= 10;
    }
    if( aval < tenpow){
      //SERIAL_PORT.print("0");
      myLog.print("0");
    }else{
      break;
    }
  }
  if(val < 0){
    //SERIAL_PORT.print(-val, decimals);
    myLog.print(-val, decimals);
  }else{
   // SERIAL_PORT.print(val, decimals);
    myLog.print(val, decimals);
  }
  // ***
}

void printScaledAGMT( ICM_20948_AGMT_t agmt){
  myLog.append("IMUdata.txt");
  // ** change the SERIAL_PORT.print calls to myLog.print calls. 
  // It will now save the data on your SD card
  //SERIAL_PORT.print("Scaled. Acc (mg) [ ");
  myLog.print("Scaled. Acc (mg) [ ");
  printFormattedFloat( myICM.accX(), 5, 2 );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printFormattedFloat( myICM.accY(), 5, 2 );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printFormattedFloat( myICM.accZ(), 5, 2 );
  //SERIAL_PORT.print(" ], Gyr (DPS) [ ");
  myLog.print(" ], Gyr (DPS) [ ");
  printFormattedFloat( myICM.gyrX(), 5, 2 );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printFormattedFloat( myICM.gyrY(), 5, 2 );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printFormattedFloat( myICM.gyrZ(), 5, 2 );
  //SERIAL_PORT.print(" ], Mag (uT) [ ");
  myLog.print(" ], Mag (uT) [ ");
  printFormattedFloat( myICM.magX(), 5, 2 );
  //SERIAL_PORT.print(", ");
  myLog.print(", ");
  printFormattedFloat( myICM.magY(), 5, 2 );
  //SERIAL_PORT.println(", ");
  myLog.println(", ");
  printFormattedFloat( myICM.magZ(), 5, 2 );
  //SERIAL_PORT.print(" ], Tmp (C) [ ");
  myLog.print(" ], Tmp (C) [ ");
  printFormattedFloat( myICM.temp(), 5, 2 );
  //SERIAL_PORT.print(" ]");
  //SERIAL_PORT.println();
  myLog.print(" ]");
  myLog.println();
  //***
}

Interestingly, this code works without clicking the reset button.

Cheers