| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 | // Simple performance test for Teensy 3.5/3.6 4.0 SDHC.// Demonstrates yield() efficiency for SDIO modes.#include "SdFat.h"// Use built-in SD for SPI modes on Teensy 3.5/3.6.// Teensy 4.0 use first SPI port.// SDCARD_SS_PIN is defined for the built-in SD on some boards.#ifndef SDCARD_SS_PINconst uint8_t SD_CS_PIN = SS;#else  // SDCARD_SS_PIN// Assume built-in SD is used.const uint8_t SD_CS_PIN = SDCARD_SS_PIN;#endif  // SDCARD_SS_PIN// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.#define SD_FAT_TYPE 3// 32 KiB buffer.const size_t BUF_DIM = 32768;// 8 MiB file.const uint32_t FILE_SIZE = 256UL*BUF_DIM;#if SD_FAT_TYPE == 0SdFat sd;File file;#elif SD_FAT_TYPE == 1SdFat32 sd;File32 file;#elif SD_FAT_TYPE == 2SdExFat sd;ExFile file;#elif SD_FAT_TYPE == 3SdFs sd;FsFile file;#else  // SD_FAT_TYPE#error Invalid SD_FAT_TYPE#endif  // SD_FAT_TYPEuint8_t buf[BUF_DIM];// buffer as uint32_tuint32_t* buf32 = (uint32_t*)buf;// Total usec in read/write calls.uint32_t totalMicros = 0;// Time in yield() function.uint32_t yieldMicros = 0;// Number of yield calls.uint32_t yieldCalls = 0;// Max busy time for single yield call.uint32_t yieldMaxUsec = 0;//------------------------------------------------------------------------------void clearSerialInput() {  uint32_t m = micros();  do {    if (Serial.read() >= 0) {      m = micros();    }  } while (micros() - m < 10000);}//------------------------------------------------------------------------------void errorHalt(const char* msg) {  Serial.print("Error: ");  Serial.println(msg);  if (sd.sdErrorCode()) {    if (sd.sdErrorCode() == SD_CARD_ERROR_ACMD41) {      Serial.println("Try power cycling the SD card.");    }    printSdErrorSymbol(&Serial, sd.sdErrorCode());    Serial.print(", ErrorData: 0X");    Serial.println(sd.sdErrorData(), HEX);  }  while (true) {}}bool ready = false;//------------------------------------------------------------------------------bool sdBusy() {  return ready ? sd.card()->isBusy() : false;}//------------------------------------------------------------------------------// Replace "weak" system yield() function.void yield() {  // Only count cardBusy time.  if (!sdBusy()) {    return;  }  uint32_t m = micros();  yieldCalls++;  while (sdBusy()) {    // Do something here.  }  m = micros() - m;  if (m > yieldMaxUsec) {    yieldMaxUsec = m;  }  yieldMicros += m;}//------------------------------------------------------------------------------void runTest() {  // Zero Stats  totalMicros = 0;  yieldMicros = 0;  yieldCalls = 0;  yieldMaxUsec = 0;  if (!file.open("TeensyDemo.bin", O_RDWR | O_CREAT)) {    errorHalt("open failed");  }  Serial.println("\nsize,write,read");  Serial.println("bytes,KB/sec,KB/sec");  for (size_t nb = 512; nb <= BUF_DIM; nb *= 2) {    uint32_t nRdWr = FILE_SIZE/nb;    if (!file.truncate(0)) {      errorHalt("truncate failed");    }    Serial.print(nb);    Serial.print(',');    uint32_t t = micros();    for (uint32_t n = 0; n < nRdWr; n++) {      // Set start and end of buffer.      buf32[0] = n;      buf32[nb/4 - 1] = n;      if (nb != file.write(buf, nb)) {        errorHalt("write failed");      }    }    t = micros() - t;    totalMicros += t;    Serial.print(1000.0*FILE_SIZE/t);    Serial.print(',');    file.rewind();    t = micros();    for (uint32_t n = 0; n < nRdWr; n++) {      if ((int)nb != file.read(buf, nb)) {        errorHalt("read failed");      }      // crude check of data.      if (buf32[0] != n || buf32[nb/4 - 1] != n) {        errorHalt("data check");      }    }    t = micros() - t;    totalMicros += t;    Serial.println(1000.0*FILE_SIZE/t);  }  file.close();  Serial.print("\ntotalMicros  ");  Serial.println(totalMicros);  Serial.print("yieldMicros  ");  Serial.println(yieldMicros);  Serial.print("yieldCalls   ");  Serial.println(yieldCalls);  Serial.print("yieldMaxUsec ");  Serial.println(yieldMaxUsec);//  Serial.print("kHzSdClk     ");//  Serial.println(kHzSdClk());  Serial.println("Done");}//------------------------------------------------------------------------------void setup() {  Serial.begin(9600);  while (!Serial) {  }}//------------------------------------------------------------------------------void loop() {  static bool warn = true;  if (warn) {    warn = false;    Serial.println(      "SD cards must be power cycled to leave\n"      "SPI mode so do SDIO tests first.\n"      "\nCycle power on the card if an error occurs.");  }  clearSerialInput();  Serial.println(    "\nType '1' for FIFO SDIO"    "\n     '2' for DMA SDIO"    "\n     '3' for Dedicated SPI"    "\n     '4' for Shared SPI");  while (!Serial.available()) {  }  char c = Serial.read();  if (c =='1') {    if (!sd.begin(SdioConfig(FIFO_SDIO))) {      errorHalt("begin failed");    }    Serial.println("\nFIFO SDIO mode.");  } else if (c == '2') {    if (!sd.begin(SdioConfig(DMA_SDIO))) {      errorHalt("begin failed");    }    Serial.println("\nDMA SDIO mode - slow for small transfers.");  } else if (c == '3') {    if (!sd.begin(SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(50)))) {      errorHalt("begin failed");    }    Serial.println("\nDedicated SPI mode.");  } else if (c == '4') {    if (!sd.begin(SdSpiConfig(SD_CS_PIN, SHARED_SPI, SD_SCK_MHZ(50)))) {      errorHalt("begin failed");    }    Serial.println("\nShared SPI mode - slow for small transfers.");  } else {    Serial.println("Invalid input");    return;  }  ready = true;  runTest();  ready = false;}
 |