Issues with 4.1 and sound module

SteveCS

Well-known member
Hi all

I'll dig out the code tonight, but I am having consistant issues on many projects with 3.2's and their associated Teensy sound boards and 4.1's and their sound boards.
They randomly emit a horrific screeching noise and it renders the code useless. Nothing but a reset will fix it.

My workmate is a wizard at coding and he suffers the same issue. He has since binned using Teensy as his 'go to' processor because of the problems.
He believes it is a memory clash issue.

My current project also uses the SD card to retrieve images, and I am wondering if that part of is the problem I am suffering with.

Anyone else get this weird screeching / noise issue?
 
I have seen that when there are signal integrity issues between the Teensy 4.1 and the audio adapter. It seems like even a momentary issue with MCLK can put it in a state giving that screeching noise that won't clear until the unit is power cycled.

In my case, I had a contention issue between MCLK and another chip output on that same pin 23 that was trying to drive that pin high. In my case MCLK was able to pull just low enough that the audio board would still work, but if you put a finger or scope probe on MCLK, it loaded it just enough that it would quite working and give that screeching noise until power was cycled.

Once I got that sorted out, I have found the Teensy 4.1 and audio to be rock solid and I build and test a lot of setups with the combo.
 
Hmm. Not sure how to fix this.

I always put a line in to make sure the sound file has finished playing (+ a slight delay), before it tries to retrieve an image from the SD card (where the sound files are also stored).

Ideally, I would like to store the sound files and the image files (128x64 colour) in memory and do away with the SD card.
Has/can this be done? Could you read an image from say a Fram breakout board (if I can find one big enough)
 
OK. Decided these Teensy Audio boards suck. Having so many problems with them that I just can't rely on them. This weird screeching issue is affecting a ew of our projects.
Seems to be some issue with the comms to the SGTL5000 (Mclk?).

Going to delete the audio board and use a 3rd party external MP3 unit. Go from there!
 
Since there are many happy users of Teensy Audio Adapter boards, I would not just discard them out of frustration.
Sure, they apparently 'suck' in your application but this forum may be of help in nailing down the issue(s) in your case.
Is it possible to share your code (and insight into any additional peripherals) so that forum users can try to replicate your problems?

Paul
 
