Teensy MM and Data Logger Carrier board won't open SD

mborgerson

Well-known member
I just started working with the Teensy MM and Data Logger Carrier Board. I can't seem to get the SD Card to start up.

I'm using IDE 2.0.1 and the latest Teensy json: https://www.pjrc.com/teensy/package_teensy_index.json

When I run the same code on a T4.1, the SD Card opens as expected. The same SD card was used for the MM and T 4.1. I checked that 3.3V was present on the carrier board 3.3_LP power pins.


Here is the test code:

Code:
// Test for SD operation on Teensy MM and Data Logger Carrier board
// MJB 11/13/22
#include "SD.h"

#if defined(ARDUINO_TEENSY_MICROMOD)
constexpr uint8_t G1  = 41; // GPIO7-05  |
#define peripheralPowerControl G1
#endif

void setup() {
  delay(500);
  // put your setup code here, to run once:
#if defined(ARDUINO_TEENSY_MICROMOD)
  Serial.println("MicroMod Peripheral power on.");
  pinMode(peripheralPowerControl, OUTPUT);
  digitalWriteFast(peripheralPowerControl, HIGH);  //turn on 3.3V power to SDIO
#endif

  Serial.println("SD Card initialization test.");
  if (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("\nSD File initialization failed.\n");
  } else {
    Serial.println("initialization done.");
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}


Does the MM and data logger carrier board require a SD card different setup than the T4.1?
 
I just tried it on my TMM Carrier Board, and it return initialized using SD.begin(10):
Code:
MicroMod Peripheral power on.
SD Card initialization test.
initialization done.

Would make sure of a couple of things
1. Card is formated correctly
and
2. Card is inserted all the way (until you hear the click)

MJS
 
I tried the same test with SD.begin(10). The function still returned false.


I found that the second test was with a different SD card that also failed on the T4.1. When I switched back to the 128GB SanDisk, it worked with SD.begin(10) on the MM but failed on the T4.1.

Does that mean that the SD card on the data logger carrier board is operating the SD card in SPI mode? Will that reduce the performance of data logging operations?
 
I found that the second test was with a different SD card that also failed on the T4.1. When I switched back to the 128GB SanDisk, it worked with SD.begin(10) on the MM but failed on the T4.1.

Does that mean that the SD card on the data logger carrier board is operating the SD card in SPI mode? Will that reduce the performance of data logging operations?

The answer is yes. Sparkfun put the SD Card on the Teensy's SPI bus on all their carrier boards from what I remember. The T4.1 SD Card uses the Built-in Card reader which is on the SDIO bus.
 
If you care about the raw speed, also check out the SD library's SdFat_Usage example. I believe we settled on a moderate SPI clock speed as the default somewhere between 1.54 to 1.57, so long wires on breadboards and low quality SD adaptor boards with slow level shifting hardware would usually "just work" (as they do with traditional Arduino boards that use 4 or 8 MHz SPI). That example shows how to configure higher SPI clocks.

According to the official SD specs, 25 MHz is the maximum for SPI mode. Higher might work, but is considered overclocking.

There's also a special optimization for SPI if you have no other SPI chips connected to the same MOSI, MISO, SCK. For some types of use it can make a nice speedup.

But again, if you write in small amounts, the SD command latency and block management which happens inside the card ultimately limits the overall speed. Higher speeds are only possible if you read or write in very large blocks. But newer cards with A1 or A2 rating are supposedly also optimized for 4096 byte access which is a nice size that's much easier than working with 256K or larger blocks.
 
The answer is yes. Sparkfun put the SD Card on the Teensy's SPI bus on all their carrier boards from what I remember. The T4.1 SD Card uses the Built-in Card reader which is on the SDIO bus.

Well, that sort of sucks! I was planning to log data from either an SPI-connected ADC or other SPI periphrals. With the MM data logger carrier board, I will have to contend with multiple devices on the SPI bus. The Sparkfun schematic fooled me. It shows connections for DAT1, DAT2, and DAT3 at the uSD connector, but no connections for those pins at the MicroMod connector.

I suppose one alternative is to wire an SD card connector to an ATP carrier board, and try to use SPI1 for sensors and SDIO for the storage. The other alternative is to stick with the T4.1 for faster logging with SPI sensors and use the MM stuff for either I2C or UART connected-sensors. I'm well-stocked with T4.1s and the Micromod stuff was under $50. Not a terribly expensive lesson, but I wish I'd taken a closer look at the carrier board schematic.

[RANT] Sparkfun: Your schematics give crappy printouts on B&W laser printers. The red and green lines are nearly the same level of illegibility. The printouts look OK on a color laser printer--unless you have red/green color-blindness issues. The best solution seems to be to load the provided Eagle files and print them yourself with a B&W pallette. I feel like consigning the person who made the color choices to the same level of Hades as the person who persists in using red characters on a black background in the error messages in the Arduino IDE. At least with IDE 2.0 I can select the light theme. I like to pretend I'm reading print on paper instead of a monitor. Over the last 70 years, my eyes have become used to black print on a white background. The only time I've ever seen red print on black paper was back in the early '80s when some software companies would print source code that way because the copying machines at the time used a green lamp that rendered both red and black as black in the copy.
[/RANT]
 
When I switched back to the 128GB SanDisk, it worked with SD.begin(10) on the MM but failed on the T4.1.

Any chance you could share a photo of that SanDisk card which fails on Teensy 4.1? And could you run the CardInfo example and tell us what it prints?

There is a known bug with SDIO on Teensy 4, which I believe came with the 1.53 to 1.54 transition from the ancient SD library to thin wrapper for SdFat. So far it has only happened with very old SD cards, from the era when their sizes were measured in megabytes rather than gigabytes. It has never been seen with any SDHC or SDXC card. There were actually 2 different specs that came before SDHC which were both called just SD and a version number that isn't ever printed on the card, but can be seen with CardInfo. Starting with 1.54 those very oldest type cards haven't worked with SDIO.
 
Any chance you could share a photo of that SanDisk card which fails on Teensy 4.1? And could you run the CardInfo example and tell us what it prints?

There is a known bug with SDIO on Teensy 4, which I believe came with the 1.53 to 1.54 transition from the ancient SD library to thin wrapper for SdFat. So far it has only happened with very old SD cards, from the era when their sizes were measured in megabytes rather than gigabytes. It has never been seen with any SDHC or SDXC card. There were actually 2 different specs that came before SDHC which were both called just SD and a version number that isn't ever printed on the card, but can be seen with CardInfo. Starting with 1.54 those very oldest type cards haven't worked with SDIO.


Several cards failed to initialize on the T4.1---but only when using SD.begin(10); They all worked fine with SD.begin(BUILTIN-SDCARD).
 
Several cards failed to initialize on the T4.1---but only when using SD.begin(10); They all worked fine with SD.begin(BUILTIN-SDCARD).

When you say they failed to initialize with SD.begin(10); were you using an external card reader? If you were using the card reader on the T4.1 it is only initialized with SD.begin(BUILTIN-SDCARD).
 
Yes, SDIO is faster than SPI, but unless your program reads or writes in large blocks it makes little difference.

My tests show that SD reads and writes on the Teensy MM Data Logging Carrier are about an order of magnitude faster for read and write block sizes greater than 512 bytes (a file system sector size). An efficient data logging program is probably going to collect and buffer sensor data in a background, then write the buffered data to SD as required in the foreground. On a TeensyMM or Teensy 4.1, I would generally use buffers of around 32KBytes.

I wrote a sketch to write and read buffers of various sizes to the SD card on both the Teensy 4.1 and Teensy Micromod. Here are the things I observed:

1. For block sizes above 512 bytes, the T4.1 writes at about 21MB/second maximum and averages about 10MB/second on a used 32GB Sandisk card.

2. For block sizes above 512 bytes, the Teensy MM writes at about 0.4 to 2.5MB/second. Read and write speeds increase on the Teensy MM between blocksize 512 and blocksize 16384. I suspect that is because the SPI-Based SD writes take advantage of multi-block writes as long as the SPI driver can handle a full block size in a single tranfer.

3. At block sizes below 512 bytes, both the T4.1 and Teensy MM only read and write at 200 to 300KB per second. File overhead and interface management dominates the SD transfer times.

4. On a used SD card, the write speed for a block often drops to about half the maximum rate when the internal SD card processor decides it needs to spend a few dozen milliseconds erasing an internal 128KB flash block.

5. It doesn't seem to make much difference whether the data buffers are in DTCM, DMAMEM, or EXTMEM.

Here is a sample of the data I collected: (Shown as a code block so it uses a monospaced font to allign columns.)
Code:
Teensy 4.1  Brand new Sandisk 128GB card
File Size:  3276800
 Read and write speeds in MB/second 
DTCM buffer memory
    32 Write:    0.224    Read:    13.348
   128 Write:    0.225    Read:    17.806
   512 Write:   21.026    Read:    20.553
  1024 Write:   20.620    Read:    20.679
  4096 Write:   21.023    Read:    20.966
 16384 Write:   20.694    Read:    21.037
102400 Write:   21.038    Read:    21.056
DMAMEM buffer memory
    32 Write:    0.225    Read:    13.347
   128 Write:    0.225    Read:    17.806
   512 Write:   20.364    Read:    20.552
  1024 Write:   20.971    Read:    20.691
  4096 Write:   20.680    Read:    20.966
 16384 Write:   21.033    Read:    21.038
102400 Write:   20.513    Read:    21.055

EXTMEM buffer memory
    32 Write:    0.225    Read:    13.300
   128 Write:    0.223    Read:    17.806
   512 Write:   20.845    Read:    20.552
  1024 Write:   20.491    Read:    20.688
  4096 Write:   21.014    Read:    20.966
 16384 Write:   20.673    Read:    21.038
102400 Write:   20.013    Read:    21.055



Teensy 4.1  Used 32GB card
File Size:  3276800
 Read and write speeds in MB/second 
DTCM buffer memory
    32 Write:    0.294    Read:    13.546
   128 Write:    0.302    Read:    17.713
   512 Write:   21.165    Read:    20.613
  1024 Write:   21.177    Read:    20.632
  4096 Write:   15.689    Read:    20.915
 16384 Write:   21.226    Read:    21.022
102400 Write:   15.951    Read:    21.010

DMAMEM buffer memory
    32 Write:    0.291    Read:    13.546
   128 Write:    0.292    Read:    17.713
   512 Write:   21.203    Read:    20.613
  1024 Write:   17.844    Read:    20.632
  4096 Write:   21.209    Read:    20.944
 16384 Write:   10.886    Read:    20.995
102400 Write:    9.566    Read:    21.013

EXTMEM buffer memory
    32 Write:    0.282    Read:    13.546
   128 Write:    0.264    Read:    17.711
   512 Write:   21.181    Read:    20.613
  1024 Write:   21.246    Read:    20.684
  4096 Write:   17.878    Read:    20.944
 16384 Write:   21.295    Read:    21.022
102400 Write:   17.157    Read:    21.039



Teensy Micromod  Used 32GB card
File Size:  3276800
 Read and write speeds in MB/second 
DTCM buffer memory
    32 Write:    0.330    Read:     1.075
   128 Write:    0.323    Read:     1.001
   512 Write:    0.439    Read:     1.074
  1024 Write:    0.638    Read:     1.395
  4096 Write:    1.776    Read:     2.298
 16384 Write:    2.265    Read:     2.601
102400 Write:    2.438    Read:     2.644


Here is the source code for the sample sketch. Both T41. and TeensyMM were run at 600Mhz

Code:
// Test for SD read/write speed on  Teensy MM  Data Logger Carrier board and T4.1
// MJB 11/13/22
#include <Arduino.h>
#include <TimeLib.h>
#include <SD.h>

#if defined(ARDUINO_TEENSY_MICROMOD)
constexpr uint8_t G1 = 41;  // GPIO7-05  |
#define peripheralPowerControl G1
#define CS_PIN 10
#else
#define CS_PIN BUILTIN_SDCARD
#endif

#define BUFFSIZE 320*1024 // 320KB
#define FILESIZE BUFFSIZE*10 // 3.2 MBytes 

uint8_t bufferDTCM[BUFFSIZE];
DMAMEM uint8_t bufferDMAMEM[BUFFSIZE];
#if defined(ARDUINO_TEENSY41)
EXTMEM  uint8_t bufferEXTMEM[BUFFSIZE];
#endif

void setup() {
  delay(500);
  Serial.println("\nSD Card read/write speed test.");
  // put your setup code here, to run once:
#if defined(ARDUINO_TEENSY_MICROMOD)
  Serial.println("MicroMod Peripheral power on.");
  pinMode(peripheralPowerControl, OUTPUT);
  digitalWriteFast(peripheralPowerControl, HIGH);  //turn on 3.3V power to SDIO
  delay(100);
#endif


  StartSDCard();
  Serial.println("\n\nPress <Enter> to run test.");
}

void loop() {
  // put your main code here, to run repeatedly:
  volatile char ch;

  if (Serial.available()) {
    ch = Serial.read();
    RunTests();
    Serial.println("\n\nPress <Enter> to run test.");
  }
}

// Run write and read tests with increasing blocksizes from different memory regions
// Data written or read  will always be FILESIZE   bytes
void RunTests(void){
  Serial.printf("File Size:  %lu\n", FILESIZE);
  Serial.println(" Read and write speeds in MB/second ");
  Serial.println("DTCM buffer memory");
  TestFile( 32,  &bufferDTCM[0]);
  TestFile( 128,  &bufferDTCM[0]);
  TestFile( 512,  &bufferDTCM[0]);
  TestFile( 1024,  &bufferDTCM[0]);
  TestFile( 4096,  &bufferDTCM[0]);
  TestFile( 16384,  &bufferDTCM[0]);
  TestFile( 100 * 1024,  &bufferDTCM[0]);

  Serial.println("\nDMAMEM buffer memory");
  TestFile( 32,  &bufferDMAMEM[0]);
  TestFile( 128,  &bufferDMAMEM[0]);
  TestFile( 512,  &bufferDMAMEM[0]);
  TestFile( 1024,  &bufferDMAMEM[0]);
  TestFile( 4096,  &bufferDMAMEM[0]);
  TestFile( 16384,  &bufferDMAMEM[0]);
  TestFile( 100 * 1024,  &bufferDMAMEM[0]);

#if defined(ARDUINO_TEENSY41)
  Serial.println("\nEXTMEM buffer memory");
  TestFile( 32,  &bufferEXTMEM[0]);
  TestFile( 128,  &bufferEXTMEM[0]);
  TestFile( 512,  &bufferEXTMEM[0]);
  TestFile( 1024,  &bufferEXTMEM[0]);
  TestFile( 4096,  &bufferEXTMEM[0]);
  TestFile( 16384,  &bufferEXTMEM[0]);
  TestFile( 100 * 1024,  &bufferEXTMEM[0]);
#endif
}

//  Do a write, then read using specified blocksize and filesize
void TestFile( uint32_t blockSize,  uint8_t *buffPtr){
File testFile;
  float readspeed, writespeed,readmicros, writemicros;
  uint32_t  startmicros ,numblocks, i;
  numblocks =  FILESIZE/blockSize;

  // Do the write test
  startmicros = micros();
  testFile = SD.open("Test.dat", FILE_WRITE_BEGIN);

  for(i= 0; i<numblocks; i++){
    testFile.write(buffPtr,blockSize);
  }
  testFile.close();
  writemicros = (float)(micros()-startmicros);
  writespeed = ((float)FILESIZE/writemicros);
  //Serial.printf("numblocks = %lu  writemicros = %6.0f\n",numblocks,writemicros);
    // Do the read test
  startmicros = micros();
  testFile = SD.open("Test.dat", O_READ);
  for(i= 0; i<numblocks; i++){
    testFile.read(buffPtr,blockSize);
  }
  testFile.close();
  readmicros = (float)(micros()-startmicros);
  readspeed = ((float)FILESIZE/readmicros);


  Serial.printf("%6lu ",blockSize);
  Serial.printf("Write: %8.3f    Read:  %8.3f\n", writespeed,readspeed);
}



/*****************************************************************************
 Read the Teensy RTC and return a time_t (Unix Seconds) value
 ***************************************************************************** */
time_t getTeensy3Time() {
  return Teensy3Clock.get();
}

/* ------------------------------------------------------------------------------
 User provided date time callback function.
 See SdFile::dateTimeCallback() for usage.
 */
void dateTime(uint16_t *date, uint16_t *time) {
  // use the year(), month() day() etc. functions from timelib

  // return date using FAT_DATE macro to format fields
  *date = FAT_DATE(year(), month(), day());

  // return time using FAT_TIME macro to format fields
  *time = FAT_TIME(hour(), minute(), second());
}

#define SD_CONFIG SdioConfig(FIFO_SDIO)

bool StartSDCard() {
  Serial.println("Starting SD initialization.");
  delay(10);
  if (!SD.begin(CS_PIN)) {
    Serial.println("\nSD File initialization failed.\n");
    return false;
  } else
    Serial.println("initialization done.");

  setSyncProvider(getTeensy3Time);  // helps put time into file directory data
  // set date time callback function
  SdFile::dateTimeCallback(dateTime);
  if (SD.sdfs.fatType() == FAT_TYPE_EXFAT) {
    Serial.println("Type is exFAT");
  } else {
    Serial.printf("Type is FAT%d\n", int16_t(SD.sdfs.fatType()));
  }
  return true;
}

My next test will be to see how reducing the CPU clock speed affects SD write times.
 
Update:

Both the T4.1 and the TeensyMM maintain their SD transfer rates with F_CPU at 150MHz.
When F_CPU is set to 24MHz, transfer rates drop by more than half. This makes sense if the SPI or SDIO clock is decreased from the standard 48MHz to 24MHz.

Code:
Teensy Micromod  Used 32GB card  150MHz
File Size:  3276800
 Read and write speeds in MB/second 
DTCM buffer memory
    32 Write:    0.392    Read:     0.948
   128 Write:    0.314    Read:     0.948
   512 Write:    0.413    Read:     0.949
  1024 Write:    0.755    Read:     1.402
  4096 Write:    1.624    Read:     2.187
 16384 Write:    1.902    Read:     2.509
102400 Write:    2.091    Read:     2.550

Teensy Micromod  Used 32GB card  24MHz
 Read and write speeds in MB/second 
DTCM buffer memory
    32 Write:    0.165    Read:     0.406
   128 Write:    0.168    Read:     0.406
   512 Write:    0.266    Read:     0.406
  1024 Write:    0.375    Read:     0.481
  4096 Write:    0.514    Read:     0.562
 16384 Write:    0.540    Read:     0.579
102400 Write:    0.551    Read:     0.581

Teensy 4.1  Used 32GB card  CPU Speed 150MHz
 Read and write speeds in MB/second 
DTCM buffer memory
    32 Write:    0.225    Read:    13.347
   128 Write:    0.225    Read:    17.806
   512 Write:   20.816    Read:    20.552
  1024 Write:   19.890    Read:    20.704
  4096 Write:   18.691    Read:    20.961
 16384 Write:   20.491    Read:    21.011
102400 Write:   21.006    Read:    21.055

Teensy 4.1  Used 32GB card  CPU Speed 24MHz
Read and write speeds in MB/second 
DTCM buffer memory
    32 Write:    0.218    Read:     3.170
   128 Write:    0.222    Read:     5.073
   512 Write:   10.334    Read:     6.686
  1024 Write:   10.829    Read:     6.784
  4096 Write:   11.665    Read:     6.969
 16384 Write:   11.737    Read:     7.019
102400 Write:   11.943    Read:     7.031
 
Back
Top