Transferring files from PC to SD card

Salchicha

Active member
Does anyone have a ready made program or sketch or some way of transferring files to the SD card on Teensy 4.1 over USB?
I know there are various libraries for doing this but I don't have the time to learn/program them, if someone has something ready built I can use I'd be grateful.
 
I know there are various libraries for doing this but I don't have the time to learn/program them
One way is to get a USB microSD card reader for your PC, copy files onto an SD that way, and then insert the SD card into your T4.1 socket. If you want to transfer directly to the SD on T4.1, search for "MTP" on this forum. That stands for "Mass Transfer Protocol" (I think), and it lets you drag/drop files between your T4.1 SD card and your PC. There will be a small amount of reading and experimentation required.
 
Unfortunately, MTP is not yet included in the standard Teensy libraries.

You have to download the MTP_t4 library from: https://github.com/WMXZ-EU/MTP_t4

I modified the mtp_example program as follows:

C++:
// From /shared/arduino/git/MTP_t4.git/trunk/examples/mtp-basic/mtp-basic.ino

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

#if defined(ARDUINO_TEENSY41)
// The Teensy 4.1 has two sets of solder pads underneath the Teensy that you
// can solder either 2 PSram chips, 1 flash memory chip, or 1 flash memory chip
// and a PSram chip.  The smaller flash chips tend to use NOR flash while the
// larger flash chips tend to use NAND flash.
#define USE_LFS_RAM            1    // T4.1 PSRAM (or RAM)
#define USE_LFS_QSPI_NOR        1    // T4.1 QSPI NOR flash (16MB)
#define USE_LFS_QSPI_NAND        1    // T4.1 QSPI NAND flash (128MB)

#else
#define USE_LFS_RAM            0    // T4.1 PSRAM (or RAM)
#define USE_LFS_QSPI_NOR        0    // T4.1 QSPI NOR flash (16MB)
#define USE_LFS_QSPI_NAND        0    // T4.1 QSPI NAND flash (128MB)
#endif

#if defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41)
// Teensy 4.0 and 4.1 can use the upper flash memory as a file system via
// LittleFS.  The top bytes (64K for Teensy 4.0 and 256K for Teensy 4.1) of
// this memory is reserved for EEPROM emulation and the LED blink restore
// program.  On the Teensy 4.0 you have 1 megabyte - 64K of flash for a
// filesystem.  On the Teensy 4.1, you have 7 megabytes - 256K of flash for the
// filesystem.
#define USE_LFS_PROGM            1    // T4.0/T4.1 Progam Flash
#else
#define USE_LFS_PROGM            0    // T4.0/T4.1 Progam Flash
#endif

#define USE_SD                1    // Use either the built-in micro SD card reader or the reader on pin 10 (audio adapter)
#define USE_LFS_SPI            1    // SPI Flash (soldered to the audio adapter or the built-in flash on the prop shield)

// If you use the audio adapter revision A through C on a Teensy LC, 3.2, 3.5,
// or 3.6, it needs to remap the MOSI/SCK pins because those pins (11 and 13)
// are also I2S pins used by the audio shield.  But the prop shield wants to
// use the normal definitions.  In general, I've used the prop shield mostly on
// the Teensy 3.2 and LC, while if I use it, I use the audio shield on the
// Teensy 3.5 or Teensy 3.6.
//
// The Teensy 4.0 and 4.1 uses the audio adapter revision D, and it uses the
// standard SPI pins.
#if defined(ARDUINO_TEENSY35) || defined(ARDUINO_TEENSY36)
#define USE_TEENSY3_AUDIO_SHIELD    1    // Whether to use the Audio shield MOSI/SCLK for Teensy 3.x processors
#else
#define USE_TEENSY3_AUDIO_SHIELD    0    // Use standard configuration
#endif

#if USE_EVENTS==1
  extern "C" int usb_init_events(void);
#else
  int usb_init_events(void) {}
#endif