It is a shame. I do like these modules, but we used them for several large installations on some commercial projects and had nothing but issues with them (those were all 3.2's + audio boards).
I am not the main programmer in the company. The guy that does the coding is far better than me and he just could not get them to be reliable (the 3.2 or the 4.1). He also thinks it is some kind of memory collision issue.

So, unfortunately, we have decided to move away from the Teensy platform and now we base our projects on esp8266'S instead with some far simpler MP3 modules that work fine for our requirements.
Anything that needs multiple audio channels, we have been using WavTrigger boards with reasonable success.

Thanks anyway
 
Without any way to see, let alone reproduce the problem, can only really guess about the problem.

My current project also uses the SD card to retrieve images, and I am wondering if that part of is the problem I am suffering with.

But it is pretty well known that access to the card from both audio library and main program isn't safe. My best guess is this very likely is the root of problems you encountered.

Years ago, before switching directions to make Teensy 3.6 and support USB host, I poured quite a bit of work into rewriting the (now very old) SD library to allow safe use from interrupts and main program. With Teensyduino 1.53 and earlier, it could be enabled by editing SD_t3.h.

Starting with Teensyduino 1.54, we discarded the ancient SD library and replaced it with a thin wrapper around SdFat. But that doesn't solve the interrupt safety issue. If your main program access the card while the audio library plays audio, it will eventually crash.

This is on my long-term list of issues to fix. How is still undecided. It might be work inside SdFat similar to that earlier effort on SD_t3.h. Or if might look like work Frank did some time ago. Or Jonathan Oakley recently made an alternate player that avoids media access in the interrupts and does everything from yield(). Or something else might be done, but very likely the ultimate solution will probably go with 1 of those 3 approaches.

You said you've already switch to ESP and dedicated MP3 playing chips. If that's working for you, great. But if you still have any of those old boards around with Teensy 3.2, you might try installing Teensyduino 1.53 into a fresh copy of Arduino IDE, and then edit SD_t3.h. The whole SD library becomes read-only, so not a solution if you need to write to the card. But if you're only reading and you use Teensy 3.2, I'm pretty sure it will solve your stability problems with reading images in the main program while playing sounds from the audio library interrupt.
 
No it's not the SD library. Well, maybe it is in this case, but the screeching noise has been a constant on several much simpler projects.
At first, we thought it was a power supply issue, but we ruled that out.

This is the first project using images. All the previous 3.2 based projects were pretty simple affairs with nothing but a few buttons to trigger effects and the sound effects.

I left it to our super wizard programmer and he couldn't get them to be 100% reliable. Not doubting it might be us, but we have never been able to fix it.
 
but the screeching noise has been a constant on several much simpler projects.

Any chance you could show the code for one of those simpler projects? Or if it's already shown anywhere, give me a link to it?

I need to have a way to reproduce the problem to have any hope of investigating and fixing it.
 
We always put the audio board on the Teensy. However in this instance, we didn't have the headroom. Pretty sure that isn't the issue, as we have the problem on several other projects where they are stacked.

I am adding the extra flash chips to the Teensy 4.1 today. My plan, even though I have no idea how to achieve it, is to put the 2x images (128x64) on the flash chip and remove those from the SD card.
My current code does have plenty of checks to ensure sound and images don't try to access the card at the same time, but that doesn't seem to be the issue. As I mentioned, this is the first project with images.

If I can, I will put the full code up. I didn't write most of the current version, so I need to check my mate is OK with sharing it.

Controller.jpg

My questions on the flash memory. I assume they have a CS pin. The small pad flash chip is pin 6? Not that I need it, but I assume there is there another pin for the other onboard flash chip.

I believe LittleFS is what I need for the flash chip. Shame there isn't an image example in the library.

The TFT image code is from a standard library. Can't remember where I found it, but it's the one I have used many times (the actual load routine is below).
Anyone got any guidance to some code for loading images from LittleFS to a TFT screen?


Code:
//------------- Send BMP to screen ------------------                                       // Display BMP file

#define BUFFPIXEL 20

void bmpDraw(char *filename, uint8_t x, uint16_t y) {

  tft.fillScreen(ST77XX_BLACK);

  File     bmpFile;
  int      bmpWidth, bmpHeight;               // W+H in pixels
  uint8_t  bmpDepth;                          // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;                    // Start of image data in file
  uint32_t rowSize;                           // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3 * BUFFPIXEL];           // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer);        // Current position in sdbuffer
  boolean  goodBmp = false;                   // Set to true on valid header parse
  boolean  flip    = true;                    // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if ((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print(F("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == 0) {
    Serial.print(F("File not found"));
    clearscreen();
    return;
  }

  // Parse BMP header
  if (read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if (read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
      if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("Image size: "));
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        rowSize = (bmpWidth * 3 + 3) & ~3;

        if (bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if ((x + w - 1) >= tft.width())  w = tft.width()  - x;
        if ((y + h - 1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        tft.startWrite();
        tft.setAddrWindow(x, y, w, h);

        for (row = 0; row < h; row++) { // For each scanline...

          if (flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if (bmpFile.position() != pos) { // Need seek?
            tft.endWrite();
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col = 0; col < w; col++) { // For each pixel...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
              tft.startWrite();
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.color565(r, g, b));
          } // end pixel
        } // end scanline
        tft.endWrite();
        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if (!goodBmp) Serial.println(F("BMP format not recognized."));
}

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

edit... OK, just found this...

https://github.com/PaulStoffregen/teensy41_extram
 
Last edited:
Don't use that old extram and SPIFFS_t4 stuff. It's outdated stuff from 3 years ago, the earliest experiments before LittleFS and proper PSRAM support were added.

Use LittleFS to access the flash memory. LittleFS comes pre-installed with all recent versions of Teensyduino, so you don't need to install anything new. It will give you "File" instances that work the same way as "File" from the SD library.

To use images, I'd recommend Larry Bank's JPEGDEC library.

https://github.com/bitbank2/JPEGDEC

Check out it's ILI9341_t3_slideshow example.
 
I've updated the readme on that old repository.

Flash memory added to Teensy 4.1 is supported by the LittleFS library, which comes installed with Teensyduino.

https://github.com/PaulStoffregen/LittleFS

The LittleFS library offers several classes for different memory types. Use LittleFS_QSPIFlash to access a NOR flash chip, or LittleFS_QPINAND to access NAND flash, or LittleFS_QSPI for either (automatically detected).
 
Wow. I have to say at this point I am baffled. Just adding a PSRAM chip to the smaller pads, as I think that will be enough.
But I have literally found about 6 different ways of implementing LittleFS and I just don't really understand what the heck I am doing.

I'll keep trying
 
These examples are great (such as the https://github.com/bitbank2/JPEGDEC), but they don't appear to show you how to get the images into the flash memory to start with.
There always seems to be some critical piece of information missing foe us hobby level folk

One method is to use MTP. There is a rather long thread about MTP:


Basically, you run the sketch, and it uses MTP to connect to the host via USB. You can use the file explorer on your system to copy files to/from your computer to any of the memory file systems or the SD card. When you are done, just re-program the Teensy.

You need to download the MTP_t4 library and put it in your libraries sections:


Note, I only use Linux. There might be additional things you need to do on Windows or Macs.

Here is one of the examples that I hacked up somewhat that I've used:

Code:
// From 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
}
 
For what it is worth, @mjs513 and I were playing with a picture viewer sketch, which is up at: https://github.com/KurtE/mtp_tft_picture_view

It cycles through pictures on a storage and displays them on a display.
It optionally can use MTP, to add/remove files from storage:
It optionally used jpgdec and pngdec to display those types of files.
And we played with several different displays.

I have not tried his image_to_c to see how well it works.
I have used some online conversion websites before, like when we were playing with earlier version of uncanny eyes.

One I see now that looks reasonable is:
https://notisrac.github.io/FileToCArray/
 
@SteveCS:

It looks like there are some image tools (UTFT), with example sources, included as part of the TeensyDuino installation (located at "C:\Program Files (x86)\Arduino\hardware\teensy\avr\libraries\UTFT\Tools" on my Windows 11pro 64-bit PC) that might be useful (I've not used them myself . . . maybe someone who has can chime in with more info). There's also an online converter made available by the author of the UTFT tools <here>. You might give that a try to see if it helps towards your intended objective . . .

Mark J Culross
KD5RXT
 
I converted the images to C and loaded it into Progmem

Then I used the Adafruit GFX.h library's bitmap routine and that seems to work well.

I used:

const uint16_t Border [] PROGMEM = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, blah blah
};

Could I write this to the additional PSRAM flash memory instead?

As for the sound, I removed the Teensy audio board and used a simple JQ8400 MP3 module (Serial)
 
I converted the images to C and loaded it into Progmem

Then I used the Adafruit GFX.h library's bitmap routine and that seems to work well.

I used:

const uint16_t Border [] PROGMEM = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, blah blah
};

Could I write this to the additional PSRAM flash memory instead?
Unfortunately you can't initialize PSRAM. But using PROGMEM and const puts the array into flash memory and not into SDRAM.
 
Wow. I have to say at this point I am baffled. Just adding a PSRAM chip to the smaller pads, as I think that will be enough.
But I have literally found about 6 different ways of implementing LittleFS and I just don't really understand what the heck I am doing.

I'll keep trying

Note, there are two types of memory that you can solder to the underneath of a Teensy 4.1.

There is PSRAM and flash. Both can be accessed as main memory. These chips use the normal cache, so as long as you are just accessing the frequently used regions, it should be reasonably fast. If the data is not in the cache, it will take somewhat longer to access. But you don't have to do anything special, just use the normal reads and writes. If you are doing DMA reads or writes to either PSRAM or flash memories, you will need to manually clear the cache.

The PSRAM chips are volatile, in that when you power cycle the Teensy they are erased. AFAIK, there is only size of PSRAM that can be used (8 megabytes or 64 megabits). You can solder either 2 PSRAM chips on the Teensy 4.1, or just one. So PSRAM is basically a way you can add more buffer space.

The flash chips are preserved across power cycles. Normally you use the flash memory with LittleFS to have a file system present, and you use normal read/write file operations like you would with a SD card. It is useful for image type operations, since you can store images and use them later. You can only mount one flash memory chip on the Teensy 4.1. Not all flash memories are supported. You need to consult the compatibility list to see what flash chips are supported. The flash chips are either NOR flash for the smaller chips (such as 16 megabytes or 128 megabits) or NAND flash for the larger chips (either 128 megabit/1 gigabit or 256 megabit/2 gigibits). You have to use different LittleFS constructors based on whether you are using NOR flash or NAND flash. In my example, it tries both NOR flash and NAND flash.

While I've done SMT soldering before, with my 65 year old eyes, I tend to prefer to pay a little extra and have protosupplies (https://protosupplies.com/product/teensy-4-1-fully-loaded/) solder the chips onto Teensy 4.1.
 
Back
Top