Teensy 4.1 crashing when closing SD card file after read.

Gremlin

Active member
I'm going to try and keep this simple.
After upgrading from:
Arduino 1.8.8, TeensyDuino 1.4.5
to
Arduino 1.8.19, Teensyduino 1.56

My SD card code for reading data from files no longer works. It now crashes the T4.1. I have tested on T3.5 and it crashes now as well. This is code that previously worked on T3.5 before upgrading dev environment. It crashes after reading to the last line and then trying to close the file. If I read some of the fields but do not try and read to the last line, I can close the file without crashing.

Here is Code. Serial log with crash report below.

Code:
#include <SD.h>

File sdDir;
int sdFileCount = 0;
int sdLastFileNum = 0;
float testData[2][162][2];
float testData_Zero = 0;
float testData_limitVal = 0;
String dataSaveFileDesc = "";

const int sdChipSelect = BUILTIN_SDCARD;

void setup(){

  Serial.begin(38400); //USB
  delay(10);
  
  while (!Serial && millis() < 10000);
  Serial.println("\n" __FILE__ " " __DATE__ " " __TIME__);
  if (CrashReport)
    Serial.print(CrashReport);
    
  if (!SD.begin(sdChipSelect)) {
    Serial.println("SD init failed!");
  }
  else {
    Serial.println("SD init passed.");

    if (SD.exists("/DATA")) {
      Serial.println("Directory Already Exists");
    }
    else {
      if (SD.mkdir("/DATA")) {   //Will create if doesnt exist
        Serial.println("Directory Created");
      }
      else {
        Serial.println("Directory Create Failed");
      }
    }
  }
delay(1000);
Serial.println("Calling File Load");

SD_loadFileData(1,0);

}

void loop(){
  Serial.println("Looping");
  delay(2000);
}


void SD_loadFileData(int _fileNumToOpen, int _dataSet) {

  //Reset Data Array
  for (int i = 0; i < 162; i++) {
    testData[_dataSet][i][0] = -1000;   //Flag -1000 for unused DataPoints
  }
  testData_Zero = 0;
  testData_limitVal = 0;

  sdDir = SD.open("/DATA");

  int _tempFileCount = 1;

  Serial.println("Looking for File #: " + String(_fileNumToOpen));
  while (true) {
    File datafile = sdDir.openNextFile();
    if (!datafile) {
      // no more files
      break;
    }
    if (!datafile.isDirectory()) {
      Serial.println("Opening: " + String(datafile.name()));

      if (_tempFileCount == _fileNumToOpen) {
        Serial.println("File Match: " + String(datafile.name()));
        size_t n;      // Length of returned field with delimiter.
        char str[24];  // Must hold longest field with delimiter and zero byte.
        char *ptr;     // Test for valid field.
        char delim[3] = ",\n";
        bool _readComplete = false;

        // Read the file and store the data in testData Array
        for (int j = 0; j < 3; j++) {        //Skip first 3 Values.
          n = skipField(&datafile, delim);
          if (n == 0) {
            dataSaveFileDesc = "Invalid File: E:3:" + String(j);
          }
        }

        n = readField(&datafile, str, sizeof(str), delim);   // Read Limit Value
        if (n == 0) {
          dataSaveFileDesc = "Invalid File: E:4";
        }
        else {
          testData_limitVal = strtod(str, &ptr);
          Serial.println("Limit Value: " + String(testData_limitVal));
          if (ptr == str) {
            dataSaveFileDesc = "Invalid File: E:4-1";
          }
        }

        n = readField(&datafile, str, sizeof(str), delim);   // Read Zero Value
        if (n == 0) {
          dataSaveFileDesc = "Invalid File: E:5";
        }
        else {
          testData_Zero = strtol(str, &ptr, 10);
          Serial.println("Zero: " + String(testData_Zero));
          if (ptr == str) {
            dataSaveFileDesc = "Invalid File: E:5-1";
          }
        }

        //break; //Wont crash if I break here and Close file.

        Serial.println(" - Reading Temp Data - ");
        for (int j = 0; j < 90; j++) {  //File has 80 (*2) Data point. Wont crash if I lower this below 80 and don't read to end of file.
          if (_readComplete) { break; };
          
          for (int i = 0; i < 2; i++) {

            n = readField(&datafile, str, sizeof(str), delim);                                      

            if (n == 0) {  //No Data
              _readComplete = true;
              Serial.println(" End of Data: Break");
              break;
            }                                                          
            else {  //Has Data
              if (i == 0) {
                testData[_dataSet][j][i] = strtod(str, &ptr);
                if (ptr == str) {
                  _readComplete = true;
                }
                else {
                  if (testData[_dataSet][j][i] < -999) {
                    Serial.println(" Bad Data: Break");
                    break;
                  }
                }

              }
              if (i == 1) {

                testData[_dataSet][j][i] = strtol(str, &ptr,10);
                if (ptr == str) {
                  _readComplete = true;
                  dataSaveFileDesc = "Invalid File: E:8-" + String(j);
                }
              }
            }
          } // for i

        } //for j
      }
    }
    Serial.println("Closing File");
    datafile.close();  //   <-----------------Crashes and resets here
    Serial.println("File Closed");
    _tempFileCount++;
    if (_tempFileCount > _fileNumToOpen) {
      Serial.println("File Count Exceeded; break"); break; }   //Already past the Needed File# 
  }
  Serial.println("Closing Dir");
  sdDir.close();

}

