STM32F405 SD card randomly stops being written to

I'm trying to create a CANbus datalogger using the STM32F405 because it's got CAN connectivity and MMC pins for directly connecting to an SD card. The code seems to work in that whenever it gets a CAN message it formats it and writes it to the card, but after varying uptimes (anywhere from a couple seconds to a few minutes) dataFile.print(bigBuf) starts returning 0 and is unrecoverable until the STM32 resets itself which is what I have it doing right now. The problem is that while it's resetting it's not storing the CAN data and can miss things you're trying to log.

I've read about every thread on similar issues that I can find. I've tried adding a capacitor across the 3.3V and ground for the SD card in case it's a power issue, I've also tried periodically flushing and not periodically flushing, but to no avail.

When I had it printing out freeMemory() (which is now commented out) it was giving me over 10000 so that leads me to believe it's not a memory issue. The unpredictability also makes me think that.

The operation of this device is that you plug it in, it records CAN data until you unplug it. When you unplug it there's a hold-up capacitor that keeps it on for about a second so that it can close down the file nicely. (this is why you see things like delaying to give the CAN wires time to make contact in setup() )

Here is my code.

#include "stm32f4xx.h"
#include <STM32SD.h>
#include <EEPROM.h>

// A bunch of CAN library stuff I didn't paste in here
// It should be its own .c and .h files but eh

File dataFile;

uint8_t counter = 0;
uint8_t frameLength = 0;
unsigned long previousMillis = 0;     // stores last time output was updated
bool haveBeenConnected = false;
unsigned long oldFileSize;
uint16_t fileVolume = 0;
uint32_t fileIndex;
char filename[32];
char buf[30];
char bigBuf[64];

void setup() {
  SerialUSB.begin(115200);            // start up the uart module and initialize
  SerialUSB.println("Startup");
  delay(100);                         // give the CAN wires time to connect
  LowPower.begin();                   // start up the low power stuff
  bool ret = CANInit(CAN_250KBPS, 2); // CAN_RX mapped to PB12, CAN_TX mapped to PB13
  uint8_t attempts = 0;
  while(!ret && attempts < 3)         // init CAN while we haven't
  {
    ret = CANInit(CAN_250KBPS, 2);
    attempts += 1;
  }
  if(attempts >= 3)
  {
    NVIC_SystemReset();
  }
  pinMode(PA5, OUTPUT); //Green LED
  pinMode(PA6, OUTPUT); //Yellow LED
  pinMode(PA7, OUTPUT); //Red LED
  pinMode(PA3, INPUT);  //Plugged in detection
  SerialUSB.print("Initializing SD card...");
  // see if the card is present and can be initialized:
  attempts = 0;
  while (!SD.begin(SD_DETECT_NONE))   // Init SD card while we haven't
  {
    delay(10);
    attempts++;
    if(attempts > 20)
    {
      SerialUSB.println("Initialization failed.");
      digitalWrite(PA7, HIGH);
      NVIC_SystemReset();
    }
  }
  SerialUSB.println("card initialized.");
  
  // Create incrementing filename
  if(EEPROM.read(4) != 0) { //This might be the first time this program has ever run
    EEPROM.write(0, 0x00);  //so initialize the filename incrementing index at 0
    EEPROM.write(1, 0x00);  //so initialize the filename incrementing index at 0
    EEPROM.write(2, 0x00);  //so initialize the filename incrementing index at 0
    EEPROM.write(3, 0x00);  //so initialize the filename incrementing index at 0
    EEPROM.write(4, 0x00);  //and store something that says it's been initialized
    EEPROM.write(5, 0x00);  //so initialize the file volume incrementing index at 0
    EEPROM.write(6, 0x00);  //so initialize the file volume incrementing index at 0
  }

  fileVolume = EEPROM.read(5) | EEPROM.read(6) << 8;
  if(fileVolume == 65535) //Unwritten EEPROM
  {
    EEPROM.write(5, 0x00);  //so initialize the file volume incrementing index at 0
    EEPROM.write(6, 0x00);  //so initialize the file volume incrementing index at 0
    fileVolume = 0;
  }

  fileIndex = EEPROM.read(0) | EEPROM.read(1) << 8 | EEPROM.read(2) << 16 | EEPROM.read(3) << 24;
  sprintf(filename, "%s_%d_%d.csv", "log", fileIndex, fileVolume);
  // open the file
  dataFile = SD.open(filename, FILE_WRITE);
  // if the file is available, seek to last position
  if (dataFile) {
    uint32_t f = fileIndex + 1;
    EEPROM.write(0, (byte) (f >> 0 & 0xFF));
    EEPROM.write(1, (byte) (f >> 8 & 0xFF));
    EEPROM.write(2, (byte) (f >> 16 & 0xFF));
    EEPROM.write(3, (byte) (f >> 24 & 0xFF));
    dataFile.seek(dataFile.size());
    oldFileSize = dataFile.size();
    SerialUSB.println("Opened file for writing");
  }
  // if the file isn't open, pop up an error, light the red LED and reset
  else {
    SerialUSB.println("error opening file for writing");
    digitalWrite(PA7, HIGH);
    NVIC_SystemReset();
  }
}