#if USE_LFS_RAM==1 ||  USE_LFS_PROGM==1 || USE_LFS_QSPI_NOR==1 || USE_LFS_QSPI_NAND==1 || USE_LFS_SPI==1
  #include "LittleFS.h"
#endif

#if defined(__IMXRT1062__)
  // following only as long usb_mtp is not included in cores
  #if !__has_include("usb_mtp.h")
    #include "usb1_mtp.h"
  #endif
#else
  #ifndef BUILTIN_SDCARD
    #define BUILTIN_SDCARD 254
  #endif
  void usb_mtp_configure(void) {}
#endif


/****  Start device specific change area  ****/
// SDClasses
#if USE_SD==1
  // edit SPI to reflect your configuration
#if USE_TEENSY3_AUDIO_SHIELD
 // Teensy audio adapter for Teensy 3.2, 3.5, and 3.6 (revision A-C) needs to remap the MOSI and SCK pins
  #define SD_MOSI  7
  #define SD_MISO 12
  #define SD_SCK  14
#else
 // Standard Teensy configuration
  #define SD_MOSI 11
  #define SD_MISO 12
  #define SD_SCK  13
#endif

  #define SPI_SPEED SD_SCK_MHZ(33)                // adjust to sd card

  #if defined (BUILTIN_SDCARD)
    const char *sd_str[]={"BUILTIN-SD", "AUDIO-SD"};        // edit to reflect your configuration
    const int cs[] = {BUILTIN_SDCARD, 10};            // edit to reflect your configuration
  #else
    const char *sd_str[]={"AUDIO-SD"};                // edit to reflect your configuration
    const int cs[] = {10};                    // edit to reflect your configuration
  #endif
  const int nsd = sizeof(sd_str)/sizeof(const char *);

SDClass sdx[nsd];
#endif

//LittleFS classes
#if USE_LFS_RAM==1
  const char *lfs_ram_str[]    = {"RAM1","RAM2"};        // edit to reflect your configuration
  const int lfs_ram_size[]    = {2'000'000, 4'000'000};    // edit to reflect your configuration
  const int nfs_ram        = sizeof(lfs_ram_str)/sizeof(const char *);

  LittleFS_RAM ramfs[nfs_ram];
#endif

#if USE_LFS_QSPI_NOR==1
  const char *lfs_qspi_nor_str[]    = {"QSPI-NOR"};        // edit to reflect your configuration
  const int nfs_qspi_nor        = sizeof(lfs_qspi_nor_str)/sizeof(const char *);

  LittleFS_QSPIFlash qspifs_nor[nfs_qspi_nor];
#endif

#if USE_LFS_QSPI_NAND==1
  const char *lfs_qspi_nand_str[]    = {"QSPI-NAND"};    // edit to reflect your configuration
  const int nfs_qspi_nand        = sizeof(lfs_qspi_nand_str)/sizeof(const char *);

  LittleFS_QPINAND qspifs_nand[nfs_qspi_nand];
#endif

#if USE_LFS_PROGM==1
  const char *lfs_progm_str[]={"PROGRAM"};            // edit to reflect your configuration
  const int lfs_progm_size[] = {1'000'000};            // edit to reflect your configuration
  const int nfs_progm = sizeof(lfs_progm_str)/sizeof(const char *);

  LittleFS_Program progmfs[nfs_progm];
#endif

#if USE_LFS_SPI==1
  const char *lfs_spi_str[]={"SPI-FLASH"};            // edit to reflect your configuration
  const int lfs_cs[] = {6};                    // edit to reflect your configuration
  const int nfs_spi = sizeof(lfs_spi_str)/sizeof(const char *);

LittleFS_SPIFlash spifs[nfs_spi];
#endif


MTPStorage_SD storage;
MTPD    mtpd(&storage);

