microSD slot on teensy 3.6

Status
Not open for further replies.
Hi --

I was attempting to use the microSD slot on the teensy 3.6 with the built in sample project in teensyduino (SD/cardinfo). When I run it with a SDHC card in the slot, I get the following output:

Initializing SD card...initialization failed. Things to check:
* is a card inserted?
* is your wiring correct?
* did you change the chipSelect pin to match your shield or module?

I've tried this with a handful of cards I have on hand -- a 8GB generic microSD card, and a set of 16GB and 32GB SanDisk microSD cards. All fail with the same message.

So I guess my first assumption is that I assumed the SD library in teensyduino supports SDHC -- is that an incorrect assumption? If not, is there some other setup I need to do on the board to enable the microSD slot or should it just be enabled by default?

Thanks!
dennis

UPDATE: just found a 2GB SanDisk microSD card I had around as well and I get the same failure message. I realize that this could still be a SDHC card, but it doesn't appear to be marked as one.
 
Last edited:
Try the SDIO library and example available from https://github.com/greiman/SdFat-beta

Just installed that library and gave the SdInfo sketch a try. I get the following error:

SdFat version: 20160913

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 10
Edit SD_CHIP_SELECT to change the SD chip select pin.
error: cardBegin failed
SD errorCode: 0X20,0XFF

I did verify that the card is recognized in my computer (2014 MacBook Pro running macOS Sierra), so it doesn't appear to be an issue with the card.

Doing some more digging on my end.
 
I just used the SdFat library on an Arduino UNO using the same card, but wired up through an SD card breakout board that I have. It looks like that same library and board work fine on the Uno.

SdFat version: 20160913

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 10
Edit SD_CHIP_SELECT to change the SD chip select pin.

init time: 755 ms

Card type: SDHC

Manufacturer ID: 0X1B
OEM ID: SM
Product: 00000
Version: 1.0
Serial number: 0X595547CC
Manufacturing date: 9/2013

cardSize: 7861.17 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true
OCR: 0XC0FF8000

SD Partition Table
part,boot,type,start,length
1,0X0,0XE,8192,2358996
2,0X0,0X85,2367188,12986668
3,0X0,0X0,0,0
4,0X0,0X0,0,0

Volume is FAT32
blocksPerCluster: 32
clusterCount: 73679
freeClusters: 5948
freeSpace: 97.45 MB (MB = 1,000,000 bytes)
fatStartBlock: 8288
fatCount: 2
blocksPerFat: 576
rootDirStart: 2
dataStartBlock: 9440
Data area is not aligned on flash erase boundaries!
Download and use formatter from www.sdcard.org!
 
So I'm not very familiar with any of the teensy models, since the 3.6 is my first one. So please forgive me if I'm missing something obvious here. Looking at the datasheet for the microcontroller, there appears to be three SPI buses on the chip. Looking at the pinout card for the teensy 3.6, my guess would be that the SD card is using SPI2, since the breakout pads for that bus is located directly underneath the microSD slot.

My question is (assuming SPI2 is being used), if I use the continuity tester on my multimeter, should I see continuity between the SCK2 pin on the bottom and the CLK pin on the microSD slot?
 
