SDFat non-blocking transfer implementation attempt

MarcelBIenvu

New member
Hi everybody,
Not sure if it is the good place or not to post this...
I've been trying to patch the SdFat, from Bill Greiman, with some ADMA capabilities and non blocking read and write operations. Looking at the manual, there is room for improvement, like SDR104 mode speeds (require some tuning...).
I took bits from the NXP SDK for the RT1062 platform but it *should* also work with Teensy 3.6. I'm looking to modify objects from the Audio Library to work with the modifications made, but I can't figure out why it is working with the little benchmark program i made, but freeze when i try to play with the play_sd_raw object.
Here is the benchmark program

Code:
#include <Entropy.h>
#include "SdFat.h"

const size_t BUF_DIM = 131072;

SdFs sd;
FsFile file;

uint8_t toWrite[BUF_DIM];
uint8_t toRead[BUF_DIM];

bool sdBusy() {
  return sd.card()->isBusy();
}

void runTest() {
  file.preAllocate(BUF_DIM);
  Serial.println("Preallocate OK");
  if (!file.open("teensyTest.bin", O_RDWR | O_CREAT)) Serial.println("open failed");
  Serial.println("Open OK");

  for(uint32_t i = 0; i < BUF_DIM; i++) {
    toWrite[i] = random(255);
  }

  Serial.print("\n------------------------------------------------------------------/ WRITING /------------------------------------------------------------------\n\n");
  Serial.printf("sectors\t\toctets\t\tcmd\t\twrite\t\tspeed\n");  

  uint8_t* bufW = (uint8_t*)toWrite;

  for(uint32_t ns = 1; ns < 512; ns *= 2) {
    uint32_t nbWr = BUF_DIM / (ns * 512);
    int32_t cmdTime, writeTime, wr = 0;
    int32_t cmdTot = 0, writeTot = 0; 

    file.rewind();
    bufW = toWrite;

    for(uint16_t j = 0; j < nbWr; j++) {
      cmdTime = writeTime = micros();
      wr = file.write(bufW, ns * 512);
      cmdTot += micros() - cmdTime;

      while(sdBusy()) {}

      writeTot += micros() - writeTime;
      bufW += ns * 512;
    }
    
    writeTot /= nbWr;
    cmdTot /= nbWr;
    float speed = (float)(ns * 512 / writeTot);
    Serial.printf("%u\t\t%1.3f Ko\t%u us\t\t%u us\t\t%1.2f Mo/s\n", wr / 512, wr / 1000.0, cmdTot, writeTot, speed);
  }

  Serial.print("\n------------------------------------------------------------------/ READING /------------------------------------------------------------------\n\n");

  uint8_t* buf = (uint8_t*)toRead;
  Serial.printf("sectors\t\toctets\t\tcmd\t\tread\t\tspeed\t\t\terrors\t\tproofs\n");
  int64_t errors = 0;
  for(uint32_t ns = 1; ns < 512; ns *= 2) {
    uint32_t nbRd = BUF_DIM / (ns * 512);
    int32_t cmdTime, readTime, rd = 0;
    int32_t cmdTot = 0, readTot = 0; 

    file.rewind();

    buf = toRead;
    memset(toRead, 0, BUF_DIM);
    for(uint16_t j = 0; j < nbRd; j++) {
      cmdTime = readTime = micros();
      rd = file.read(buf, ns * 512);
      cmdTot += micros() - cmdTime;

      while(sdBusy()) {}

      readTot += micros() - readTime;
      buf += ns * 512;
    }
    errors = memcmp(toWrite, toRead, BUF_DIM);
    readTot /= nbRd;
    cmdTot /= nbRd;
    float speed = (float)(ns * 512 / readTot);
    Serial.printf("%u\t\t%1.3f Ko\t", rd / 512, rd / 1000.0);
    Serial.printf("%u us\t\t%u us\t", cmdTot, readTot);
    Serial.printf("\t%1.2f Mo/s\t\t%u", speed, errors);
    Serial.printf("\t\t[%u - %u | %u - %u | %u - %u]\n", toWrite[ns], toRead[ns], toWrite[ns + 64], toRead[ns + 64], toWrite[ns+256], toRead[ns+256]);
  }
  file.close();
  sd.remove("teensyTest.bin");
  sd.ls();
  Serial.print("\nOver and out...");
}