void storage_configure()
{
  #if USE_SD==1
    #if defined SD_SCK
      SPI.setMOSI(SD_MOSI);
      SPI.setMISO(SD_MISO);
      SPI.setSCK(SD_SCK);
    #endif

    for(int ii=0; ii<nsd; ii++)
    {
      #if defined(BUILTIN_SDCARD)
        if(cs[ii] == BUILTIN_SDCARD)
        {
          if(!sdx[ii].sdfs.begin(SdioConfig(FIFO_SDIO)))
          { Serial.printf("SDIO Storage %d %d %s failed or missing",ii,cs[ii],sd_str[ii]);  Serial.println();
          }
          else
          {
            storage.addFilesystem(sdx[ii], sd_str[ii]);
            uint64_t totalSize = sdx[ii].totalSize();
            uint64_t usedSize  = sdx[ii].usedSize();
            Serial.printf("SDIO Storage %d %d %s ",ii,cs[ii],sd_str[ii]);
            Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
          }
        }
        else if(cs[ii]<BUILTIN_SDCARD)
      #endif
      {
        pinMode(cs[ii],OUTPUT); digitalWriteFast(cs[ii],HIGH);
        if(!sdx[ii].sdfs.begin(SdSpiConfig(cs[ii], SHARED_SPI, SPI_SPEED)))
        { Serial.printf("SD Storage %d %d %s failed or missing",ii,cs[ii],sd_str[ii]);  Serial.println();
        }
        else
        {
          storage.addFilesystem(sdx[ii], sd_str[ii]);
          uint64_t totalSize = sdx[ii].totalSize();
          uint64_t usedSize  = sdx[ii].usedSize();
          Serial.printf("SD Storage %d %d %s ",ii,cs[ii],sd_str[ii]);
          Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
        }
      }
    }
    #endif

    #if USE_LFS_RAM==1
    for(int ii=0; ii<nfs_ram;ii++)
    {
      if(!ramfs[ii].begin(lfs_ram_size[ii]))
      { Serial.printf("Ram Storage %d %s failed or missing",ii,lfs_ram_str[ii]); Serial.println();
      }
      else
      {
        storage.addFilesystem(ramfs[ii], lfs_ram_str[ii]);
        uint64_t totalSize = ramfs[ii].totalSize();
        uint64_t usedSize  = ramfs[ii].usedSize();
        Serial.printf("RAM Storage %d %s ",ii,lfs_ram_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
      }
    }
    #endif

    #if USE_LFS_PROGM==1
    for(int ii=0; ii<nfs_progm;ii++)
    {
      if(!progmfs[ii].begin(lfs_progm_size[ii]))
      { Serial.printf("Program Storage %d %s failed or missing",ii,lfs_progm_str[ii]); Serial.println();
      }
      else
      {
        storage.addFilesystem(progmfs[ii], lfs_progm_str[ii]);
        uint64_t totalSize = progmfs[ii].totalSize();
        uint64_t usedSize  = progmfs[ii].usedSize();
        Serial.printf("Program Storage %d %s ",ii,lfs_progm_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
      }
    }
    #endif

    #if USE_LFS_QSPI_NOR==1
    for(int ii=0; ii<nfs_qspi_nor;ii++)
    {
      if(!qspifs_nor[ii].begin())
      { Serial.printf("QSPI Storage %d %s failed or missing",ii,lfs_qspi_nor_str[ii]); Serial.println();
      }
      else
      {
        storage.addFilesystem(qspifs_nor[ii], lfs_qspi_nor_str[ii]);
        uint64_t totalSize = qspifs_nor[ii].totalSize();
        uint64_t usedSize  = qspifs_nor[ii].usedSize();
        Serial.printf("QSPI NOR Storage %d %s ",ii,lfs_qspi_nor_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
      }
    }
    #endif

    #if USE_LFS_QSPI_NAND==1
    for(int ii=0; ii<nfs_qspi_nand;ii++)
    {
      if(!qspifs_nand[ii].begin())
      { Serial.printf("QSPI Storage %d %s failed or missing",ii,lfs_qspi_nand_str[ii]); Serial.println();
      }
      else
      {
        storage.addFilesystem(qspifs_nand[ii], lfs_qspi_nand_str[ii]);
        uint64_t totalSize = qspifs_nand[ii].totalSize();
        uint64_t usedSize  = qspifs_nand[ii].usedSize();
        Serial.printf("QSPI NAND Storage %d %s ",ii,lfs_qspi_nand_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
      }
    }
    #endif

    #if USE_LFS_SPI==1
    for(int ii=0; ii<nfs_spi;ii++)
    {
      if(!spifs[ii].begin(lfs_cs[ii]))
      { Serial.printf("SPIFlash Storage %d %d %s failed or missing",ii,lfs_cs[ii],lfs_spi_str[ii]); Serial.println();
      }
      else
      {
        storage.addFilesystem(spifs[ii], lfs_spi_str[ii]);
        uint64_t totalSize = spifs[ii].totalSize();
        uint64_t usedSize  = spifs[ii].usedSize();
        Serial.printf("SPIFlash Storage %d %d %s ",ii,lfs_cs[ii],lfs_spi_str[ii]); Serial.print(totalSize); Serial.print(" "); Serial.println(usedSize);
      }
    }
    #endif
}

void setup()
{
  while (!Serial && millis () < 3000)
    ;

  Serial.println("MTP_test");
  Serial.printf ("USE_LFS_RAM              = %d\n", USE_LFS_RAM);
  Serial.printf ("USE_LFS_QSPI_NOR         = %d\n", USE_LFS_QSPI_NOR);
  Serial.printf ("USE_LFS_QSPI_NAND        = %d\n", USE_LFS_QSPI_NAND);
  Serial.printf ("USE_LFS_PROGM            = %d\n", USE_LFS_PROGM);
  Serial.printf ("USE_SD                   = %d\n", USE_SD);
  Serial.printf ("USE_LFS_SPI              = %d\n", USE_LFS_SPI);
  Serial.printf ("USE_TEENSY3_AUDIO_SHIELD = %d\n", USE_TEENSY3_AUDIO_SHIELD);
  Serial.println ("");

  #if USE_EVENTS==1
    usb_init_events();
  #endif

  #if !__has_include("usb_mtp.h")
    usb_mtp_configure();
  #endif
  storage_configure();

}

void loop()
{
  mtpd.loop();

#if USE_EVENTS==1
  if(Serial.available())
  {
    char ch=Serial.read();
    Serial.println(ch);
    if(ch=='r')
    {
      Serial.println("Reset");
      mtpd.send_DeviceResetEvent();
    }
  }
#endif
}

Then do Tools -> USB Type -> Serial + MTP Disk (Expermental).

Build and install the sketch.

Depending on which OS you have, you can transfer files to/from the Teensy. On my Linux system, I need to bring up the file explorer and each of the devices on the system will be represented, and you can select the particular storage units, using the normal file explorer cut, paste, copy, etc. commands to transfer data.

You can transfer files to/from
  • The 1 or 2 8 megabyte PSram chip(s) soldered underneath the Teensy 4.1 (note PSram chips are volatile are are erased when the Teensy is powered up)
  • Files stored in flash memory soldered underneath the Teensy 4.1 (the code supports either smaller flash memories up to 16 megabytes using NOR flash or up to 2 gigabytes using NAND flash)
  • Files stored in the upper flash memory of the Teensy 4.0 (around 1 megabyte) or 4.1 (around 7 megabytes)
  • Files stored in the SD card on the Teensy 4.1/3.6/3.5 or external SD card soldered to the Teensy 4.0 underneath solder pads
  • Files stored in the SD card in the audio adapter (CS pin is 10 by default) or an external SD card reader using CS pin 10
  • Files stored in flash memory (CS pin is 6 by default) -- either if you have a flash memory chip soldered to the audio adapter, you use the old Teensy prop shield, or you have an external flash chip using CS pin 6
 
Last edited:
Back
Top