SD.open()?

Thank you! BTW. I guess all search out all my calls to strlen().
Code:
$ /usr/bin/arm-none-eabi-objdump -S handheld.ino.elf |grep 2c580
     d0a:    f02b fc39     bl    2c580 <strlen>
    3142:    f029 fa1d     bl    2c580 <strlen>
    31d4:    f029 f9d4     bl    2c580 <strlen>
    34a2:    f029 f86d     bl    2c580 <strlen>
    3a3c:    f028 fda0     bl    2c580 <strlen>
    4406:    f028 f8bb     bl    2c580 <strlen>
    4704:    f027 ff3c     bl    2c580 <strlen>
    470c:    f027 ff38     bl    2c580 <strlen>
    479c:    f027 fef0     bl    2c580 <strlen>
    47b0:    f027 fee6     bl    2c580 <strlen>
    4844:    f027 fe9c     bl    2c580 <strlen>
    487a:    f027 fe81     bl    2c580 <strlen>
    7304:    f025 f93c     bl    2c580 <strlen>
    e598:    f01d fff2     bl    2c580 <strlen>
    e5a0:    f01d ffee     bl    2c580 <strlen>
    e5f8:    f01d ffc2     bl    2c580 <strlen>
    e610:    f01d ffb6     bl    2c580 <strlen>
    e62c:    f01d ffa8     bl    2c580 <strlen>
    eca6:    f01d fc6b     bl    2c580 <strlen>
   1099e:    f01b fdef     bl    2c580 <strlen>
   10a24:    f01b fdac     bl    2c580 <strlen>
   10c6e:    f01b fc87     bl    2c580 <strlen>
   11a10:    f01a fdb6     bl    2c580 <strlen>
   11b86:    f01a fcfb     bl    2c580 <strlen>
   11b92:    f01a fcf5     bl    2c580 <strlen>
   11bb4:    f01a fce4     bl    2c580 <strlen>
   11bd2:    f01a fcd5     bl    2c580 <strlen>
   11f30:    f01a fb26     bl    2c580 <strlen>
   120c8:    f01a fa5a     bl    2c580 <strlen>
   120d2:    f01a fa55     bl    2c580 <strlen>
   12138:    f01a fa22     bl    2c580 <strlen>
   122b4:    f01a f964     bl    2c580 <strlen>
   122f4:    f01a f944     bl    2c580 <strlen>
   1232e:    f01a f927     bl    2c580 <strlen>
   1256c:    f01a f808     bl    2c580 <strlen>
   12742:    f019 ff1d     bl    2c580 <strlen>
   127e6:    f019 fecb     bl    2c580 <strlen>
   12876:    f019 fe83     bl    2c580 <strlen>
   146d6:    f017 ff53     bl    2c580 <strlen>
   1b02a:    f011 faa9     bl    2c580 <strlen>
   1bea6:    f010 fb6b     bl    2c580 <strlen>
   1bec8:    f010 fb5a     bl    2c580 <strlen>
   1bf2c:    f010 fb28     bl    2c580 <strlen>
   1bf90:    f010 faf6     bl    2c580 <strlen>
   1c530:    f010 f826     bl    2c580 <strlen>
   1d6a4:    f00e ff6c     bl    2c580 <strlen>
   1d6dc:    f00e ff50     bl    2c580 <strlen>
   1d9f4:    f00e fdc4     bl    2c580 <strlen>
   1e4a6:    f00e f86b     bl    2c580 <strlen>
   1e866:    f00d fe8b     bl    2c580 <strlen>
   1e932:    f00d fe25     bl    2c580 <strlen>
   1eab0:    f00d fd66     bl    2c580 <strlen>
   1eb1a:    f00d fd31     bl    2c580 <strlen>
   1eb2e:    f00d fd27     bl    2c580 <strlen>
   223f0:    f00a f8c6     bl    2c580 <strlen>
   22570:    f00a f806     bl    2c580 <strlen>
   235f8:    f008 ffc2     bl    2c580 <strlen>
   23620:    f008 ffae     bl    2c580 <strlen>
   236b8:    f008 ff62     bl    2c580 <strlen>
   236f2:    f008 ff45     bl    2c580 <strlen>
   237a8:    f008 feea     bl    2c580 <strlen>
   23930:    f008 fe26     bl    2c580 <strlen>
   258ac:    f006 fe68     bl    2c580 <strlen>
   2696c:    f005 fe08     bl    2c580 <strlen>
   2bf10:    f000 fb36     bl    2c580 <strlen>