Sorry for yet another reply, but I was able to get the teensy working with the SD card, but only by using the breakout board. I just wired it up to SPI0 (figured out that it wasn't on SPI2, as you can tell) and it worked.

SdFat version: 20160913

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 10
Edit SD_CHIP_SELECT to change the SD chip select pin.

type any character to start

init time: 147 ms

Card type: SDHC

Manufacturer ID: 0X1B
OEM ID: SM
Product: 00000
Version: 1.0
Serial number: 0X595547CC
Manufacturing date: 9/2013

cardSize: 7861.17 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true
OCR: 0XC0FF8000

SD Partition Table
part,boot,type,start,length
1,0X0,0XE,8192,2358996
2,0X0,0X85,2367188,12986668
3,0X0,0X0,0,0
4,0X0,0X0,0,0

Volume is FAT32
blocksPerCluster: 32
clusterCount: 73679
freeClusters: 5948
freeSpace: 97.45 MB (MB = 1,000,000 bytes)
fatStartBlock: 8288
fatCount: 2
blocksPerFat: 576
rootDirStart: 2
dataStartBlock: 9440
Data area is not aligned on flash erase boundaries!
Download and use formatter from www.sdcard.org!

Moving the card to the internal SD card slot fails with the 0x20,0xFF error as before.

Is it possible I got a bad SD card slot?
 
So I'm not very familiar with any of the teensy models, since the 3.6 is my first one. So please forgive me if I'm missing something obvious here. Looking at the datasheet for the microcontroller, there appears to be three SPI buses on the chip. Looking at the pinout card for the teensy 3.6, my guess would be that the SD card is using SPI2, since the breakout pads for that bus is located directly underneath the microSD slot.

My question is (assuming SPI2 is being used), if I use the continuity tester on my multimeter, should I see continuity between the SCK2 pin on the bottom and the CLK pin on the microSD slot?

The T_3.5 & T_3.6 share common heritage - but these new models have extended hardware capabilities that are new to all and evolving - the SD adapter is one of those things.

The onboard SD adapter does not use any of the exposed SPI interfaces. There are dedicated SDIO lines providing a 4 bit parallel SPI interface - the is what the post #2 link interfaces to. Pull down that code and put the SDFAT folder in 'your_sketchbook/libraries' and run the "Examples / TeensySdioDemo" - IIRC that is how that one worked for me.
 
As dfragster stated above the new Teensy 3.5 and Teensy 3.6 onboard SD card utilizes a special SD card controller in the microprocessor that has dedicated SDIO lines to the SD card. You need to modify the example code to switch from the old 1bit SPI interface to the new 4bit SDIO interface when trying to use the new onboard SD Card.

The key change is to edit this line -> #define USE_SDIO 1

Code:
/*
 * This program attempts to initialize an SD card and analyze its structure.
 */
#include <SPI.h>
#include <SdFat.h>

// Set USE_SDIO to zero for SPI card access. 
#define USE_SDIO 1
/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */
const uint8_t SD_CHIP_SELECT = SS;
/*
 * Set DISABLE_CHIP_SELECT to disable a second SPI device.
 * For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
 * to 10 to disable the Ethernet controller.
 */
const int8_t DISABLE_CHIP_SELECT = -1;

#if USE_SDIO
// Use faster SdioCardEX
SdFatSdioEX sd;
// SdFatSdio sd;
#else // USE_SDIO
SdFat sd;
#endif  // USE_SDIO

// serial output steam
ArduinoOutStream cout(Serial);

// global for card size
uint32_t cardSize;

// global for card erase size
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sd.errorPrint(F(msg));
//------------------------------------------------------------------------------
uint8_t cidDmp() {
  cid_t cid;
  if (!sd.card()->readCID(&cid)) {
    sdErrorMsg("readCID failed");
    return false;
  }
  cout << F("\nManufacturer ID: ");
  cout << hex << int(cid.mid) << dec << endl;
  cout << F("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
  cout << F("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << cid.pnm[i];
  }
  cout << F("\nVersion: ");
  cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
  cout << F("Serial number: ") << hex << cid.psn << dec << endl;
  cout << F("Manufacturing date: ");
  cout << int(cid.mdt_month) << '/';
  cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
uint8_t csdDmp() {
  csd_t csd;
  uint8_t eraseSingleBlock;
  if (!sd.card()->readCSD(&csd)) {
    sdErrorMsg("readCSD failed");
    return false;
  }
  if (csd.v1.csd_ver == 0) {
    eraseSingleBlock = csd.v1.erase_blk_en;
    eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
  } else if (csd.v2.csd_ver == 1) {
    eraseSingleBlock = csd.v2.erase_blk_en;
    eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
  } else {
    cout << F("csd version error\n");
    return false;
  }
  eraseSize++;
  cout << F("cardSize: ") << 0.000512*cardSize;
  cout << F(" MB (MB = 1,000,000 bytes)\n");

  cout << F("flashEraseSize: ") << int(eraseSize) << F(" blocks\n");
  cout << F("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << F("true\n");
  } else {
    cout << F("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
  mbr_t mbr;
  if (!sd.card()->readBlock(0, (uint8_t*)&mbr)) {
    sdErrorMsg("read MBR failed");
    return false;
  }
  for (uint8_t ip = 1; ip < 5; ip++) {
    part_t *pt = &mbr.part[ip - 1];
    if ((pt->boot & 0X7F) != 0 || pt->firstSector > cardSize) {
      cout << F("\nNo MBR. Assuming Super Floppy format.\n");
      return true;
    }
  }
  cout << F("\nSD Partition Table\n");
  cout << F("part,boot,type,start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    part_t *pt = &mbr.part[ip - 1];
    cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
    cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
  }
  return true;
}
//------------------------------------------------------------------------------
void volDmp() {
  cout << F("\nVolume is FAT") << int(sd.vol()->fatType()) << endl;
  cout << F("blocksPerCluster: ") << int(sd.vol()->blocksPerCluster()) << endl;
  cout << F("clusterCount: ") << sd.vol()->clusterCount() << endl;
  cout << F("freeClusters: ");
  uint32_t volFree = sd.vol()->freeClusterCount();
  cout <<  volFree << endl;
  float fs = 0.000512*volFree*sd.vol()->blocksPerCluster();
  cout << F("freeSpace: ") << fs << F(" MB (MB = 1,000,000 bytes)\n");
  cout << F("fatStartBlock: ") << sd.vol()->fatStartBlock() << endl;
  cout << F("fatCount: ") << int(sd.vol()->fatCount()) << endl;
  cout << F("blocksPerFat: ") << sd.vol()->blocksPerFat() << endl;
  cout << F("rootDirStart: ") << sd.vol()->rootDirStart() << endl;
  cout << F("dataStartBlock: ") << sd.vol()->dataStartBlock() << endl;
  if (sd.vol()->dataStartBlock() % eraseSize) {
    cout << F("Data area is not aligned on flash erase boundaries!\n");
    cout << F("Download and use formatter from www.sdcard.org!\n");
  }
}
//------------------------------------------------------------------------------
void setup() {
  delay(2000);
  Serial.begin(9600);
  
  // Wait for USB Serial 
  while (!Serial) {
    SysCall::yield();
  }

  // use uppercase in hex and use 0X base prefix
  cout << uppercase << showbase << endl;

  // F stores strings in flash to save RAM
  cout << F("SdFat version: ") << SD_FAT_VERSION << endl;
#if !USE_SDIO  
  if (DISABLE_CHIP_SELECT < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CHIP_SELECT to disable another device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CHIP_SELECT) << endl;
    pinMode(DISABLE_CHIP_SELECT, OUTPUT);
    digitalWrite(DISABLE_CHIP_SELECT, HIGH);
  }
  cout << F("\nAssuming the SD chip select pin is: ") <<int(SD_CHIP_SELECT);
  cout << F("\nEdit SD_CHIP_SELECT to change the SD chip select pin.\n");
#endif  // !USE_SDIO  
}
//------------------------------------------------------------------------------
void loop() {
  // Read any existing Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);

  // F stores strings in flash to save RAM
  cout << F("\ntype any character to start\n");
  while (!Serial.available()) {
    SysCall::yield();
  }

  uint32_t t = millis();
#if USE_SDIO
  if (!sd.cardBegin()) {
    sdErrorMsg("\ncardBegin failed");
    return;
  }
#else  // USE_SDIO
  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.cardBegin(SD_CHIP_SELECT, SD_SCK_MHZ(50))) {
    sdErrorMsg("cardBegin failed");
    return;
  }
 #endif  // USE_SDIO 
  t = millis() - t;

  cardSize = sd.card()->cardSize();
  if (cardSize == 0) {
    sdErrorMsg("cardSize failed");
    return;
  }
  cout << F("\ninit time: ") << t << " ms" << endl;
  cout << F("\nCard type: ");
  switch (sd.card()->type()) {
  case SD_CARD_TYPE_SD1:
    cout << F("SD1\n");
    break;

  case SD_CARD_TYPE_SD2:
    cout << F("SD2\n");
    break;

  case SD_CARD_TYPE_SDHC:
    if (cardSize < 70000000) {
      cout << F("SDHC\n");
    } else {
      cout << F("SDXC\n");
    }
    break;

  default:
    cout << F("Unknown\n");
  }
  if (!cidDmp()) {
    return;
  }
  if (!csdDmp()) {
    return;
  }
  uint32_t ocr;
  if (!sd.card()->readOCR(&ocr)) {
    sdErrorMsg("\nreadOCR failed");
    return;
  }
  cout << F("OCR: ") << hex << ocr << dec << endl;
  if (!partDmp()) {
    return;
  }
  if (!sd.fsBegin()) {
    sdErrorMsg("\nFile System initialization failed.\n");
    return;
  }
  volDmp();
}

You will then see output similar to this from a SD card inserted into the onboard SD card holder.

Code:
SdFat version: 20160913

type any character to start

init time: 229 ms

Card type: SD2

Manufacturer ID: 0X1B
OEM ID: SM
Product: 00000
Version: 1.0
Serial number: 0XE162AF16
Manufacturing date: 1/2012

cardSize: 2002.78 MB (MB = 1,000,000 bytes)
flashEraseSize: 64 blocks
eraseSingleBlock: true
OCR: 0X80FF8000

SD Partition Table
part,boot,type,start,length
1,0X0,0XE,129,3911551
2,0X0,0X0,0,0
3,0X0,0X0,0,0
4,0X0,0X0,0,0

Volume is FAT16
blocksPerCluster: 64
clusterCount: 61109
freeClusters: 56909
freeSpace: 1864.79 MB (MB = 1,000,000 bytes)
fatStartBlock: 131
fatCount: 2
blocksPerFat: 239
rootDirStart: 609
dataStartBlock: 641
Data area is not aligned on flash erase boundaries!
Download and use formatter from www.sdcard.org!
 
Last edited:
Since it has the SDIO 4-bit interface, T3.6 is capable of doing about 20 Mbyte/sec I/O to a SD card. That's pretty impressive, and I don't think that kind of performance happens with any traditional Arduino using only 1-bit SPI.
 
As dfragster stated above the new Teensy 3.5 and Teensy 3.6 onboard SD card utilizes a special SD card controller in the microprocessor that has dedicated SDIO lines to the SD card. You need to modify the example code to switch from the old 1bit SPI interface to the new 4bit SDIO interface when trying to use the new onboard SD Card.

The key change is to edit this line -> #define USE_SDIO 1

This is what I was missing. I somehow had missed that that built in microSD slot had a native SD interface instead of using SPI like pretty much everything else in the Arduino world. Once I made that change, the SdInfo example worked with the built in microSD slot.

Thanks for your help everyone!
 
Please allow me to apologize, as I had meant to get basic (not necessarily optimized) 4 bit SDIO support into the default Arduino SD library by this point.... but Kickstarter....

I'm still in New York, writing this from a hotel room, but traveling back to Oregon later today. I will work on the SD lib this week and hopefully get a 1.31-beta2 version by the weekend. Support for the on-board SD card and fixing the serial number in HSRUN mode are my top priorities.

Later I'm planning to complete the SD lib optimization work I started in January, to use more memory for caching and multi-sector reads, and leverage DMA, to (hopefully) allow the much faster performance to be seen with most sketches, not just specific benchmarks.
 
Later I'm planning to complete the SD lib optimization work I started in January, to use more memory for caching and multi-sector reads, and leverage DMA, to (hopefully) allow the much faster performance to be seen with most sketches, not just specific benchmarks.
What would be rather useful is an asynchronous API - e.g. files with "readAsync()", "writeAsync()", "asyncProgress()" (returns how much has been read / written so that partial data can be used).

Another useful feature would be support for pre-allocating, pre-erasing a file that will then support much faster / lower latency writes.
 
What would be rather useful is an asynchronous API - e.g. files with "readAsync()", "writeAsync()", "asyncProgress()" (returns how much has been read / written so that partial data can be used).

Another useful feature would be support for pre-allocating, pre-erasing a file that will then support much faster / lower latency writes.

Here it becomes tricky. It is not difficult to have, for example, async operations with SDIO (after all the K66 has its own internal DMA for sdio operations) and my approach is using this, but this does not mean that the existing FS (being it Bill Greiman's or CHaN's implementation) would support async operations. For example you cannot simply make all read/write async, as the FS needs do also synchronous operations. So if the FS for which you provide the SDIO interface is not supporting a mix of async operations, then you have to wait after each read/write operation for completion.
At least that is how I do it. All read/write use internal DMA and are async but the FS interface (diskio.c) waits for completion. I did this, because for simple data logging, I wrote my own loggingFS, that can indeed write asynchronously to disk. But this is I not a general FS and functionality is limited to write-only.

Next: pre-allococation, pre-erasing are FS functionality and not SDIO. Interestingly, the write/read start/stop operation available for SPI seems to be missing in the SDIO world, at least I have not found it.
 
Please allow me to apologize, as I had meant to get basic (not necessarily optimized) 4 bit SDIO support into the default Arduino SD library by this point.... but Kickstarter....

Not a problem at all. If I had made the connection that the SD slot was using SDIO, I probably would've figured things out a bit sooner :D Given that this board just came out, I'm impressed with how much is already supported. Thanks again!
 
I've committed on github the first attempt at 4 bit SDIO support in the Arduino SD library.

https://github.com/PaulStoffregen/SD

If anyone wants to try this, just replace your copy of the SD lib in hardware/teensy/avr/libraries/SD with this copy from github. Do *not* edit SD_t3.h for the optimized stuff.

In your program, use BUILTIN_SDCARD for the chip select pin. Like this:

Code:
  if (!(SD.begin(BUILTIN_SDCARD))) {
    while (1) {
      Serial.println("Unable to access the SD card");
      delay(500);
    }
  }

If you use it, please reply here to let me know how it works for you? My hope is to release 1.31-beta2 by this weekend, with this and several other fixes.
 
Great !
Tested with my audiocodecs ( mp3 & aac ) : Works.
A first quick'n dirty benchmark shows ~1.6 MB/sec reading. Way too slow for video, but might be enough for most use-cases..
 
Last edited:
OK, after tidying up my sketchbook/libraries (?new SdFat conflict), i installled the new SD library on 1.6.11/1.30. listed and read files OK. Paul's version is not optimized yet (only single sector reads), but here are comparisons for file read of 512 bytes and 2048 bytes using K64 (T3.5)

Code:
              Times microseconds (megabits/sec)
              pjrc SD      SdFat       uSDFS          SPI0 external SD
             4-bit SDIO  4-bit SDIO  4-bit SDIO      SD.h      SdFat.h
read 512     453  (9.0)   313 (13.1)    295 (15)    456 (9.0)  492 (8.3)
read 2048   1563 (10.5)   394 (41.6)    396 (41)   1882 (8.7)  967 (16.9)

More SdFat info
https://forum.pjrc.com/threads/36737-Try-SdFat-forTeensy-3-5-3-6
https://forum.pjrc.com/threads/36331-Teensy-3-6-microSD-pins
 
Last edited:
OK, after tidying up my sketchbook/libraries (?new SdFat conflict), i installled the new SD library on 1.6.11/1.30. listed and read files OK. Paul's version is not optimized yet (only single sector reads), but here are comparisons for file read of 512 bytes and 2048 bytes using K64 (T3.5)

Code:
              Times microseconds (megabits/sec)
              pjrc SD      SdFat       uSDFS          SPI0 external SD
             4-bit SDIO  4-bit SDIO  4-bit SDIO      SD.h      SdFat.h
read 512     453  (9.0)   313 (13.1)    295 (15)    456 (9.0)  492 (8.3)
read 2048   1563 (10.5)   394 (41.6)    396 (41)   1882 (8.7)  967 (16.9)

More SdFat info
https://forum.pjrc.com/threads/36737-Try-SdFat-forTeensy-3-5-3-6
https://forum.pjrc.com/threads/36331-Teensy-3-6-microSD-pins
Are you using the latest SdFat-beta? Are you using the SdFatSdioEX class?

Here are Teensy 3.5 results using a 32GB Samsung Pro+ with the TeensySdioDemo example.

SDIO SdFatSdioEX class:

size,write,read
bytes,KB/sec,KB/sec
size,write,read
bytes,KB/sec,KB/sec
512,14901.45,15329.58
1024,15151.93,15570.79
2048,15424.21,15896.00
4096,15654.45,16053.19
8192,15729.68,16129.95
16384,15774.26,16128.96
32768,15852.30,16104.16

Read for 512 bytes is 15329 KB/sec or 122 megabits/sec. Read for 2048 KB/sec is 15896 KB/sec or 127 megabits/sec.

If you can dedicate an SPI port, you can use the SdFatEX class with an SPI SD module.

With a Teensy 3.6 using SdFatEX at 180 MHz and the bench example:

Read speed for 512 byte buffers with SPI is 3293 KB/sec or 26 megabits/sec.

Read speed for 2048 byte buffers with SPI is 3299 KB/sec also 26 megabits/sec.

Speed is limited by my SPI driver. It is program I/O using the SPI FIFO.
 
With a Teensy 3.6 using SdFatEX at 180 MHz and the bench example:

Read speed for 512 byte buffers with SPI is 3293 KB/sec or 26 megabits/sec.

Read speed for 2048 byte buffers with SPI is 3299 KB/sec also 26 megabits/sec.

Speed is limited by my SPI driver. It is program I/O using the SPI FIFO.

Why is the 3.6 lagging behind the 3.5 in this test, or am I missing something?
 
Why is the 3.6 lagging behind the 3.5 in this test, or am I missing something?

The 3.5 uses SDIO with the builtin socket. A 3.6 will be even faster using SDIO with the SdFatSdioEX class.

Here is a 3.6 at 180 MHz with SdFatSdioEX.

size,write,read
bytes,KB/sec,KB/sec
512,18054.97,18628.56
1024,18160.34,18759.33
2048,17940.78,18871.71
4096,17907.46,19007.74
8192,17898.33,19035.99
16384,17800.50,19051.21
32768,17878.27,19021.57

Here is a 3.6 at 240 MHz with SdFatSdioEX.

size,write,read
bytes,KB/sec,KB/sec
512,19433.28,20050.26
1024,19553.27,20139.75
2048,19159.38,20237.90
4096,19212.21,20224.19
8192,19168.66,20314.15
16384,19278.66,20384.25
32768,19360.17,20308.25

The 240 MHz test is limited by a max SDIO clock of 48 MHz which is 240/5. The 180 MHz test runs with an SDIO clock of 45 MHz which is 180/4. Too bad the max SD clock speed of 50 MHz is not possible. I have not tried overclocking the Samsung Pro+ microSD, it might run at a rate higher than 50 MHz. The Pro+ microSD supports 208 MHz clock in UH I bus mode but the Teensy does not

I used the 3.6 for an SPI example since I don't have a 3.5 with an attached SPI SD module. A 3.5 will be slightly slower in the SPI test.
 
Last edited:
Tried overclocking a Samsung PRO Select 32 GB microSD.

At 60 MHz SDIO clock = 240 MHz / 4.

size,write,read
bytes,KB/sec,KB/sec
512,23488.95,24153.22
1024,23554.44,24420.63
2048,23867.68,24657.51
4096,23614.32,24885.07
8192,24011.01,24889.28
16384,24028.41,24983.72
32768,23721.16,24862.80

At 80 MHz SDIO clock = 240 MHz / 3.

size,write,read
bytes,KB/sec,KB/sec
512,29232.88,30546.46
1024,29664.37,31105.21
2048,29523.73,31342.76
4096,29550.25,31830.49
8192,30222.68,31637.34
16384,30247.86,31734.04
32768,29727.13,31926.68

Don't expect me to support it but at line 518 of SdioTeensy.cpp

Code:
//    kHzSdClk = 50000;
    kHzSdClk = 80000;
 
Did you use CMD6 to put the card into high speed mode?
Yes but the spec for high speed mode is 50 MHz max.

See Section 4.3.11 of the SD physical layer spec.

Although the Rev 1.01 SD memory card supports up to 12.5 MB/sec interface speed, the speed of 25
MB/sec is necessary to support increasing performance needs of the host and because memory size
continues to grow.
To achieve the 25 MB/sec interface speed, the clock rate is increased to 50 MHz and CLK/CMD/DAT
signal timing and circuit conditions are reconsidered and changed from the Physical Layer Specification
Version 1.01.
After power up, the SD memory card is in the default speed mode, and by using Switch Function
command (CMD6), the Version 1.10 and higher SD memory card can be placed in High-Speed mode.
The High-Speed function is a function in the access mode group (see Table 4-11). Supporting High-
Speed mode is optional.

The SDIO interface on most micro-controllers is limited to the 3.3V 1.10 standard. I was surprised that the card and Teensy controller worked at 80 MHz.

the card supports 208 MHz UH I with 1.8V signaling.

You might also want to read section 4.13 of the standard before you continue with your cache optimization. Modern SD cards are nasty. I really had to fight to get this 30 MB/sec performance. This is 30 MB/sec reading into a 512 byte buffer with no additional cache in the Teensy.

I use tricks in the driver to use the internals of the card instead of more cache in the Teensy.
 
Last edited:
Read all this good info but I have a simple question - should I use SD library in teensyduino 1.34 (which I have already), or install SdFat library separately?

I have existing (non-teensy) code I would like to reuse ...
I do use long filenames ...
higher/performance speed is always good, but not critical in my applications (so far) ...

Edit: I just spotted the 'Data Manipulation Libraries' section at bottom of teensyduino 'Main List' and it lists both SD and SdFat (although no hyperlinks yet). So perhaps they are both built into teensyduino anyway??
What is the overlap between teensyduino and arduino stuff? For example if teensyduino lists SD does that mean it is separate from arduino SD lib, or the arduino SD lib has teensy mods built in?
 
Last edited:
Status
Not open for further replies.
Back
Top