void setup() {
  Serial.begin(9600);
  while (!Serial) {}
  Serial.println("Type to begin tests...");
  while (!Serial.available()) {}
    if (!sd.begin(SdioConfig(DMA_SDIO))) {
      Serial.println("begin failed");
    }
    Serial.println("Init OK");
    Entropy.Initialize();
    runTest();
}

void loop() {}

And the results with a Kingston Canvas Go Plus:
kHzSdClk = 100000 in SdioTeensy.cpp
Code:
------------------------------------------------------------------/ WRITING /------------------------------------------------------------------

sectors         octets          cmd             write           speed
1               0.512 Ko        4 us            493 us          1.00 Mo/s
2               1.024 Ko        358 us          520 us          1.00 Mo/s
4               2.048 Ko        366 us          582 us          3.00 Mo/s
8               4.096 Ko        338 us          606 us          6.00 Mo/s
16              8.192 Ko        381 us          840 us          9.00 Mo/s
32              16.384 Ko       259 us          684 us          23.00 Mo/s
64              32.768 Ko       375 us          2031 us         16.00 Mo/s
128             65.536 Ko       443 us          1920 us         34.00 Mo/s
256             131.072 Ko      527 us          6935 us         18.00 Mo/s

------------------------------------------------------------------/ READING /------------------------------------------------------------------

sectors         octets          cmd             read            speed                   errors          proofs
1               0.512 Ko        139 us          141 us          3.00 Mo/s               0               [21 - 21 | 238 - 238 | 195 - 195]
2               1.024 Ko        4 us            198 us          5.00 Mo/s               0               [140 - 140 | 23 - 23 | 189 - 189]
4               2.048 Ko        4 us            196 us          10.00 Mo/s              0               [181 - 181 | 226 - 226 | 34 - 34]
8               4.096 Ko        4 us            213 us          19.00 Mo/s              0               [158 - 158 | 177 - 177 | 166 - 166]
16              8.192 Ko        4 us            461 us          17.00 Mo/s              0               [149 - 149 | 78 - 78 | 50 - 50]
32              16.384 Ko       4 us            645 us          25.00 Mo/s              0               [139 - 139 | 201 - 201 | 47 - 47]
64              32.768 Ko       4 us            960 us          34.00 Mo/s              0               [7 - 7 | 24 - 24 | 86 - 86]
128             65.536 Ko       4 us            1640 us         39.00 Mo/s              0               [24 - 24 | 208 - 208 | 122 - 122]
256             131.072 Ko      4 us            3008 us         43.00 Mo/s              0               [47 - 47 | 86 - 86 | 34 - 34]

kHzSdClk = 200000 {writing is done with simple DMA at this speed)
Code:
------------------------------------------------------------------/ READING /------------------------------------------------------------------

sectors         octets          cmd             read            speed                   errors          proofs
1               0.512 Ko        106 us          108 us          4.00 Mo/s               0               [21 - 21 | 238 - 238 | 195 - 195]
2               1.024 Ko        3 us            141 us          7.00 Mo/s               0               [140 - 140 | 23 - 23 | 189 - 189]
4               2.048 Ko        3 us            157 us          13.00 Mo/s              0               [181 - 181 | 226 - 226 | 34 - 34]
8               4.096 Ko        3 us            152 us          26.00 Mo/s              0               [158 - 158 | 177 - 177 | 166 - 166]
16              8.192 Ko        3 us            302 us          27.00 Mo/s              0               [149 - 149 | 78 - 78 | 50 - 50]
32              16.384 Ko       3 us            414 us          39.00 Mo/s              0               [139 - 139 | 201 - 201 | 47 - 47]
64              32.768 Ko       3 us            620 us          52.00 Mo/s              0               [7 - 7 | 24 - 24 | 86 - 86]
128             65.536 Ko       3 us            967 us          67.00 Mo/s              0               [24 - 24 | 208 - 208 | 122 - 122]
256             131.072 Ko      3 us            1649 us         79.00 Mo/s              0               [47 - 47 | 86 - 86 | 34 - 34]

