[Solved] SdFat writes data twice to the SD card

Been tinkering with the SdFat library and long file names. It works, but it writes the data twice to the card. Why is this and how do I resolve this? This is the code as of now. Using a Nano with PlatformIO on VSCode.

EDIT: The SD card is FAT32 formatted.

#include <Arduino.h>
#include <SPI.h>
#include <SdFat.h>

#define SD_CS_PIN 10

SdFat SD;
File dataFile;

void setup()
{
  // Open serial comms
  Serial.begin(9600);

  Serial.println("\nInitializing SD card...");

  if (!SD.begin(SD_CS_PIN))
  {
    Serial.println(" failed!");
    return;
  }
  else
  {
    Serial.println(" done!");
  }

  String fileName;

  fileName = "GPSData_";
  fileName += String("01");
  fileName += String("01");
  fileName += String("2024");
  fileName += String("_");
  fileName += String("20");
  fileName += String("45");
  fileName += String("33");
  fileName += String(".kml");

  Serial.print("File name is: ");
  Serial.println(fileName);

  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  dataFile = SD.open(fileName, FILE_WRITE);

  // if the file opened okay, write to it:
  if (dataFile)
  {
    Serial.println("Writing to file...");

    dataFile.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
    dataFile.println("<kml xmlns=\"http://www.opengis.net/kml/2.2\">");
    dataFile.println("");
    dataFile.println("  <Document>");
    dataFile.println("    <name>Views with Time</name>");
    dataFile.println("    <open>1</open>");
    dataFile.println("    <description>");
    dataFile.println("      In Google Earth, enable historical imagery and sunlight,");
    dataFile.println("      then click on each placemark to fly to that point in time.");
    dataFile.println("    </description>");
    dataFile.println("");
    dataFile.println("    <Placemark>");
    dataFile.println("      <name>Sutro Baths in 1946</name>");
    dataFile.println("      <gx:TimeStamp>");
    dataFile.println("        <when>1946-07-29T05:00:00-08:00</when>");
    dataFile.println("      </gx:TimeStamp>");
    dataFile.println("      <longitude>-122.518172</longitude>");
    dataFile.println("      <latitude>37.778036</latitude>");
    dataFile.println("      <altitude>221.0</altitude>");
    dataFile.println("    </Placemark>");
    dataFile.println("");
    dataFile.println("  </Document>");
    dataFile.println("</kml>");

    dataFile.close();
  }
  else
  {
    // if the file didn't open, print an error:
    Serial.println("Error opening file for writing!!");
  }

  // re-open the file for reading:
  Serial.print("\n\nReading from file: ");
  Serial.println(fileName);

  dataFile = SD.open(fileName, FILE_READ);
  if (dataFile)
  {
    // read from the file until there's nothing else in it:
    while (dataFile.available())
    {
      Serial.write(dataFile.read());
    }
    // close the file:
    dataFile.close();
  }
  else
  {
    // if the file didn't open, print an error:
    Serial.println("Error opening file for reading!!");
  }
}

void loop()
{
  // nothing happens after setup
}

I will take a SWAG and say it is a FAT file structure on the SD card. If this is true it has an area for data and another for the directory. Any changes in the data (probably the first write) then it updates the directory (second write). You did not indicate any errors so at this point I think it is working correctly.

However, there is no change in the data being written. It does work without errors, just that it writes the same data twice to the file on the SD card. Missed mentioning that the SD card is FAT32 formatted.

FILE_WRITE will add the content to the end of the file if it already existed.

You might want to use (O_READ | O_WRITE | O_CREAT) instead. That will (IIRC) erase the file if it’s already there

It does but writes the same data twice even though its meant to be written only once. FILE_WRITE expands to (O_RDWR | O_CREAT | O_AT_END)

This worked and erases any previous content and writes what the program tells it to. This is okay for this program since its just a test.

However, in the final program, the coordinates will keep updating and be added to the file while keeping its previous contents intact. How do I do that? With FILE_WRITE it writes the same content twice, even if its a brand new file.

I tried multiple combinations of O_WRONLY, O_RDWR, O_APPEND, O_CREAT and O_AT_END but I see the same behaviour of it being written twice. I want the data to be written only once and then every subsequent write is appended to the same file, again, only once.

So I think you write twice - may be you don’t see it but when you upload the program runs and then when you open the serial monitor it reboots and writes again and thus you have the content twice


That’s where it’s defined

#define FILE_WRITE (O_READ | O_WRITE | O_CREAT | O_APPEND)

This is the SdFat library and not the SD library. Its defined here,

Right. I had missed you were using SdFat

Are you keeping the serial monitor open?

In the code above, it is open but in the latest code on my machine, I've added a Serial.end() at the end of setup()

I'm waiting on a new GPS module, which will let me generate dynamic real-time filenames. Let me test it with that and see what I see on the file. Will keep you posted.

can you add blinking code of the built in LED for 5 seconds at the start of the setup before you write. This way you can see what's going on. just upload the code, don't open the serial monitor

Hey!!! It only wrote once! Upon modifying the content and re-uploading with the same filename, it appended the new content to the existing file — exactly the functionality I was looking for. TBH, I did not add the blinky code. I just did not open the serial monitor after upload.

This is news to me. Thank you for walking me through the debug and solution!

glad you solved it!

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.