size_t readField(File* file, char* str, size_t size, char* delim) {
  char ch;
  size_t n = 0;
  while ((n + 1) < size && file->read(&ch, 1) == 1) {
    // Delete CR.
    if (ch == '\r') {
      continue;
    }
    str[n++] = ch;
    if (strchr(delim, ch)) {
      break;
    }
  }
  str[n-1] = '\0';
  return n;
}

size_t skipField(File* file, char* delim) {
  char ch;
  size_t n = 0;
  
  while ((n + 1) < 24 && file->read(&ch, 1) == 1) {
    // Delete CR.
    n++;
    if (strchr(delim, ch)) {
      break;
    }
  }
  return n;
}

Log
Code:
CrashReport:
  A problem occurred at (system time) 19:4:32
  Code was executing from address 0xD2A
  CFSR: 82
	(DACCVIOL) Data Access Violation
	(MMARVALID) Accessed Address: 0x4615222C
  Temperature inside the chip was 37.84 °C
  Startup CPU clock speed is 151MHz
  Reboot was caused by auto reboot after fault or bad interrupt detected
SD init passed.
Directory Already Exists
Calling File Load
Looking for File #: 1
Opening: 0000001.csv
File Match: 0000001.csv
Limit Value: 21.00
Zero: 80.00
 - Reading Temp Data - 
 End of Data: Break
Closing File
 
I have reverted the SD library back to the 1.2.2 located here:
https://github.com/PaulStoffregen/SD/tree/master
I found that at Teensyduino 1.54, Paul changed the SD library to be just a wrapper for SDFat.
Changing back to earlier library resolves the crash. Something about the change to SDfat library is causing the crash.
I'm going to move on for now but would like to figure out how I can use the newer library without crashing.
 
I have reverted the SD library back to the 1.2.2 located here:
https://github.com/PaulStoffregen/SD/tree/master
I found that at Teensyduino 1.54, Paul changed the SD library to be just a wrapper for SDFat.
Changing back to earlier library resolves the crash. Something about the change to SDfat library is causing the crash.
I'm going to move on for now but would like to figure out how I can use the newer library without crashing.

I was about to explain that there were big changes to SD support since your last update. Can you please try updating to the latest TeensyDuino 1.57. There were important SD changes and fixes in 1.57 relative to 1.56.
 
I am willing to try that but I have a million things going on in this project and I don't want to break anything else.
You don't have to read this but here is what i'm dealing with as far as features.
https://forum.pjrc.com/threads/70182-Switching-Product-from-T3-5-to-T4-1?p=305369&viewfull=1#post305369

Instead of installing 1.57, I think I will try and find the latest SD and SDFat libraries and just throw those in
"C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\..."