As you can see, the time taken to send the command is around 3us, so it can be relevant for Audio processing (FrankB's Teensy-WavePlayer or teensy-variable-playback for interpolation) and other interrupts related situations. the 106us for the 1 block reading is due to the CMD17 being still blocking method, as filesystem functions seems to rely on classic transfer methods to not crash. (I don't understand it fully)
Here is the bit of code added at the end of SdioTeensy.cpp:

Code:
#define ADMA2_DESCRIPTOR_LENGTH_SHIFT           16U
#define ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY   0xFFFFUL
#define ADMA2_DESCRIPTOR_BUFFER_SIZE            32U
#define ADMA2_DESCRIPTOR_BUFFER_ALIGN_SIZE      4U
#define ADMA2_DESCRIPTOR_END_FLAG               1U << 1U
#define ADMA2_DESCRIPTOR_ACTIVITY2_FLAG         0x20
#define ADMA2_DESCRIPTOR_TRANSFER_FLAG          0x21

#define ADMA2_LENGTH_ALIGN                    4U
#define SDHC_PROCTL_DMAS_MASK                 0x300U

struct Sdhc_Adma2_Descriptor {
    uint32_t attribute;                     /*!< The control and status field */
    const uint32_t *address;                /*!< The address field */
};

static uint32_t HostDmaBuffer[ADMA2_DESCRIPTOR_BUFFER_SIZE] __attribute__((aligned(ADMA2_DESCRIPTOR_BUFFER_ALIGN_SIZE))); 

bool SetAdma2TableConfig(uint32_t *table, uint32_t tableWords, const uint32_t *data, uint32_t dataBytes) {
    const uint32_t *startAddress = data;
    uint32_t entries;
    uint32_t i;

    Sdhc_Adma2_Descriptor *adma2EntryAddress;

    if (table == NULL || tableWords == 0UL || data == NULL || dataBytes == 0UL) {
        return false;
    }
    else if (((uint32_t)startAddress % ADMA2_LENGTH_ALIGN) != 0UL) {
        return false;
    } else {
        if (dataBytes % sizeof(uint32_t) != 0U) {
            dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t)); /* make the data length as word-aligned */
        }
        entries = ((dataBytes / ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
        if (entries > ((tableWords * sizeof(uint32_t)) / sizeof(Sdhc_Adma2_Descriptor))) {                                           // TODO sizeof() !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            return false;
        } else {
                adma2EntryAddress = (Sdhc_Adma2_Descriptor*)(uint32_t)(table);
                for (i = 0; i < entries; i++) {
                    /* Each descriptor for ADMA2 is 64-bit in length */
                    if ((dataBytes - ((uint32_t)startAddress - (uint32_t)data)) <= ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) {
                        /* The last piece of data, setting end flag in descriptor */
                        adma2EntryAddress[i].address   = startAddress;
                        adma2EntryAddress[i].attribute = ((dataBytes - ((uint32_t)startAddress - (uint32_t)data)) << ADMA2_DESCRIPTOR_LENGTH_SHIFT);
                        adma2EntryAddress[i].attribute |= ADMA2_DESCRIPTOR_TRANSFER_FLAG | ADMA2_DESCRIPTOR_END_FLAG;
                    } else {
                        adma2EntryAddress[i].address = startAddress;
                        adma2EntryAddress[i].attribute = (((ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t)) * sizeof(uint32_t)) << ADMA2_DESCRIPTOR_LENGTH_SHIFT);
                        adma2EntryAddress[i].attribute |= ADMA2_DESCRIPTOR_TRANSFER_FLAG;
                        startAddress += (ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY / sizeof(uint32_t));
                    }
                    //Serial.printf("\t\t________________________________________________________________\n");
                    //Serial.printf("\t\t|      Attribute field      |   Length field   | Address field |\n");
                    //Serial.printf("\t\t|Valid|End|Int|x|Act 1|Act 2|   16bit length   | 32-bit length |\n");
                    //Serial.printf("\t\t|  %u  | %u | %u |x|  %u  |  %u  |", bitRead(adma2EntryAddress[i].attribute, 0), bitRead(adma2EntryAddress[i].attribute, 1), bitRead(adma2EntryAddress[i].attribute, 2), bitRead(adma2EntryAddress[i].attribute, 4), bitRead(adma2EntryAddress[i].attribute, 5));
                    //Serial.printf("       %u       |   %u   |\n", adma2EntryAddress[i].attribute >> 16, adma2EntryAddress[i].address);                
                }
                SDHC_DSADDR  = 0U;
                SDHC_ADSADDR = (uint32_t)table;
            }       
    }
    return true;
}

