Teensy Audio Adapter Board + Teensy 4.0 : write to an USB stick instead of SD card ?

samyrabih

Active member
Hi !
I use Audio Adapter Board with success on one of my projects, with a Teensy 4.0 and a SD card to record audio (a phone-based guestbook).
I'm wondering if it is possible to write audio content recorded by the Audio Adapter to an USB stick.

I saw there are USB host pins on the Teensy 4.0 but as the sound is recorded and written by the Audio Adapter Board I don't know if i can use it here.

(and I didn't found any SD to USB stick adapter, to put an USB stick in a SD card reader)

If you have any idea ;)

Thanks
 
Not sure if this works reliably over USB with the small buffer sizes, but possibly you could use the procedure in the example from the Teensyduino "...Audio/Recorder" and change the write procedure.
I don't know if this is up to date:

...and maybe you find some hints in the examples under USBhost_t36/storage?
 
UsbMscFat is very much obsolete. Everything you need to read or write to a USB storage device is built into Teensyduino. You only need to include "USBHost_t36.h" in your sketch. Check out the examples in the "USBHost_t36/storage/examples" folder. Only the setup is different than using an SD card otherwise the file i/o commands are the same. Both SD cards and USB sticks use the same FS.h abstraction layer...
 
Last edited:
Generally if you are going to be using USB host for things like USB sticks a Teensy 4.1 will be easier to deal with because it has 5 standard 2.54mm holes on the inside that you can solder a USB A cable to attach devices. With the Teensy 4.0, you have to solder wires to the D+/D- pads underneath (along with ground and VIN/VUSB). If you use the Teensy 4.0, obviously secure the wires so any yanks on the USB cable won't rip the wires from the Teensy.

Here is the USB cable for the Teensy 4.1 that PJRC sells (but you can also get it elsewhere since it was a standard part in building computers with USB 2.0):

One thing you can do down the road is to use the MTP support to make the SD card or USB sticks available as a removable device when the Teensy is connected via USB:
I could imagine instead of writing to a USB stick, you could write to a SD card, and then using your Windows/Linux systems file explorer to access the files and copy them. Evidently with the MAC you have to use other apps to access MTP devices.

The Teensy 4.0 does have solder pads for connecting a SD card, but it is fine pitch surface mount soldering. Again the Teensy 4.1 is easier since it has the card slot built in. You can use the SD card slot on the Audio Adapter (note, the built-in SD card on the Teensy 4.1 is somewhat faster than the SD card on the audio adapter).

Alternatively, you could continue to write to a SD card, and then use a SD card reader to convert the card into a flash drive.
 
Thanks all for your advices !

@MichaelMeissner can the Audio Adapter board read/write on the SD of the Teensy 4.1 ? (I imagine MTP access is only possible for Teensy 4.1 built-in SD card and not the SD card on the Audio Adapter board)
 
Thanks all for your advices !

@MichaelMeissner can the Audio Adapter board read/write on the SD of the Teensy 4.1 ? (I imagine MTP access is only possible for Teensy 4.1 built-in SD card and not the SD card on the Audio Adapter board)
MTP is able to access the SD card in the audio adapter as well as the built-in SD card. Due to having 4 bits for data transfer, the built-in SD card is slightly faster, but MTP can access any file system object. Within the LittleFS code, there are supports for various file systems.

Here is an example MTP sketch that provides access to the Audio Adapter SD, the built-in SD, NOR and NAND flash soldered to the Teensy 4.1, extra space available in the flash memory of the Teensy, the PSram cards soldered to the Teensy 4.1, and external flash memory (either soldered to the audio adapter or the old prop shield):

Code:
// From the 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
}
 
Back
Top