I will let you know how it goes.
EDIT: Im grabbing these two.
https://github.com/PaulStoffregen/SD/tree/Juse_Use_SdFat
https://github.com/greiman/SdFat/tree/2.2.0 ...Wrong...
https://github.com/PaulStoffregen/SdFat
 
Last edited:
Post #1 code on T_4.1 with SD card runs fine here to 'Looping ...'
Programmed, reprogrammed, power off restart.

Win 11, IDE 1.8.19 and TeensyDuino 1.57

Another example showing a failure would be needed. Or as @joepasquariello noted: "You might as well use the latest because that will allow others to help you."

Not sure what the problem might be as that code as presented functions here:
Code:
...
"C:\\T_Drive\\arduino-1.8.19\\hardware\\teensy/../tools/teensy_size" "R:\\temp\\arduino_build_SDcrashClose.ino/SDcrashClose.ino.elf"
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:   FLASH: code:68564, data:11160, headers:8336   free for files:8038404
teensy_size:    RAM1: variables:15712, code:64088, padding:1448   free for local variables:443040
teensy_size:    RAM2: variables:12384  free for malloc/new:511904
Multiple libraries were found for "SD.h"
 Used: C:\T_Drive\arduino-1.8.19\hardware\teensy\avr\libraries\SD
 Not used: C:\T_Drive\Arduino-1.8.19\libraries\SD
Using library SD at version 2.0.0 in folder: C:\T_Drive\arduino-1.8.19\hardware\teensy\avr\libraries\SD 
Using library SdFat at version 2.1.2 in folder: C:\T_Drive\arduino-1.8.19\hardware\teensy\avr\libraries\SdFat 
Using library SPI at version 1.0 in folder: C:\T_Drive\arduino-1.8.19\hardware\teensy\avr\libraries\SPI 
Waiting for user selection
       upload@8983390-Teensy  Uploading to board '8983390-Teensy' (Teensy 4.1)
       upload@8983390-Teensy  Triggering board reboot
       upload@8983390-Teensy  Waiting for Teensy Loader

And another power off restart:
Code:
C:\T_Drive\tCode\FORUM\SDcrashClose\SDcrashClose.ino Aug 20 2022 18:42:49
SD init passed.
Directory Already Exists
Calling File Load
Looking for File #: 1
Closing Dir
Looping
Looping
...
 
Looks like I would have to give you the file that is on the SD card.
When you are running it, it isn't finding a file so it doesn't read data, close, then crash.
Attached is the file that is on the DATA folder on sd card. Rename it to "0000001.csv".

You should be seeing..
Code:
Opening: 0000001.csv
File Match: 0000001.csv
Limit Value: 21.00
Zero: 80.00
 - Reading Temp Data - 
 End of Data: Break
Closing File
 

Attachments

  • 0000001.txt
    921 bytes · Views: 32
@PaulStoffregen - see breadcrumb on CRASH data below - not sure why that is printing as the code didn't set them - they do not appear on recurring crash - only on power up.

Indeed, with THAT file in "DATA" it does Fault.
Code:
C:\T_Drive\tCode\FORUM\SDcrashClose\SDcrashClose.ino Aug 20 2022 18:42:49
SD init passed.
Directory Already Exists
Calling File Load
Looking for File #: 1
Opening: 0000001.csv
File Match: 0000001.csv
Limit Value: 21.00
Zero: 80.00
 - Reading Temp Data - 
 End of Data: Break
Closing File

C:\T_Drive\tCode\FORUM\SDcrashClose\SDcrashClose.ino Aug 20 2022 18:42:49
CrashReport:
  A problem occurred at (system time) 0:0:1
  Code was executing from address 0xD2A
  CFSR: 82
	(DACCVIOL) Data Access Violation
	(MMARVALID) Accessed Address: 0x4615222C
  Temperature inside the chip was 47.07 °C
  Startup CPU clock speed is 600MHz
  Reboot was caused by auto reboot after fault or bad interrupt detected
  Breadcrumb #2 was 3813566020 (0xE34E6644)
  Breadcrumb #3 was 329523457 (0x13A42101)
  Breadcrumb #4 was 3748593130 (0xDF6EFDEA)
  Breadcrumb #5 was 705702547 (0x2A102A93)
  Breadcrumb #6 was 927862285 (0x374E0E0D)