static void admaEnable(bool enable) {
  if(enable) {
    SDHC_PROCTL |= SDHC_PROCTL_DMAS(2);
  } else {
    SDHC_PROCTL &= ~SDHC_PROCTL_DMAS_MASK;
  }
}

static bool sectorsReadWriteNonBlocking(uint32_t xfertyp, uint32_t sector, uint8_t* buf, size_t n) {  
  if (waitTimeout(isBusyCommandInhibit)) {
    return false;  // Caller will set errorCode.
  }

  uint32_t* temp = (uint32_t *)(uint32_t)buf;                                                           // 4 Bytes aligned pointer 

  if(!SetAdma2TableConfig(HostDmaBuffer, ADMA2_DESCRIPTOR_BUFFER_SIZE, temp, (n * 512))) return false;  // Configure ADMA descriptor(s)
 

  admaEnable(true);                                                                                     // Enable and select Adma
  SDHC_IRQSIGEN |= SDHC_IRQSIGEN_MASK;                                          // Enable interrupts Signal
  SDHC_BLKATTR = SDHC_BLKATTR_BLKSIZE(512) | SDHC_BLKATTR_BLKCNT(n);
  if(!cardCommand(xfertyp, sector)) return false;
  return true;
}

static bool rdWrSectors(uint32_t xfertyp, uint32_t sector, uint8_t* buf, size_t n) {
  if ((3 & (uint32_t)buf) || n == 0) {
    return sdError(SD_CARD_ERROR_DMA);
  }

  if(isAdma) {
    while(!waitDmaStatus()) {}
    setIsAdma(false);
  }

  if (yieldTimeout(isBusyCMD13)) {
    return sdError(SD_CARD_ERROR_CMD13);
  }
  enableDmaIrs();
  if(xfertyp == CMD17_DMA_XFERTYP || xfertyp == CMD18_DMA_XFERTYP || xfertyp == CMD25_DMA_XFERTYP || xfertyp == CMD24_DMA_XFERTYP) {
    if(!sectorsReadWriteNonBlocking(xfertyp, sector, buf, n)) return false;
    setIsAdma(true);
    if(xfertyp == CMD17_DMA_XFERTYP) {                                          // Blocking... Ensure that common filesystem functions works
      while(!waitDmaStatus()) {}
      setIsAdma(false);
    } 
    return true;
  } else {
    admaEnable(false);
    SDHC_DSADDR  = (uint32_t)buf;
    SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512);
    SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
    if (!cardCommand(xfertyp, m_highCapacity ? sector : 512*sector)) {
      return false;
    }
    return waitDmaStatus();
  }
}