0002c580 <strlen>:
   2c580:    f890 f000     pld    [r0]
   2c9e0:    f7ff fdce     bl    2c580 <strlen>
   2cb6a:    f7ff fd09     bl    2c580 <strlen>
   2dfe0:    f7fe face     bl    2c580 <strlen>
   303dc:    f7fc f8d0     bl    2c580 <strlen>
   310fa:    f7fb fa41     bl    2c580 <strlen>
 
Wait, is this saying that passing a NULL to strlen() is causing a crash?

Calling strlen(NULL) will definitely crash. Reading memory from a NULL pointer is not allowed!

Same crash behavior happens on regular operating systems too.

1780019453044.png
 
However, on old boards like Teensy 3.2 which lack memory protection hardware, you can call strlen(NULL). It will read whatever bytes happen to be at address zero and give you a result. Of course that's meaningless because those bytes on Teensy 3.2 are the reset vector and interrupt addresses.

On Teensy 4.0, we have MMU hardware that enforces proper memory access. If you use a pointer to read or write invalid addresses, or if you try to call functions in memory that's meant only for data, or if you try to write to memory that's meant to executable code, you get a memory fault because the MMU doesn't allow invalid usage. The default fault handler on Teensy 4.1 stores CrashReport info and then waits 8 seconds before rebooting.

Teensy 3.2 had very limited memory fault detection, because no MMU. Its default fault handler just does nothing, waiting forever in a loop which tried to keep USB and the 3 serial ports responding, so anything you sent with Serial.print() might still manage to transmit correctly even after the "crash". But it didn't log anything, didn't reboot after 8 seconds, and didn't have CrashReport to give you info.

As you're porting a large code base from Teensy 3.2 to Teensy 4, this improved MMU detection of illegal memory access is a key difference. You may have code which illegally used NULL pointers which Teensy 3.2 just ignored and "worked" with wrong data. But on Teensy 4, that sort of wrong pointer usage gets caught by the MMU.
 
OMG, I always thought dropping a NULL into strlen() was fine and would just return a 0. So I never really fine-tooth checked for that. Well, that's one thing I can work on tomorrow.

Thanks millions for that!

Wait.. How about strcat()? atoi().. Gulp! I may be really really busy tomorrow.
 
Huh, I’m not the only one. Thanks for looking that up. I’d just assumed I was being dumb and was moving on. But looking at those Dates, I can see why I fell into that one. The bulk of my programming predates when it changed.

Problem is, that this is an error that I believe is just a symptom of the original error. I’m very, no - extremely happy to plug up this logical hole in my code. I’m hoping, fingers crossed, that it will lead me closer to where the original error lies.

Thanks again for that.
 
I learned strlen() straight from K&R. In the several example versions of strlen() shown in that book, none check for a NULL pointer. It is simply assumed that the programmer is better than that.
 
Code:
$ /usr/bin/arm-none-eabi-objdump -S handheld.ino.elf |less
...