void loop() {
  CAN_msg_t CAN_TX_msg;
  CAN_msg_t CAN_RX_msg;

  bool connectedToCAN = digitalRead(PA3) == HIGH;
  if(SerialUSB.available()) connectedToCAN = false;
  digitalWrite(PA5, connectedToCAN); //green LED is CAN connection status
  if(connectedToCAN) {
    uint8_t recv_ch = 2;
    digitalWrite(PA6, LOW);
    if(CANMsgAvail(recv_ch)) {
      haveBeenConnected = true;
      digitalWrite(PA6, HIGH);  //light the yellow LED cause we've got a message
      CANReceive(recv_ch, &CAN_RX_msg);

      if(dataFile) { //if the file's still open
        //Add timestamp,messageID,byte,byte,byte,...
        uint8_t index = 0;
        //clear out bigBuf
        for(int i = 0; i < sizeof(bigBuf); i++)
        {
          bigBuf[i] = '\0';
        }

        sprintf(buf, "%ld,\0", millis() - previousMillis);
        previousMillis = millis();
        index = insertStr(index, buf, bigBuf);
        //dataFile.print(buf);
        sprintf(buf, "%X,\0", CAN_RX_msg.id);
        index = insertStr(index, buf, bigBuf);
        //dataFile.print(buf);
        for(uint8_t i=0; i<CAN_RX_msg.len; i++) {
          sprintf(buf, "%02X\0", CAN_RX_msg.data[i]);
          index = insertStr(index, buf, bigBuf);
          //dataFile.print(buf);
        }
        index = insertStr(index, "\r\n\0", bigBuf);
        if(!dataFile.print(bigBuf))
        {
          SerialUSB.print("Error writing \"");
          SerialUSB.print(bigBuf);
          SerialUSB.println("\" to file");
          digitalWrite(PA5, LOW);
          digitalWrite(PA6, LOW);
          digitalWrite(PA7, HIGH);
//          uint8_t attempts =  0;
//          SerialUSB.println("Reopening");
//          while(!dataFile && attempts < 3)
//          {
//            SerialUSB.print(".");
//            dataFile.close();
//            dataFile = SD.open(filename, FILE_WRITE);
//            attempts += 1;
//            delay(10);
//          }
//          if(attempts >= 3)
//          {
            dataFile.close();
            EEPROM.write(0, (byte) (fileIndex >> 0 & 0xFF)); //Write current file index to EEPROM so
            EEPROM.write(1, (byte) (fileIndex >> 8 & 0xFF)); //we open the same file when we start back up
            EEPROM.write(2, (byte) (fileIndex >> 16 & 0xFF));
            EEPROM.write(3, (byte) (fileIndex >> 24 & 0xFF));
//            SerialUSB.println("Reopen Failed");
            NVIC_SystemReset();
//          }
//          SerialUSB.println("Reopened");
//          SerialUSB.println(freeMemory());
        }

        if(dataFile.size() - oldFileSize > 500) { //Write to SD card before unwritten data becomes too large
          digitalWrite(PA7, HIGH); //indicate that we're writing to the SD card
          dataFile.flush();
          digitalWrite(PA7, LOW);
          oldFileSize = dataFile.size();
          SerialUSB.println(oldFileSize);
        }
        
        if(dataFile.size() > 16777000) { //Limit individual file size to ~16MB
          dataFile.close();
          fileVolume += 1;
          sprintf(filename, "%s_%d%d.csv", "log", fileIndex, fileVolume);
          dataFile = SD.open(filename, FILE_WRITE);
          EEPROM.write(5, (byte) (fileVolume & 0xFF));
          EEPROM.write(6, (byte) (fileVolume >> 8 & 0xFF));
          oldFileSize = dataFile.size();
        }
      }
      else
      {
        SerialUSB.println("Error writing to file");
        digitalWrite(PA5, LOW);
        digitalWrite(PA6, HIGH);
        digitalWrite(PA7, LOW);
        uint8_t attempts =  0;
        SerialUSB.print("Reopening");
        while(!dataFile && attempts < 3)
        {
          SerialUSB.print(".");
          dataFile.close();
          dataFile = SD.open(filename, FILE_WRITE);
          attempts += 1;
          delay(10);
        }
        if(attempts >= 3)
        {
          EEPROM.write(0, (byte) (fileIndex >> 0 & 0xFF)); //Write current file index to EEPROM so
          EEPROM.write(1, (byte) (fileIndex >> 8 & 0xFF)); //we open the same file when we start back up
          EEPROM.write(2, (byte) (fileIndex >> 16 & 0xFF));
          EEPROM.write(3, (byte) (fileIndex >> 24 & 0xFF));
          SerialUSB.println("Reopen Failed");
          NVIC_SystemReset();
        }
        SerialUSB.println("Reopened");
        SerialUSB.println(freeMemory());
      }
    }
  }
  else if(haveBeenConnected)
  {
    SerialUSB.println("Powering Down");
    dataFile.close(); //Neatly close down the file before we lose power (same as flush but also closes file)
    EEPROM.write(5, 0x00);  //Start at volume 0 on power up
    EEPROM.write(6, 0x00);  //Start at volume 0 on power up
    digitalWrite(PA5, HIGH); //Shut off red and yellow lights
    digitalWrite(PA6, LOW);
    digitalWrite(PA7, LOW);

    while(true) ;
  }
}

No reply. Here's a little more information in case it's a hardware issue, but there's not a whole lot more to tell.

This is the schematic of the circuit I've got for this project. In addition to the two capacitors on the SD card there is also a 100uF electrolytic in parallel that I added later. The 3.3V regulator is this one from Digikey which should be able to provide 1.2A. More than enough for what this circuit draws.

Is there a dedicated STM forum? If there is, you might be better of asking there.

You might try contacting your local application engineer.