element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • Product Groups
  • Store
    Store
    • Visit Your Store
    • Choose Another Store
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
Raspberry Pi
  • Products
  • More
Raspberry Pi
Blog RP2040 SD Card SPI Benchmark
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Raspberry Pi requires membership for participation - click to join
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: ralphjy
  • Date Created: 17 Mar 2022 4:43 AM Date Created
  • Views 6134 views
  • Likes 10 likes
  • Comments 9 comments
Related
Recommended
  • rp2040
  • sd-card

RP2040 SD Card SPI Benchmark

ralphjy
ralphjy
17 Mar 2022

When I posted earlier about the SparkFun RP2040 mikroBUS Development Board for Happy Pi Day, DAB had mentioned that he was curious as to the SD card size and write rates.

I have to admit that I've never run a speed test on an SD card setup with a microcontroller.  

image

I'm going to do a quick test using the method that I normally use - the SPI interface with the Arduino SDFat library.  The library includes a simple write/read benchmark example.  Unfortunately, SparkFun doesn't have a dedicated Board library for this board, so I am going to use the Raspberry Pi Pico Mbed library and modify the SPI pins in the variant.h file.

For this test I'm using a SanDisk Ultra 16GB UHS-I card rated at a max speed of 80MB/s.  The SPI interface will be substantially slower than that.  The SPI Clock frequency in the program is set to 50MHz.

Here is the program for reference:
RP2040_MikroBUS_SDcard_bench.ino

/*
 * This program is a simple binary write/read benchmark.
 */
#include "SdFat.h"
#include "sdios.h"
#include "FreeStack.h"

// 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 0
/*
  Change the value of SD_CS_PIN if you are using SPI and
  your hardware does not use the default value, SS.
  Common values are:
  Arduino Ethernet shield: pin 4
  Sparkfun SD shield: pin 8
  Adafruit SD shields and modules: pin 10
*/
// SDCARD_SS_PIN is defined for the built-in SD on some boards.
#ifndef SDCARD_SS_PIN
const 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

// Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
#define SPI_CLOCK SD_SCK_MHZ(50)

// Try to select the best SD card configuration.
#if HAS_SDIO_CLASS
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#elif ENABLE_DEDICATED_SPI
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
#else  // HAS_SDIO_CLASS
#define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
#endif  // HAS_SDIO_CLASS

// Set PRE_ALLOCATE true to pre-allocate file clusters.
const bool PRE_ALLOCATE = true;

// Set SKIP_FIRST_LATENCY true if the first read/write to the SD can
// be avoid by writing a file header or reading the first record.
const bool SKIP_FIRST_LATENCY = true;

// Size of read/write.
const size_t BUF_SIZE = 512;

// File size in MB where MB = 1,000,000 bytes.
const uint32_t FILE_SIZE_MB = 5;

// Write pass count.
const uint8_t WRITE_COUNT = 2;

// Read pass count.
const uint8_t READ_COUNT = 2;
//==============================================================================
// End of configuration constants.
//------------------------------------------------------------------------------
// File size in bytes.
const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB;

// Insure 4-byte alignment.
uint32_t buf32[(BUF_SIZE + 3)/4];
uint8_t* buf = (uint8_t*)buf32;

#if SD_FAT_TYPE == 0
SdFat sd;
File file;
#elif SD_FAT_TYPE == 1
SdFat32 sd;
File32 file;
#elif SD_FAT_TYPE == 2
SdExFat sd;
ExFile file;
#elif SD_FAT_TYPE == 3
SdFs sd;
FsFile file;
#else  // SD_FAT_TYPE
#error Invalid SD_FAT_TYPE
#endif  // SD_FAT_TYPE

