Simple SdFat write benchmark for T3.5/3.6

XFer

Well-known member
Curious about your T3.5/3.6 microSD write speed and write latency?

Here's a simple benchmark, derived from https://github.com/greiman/SdFat/blob/master/examples/TeensySdioDemo/TeensySdioDemo.ino

Shows sequential write speed, average write latency (for given transfer size) and worst case write latency:

Code:
// SdFatSdioEx simple performance test for Teensy 3.5/3.6 onboard uSD
#include "SdFat.h"

#define SERIAL_SPEED 115200
#define BLOCK_DIM 512
// Check SD free space!
#define PREALLOCATED_BLOCKS 512000UL  // 256 MB; compromise between statistics and total benchmark time
#define BUF_DIM 256*BLOCK_DIM // 128KiB: will comfortably fit T3.5/3.6
#define FILE_SIZE PREALLOCATED_BLOCKS*BLOCK_DIM

SdFatSdioEX sdEx;
File file;

uint8_t buf[BUF_DIM];

// buffer as uint32_t
uint32_t* buf32 = (uint32_t*)buf;

void errorHalt(const char* msg) 
{
    sdEx.errorHalt(msg);
}
//------------------------------------------------------------------------------
uint32_t kHzSdClk() 
{
  return sdEx.card()->kHzSdClk(); 
}  
//------------------------------------------------------------------------------


////////////
// RUNTEST
////////////

void runTest() 
{    
  // Fill buffer with 0
  memset(buf32, 0, sizeof(buf32));
  
  // Zero Stats
  uint32_t singleWriteMicros = 0;
  uint32_t maxSingleWriteMicros = 0;
  
  if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) 
  {
    errorHalt("open failed");
  }  
  Serial.println("\nPreallocating file (takes awhile)...\n");
  // Preallocate (off cycle)
  for (uint32_t i = 0; i < PREALLOCATED_BLOCKS; i++)
  {
    uint32_t nblocks = file.write(buf, BLOCK_DIM);
    if (nblocks != BLOCK_DIM)
    {
      errorHalt("Preallocation failed");
    }
  }
  file.rewind();
  Serial.println("Starting write benchmark");
  delay(2000);
  
  Serial.println("\nTransfer size\tWrite speed\tAvg write time\tMax write time");
  Serial.println("bytes\t\tKB/s\t\tus\t\tus\n");
  for (size_t nb = BLOCK_DIM; nb <= BUF_DIM; nb *= 2) 
  {
    maxSingleWriteMicros = 0;
    uint32_t nRdWr = FILE_SIZE/nb;
    Serial.print(nb);
    Serial.print("\t\t");
    uint32_t t = micros();
    for (uint32_t n = 0; n < nRdWr; n++) 
    {
      singleWriteMicros = micros();
      if (nb != file.write(buf, nb)) 
      {
        errorHalt("write failed");
      }
      singleWriteMicros = micros() - singleWriteMicros;
      if (singleWriteMicros > maxSingleWriteMicros)
        maxSingleWriteMicros = singleWriteMicros;
    }
    t = micros() - t;
    // Write speed
    Serial.print(1000.0f*FILE_SIZE/t, 1);
    Serial.print("\t\t");
    // Avg write time (us)
    Serial.print(t / nRdWr);
    Serial.print("\t\t");
    // Max write time (us)
    Serial.println(maxSingleWriteMicros);
    
    file.rewind();  // Ready for next write size
    t = micros();
  }
  file.close();
  Serial.print("\n SD clock speed (kHzSdClk): ");
  Serial.print(kHzSdClk());
  Serial.println(" KHz\n");
  Serial.println("Done");
}
//-----------------------------------------------------------------------------

//////////
//
// SETUP
//
//////////

void setup() 
{
  Serial.begin(SERIAL_SPEED);
  while (!Serial);
  Serial.println("SdFatSdioEX write benchmark\nSdFatSdioEx uses extended multi-block transfers without DMA");
  
  if (!sdEx.begin()) 
  {
    sdEx.initErrorHalt("SdFatSdioEX begin() failed");
  }
  // make sdEx the current volume.
  sdEx.chvol();
  
  runTest();
}
//-----------------------------------------------------------------------------


/////////
//
// LOOP
//
/////////

void loop() 
{
}



Results for my Teensy 3.6 overclocked to 240 MHz: card is an old Lexar 4GB class10 (not UHS):

Code:
SdFatSdioEX write benchmark
SdFatSdioEx uses extended multi-block transfers without DMA

Preallocating file (takes awhile)...

Starting write benchmark

Transfer size	Write speed	Avg write time	Max write time
bytes		KB/s		us		us

512		13227.7		38		94524
1024		13316.5		76		94673
2048		13483.4		151		9957
4096		12967.5		315		97443
8192		13206.4		620		95952
16384		13214.3		1239		98412
32768		13189.5		2484		98668
65536		13071.9		5013		193157
131072		13187.0		9939		106151

 SD clock speed (kHzSdClk): 48000 KHz

Done

Many thanks to Bill Greiman for his excellent SdFat library! :)
 
Last edited:
Just started test my SD card... for reference I will post my results here:

Scandisk Ultra micro SDHC(tm) UHS-1 Card with Adaptor
"A1 for fatser mobile app performance"
32GB
"speed up to 98 MB/s** "

Bought for 8,39 euro at
https://www.dataio.nl/sandisk-32gb-micro-sd-ultra-geheugenkaart-uhs-i-a1-adapter/

Code:
SdFatSdioEX write benchmark
SdFatSdioEx uses extended multi-block transfers without DMA

Preallocating file (takes awhile)...

Starting write benchmark

Transfer size	Write speed	Avg write time	Max write time
bytes		KB/s		us		us

512		16304.1		31		32621
1024		16474.7		62		33666
2048		16660.3		122		31939
4096		16734.3		244		33944
8192		16721.3		489		43084
16384		16759.0		977		35176
32768		16751.5		1956		32693
65536		16866.5		3885		58195
131072		16851.0		7778		38035

 SD clock speed (kHzSdClk): 48000 KHz

Done
 
Just started test my SD card... for reference I will post my results here:

Scandisk Ultra micro SDHC(tm) UHS-1 Card with Adaptor
"A1 for fatser mobile app performance"
32GB
"speed up to 98 MB/s** "

Bought for 8,39 euro at
https://www.dataio.nl/sandisk-32gb-micro-sd-ultra-geheugenkaart-uhs-i-a1-adapter/

Code:
SdFatSdioEX write benchmark
SdFatSdioEx uses extended multi-block transfers without DMA

Preallocating file (takes awhile)...

Starting write benchmark

Transfer size	Write speed	Avg write time	Max write time
bytes		KB/s		us		us

512		16304.1		31		32621
1024		16474.7		62		33666
2048		16660.3		122		31939
4096		16734.3		244		33944
8192		16721.3		489		43084
16384		16759.0		977		35176
32768		16751.5		1956		32693
65536		16866.5		3885		58195
131072		16851.0		7778		38035

 SD clock speed (kHzSdClk): 48000 KHz

Done

Which Teensy were you using?
 
Back
Top