the rdWrSectors function is modified to route the read/write operations depending on the card speed set with kHzSdClk. At 100000, I can read and write, but at 200000, only read operations are possible so it is asked to comment out CMD24 and CMD25 in the if() statement.
the isBusy function has been modified as well:
Code:
  if (isAdma) {
    if(m_dmaBusy && !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR))) return true;
    setIsAdma(false);
    return false;
  }
  if (m_sdioConfig.useDma()) {
    return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
  } else {
    if (m_transferActive) {
      if (isBusyTransferComplete()) {
        return true;
      } ...
The way wait for Transfer Complete is handled is surely a little fiddly, but I cannot figure out how to call sd.isBusy() another way.
And the related variable and function added among declaration at the beginning of the file:
Code:
//==============================================================================
bool isAdma = false;
static void setIsAdma(bool enable) {isAdma = enable;}
//==============================================================================
I can post the whole sources (PlatformIO format) if someone is interested to proof test the modifications (a little help?), or just want to look at it.
Sorry for the weird code or formatting, I'm definitely no developer, just trying to understand and apply
Have a great evening!
 
Hi Marcel,
from your post it is not clear -at least for me-, what is your intention of this post?
As you have not shared your code, people would have to guess, what might be the reasons for problems.
About your benchmarks: I had to learn, that such impressing one-shot-measurements results are not really helpful, because at "random" times there will be "write latency", when the card's controller has to erase a block or when it finds a bad block. Here https://forum.pjrc.com/threads/69299-Feasibility-Looper-8-Tracks-Mono-with-storage-onto-SD-card I have posted some measurements, which show that a transfer rate can go down very very much. You did not mention, what buffer size you have implemented.
Christof
 
you have to consider that FS needs blocking.
E.g. to open a file FS must first read the directory (cache may be empty) AND this can not be done without waiting for result.
Even when writing data to disk, FS must read FAT/Bit table to know where to write.
So, FS must be setup to have both blocking and non-blocking read/write access.
Unfortunately, Bill Greiman's SdFat has no simple interface to disk access routines (as Elm Chan`s FatFS has). Only SPI access can be customized, so a clear interface exists, but SDIO is completely integrated.
I'm not saying it is impossible, but you have to digest Bill's programming paradigm.
 
Thanks for the answers!
to cebersp:
Sorry it was definitely not clear, I worked on this for 2 weeks, and I guess was a little 'under the water' regarding the global functioning of the library, and needed some insight.
I should have posted in the 'Technical and Support' first and then here for the audio related stuff. It's a 2 steps path, first getting the SdFat library working with non-blocking transfers, then apply it to practical cases. I was thinking that it may be beneficial to wav-recorders/players to have minimum time doing SD stuff and maximum time to do DSP stuff. Here is a quote from Paul
2: No matter what we do, we're looking at 415 to 550 microseconds latency. For audio, our max timing budget is 2902 microseconds, so 500 is good in that it uses only about 1/6th of the available time, but on the other hand not so wonderful that we spend a good size chunk of the time we could have been number crunching DSP just blocking waiting for a read to fill buffers (which we won't even use until the next 2902 time slot). When users put many instances of numerically heavy effects like ladder filters, reverb, bandwidth limited oscillators into their project, all that DSP work uses some of the 2902 budget. An API where we could spend minimum time starting 1 read operation during those 2902 microseconds and then harvest the data from a buffer during the next 2902 microsecond time would be so much better that wasting ~500 of the 2902 microseconds just setting in a loop waiting for data we don't even need until the next period.
They mention using RTOS, but I know little to nothing about this so I took the path of modifying the library. It may not be the best way though. I tried your benchmark program with different buffer size (131072 bytes buffer), but I'm not sure I am doing the modification correctly.
for WMXZ:
Thank you for the insights. You more or less pinpointed the questions I had. So I went through the library again to understand the logic better, and now see the need for "both blocking and non-blocking read/write access". I modified the read and write methods to include a 'mode' parameter to give the choice about the transfer method. It gives, for example:
Code:
file.read(buffer, bytes_to_read, FIFO);
file.write(source, bytes_to_write, ADMA);
this routes the methods to call the related function in the SdioCard class. If no mode parameter is provided, it assume FIFO mode.
Here is Bill Greiman's read benchmark from: https://forum.pjrc.com/threads/68418-Which-SD-is-Best-for-Audio-Projects with MAX_SECTORS = 128 and kHzSdClk = 100000
Code:
Type any character to start
Create files
Create micros: 129817
Sequential Write: 20239.43 KB/sec
Begin Random Read Test
ns - read size sectors, nf - number of files, maxLat - latency micros
ns: 128 nf: 1   maxLatCmd: 5    maxLat: 1762    total KB/sec: 40734.05  file KB/sec: 40734.05
ns: 128 nf: 2   maxLatCmd: 5    maxLat: 1665    total KB/sec: 40904.88  file KB/sec: 20452.44
ns: 128 nf: 4   maxLatCmd: 5    maxLat: 1681    total KB/sec: 40800.62  file KB/sec: 10200.16
ns: 128 nf: 8   maxLatCmd: 5    maxLat: 1756    total KB/sec: 40089.88  file KB/sec: 5011.24
ns: 128 nf: 16  maxLatCmd: 5    maxLat: 1753    total KB/sec: 38905.49  file KB/sec: 2431.59
ns: 64  nf: 1   maxLatCmd: 5    maxLat: 1014    total KB/sec: 32927.49  file KB/sec: 32927.49
ns: 64  nf: 2   maxLatCmd: 5    maxLat: 1072    total KB/sec: 32738.33  file KB/sec: 16369.16
ns: 64  nf: 4   maxLatCmd: 5    maxLat: 1088    total KB/sec: 32788.75  file KB/sec: 8197.19
ns: 64  nf: 8   maxLatCmd: 5    maxLat: 1085    total KB/sec: 32838.94  file KB/sec: 4104.87
ns: 64  nf: 16  maxLatCmd: 5    maxLat: 1094    total KB/sec: 31013.95  file KB/sec: 1938.37
ns: 32  nf: 1   maxLatCmd: 5    maxLat: 636     total KB/sec: 27170.11  file KB/sec: 27170.11
ns: 32  nf: 2   maxLatCmd: 5    maxLat: 692     total KB/sec: 26346.46  file KB/sec: 13173.23
ns: 32  nf: 4   maxLatCmd: 5    maxLat: 686     total KB/sec: 25996.68  file KB/sec: 6499.17
ns: 32  nf: 8   maxLatCmd: 5    maxLat: 800     total KB/sec: 25812.29  file KB/sec: 3226.54
ns: 32  nf: 16  maxLatCmd: 5    maxLat: 855     total KB/sec: 23454.11  file KB/sec: 1465.88
ns: 16  nf: 1   maxLatCmd: 5    maxLat: 500     total KB/sec: 18487.86  file KB/sec: 18487.86
ns: 16  nf: 2   maxLatCmd: 5    maxLat: 502     total KB/sec: 18401.56  file KB/sec: 9200.78
ns: 16  nf: 4   maxLatCmd: 5    maxLat: 501     total KB/sec: 18450.21  file KB/sec: 4612.55
ns: 16  nf: 8   maxLatCmd: 5    maxLat: 671     total KB/sec: 18277.86  file KB/sec: 2284.73
ns: 16  nf: 16  maxLatCmd: 5    maxLat: 672     total KB/sec: 15949.09  file KB/sec: 996.82
ns: 8   nf: 1   maxLatCmd: 5    maxLat: 267     total KB/sec: 20731.45  file KB/sec: 20731.45
ns: 8   nf: 2   maxLatCmd: 5    maxLat: 270     total KB/sec: 20477.60  file KB/sec: 10238.80
ns: 8   nf: 4   maxLatCmd: 5    maxLat: 270     total KB/sec: 20500.52  file KB/sec: 5125.13
ns: 8   nf: 8   maxLatCmd: 5    maxLat: 271     total KB/sec: 20452.19  file KB/sec: 2556.52
ns: 8   nf: 16  maxLatCmd: 5    maxLat: 272     total KB/sec: 16362.64  file KB/sec: 1022.66
ns: 4   nf: 1   maxLatCmd: 5    maxLat: 268     total KB/sec: 11710.04  file KB/sec: 11710.04
ns: 4   nf: 2   maxLatCmd: 5    maxLat: 296     total KB/sec: 11508.21  file KB/sec: 5754.10
ns: 4   nf: 4   maxLatCmd: 5    maxLat: 297     total KB/sec: 11542.16  file KB/sec: 2885.54
ns: 4   nf: 8   maxLatCmd: 5    maxLat: 393     total KB/sec: 11377.95  file KB/sec: 1422.24
ns: 4   nf: 16  maxLatCmd: 5    maxLat: 461     total KB/sec: 8603.77   file KB/sec: 537.74
ns: 2   nf: 1   maxLatCmd: 5    maxLat: 297     total KB/sec: 5978.06   file KB/sec: 5978.06
ns: 2   nf: 2   maxLatCmd: 5    maxLat: 298     total KB/sec: 5856.30   file KB/sec: 2928.15
ns: 2   nf: 4   maxLatCmd: 5    maxLat: 302     total KB/sec: 5841.34   file KB/sec: 1460.33
ns: 2   nf: 8   maxLatCmd: 5    maxLat: 468     total KB/sec: 5716.04   file KB/sec: 714.50
ns: 2   nf: 16  maxLatCmd: 5    maxLat: 469     total KB/sec: 4245.98   file KB/sec: 265.37
ns: 1   nf: 1   maxLatCmd: 5    maxLat: 187     total KB/sec: 4517.62   file KB/sec: 4517.62
ns: 1   nf: 2   maxLatCmd: 5    maxLat: 186     total KB/sec: 4408.19   file KB/sec: 2204.09
ns: 1   nf: 4   maxLatCmd: 5    maxLat: 186     total KB/sec: 4420.38   file KB/sec: 1105.09
ns: 1   nf: 8   maxLatCmd: 5    maxLat: 186     total KB/sec: 4418.88   file KB/sec: 552.36
ns: 1   nf: 16  maxLatCmd: 5    maxLat: 193     total KB/sec: 3092.22   file KB/sec: 193.26
End Random Read Test
Type any character to remove files
Remove micros: 62262
Done
and kHzSdClk = 200000
Code:
Type any character to start
Create files
Create micros: 86948
Sequential Write: 25841.08 KB/sec
Begin Random Read Test
ns - read size sectors, nf - number of files, maxLat - latency micros
ns: 128 nf: 1   maxLatCmd: 4    maxLat: 1142    total KB/sec: 64282.49  file KB/sec: 64282.49
ns: 128 nf: 2   maxLatCmd: 4    maxLat: 1088    total KB/sec: 64470.22  file KB/sec: 32235.11
ns: 128 nf: 4   maxLatCmd: 4    maxLat: 1098    total KB/sec: 64001.95  file KB/sec: 16000.49
ns: 128 nf: 8   maxLatCmd: 4    maxLat: 1107    total KB/sec: 63475.53  file KB/sec: 7934.44
ns: 128 nf: 16  maxLatCmd: 4    maxLat: 1112    total KB/sec: 60272.08  file KB/sec: 3767.01
ns: 64  nf: 1   maxLatCmd: 4    maxLat: 731     total KB/sec: 50707.29  file KB/sec: 50707.29
ns: 64  nf: 2   maxLatCmd: 4    maxLat: 733     total KB/sec: 51170.02  file KB/sec: 25585.01
ns: 64  nf: 4   maxLatCmd: 4    maxLat: 737     total KB/sec: 51053.54  file KB/sec: 12763.39
ns: 64  nf: 8   maxLatCmd: 4    maxLat: 870     total KB/sec: 50321.58  file KB/sec: 6290.20
ns: 64  nf: 16  maxLatCmd: 4    maxLat: 857     total KB/sec: 45923.83  file KB/sec: 2870.24
ns: 32  nf: 1   maxLatCmd: 4    maxLat: 462     total KB/sec: 38850.54  file KB/sec: 38850.54
ns: 32  nf: 2   maxLatCmd: 4    maxLat: 517     total KB/sec: 38453.75  file KB/sec: 19226.87
ns: 32  nf: 4   maxLatCmd: 4    maxLat: 519     total KB/sec: 38420.98  file KB/sec: 9605.25
ns: 32  nf: 8   maxLatCmd: 4    maxLat: 583     total KB/sec: 37983.97  file KB/sec: 4748.00
ns: 32  nf: 16  maxLatCmd: 4    maxLat: 627     total KB/sec: 33045.79  file KB/sec: 2065.36
ns: 16  nf: 1   maxLatCmd: 4    maxLat: 377     total KB/sec: 26898.29  file KB/sec: 26898.29
ns: 16  nf: 2   maxLatCmd: 4    maxLat: 395     total KB/sec: 26607.53  file KB/sec: 13303.76
ns: 16  nf: 4   maxLatCmd: 4    maxLat: 393     total KB/sec: 26631.85  file KB/sec: 6657.96
ns: 16  nf: 8   maxLatCmd: 4    maxLat: 595     total KB/sec: 26217.19  file KB/sec: 3277.15
ns: 16  nf: 16  maxLatCmd: 4    maxLat: 500     total KB/sec: 21628.09  file KB/sec: 1351.76
ns: 8   nf: 1   maxLatCmd: 4    maxLat: 223     total KB/sec: 26497.93  file KB/sec: 26497.93
ns: 8   nf: 2   maxLatCmd: 4    maxLat: 227     total KB/sec: 26046.72  file KB/sec: 13023.36
ns: 8   nf: 4   maxLatCmd: 4    maxLat: 225     total KB/sec: 26084.95  file KB/sec: 6521.24
ns: 8   nf: 8   maxLatCmd: 4    maxLat: 226     total KB/sec: 26062.02  file KB/sec: 3257.75
ns: 8   nf: 16  maxLatCmd: 4    maxLat: 229     total KB/sec: 19019.78  file KB/sec: 1188.74
ns: 4   nf: 1   maxLatCmd: 4    maxLat: 259     total KB/sec: 12796.41  file KB/sec: 12796.41
ns: 4   nf: 2   maxLatCmd: 4    maxLat: 294     total KB/sec: 12661.51  file KB/sec: 6330.76
ns: 4   nf: 4   maxLatCmd: 4    maxLat: 300     total KB/sec: 12663.54  file KB/sec: 3165.89
ns: 4   nf: 8   maxLatCmd: 4    maxLat: 416     total KB/sec: 12502.51  file KB/sec: 1562.81
ns: 4   nf: 16  maxLatCmd: 4    maxLat: 485     total KB/sec: 9059.84   file KB/sec: 566.24
ns: 2   nf: 1   maxLatCmd: 4    maxLat: 357     total KB/sec: 7212.26   file KB/sec: 7212.26
ns: 2   nf: 2   maxLatCmd: 4    maxLat: 357     total KB/sec: 7040.16   file KB/sec: 3520.08
ns: 2   nf: 4   maxLatCmd: 4    maxLat: 361     total KB/sec: 7020.24   file KB/sec: 1755.06
ns: 2   nf: 8   maxLatCmd: 4    maxLat: 431     total KB/sec: 6953.53   file KB/sec: 869.19
ns: 2   nf: 16  maxLatCmd: 4    maxLat: 432     total KB/sec: 4813.20   file KB/sec: 300.83
ns: 1   nf: 1   maxLatCmd: 4    maxLat: 179     total KB/sec: 4746.77   file KB/sec: 4746.77
ns: 1   nf: 2   maxLatCmd: 4    maxLat: 178     total KB/sec: 4660.83   file KB/sec: 2330.42
ns: 1   nf: 4   maxLatCmd: 4    maxLat: 178     total KB/sec: 4645.18   file KB/sec: 1161.30
ns: 1   nf: 8   maxLatCmd: 4    maxLat: 179     total KB/sec: 4638.80   file KB/sec: 579.85
ns: 1   nf: 16  maxLatCmd: 4    maxLat: 187     total KB/sec: 3047.99   file KB/sec: 190.50
End Random Read Test
Type any character to remove files
Remove micros: 61683
Done
the write methods are still buggy, but I feel like it is progressing
I put sources are in a github repository, so it is easier to test: https://github.com/marcelbienvu/SdFat
Will try it with play_sd_raw tonight
 
Back
Top