// Serial output stream
ArduinoOutStream cout(Serial);
//------------------------------------------------------------------------------
// Store error strings in flash to save RAM.
#define error(s) sd.errorHalt(&Serial, F(s))
//------------------------------------------------------------------------------
void cidDmp() {
  cid_t cid;
  if (!sd.card()->readCID(&cid)) {

    error("readCID failed");
  }
  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;
}
//------------------------------------------------------------------------------
void clearSerialInput() {
  uint32_t m = micros();
  do {
    if (Serial.read() >= 0) {
      m = micros();
    }
  } while (micros() - m < 10000);
}
//------------------------------------------------------------------------------
void setup() {
  Serial.begin(115200);

  // Wait for USB Serial
  while (!Serial) {
    yield();
  }
  delay(1000);
  cout << F("\nUse a freshly formatted SD for best performance.\n");
  if (!ENABLE_DEDICATED_SPI) {
    cout << F(
      "\nSet ENABLE_DEDICATED_SPI nonzero in\n"
      "SdFatConfig.h for best SPI performance.\n");
  }
  // use uppercase in hex and use 0X base prefix
  cout << uppercase << showbase << endl;
}
//------------------------------------------------------------------------------
void loop() {
  float s;
  uint32_t t;
  uint32_t maxLatency;
  uint32_t minLatency;
  uint32_t totalLatency;
  bool skipLatency;

  // Discard any input.
  clearSerialInput();

  // F() stores strings in flash to save RAM
  cout << F("Type any character to start\n");
  while (!Serial.available()) {
    yield();
  }
#if HAS_UNUSED_STACK
  cout << F("FreeStack: ") << FreeStack() << endl;
#endif  // HAS_UNUSED_STACK

  if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial);
  }
  if (sd.fatType() == FAT_TYPE_EXFAT) {
    cout << F("Type is exFAT") << endl;
  } else {
    cout << F("Type is FAT") << int(sd.fatType()) << endl;
  }

  cout << F("Card size: ") << sd.card()->sectorCount()*512E-9;
  cout << F(" GB (GB = 1E9 bytes)") << endl;

  cidDmp();

  // open or create file - truncate existing file.
  if (!file.open("bench.dat", O_RDWR | O_CREAT | O_TRUNC)) {
    error("open failed");
  }

  // fill buf with known data
  if (BUF_SIZE > 1) {
    for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
      buf[i] = 'A' + (i % 26);
    }
    buf[BUF_SIZE-2] = '\r';
  }
  buf[BUF_SIZE-1] = '\n';

  cout << F("FILE_SIZE_MB = ") << FILE_SIZE_MB << endl;
  cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n");
  cout << F("Starting write test, please wait.") << endl << endl;

  // do write test
  uint32_t n = FILE_SIZE/BUF_SIZE;
  cout <<F("write speed and latency") << endl;
  cout << F("speed,max,min,avg") << endl;
  cout << F("KB/Sec,usec,usec,usec") << endl;
  for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
    file.truncate(0);
    if (PRE_ALLOCATE) {
      if (!file.preAllocate(FILE_SIZE)) {
        error("preAllocate failed");
      }
    }
    maxLatency = 0;
    minLatency = 9999999;
    totalLatency = 0;
    skipLatency = SKIP_FIRST_LATENCY;
    t = millis();
    for (uint32_t i = 0; i < n; i++) {
      uint32_t m = micros();
      if (file.write(buf, BUF_SIZE) != BUF_SIZE) {
        error("write failed");
      }
      m = micros() - m;
      totalLatency += m;
      if (skipLatency) {
        // Wait until first write to SD, not just a copy to the cache.
        skipLatency = file.curPosition() < 512;
      } else {
        if (maxLatency < m) {
          maxLatency = m;
        }
        if (minLatency > m) {
          minLatency = m;
        }
      }
    }
    file.sync();
    t = millis() - t;
    s = file.fileSize();
    cout << s/t <<',' << maxLatency << ',' << minLatency;
    cout << ',' << totalLatency/n << endl;
  }
  cout << endl << F("Starting read test, please wait.") << endl;
  cout << endl <<F("read speed and latency") << endl;
  cout << F("speed,max,min,avg") << endl;
  cout << F("KB/Sec,usec,usec,usec") << endl;

  // do read test
  for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
    file.rewind();
    maxLatency = 0;
    minLatency = 9999999;
    totalLatency = 0;
    skipLatency = SKIP_FIRST_LATENCY;
    t = millis();
    for (uint32_t i = 0; i < n; i++) {
      buf[BUF_SIZE-1] = 0;
      uint32_t m = micros();
      int32_t nr = file.read(buf, BUF_SIZE);
      if (nr != BUF_SIZE) {
        error("read failed");
      }
      m = micros() - m;
      totalLatency += m;
      if (buf[BUF_SIZE-1] != '\n') {

        error("data check error");
      }
      if (skipLatency) {
        skipLatency = false;
      } else {
        if (maxLatency < m) {
          maxLatency = m;
        }
        if (minLatency > m) {
          minLatency = m;
        }
      }
    }
    s = file.fileSize();
    t = millis() - t;
    cout << s/t <<',' << maxLatency << ',' << minLatency;
    cout << ',' << totalLatency/n << endl;
  }
  cout << endl << F("Done") << endl;
  file.close();
}

