External SD card on Teensy 4.1

Is it possible to use an external micro SD card on a Teensy 4.1 ?

I have some test code, see below, that works fine on the Teensies built in micro SD card.

But I want to use an external additional micro SD card as the location of the Teensies own card is not convienent.

I modified the program with these lines;

SPI.setSCK(13); //set SPI pins for SD card
SPI.setMISO(12);
SPI.setMOSI(11);

And connected up a external micro SD card holder, but the SD card does not initialise. The same program, and card holder, works OK on ESP32.

So before I troubleshoot further can anyone confirm if the SD library for Teensy should work on the SPI interface instaed of SPI2 ?


Code:
/*******************************************************************************************************
  Program Operation - This test program has been written to check that a connected SD card adapter, Micro
  or standard, is functional. 
  
  The program creates a file called LOGXXXX.TXT, where XXXX is a number that increases every time the
  program is restarted. The program opens the file and writes a line like this to the file;

  #1 Hello World!

  The file is closed and the file contents are written to the IDE serial monitor and a directory of the
  SD card printed too. The process repeats with #2 Hello World! being appended to the file next. The
  directory listing allows you to keep track of the increasing size of the logFile. Problems with reading
  or writing to the SD card should result in an ERROR message on the IDE serial monitor.

  Serial monitor baud rate is set at 115200
*******************************************************************************************************/

#include <SPI.h>
#include <SD.h>


//#define SDCS 10                                       //enable define for external SD card on SPI 
#define SDCS BUILTIN_SDCARD                     //enable define for Teensies built in SD card on SPI2  


char filename[] = "/LOG0000.TXT";                //filename used as base for creating root, 0000 replaced with numbers
uint16_t linenumber = 0;

File logFile;


void loop()
{
  linenumber++;

  Serial.print("Write to file > ");
  Serial.print("#");
  Serial.print(linenumber);
  Serial.println(" Hello World!");

  logFile = SD.open(filename, FILE_WRITE);
  logFile.print("#");
  logFile.print(linenumber);
  logFile.println(" Hello World!");
  logFile.close();
  dumpFile(filename);
  Serial.println();

  logFile = SD.open("/");
  logFile.rewindDirectory();
  printDirectory(logFile, 0);

  Serial.println();
  delay(1500);
}