0002c6c0 <strlen>:
   2c6c0:       f890 f000       pld     [r0]
   2c6c4:       e96d 4502       strd    r4, r5, [sp, #-8]!
   2c6c8:       f020 0107       bic.w   r1, r0, #7
   2c6cc:       f06f 0c00       mvn.w   ip, #0
   2c6d0:       f010 0407       ands.w  r4, r0, #7
   2c6d4:       f891 f020       pld     [r1, #32]
   2c6d8:       f040 8049       bne.w   2c76e <strlen+0xae>
   2c6dc:       f04f 0400       mov.w   r4, #0
   2c6e0:       f06f 0007       mvn.w   r0, #7
   2c6e4:       e9d1 2300       ldrd    r2, r3, [r1]
   2c6e8:       f891 f040       pld     [r1, #64]       @ 0x40
 
Ah, but I finally came up with a simple test program, using none of my code, that fails in the same way.

C++:
//#include <ST7796_t3.h>  // The teensy display lib.
#include <SD.h>         // The SD lib.
//#include <LC_SPI.h>     // My lib that supplies the LC_DC value.

#define SD_CS     4
#define DSP_CS    10
#define DSP_RST   26

//ST7796_t3 disp(DSP_CS,LC_DC,DSP_RST);

#define PATH1 "/SYSTEM"
#define PATH2 "/SYSTEM/ICONS"
#define PATH3 "/SYSTEM/ICONS/STANDARD"
#define PATH4 "/SYSTEM/ICONS/STANDARD/CROSS32.BMP"
#define PATH5 "/SYSTEM/IMAGES"
#define PATH6 "/SYSTEM/IMAGES/LAKE.BMP"
#define PATH7 "/SYSTEM/APPFILES"
#define PATH8 "/SYSTEM/APPFILES/BREAKOUT"
#define PATH9 "/SYSTEM/APPFILES/BREAKOUT.BMP"
#define PATH10 "/SYSTEM/APPFILES/SETT"
#define PATH11 "/SYSTEM/APPFILES/SETT/SETT.BMP"


void setup() {

  Serial.begin(9600);           // Fire up serial
  delay(2000);                  // Sometimes the Mac needs a smoko before starting.
  //disp.init(320, 480);                // Do the init() like the example.
  //disp.invertDisplay(true);  // This LCD requires colors to be inverted.
  if (!SD.begin(SD_CS)) {
    Serial.println("SD.begin() failed!");
  }
}


void testFile(char* inPath) {

  File aFile;

  Serial.print("Path\t");
  Serial.print(inPath);
  Serial.print("\t");

  aFile = SD.open(inPath,FILE_READ);
  if (aFile) {
   if (aFile.isDirectory()) Serial.println(" Directory"); else Serial.println(" File");
   aFile.close();
  } else {
    Serial.println(" ***** Failed! *****");
    while(!Serial.available()) delay(10);
  }
}


void loop() {

  testFile(PATH1);
  testFile(PATH2);
  testFile(PATH3);
  testFile(PATH4);
  testFile(PATH5);
  testFile(PATH6);
  testFile(PATH7);
  testFile(PATH8);
  testFile(PATH9);
  testFile(PATH10);
  testFile(PATH10);
  delay(100);
}

I realize I call PATH10 twice now that I look at it. But this is what I ran so this is what I'll post. It fails on my system within about 10 seconds or so.
 
Can you give us a ZIP file with the .BMP files to put onto a SD card? Without those files, nobody can actually run this to reproduce the problem.
 
OK guys. I need some help..

Using just.. A teensy 4.0 hardwired to ONLY an SD drive card. (From Adafruit)
Running that simple program above.
With the SD card image of the one in the above from the .elf repo..

Still fails exactly the same. Path9 fails.

This has none of my library code in it. Not using the TFT or it's driver code. Just straight Arduino/Teensy stuff.

Thanks!

P.S. 528 Meg optimized "fast".
 
A search turns up a discussion where the SD library has/had a memory leak problem which would cause trouble with repeated file open/close operations. SDFat was said to not have this problem.
 
It can leak out all the 4.0's memory in 9 open file calls? That would not be a "leak" but no bottom to the bucket at all.
 
@jim lee - Is this what you were looking for?
Code:
Path    /System  Directory
Path    /System/icons    Directory
Path    /System/icons/standard   Directory
Path    /System/icons/standard/cross32.bmp       File
Path    /System/images   Directory
Path    /System/images/lake.bmp  File
Path    /System/appFiles         Directory
Path    /System/appFiles/breakout        Directory                                                            
Path    /System/appFiles/breakout/breakout.bmp   File                                                        
Path    /System/appFiles/sett    Directory                                                                    
Path    /System/appFiles/sett/sett.bmp   File
First fixed these warnings:
Code:
SDtest: In function 'void loop()':
SDtest:24: warning: ISO C++ forbids converting a string constant to 'char*'
   24 | #define PATH1 "/System"
      |               ^~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:70:12: note: in expansion of macro 'PATH1'
   70 |   testFile(PATH1);
      |            ^~~~~
SDtest:25: warning: ISO C++ forbids converting a string constant to 'char*'
   25 | #define PATH2 "/System/icons"
      |               ^~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:71:12: note: in expansion of macro 'PATH2'
   71 |   testFile(PATH2);
      |            ^~~~~
SDtest:26: warning: ISO C++ forbids converting a string constant to 'char*'
   26 | #define PATH3 "/System/icons/standard"
      |               ^~~~~~~~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:72:12: note: in expansion of macro 'PATH3'
   72 |   testFile(PATH3);
      |            ^~~~~
SDtest:27: warning: ISO C++ forbids converting a string constant to 'char*'
   27 | #define PATH4 "/System/icons/standard/cross32.bmp"
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:73:12: note: in expansion of macro 'PATH4'
   73 |   testFile(PATH4);
      |            ^~~~~
SDtest:28: warning: ISO C++ forbids converting a string constant to 'char*'
   28 | #define PATH5 "/System/images"
      |               ^~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:74:12: note: in expansion of macro 'PATH5'
   74 |   testFile(PATH5);
      |            ^~~~~
SDtest:29: warning: ISO C++ forbids converting a string constant to 'char*'
   29 | #define PATH6 "/System/images/lake.bmp"
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:75:12: note: in expansion of macro 'PATH6'
   75 |   testFile(PATH6);
      |            ^~~~~
SDtest:30: warning: ISO C++ forbids converting a string constant to 'char*'
   30 | #define PATH7 "/System/appFiles"
      |               ^~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:76:12: note: in expansion of macro 'PATH7'
   76 |   testFile(PATH7);
      |            ^~~~~
SDtest:31: warning: ISO C++ forbids converting a string constant to 'char*'
   31 | #define PATH8 "/System/appFiles/breakout"
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:77:12: note: in expansion of macro 'PATH8'
   77 |   testFile(PATH8);
      |            ^~~~~
SDtest:32: warning: ISO C++ forbids converting a string constant to 'char*'
   32 | #define PATH9 "/System/appFiles/breakout/breakout.bmp" // was missing "breakout/" directory name
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:78:12: note: in expansion of macro 'PATH9'
   78 |   testFile(PATH9);
      |            ^~~~~
SDtest:33: warning: ISO C++ forbids converting a string constant to 'char*'
   33 | #define PATH10 "/System/appFiles/sett"
      |                ^~~~~~~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:79:12: note: in expansion of macro 'PATH10'
   79 |   testFile(PATH10);
      |            ^~~~~~
SDtest:33: warning: ISO C++ forbids converting a string constant to 'char*'
   33 | #define PATH10 "/System/appFiles/sett"
      |                ^~~~~~~~~~~~~~~~~~~~~~~
/home/wwatson/Arduino/SDtest/SDtest.ino:80:12: note: in expansion of macro 'PATH10'
   80 |   testFile(PATH10);
      |            ^~~~~~

The main issue is/was the fact that directory and file names are case sensitive. All of your path names were in upper case and they are mixed (upper and lower) case on the SD card so they were not recognized by SD or SDfat. There were a couple of other little issues that were fixed as well.
Here is your modified sketch that seems to be working if I understood your issue correctly:
Code:
//#include <ST7796_t3.h>  // The teensy display lib.
#include <SD.h>         // The SD lib.
//#include <LC_SPI.h>     // My lib that supplies the LC_DC value.

#define SD_CS     4 //BUILTIN_SDCARD //4
#define DSP_CS    10
#define DSP_RST   26

//ST7796_t3 disp(DSP_CS,LC_DC,DSP_RST);
/*
#define PATH1 "/SYSTEM"
#define PATH2 "/SYSTEM/ICONS"
#define PATH3 "/SYSTEM/ICONS/STANDARD"
#define PATH4 "/SYSTEM/ICONS/STANDARD/CROSS32.BMP"
#define PATH5 "/SYSTEM/IMAGES"
#define PATH6 "/SYSTEM/IMAGES/LAKE.BMP"
#define PATH7 "/SYSTEM/APPFILES"
#define PATH8 "/SYSTEM/APPFILES/BREAKOUT"
#define PATH9 "/SYSTEM/APPFILES/BREAKOUT.BMP" <-- Invalad path see PATH9 below
#define PATH10 "/SYSTEM/APPFILES/SETT"
#define PATH11 "/SYSTEM/APPFILES/SETT/SETT.BMP"
*/
// File names are case sensitive:) Also changed from a defines to an initialized array.
// to avoid compiler warnings. There is probably a better way to this.
char PATH1[] = "/System"; // Changed defines to a character array to avoid compiler warnings.
char PATH2[] = "/System/icons";
char PATH3[] = "/System/icons/standard";
char PATH4[] = "/System/icons/standard/cross32.bmp";
char PATH5[] = "/System/images";
char PATH6[] = "/System/images/lake.bmp";
char PATH7[] = "/System/appFiles";
char PATH8[] = "/System/appFiles/breakout";
char PATH9[] = "/System/appFiles/breakout/breakout.bmp"; // was missing "breakout/" directory name
char PATH10[] = "/System/appFiles/sett";
char PATH11[] = "/System/appFiles/sett/sett.bmp";


void setup() {

  Serial.begin(9600);           // Fire up serial
  delay(2000);                  // Sometimes the Mac needs a smoko before starting.
  //disp.init(320, 480);                // Do the init() like the example.
  //disp.invertDisplay(true);  // This LCD requires colors to be inverted.
  if (!SD.begin(SD_CS)) {
    Serial.println("SD.begin() failed!");
  }
}


void testFile(char* inPath) {

  File aFile;

  Serial.print("Path\t");
  Serial.print(inPath);
  Serial.print("\t");

  aFile = SD.open(inPath,FILE_READ);
//Serial.printf("Here...\n");
  if (aFile) {
   if (aFile.isDirectory()) Serial.println(" Directory"); else Serial.println(" File");
   aFile.close();
  } else {
    Serial.println(" ***** Failed! *****");
  }
}


void loop() {

  testFile(PATH1);
  testFile(PATH2);
  testFile(PATH3);
  testFile(PATH4);
  testFile(PATH5);
  testFile(PATH6);
  testFile(PATH7);
  testFile(PATH8);
  testFile(PATH9);
  testFile(PATH10);
  testFile(PATH11); // Changed from PATH10 to PATH11
  delay(100);
    while(!Serial.available()) delay(10);
}
Hope this helps...

EDIT: Tested with a T4.0.
 
Last edited:
My bad. Nothing like a typo. to mess up a test. Sorry folks!

On this one : #define PATH9 "/SYSTEM/APPFILES/BREAKOUT.BMP" <-- Invalid path see PATH9 below
you beat me to it by a couple hours. I didn't realize I typed that path wrong was going to change and re-test it when I saw your post. I thought I'd cornered the beast. But alas, it was just me, again.

Since when are these SD files case sensitive? I've never run into that before that I can remember? I'll have to go back and look at my stuff to see.

The good news is, it seems Mr Teensy is fine.
 
Glad to here it. Most Windows fans don't have to deal with case sensitive path names. In Linux the path names are case sensitive. SDfat uses Linux style path names including the forward slash, "/" as a directory separator.
 
You know I'm trying this with all sorts of mixed case chars and I can't see any issues with it.
 
You know I'm trying this with all sorts of mixed case chars and I can't see any issues with it.
Odd, what version of Arduino and Teensyduino are you using? Good practice is to match upper and lower case. Try setting all the path names in the sketch to upper case again and see if it works.
 
Back
Top