Here is the Serial Console output:

image

So, looks like write and read are about 140KB/s.  The SD card interface is wired for SDIO, so that may be an option if I need more speed in the future.  I haven't used SDIO yet, but I think the current library available for it is 4 bit read and 1 bit write.

image

  • Sign in to reply
  • ralphjy
    ralphjy over 1 year ago in reply to LeScherd

    Hi Bill,

    Thanks for the code.

    I tried your code and it does improve my performance - except nowhere near the results that you got.

    08:18:20.606 -> Use a freshly formatted SD for best performance.
    08:18:20.606 ->
    08:18:20.606 -> Type any character to start
    08:18:25.444 -> FreeStack: -12376
    08:18:25.491 -> Type is FAT32
    08:18:25.491 -> Card size: 15.93 GB (GB = 1E9 bytes)
    08:18:25.491 ->
    08:18:25.491 -> Manufacturer ID: 0X3
    08:18:25.491 -> OEM ID: SD
    08:18:25.491 -> Product: SB16G
    08:18:25.491 -> Version: 8.0
    08:18:25.491 -> Serial number: 0XAABBFB4
    08:18:25.491 -> Manufacturing date: 3/2014
    08:18:25.491 ->
    08:18:25.491 -> FILE_SIZE_MB = 5
    08:18:25.491 -> BUF_SIZE = 512 bytes
    08:18:25.539 -> Starting write test, please wait.
    08:18:25.539 ->
    08:18:25.539 -> write speed and latency
    08:18:25.539 -> speed,max,min,avg
    08:18:25.539 -> KB/Sec,usec,usec,usec
    08:18:45.169 -> 254.85,2722,2004,2006
    08:19:04.880 -> 254.26,47201,2004,2011
    08:19:04.880 ->
    08:19:04.880 -> Starting read test, please wait.
    08:19:04.880 ->
    08:19:04.880 -> read speed and latency
    08:19:04.880 -> speed,max,min,avg
    08:19:04.880 -> KB/Sec,usec,usec,usec
    08:19:24.484 -> 255.58,2003,1999,2000
    08:19:44.025 -> 255.60,2002,1999,2000
    08:19:44.025 ->
    08:19:44.025 -> Done

    The code that I was using did not set the system clock or the voltage regulator, so I'm not sure what the defaults are for those.

    I don't have the time to dive into this at the moment, but I guess the other major difference is that the SparkFun board uses SPI1 for the SD card.  So maybe there are some configuration settings that I've missed.  At least it is functional Slight smile.

    Thanks again for you data - I'll need to figure this out later -> maybe try it with SPI0.

    Ralph

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • LeScherd
    LeScherd over 1 year ago in reply to LeScherd

    image

    This is my setup... just a hand wired test bed.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • LeScherd
    LeScherd over 1 year ago in reply to ralphjy

    And here is the code I used. Results shown below were for 240MHz PicoPi clock with 24MHz SPI clock:

    /*
    * This program is a simple binary write/read benchmark.
    */
    #include "SdFat.h"
    #include "sdios.h"
    #include "FreeStack.h"
    #include "hardware/vreg.h"
    #include <stdlib.h>
    #include "hardware/pll.h"
    #include "hardware/clocks.h"

    // 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 1
    /*
    Change the value of SD_CS_PIN if you are using SPI and
    your hardware does not use the default value, SS.
    Common values are:
    Arduino Ethernet shield: pin 4
    Sparkfun SD shield: pin 8
    Adafruit SD shields and modules: pin 10
    */
    // SDCARD_SS_PIN is defined for the built-in SD on some boards.
    #ifndef SDCARD_SS_PIN
    const 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

    // Try max SPI clock for an SD. Reduce SPI_CLOCK if errors occur.
    #define SPI_CLOCK SD_SCK_MHZ(24) //was 30

    // Try to select the best SD card configuration.
    #if HAS_SDIO_CLASS
    #define SD_CONFIG SdioConfig(FIFO_SDIO)
    #elif ENABLE_DEDICATED_SPI
    #define SD_CONFIG SdSpiConfig(SD_CS_PIN, DEDICATED_SPI, SPI_CLOCK)
    #else // HAS_SDIO_CLASS
    #define SD_CONFIG SdSpiConfig(SD_CS_PIN, SHARED_SPI, SPI_CLOCK)
    #endif // HAS_SDIO_CLASS

    // Set PRE_ALLOCATE true to pre-allocate file clusters.
    const bool PRE_ALLOCATE = true;

    // Set SKIP_FIRST_LATENCY true if the first read/write to the SD can
    // be avoid by writing a file header or reading the first record.
    const bool SKIP_FIRST_LATENCY = true;

    // Size of read/write.
    const size_t BUF_SIZE = 512;

    // File size in MB where MB = 1,000,000 bytes.
    const uint32_t FILE_SIZE_MB = 5;

    // Write pass count.
    const uint8_t WRITE_COUNT = 2;

    // Read pass count.
    const uint8_t READ_COUNT = 2;
    //==============================================================================
    // End of configuration constants.
    //------------------------------------------------------------------------------
    // File size in bytes.
    const uint32_t FILE_SIZE = 1000000UL*FILE_SIZE_MB;

    // Insure 4-byte alignment.
    uint32_t buf32[(BUF_SIZE + 3)/4];
    uint8_t* buf = (uint8_t*)buf32;

    #if SD_FAT_TYPE == 0
    SdFat sd;
    File file;
    #elif SD_FAT_TYPE == 1
    SdFat32 sd;
    File32 file;
    #elif SD_FAT_TYPE == 2
    SdExFat sd;
    ExFile file;
    #elif SD_FAT_TYPE == 3
    SdFs sd;
    FsFile file;
    #else // SD_FAT_TYPE
    #error Invalid SD_FAT_TYPE
    #endif // SD_FAT_TYPE

    // Serial output stream
    ArduinoOutStream cout(Serial);
    //------------------------------------------------------------------------------
    // Store error strings in flash to save RAM.
    #define error(s) sd.errorHalt(&Serial, F(s))
    //------------------------------------------------------------------------------
    void cidDmp() {
    cid_t cid;
    if (!sd.card()->readCID(&cid)) {

    error("readCID failed");
    }
    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;
    }
    //------------------------------------------------------------------------------
    void clearSerialInput() {
    uint32_t m = micros();
    do {
    if (Serial.read() >= 0) {
    m = micros();
    }
    } while (micros() - m < 10000);
    }

    void set_sys_clock_pll(uint32_t vco_freq, uint post_div1, uint post_div2) {
    if (!running_on_fpga()) {
    clock_configure(clk_sys,
    CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
    CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
    48 * MHZ,
    48 * MHZ);

    pll_init(pll_sys, 1, vco_freq, post_div1, post_div2);
    uint32_t freq = vco_freq / (post_div1 * post_div2);

    // Configure clocks
    // CLK_REF = XOSC (12MHz) / 1 = 12MHz
    clock_configure(clk_ref,
    CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC,
    0, // No aux mux
    12 * MHZ,
    12 * MHZ);

    // CLK SYS = PLL SYS (125MHz) / 1 = 125MHz
    clock_configure(clk_sys,
    CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX,
    CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS,
    freq, freq);

    clock_configure(clk_peri,
    0, // Only AUX mux on ADC
    CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
    48 * MHZ,
    48 * MHZ);
    }
    }
    bool check_sys_clock_khz(uint32_t freq_khz, uint *vco_out, uint *postdiv1_out, uint *postdiv_out) {
    uint crystal_freq_khz = clock_get_hz(clk_ref) / 1000;
    for (uint fbdiv = 320; fbdiv >= 16; fbdiv--) {
    uint vco = fbdiv * crystal_freq_khz;
    if (vco < 400000 || vco > 1600000) continue;
    for (uint postdiv1 = 7; postdiv1 >= 1; postdiv1--) {
    for (uint postdiv2 = postdiv1; postdiv2 >= 1; postdiv2--) {
    uint out = vco / (postdiv1 * postdiv2);
    if (out == freq_khz && !(vco % (postdiv1 * postdiv2))) {
    *vco_out = vco * 1000;
    *postdiv1_out = postdiv1;
    *postdiv_out = postdiv2;
    return true;
    }
    }
    }
    }
    return false;
    }
    static inline bool set_sys_clock_khz(uint32_t freq_khz, bool required) {
    uint vco, postdiv1, postdiv2;
    if (check_sys_clock_khz(freq_khz, &vco, &postdiv1, &postdiv2)) {
    set_sys_clock_pll(vco, postdiv1, postdiv2);
    return true;
    } else if (required) {
    panic("System clock of %u kHz cannot be exactly achieved", freq_khz);
    }
    return false;
    }
    //------------------------------------------------------------------------------
    void setup() {
    vreg_set_voltage(VREG_VOLTAGE_1_30);
    set_sys_clock_khz(240000,true);
    Serial.begin(9600);

    // Wait for USB Serial
    while (!Serial) {
    SysCall::yield();
    }
    delay(1000);
    cout << F("\nUse a freshly formatted SD for best performance.\n");
    if (!ENABLE_DEDICATED_SPI) {
    cout << F(
    "\nSet ENABLE_DEDICATED_SPI nonzero in\n"
    "SdFatConfig.h for best SPI performance.\n");
    }
    // use uppercase in hex and use 0X base prefix
    cout << uppercase << showbase << endl;
    }
    //------------------------------------------------------------------------------
    void loop() {
    float s;
    uint32_t t;
    uint32_t maxLatency;
    uint32_t minLatency;
    uint32_t totalLatency;
    bool skipLatency;

    // Discard any input.
    clearSerialInput();

    // F() stores strings in flash to save RAM
    cout << F("Type any character to start\n");
    while (!Serial.available()) {
    SysCall::yield();
    }
    #if HAS_UNUSED_STACK
    cout << F("FreeStack: ") << FreeStack() << endl;
    #endif // HAS_UNUSED_STACK

    if (!sd.begin(SD_CONFIG)) {
    sd.initErrorHalt(&Serial);
    }
    if (sd.fatType() == FAT_TYPE_EXFAT) {
    cout << F("Type is exFAT") << endl;
    } else {
    cout << F("Type is FAT") << int(sd.fatType()) << endl;
    }

    cout << F("Card size: ") << sd.card()->sectorCount()*512E-9;
    cout << F(" GB (GB = 1E9 bytes)") << endl;

    cidDmp();

    // open or create file - truncate existing file.
    if (!file.open("bench.dat", O_RDWR | O_CREAT | O_TRUNC)) {
    error("open failed");
    }

    // fill buf with known data
    if (BUF_SIZE > 1) {
    for (size_t i = 0; i < (BUF_SIZE - 2); i++) {
    buf[i] = 'A' + (i % 26);
    }
    buf[BUF_SIZE-2] = '\r';
    }
    buf[BUF_SIZE-1] = '\n';

    cout << F("FILE_SIZE_MB = ") << FILE_SIZE_MB << endl;
    cout << F("BUF_SIZE = ") << BUF_SIZE << F(" bytes\n");
    cout << F("Starting write test, please wait.") << endl << endl;

    // do write test
    uint32_t n = FILE_SIZE/BUF_SIZE;
    cout <<F("write speed and latency") << endl;
    cout << F("speed,max,min,avg") << endl;
    cout << F("KB/Sec,usec,usec,usec") << endl;
    for (uint8_t nTest = 0; nTest < WRITE_COUNT; nTest++) {
    file.truncate(0);
    if (PRE_ALLOCATE) {
    if (!file.preAllocate(FILE_SIZE)) {
    error("preAllocate failed");
    }
    }
    maxLatency = 0;
    minLatency = 9999999;
    totalLatency = 0;
    skipLatency = SKIP_FIRST_LATENCY;
    t = millis();
    for (uint32_t i = 0; i < n; i++) {
    uint32_t m = micros();
    if (file.write(buf, BUF_SIZE) != BUF_SIZE) {
    error("write failed");
    }
    m = micros() - m;
    totalLatency += m;
    if (skipLatency) {
    // Wait until first write to SD, not just a copy to the cache.
    skipLatency = file.curPosition() < 512;
    } else {
    if (maxLatency < m) {
    maxLatency = m;
    }
    if (minLatency > m) {
    minLatency = m;
    }
    }
    }
    file.sync();
    t = millis() - t;
    s = file.fileSize();
    cout << s/t <<',' << maxLatency << ',' << minLatency;
    cout << ',' << totalLatency/n << endl;
    }
    cout << endl << F("Starting read test, please wait.") << endl;
    cout << endl <<F("read speed and latency") << endl;
    cout << F("speed,max,min,avg") << endl;
    cout << F("KB/Sec,usec,usec,usec") << endl;

    // do read test
    for (uint8_t nTest = 0; nTest < READ_COUNT; nTest++) {
    file.rewind();
    maxLatency = 0;
    minLatency = 9999999;
    totalLatency = 0;
    skipLatency = SKIP_FIRST_LATENCY;
    t = millis();
    for (uint32_t i = 0; i < n; i++) {
    buf[BUF_SIZE-1] = 0;
    uint32_t m = micros();
    int32_t nr = file.read(buf, BUF_SIZE);
    if (nr != BUF_SIZE) {
    error("read failed");
    }
    m = micros() - m;
    totalLatency += m;
    if (buf[BUF_SIZE-1] != '\n') {

    error("data check error");
    }
    if (skipLatency) {
    skipLatency = false;
    } else {
    if (maxLatency < m) {
    maxLatency = m;
    }
    if (minLatency > m) {
    minLatency = m;
    }
    }
    }
    s = file.fileSize();
    t = millis() - t;
    cout << s/t <<',' << maxLatency << ',' << minLatency;
    cout << ',' << totalLatency/n << endl;
    }
    cout << endl << F("Done") << endl;
    file.close();
    }

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • LeScherd
    LeScherd over 1 year ago in reply to ralphjy

    Ralph,

    Here are the results for two different cards I had on hand:

    Sandisk Extreme Plus 32GB
    Use a freshly formatted SD for best performance.

    Type any character to start
    FreeStack: -12376
    Type is FAT32
    Card size: 31.91 GB (GB = 1E9 bytes)

    Manufacturer ID: 0X3
    OEM ID: SD
    Product: SP32G
    Version: 8.0
    Serial number: 0X80034A71
    Manufacturing date: 1/2015

    FILE_SIZE_MB = 5
    BUF_SIZE = 512 bytes
    Starting write test, please wait.

    write speed and latency
    speed,max,min,avg
    KB/Sec,usec,usec,usec
    2010.45,1031,249,252
    2008.84,1579,249,252

    Starting read test, please wait.

    read speed and latency
    speed,max,min,avg
    KB/Sec,usec,usec,usec
    2099.96,246,239,241
    2099.08,245,240,241

    Done
    Type any character to start

    ONN (Walmart Brand) 32GB
    Use a freshly formatted SD for best performance.

    Type any character to start
    FreeStack: -12376
    Type is FAT32
    Card size: 30.94 GB (GB = 1E9 bytes)

    Manufacturer ID: 0X27
    OEM ID: PH
    Product: SD32G
    Version: 6.0
    Serial number: 0X32000000
    Manufacturing date: 4/2015

    FILE_SIZE_MB = 5
    BUF_SIZE = 512 bytes
    Starting write test, please wait.

    write speed and latency
    speed,max,min,avg
    KB/Sec,usec,usec,usec
    1838.24,581,271,276
    1837.56,546,271,276

    Starting read test, please wait.

    read speed and latency
    speed,max,min,avg
    KB/Sec,usec,usec,usec
    1643.66,313,305,309
    1643.66,316,305,309

    Done
    Type any character to start

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • ralphjy
    ralphjy over 1 year ago in reply to LeScherd

    Hi Bill,

    Yes, I'd be interested.  Also if you could share the code and the setup.  You did get a lot better results.  I'd like to try to reproduce them.

    Thanks,

    Ralph

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • Facebook
  • Twitter
  • linkedin
  • YouTube