SD init passed.
Directory Already Exists
Calling File Load
Looking for File #: 1
Opening: 0000001.csv
File Match: 0000001.csv
Limit Value: 21.00
Zero: 80.00
 - Reading Temp Data - 
 End of Data: Break
Closing File

Not looked beyond this repro at this time ... but it does present as shown - if allowed to Crash and restart the Breadcrumb data is not present - until the next power on.
 
Here's your problem:
Code:
size_t readField(File* file, char* str, size_t size, char* delim) {
  char ch;
  [COLOR="#FF0000"]size_t n = 0;[/COLOR]
  while ((n + 1) < size && file->read(&ch, 1) == 1) {
    // Delete CR.
    if (ch == '\r') {
      continue;
    }
    str[n++] = ch;
    if (strchr(delim, ch)) {
      break;
    }
  }
  [COLOR="#FF0000"]str[n-1] = '\0';[/COLOR]
  return n;
}
You don't check for "absolutely no characters at all in the next field", and try to overwrite a non-existent terminator! This turns out to be a vital piece of data in the file descriptor, and boom... It's possible it worked before because there wasn't anything vital to hit.
 
Here's your problem:
...
You don't check for "absolutely no characters at all in the next field", and try to overwrite a non-existent terminator! This turns out to be a vital piece of data in the file descriptor, and boom... It's possible it worked before because there wasn't anything vital to hit.

Great catch - read right across that here.
 
@PaulStoffregen - see breadcrumb on CRASH data below - not sure why that is printing as the code didn't set them - they do not appear on recurring crash - only on power up.

Indeed, with THAT file in "DATA" it does Fault.
..........
Not looked beyond this repro at this time ... but it does present as shown - if allowed to Crash and restart the Breadcrumb data is not present - until the next power on.


@defragster @PaulStoffregen

I've been getting the same with breadcrumbs (random values in unused breadcrumbs). I'm using 1.57 on a MicroMod.

It looks like the breadcrumb bitmask might not get initialised to zero on powerup?

The bitmask does get zeroed after the report is printed meaning after one crash and report it all looks good.

Cheers, Paul
 
Great catch - read right across that here.
Thanks. Never made a mistake like that myself, of course :rolleyes:. Kudos to Gremlin for providing the code and example file to reproduce the problem exactly. And ftrias for TeensyDebug, which made it easy to stick a breakpoint where I thought the problem was.
 
@defragster @PaulStoffregen

I've been getting the same with breadcrumbs (random values in unused breadcrumbs). I'm using 1.57 on a MicroMod.

It looks like the breadcrumb bitmask might not get initialised to zero on powerup?

The bitmask does get zeroed after the report is printed meaning after one crash and report it all looks good.

Cheers, Paul

Problem maybe there is no .begin for Crash Report to set them? - it is optional called after the fact and the check for use is somehow fooled.

Will spend a few minutes on it - may also extend breadCrumbs 7,8,9,10 from 1062's 4 DWORDS from RTC RAM that holds with power same as the RAM2/DMAMEM that is used. That would require a .begin or trigger on use of the magic bit to enable those DWORDS.
 
h4yn0nnym0u5e , Thank you for the help in spotting this bug. And thank you defragster for taking your time to reproduce the issue. I was focused more on the SD library change as being the problem since this code has always worked in the past. I have somehow dodged a bullet for years with this code. I have hundreds of T3.5's in the field running this...eeeek.
It looks like this may have brought to light some issue with crashreport as well. Good luck with that defragster.
TeensyDebug looks really cool.. Wish I had time to learn how to use it properly.

My fix for the code is to just make sure I found at least one character before terminating.
Code:
if (n > 0) {
		str[n - 1] = '\0';
	}
 
Assuming that return of n==0 always gets ignored that should be a good fix when nothing will attempt to use the string without a NULL at [0].
 
Back
Top