Teensy 4.1: SdFat Beta only option?

XFer

Well-known member
Hi,

so I have this shiny new 4.1 and want to play with the onboard SD. :D

Installed the latest TeensyDuino 1.52b6 on Arduino IDE 1.8.12.

I tried to rebuild an old test of mine, for T3.6, which was based upon Bill's SdFat; but the "regular" SdFat (latest from GitHub) is not happy about "SdFatSdioEx" type when selecting T4.1 (builds OK for T3.6).

I suppose Bill did not add T4.1 to the regular SdFat yet?

Is my only option to install the new "SdFat Beta"? Pity since it's not compatible with my existing codebase. :p

Just for completeness, this is my source code:

Code:
// SdFatSdioEx simple write latency test for Teensy 3.5/3.6 onboard uSD
// Last Modified FC aka xfer 20181115
// IMPORTANT NOTE: DO NOT use "LTO" as build option, or it will not run!

#include <SdFat.h>

#define MIN(a,b) ((a<b)?a:b)

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

SdFatSdioEX sdEx;

File file;

uint8_t buf[BUF_DIM];

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

// Replace "weak" system yield() function
// Usually it checks for serial data etc.; we don't need it
void yield() 
{
}

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

void runTest(const bool contiguousFile = true, const bool preEraseFile = true) 
{    
  const char filename[] = "T3sdioex.bin";
  uint32_t first_sector, last_sector;	// 1 sector = 512 bytes
  uint32_t first_erase_sector;
  const size_t erase_count = 2048; // number of sectors to erase at once. 2048*512 = 1 MiB
  const float fMiBs = PREALLOCATED_BLOCKS / 2000.0f;
   
  // Fill buffer with dummy data
  memset(buf, 128, BUF_DIM);
  
  // Zero Stats
  uint32_t singleWriteMicros = 0;
  uint32_t maxSingleWriteMicros = 0;
  
  sdEx.remove(filename);
  Serial.print("Preallocating "); Serial.print(fMiBs, 1); Serial.println(" MiB file");
  if (!file.createContiguous(sdEx.vwd(), filename, FILE_SIZE))
  {
	  Serial.println("Error from file.createContiguous");
	  exit(1);
  }

  if (!file.contiguousRange(&first_sector, &last_sector))
  {
	  Serial.println("Error from contiguousRange. Exiting...");
	  exit(1);
  }
  first_erase_sector = first_sector;
  Serial.println("Pre-erasing file: please wait...");
  while (first_erase_sector <= last_sector)
  {
	  if (!sdEx.card()->erase(first_erase_sector, MIN(first_erase_sector + erase_count, last_sector)))
	  {
		  Serial.print("Error from erase; start sector = "); Serial.println(first_erase_sector);
		  file.close();
		  exit(1);
	  }
	  first_erase_sector += erase_count;
  }
  file.flush();
  file.rewind();
  Serial.println("\nStarting write benchmark. First writes are quite slow: please be patient");
  delay(200);
  
  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) // Loop for growing write sizes (nb)
  {
    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++) // Number of writes to fill the file, with current write size
    {
      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");
}
//-----------------------------------------------------------------------------

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

void setup() 
{
  Serial.begin(SERIAL_SPEED);
  while (!Serial);
  Serial.println("Teensy 3.5/3.6 SdFatSdioEx write latency benchmark\n");

  if (!sdEx.begin()) 
  {
      sdEx.initErrorHalt("SdFatSdioEX begin() failed");
  }
    // make sdEx the current volume.
  sdEx.chvol();
  
  runTest();
  
  Serial.println("\n*** End of test ***");
}
//-----------------------------------------------------------------------------


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

void loop() 
{
}

Error:

Code:
TeensySdioLatencyBench_fc:16: error: 'SdFatSdioEX' does not name a type
SdFatSdioEX sdEx;
 
Yes, well, the problem is that SdFat Beta does not have SdFatSdioEx at all, not even for T3.6, so it breaks a lot of my code. :(
 
Yes, well, the problem is that SdFat Beta does not have SdFatSdioEx at all, not even for T3.6, so it breaks a lot of my code. :(

If you wanted to use always the latest HW, you should go with SdFat-beta where Bill is testing out new things.
 
Actually I just wanted to test T4.1 vs T3.6; let's wait and see if Bill is going to backport T4.1 support in SdFat v1.
I'm not in the mood to rewrite so much code at the moment. :rolleyes:
 
I'm trying to understand the problem. It is anything specific to Teensy 4.1? Or is the main issue Bill changed SdFat's API without compatibility for programs written using the older API? Or some combination?
 
not sure, the teensySDIOdemo does not work from sdfat beta and all my previous works which use SdFatSdioEx no longer work.
the SDIO demo says "SdSpiConfig" was not declared.
 
...Or is the main issue Bill changed SdFat's API without compatibility for programs written using the older API?...

In my experience at least, it was that. On the Teensy 4.x, when I moved the changes in my fork of SdFat over to SdFat-beta I probably had about an hour's tinkering to get it back up and running. Most of that was due to constants and structure fields in SdFat-beta having their names changed. And most of what I had to change was in my additions; the #defines for some of the attribute bits had changed. But as there are existing methods to read the values of the attributes, you usually wouldn't notice the change. But since I had added methods to set those bits, I did.

There were some similar changes to the file timestamp field names as well. Those would probably be noticeable to more people.

And there was one method in FatVolume (vwd()) that went from being public to private. But in my case it wasn't a major issue. The one place in the code I was using called it could be easily replaced (f.rename(SD.vwd(), newname) became f.rename(newname), which in SdFat-beta amounted to exactly the same thing).

So while I did have a bit of work to make the migration (and a good half of what I had to change was in my internal additions to SdFat-beta), I don't think any of it was due to the Teensy 4.x.
 
I'm trying to understand the problem. It is anything specific to Teensy 4.1? Or is the main issue Bill changed SdFat's API without compatibility for programs written using the older API? Or some combination?

It's a mix.

1) SdFat v1 does not support Teensy 4.1, so if you try buliding for it, a lot of types are not defined and the build fails.

2) SdFat Beta supports Teensy 4.1, but is not backward-compatible with v1, so old code would not build (for example: no "SdFatSdioEX").

So it's a bit of "Catch 22".
 
Back
Top