void printDirectory(File dir, int numTabs)
{
  Serial.println("Card directory");

  while (true)
  {
    File entry =  dir.openNextFile();
    if (! entry)
    {
      // no more files
      break;
    }

    for (uint8_t i = 0; i < numTabs; i++)
    {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory())
    {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    }
    else
    {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}


bool dumpFile(char *buff)
{
  Serial.print("Print file ");

  if (SD.exists(buff))
  {
    Serial.println(buff);
  }
  else
  {
    Serial.print("ERROR ");
    Serial.print(buff);
    Serial.println(" not found - program halted");
    while (1);
    //return false;
  }

  logFile = SD.open(buff);
  logFile.seek(0);

  if (logFile)                                    //if the file is available, read from it
  {
    while (logFile.available())
    {
      Serial.write(logFile.read());
    }
    logFile.close();
    return true;
  }
  else
  {
  Serial.print("ERROR ");
  Serial.println(" dumping file ");
  Serial.print(buff);
  Serial.println(" - program halted");
  while (1);
  //return false;
  }
}


uint8_t setupSDLOG(char *buff)
{
  //creats a new filename

  uint16_t index;

  File dir;

  for (index = 1; index <= 9999; index++)
  {
    buff[4] = index / 1000 + '0';
    buff[5] = ((index % 1000) / 100) + '0';
    buff[6] = ((index % 100) / 10) + '0';
    buff[7] = index % 10 + '0' ;

    if (! SD.exists(filename))
    {
      // only open a new file if it doesn't exist
      dir = SD.open(buff, FILE_WRITE);
      break;
    }
  }

  dir.rewindDirectory();                          //stops SD.exists() command causing issues with directory listings
  dir.close();

  if (!dir)
  {
    return 0;
  }
  return index;                                   //return number of root created
}



void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println();
  Serial.print(__FILE__);
  Serial.println();
  
  //SPI.setSCK(13);                                  //set SPI pins for SD card  
  //SPI.setMISO(12);
  //SPI.setMOSI(11);

  SPI.begin();

  //SPI.setSCK(13);                                  //set SPI pins for SD card  
  //SPI.setMISO(12);
  //SPI.setMOSI(11);

  if (!SD.begin(SDCS))
  {
    Serial.println();
    Serial.println("ERROR Card Mount Failed - program halted");
    Serial.println();
    //while (1);
  }

  Serial.println("Card Mount OK");

  logFile = SD.open("/");
  setupSDLOG(filename);
}
 
@StuartsProjects - Yes I can confirm external sd card readers will work on the Teensy 4.1 been using one for a long time.

In the example you posted the external card reader will never initialize on SPI unless you set the enable pin to something other than BUILTIN_SDCARD. That is reserved for use with the card reader on the T4.1 so it should read
Code:
#define SDCS 10                                       //enable define for external SD card on SPI 
//#define SDCS BUILTIN_SDCARD                     //enable define for Teensies built in SD card on SPI2
assuming your chip select is on pin 10.

Also you don't need to do an SPI.begin or set pins, defaults to SPI if not using BUILTIN_SDCARD. From the listfiles example for SD:
Code:
#include <SD.h>

// change this to match your SD shield or module;
// Teensy 2.0: pin 0
// Teensy++ 2.0: pin 20
// Wiz820+SD board: pin 4
// Teensy audio board: pin 10
// Teensy 3.5 & 3.6 & 4.1 on-board: BUILTIN_SDCARD
const int chipSelect = 10;

void setup()
{
 
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect.
  }

  Serial.print("Initializing SD card...");

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
 
For SPI,
you always should check that CLK,MOSI,MISO and chip select of your board correspond to your program. The Teensy card may help to figure out the standard values.
 
Thanks for the confirmation.

I tried the listfiles and that does indeed work for the external SD card holder.

And what odd is that when I then re-tried the test program I posted above, it now works.

I discovered the SPI.setSCK(), SPI.setMISO(), SPI.setMOSI(), seem to have no effect, even when the pins are wrong, and as you said there is no need for SPI.begin().

I even have the external SD card sharing the same SPI bus as a LoRa module. I am next going to try a LoRa image\file transfer progrma I wrote, I have been using DUEs, wanted to see if the Teensy is faster.

Why the SD card test program did not work in the first place I do not know.
 
I discovered the SPI.setSCK(), SPI.setMISO(), SPI.setMOSI(), seem to have no effect,

Yes, confirmed, these functions only have an effect if used with an alternate pin which is capable of having that signal. Only SPI2 on Teensy 4.1 has alternate SPI pins, shown in gray on the pinout reference card.

These functions are mostly useful on Teensy 3.2, 3.5, 3.6 where many alternate SPI pins exist, and where the only pins usable for I2S digital audio conflict with the default SPI pins. On these newer IMXRT chips, NXP didn't route (inside the chip) the SPI signals to as many different pins as with prior generations of chips. When Teensy 4 was designed, many difficult decisions about how to assign the pins to gain access to as many features as possible in the limited Teensy 4.0 form factor resulted in no access to alternate SPI pins.
 
An additional question if I may;

Is it possible on the Teensy 4.1 to run an external SD card on SPI1 ?

Yes it is possible.

Look at the SdFat_Usage.ino example sketch under SD you will see several examples of different ways to initialize the SD library through more advanced features of SDFat...

// Different SPI port (Teensy 4.1 SPI1 is MOSI1:pin26, MISO1:pin1, SCK1:pin27)
// photo: https://forum.pjrc.com/threads/69254?p=297875&viewfull=1#post297875
//ok = SD.sdfs.begin(SdSpiConfig(chipSelect, SHARED_SPI, SD_SCK_MHZ(16), &SPI1));
 
An additional question if I may;

Is it possible on the Teensy 4.1 to run an external SD card on SPI1 ?

From T4.1 card, I see
SCK,MOSI,MISO
SCK1,MOSI1,MISO1
SCK2,MOSI2,MISO2

You should be able to use any set for talking to uSD cards
HOWEVER, you must then adapt the SD card interface accordingly.
There may be also interferences with other usage.
 
Excellant, I will give that a go.

The different SPI port bit does not appear in my Arduino Teensy Install.

Some SD cards dont appear to play nicely with the LoRa modules I am using, its mostly OK, but for better reliability it would be better to have the LoRa module and micro SD cards on different SPI buses.
 
Back
Top