You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
5.3KB

  1. /*
  2. * This program illustrates raw write functions in SdFat that
  3. * can be used for high speed data logging.
  4. *
  5. * This program simulates logging from a source that produces
  6. * data at a constant rate of RATE_KB_PER_SEC.
  7. *
  8. * Note: Apps should create a very large file then truncates it
  9. * to the length that is used for a logging. It only takes
  10. * a few seconds to erase a 500 MB file since the card only
  11. * marks the blocks as erased; no data transfer is required.
  12. */
  13. #include <SPI.h>
  14. #include "SdFat.h"
  15. #include "sdios.h"
  16. #include "FreeStack.h"
  17. // SD chip select pin
  18. const uint8_t chipSelect = SS;
  19. const uint32_t RATE_KB_PER_SEC = 100;
  20. const uint32_t TEST_TIME_SEC = 100;
  21. // Time between printing progress dots
  22. const uint32_t DOT_TIME_MS = 5000UL;
  23. // number of blocks in the contiguous file
  24. const uint32_t BLOCK_COUNT = (1000*RATE_KB_PER_SEC*TEST_TIME_SEC + 511)/512;
  25. // file system
  26. SdFat sd;
  27. // test file
  28. SdFile file;
  29. // file extent
  30. uint32_t bgnBlock, endBlock;
  31. // Serial output stream
  32. ArduinoOutStream cout(Serial);
  33. //------------------------------------------------------------------------------
  34. // store error strings in flash to save RAM
  35. #define error(s) sd.errorHalt(F(s))
  36. //------------------------------------------------------------------------------
  37. void setup(void) {
  38. Serial.begin(9600);
  39. // Wait for USB Serial
  40. while (!Serial) {
  41. SysCall::yield();
  42. }
  43. }
  44. //------------------------------------------------------------------------------
  45. void loop(void) {
  46. // Read any extra Serial data.
  47. do {
  48. delay(10);
  49. } while (Serial.available() && Serial.read() >= 0);
  50. // F stores strings in flash to save RAM
  51. cout << F("Type any character to start\n");
  52. while (!Serial.available()) {
  53. SysCall::yield();
  54. }
  55. cout << F("FreeStack: ") << FreeStack() << endl;
  56. // Initialize at the highest speed supported by the board that is
  57. // not over 50 MHz. Try a lower speed if SPI errors occur.
  58. if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
  59. sd.initErrorHalt();
  60. }
  61. // delete possible existing file
  62. sd.remove("RawWrite.txt");
  63. // create a contiguous file
  64. if (!file.createContiguous("RawWrite.txt", 512UL*BLOCK_COUNT)) {
  65. error("createContiguous failed");
  66. }
  67. // get the location of the file's blocks
  68. if (!file.contiguousRange(&bgnBlock, &endBlock)) {
  69. error("contiguousRange failed");
  70. }
  71. //*********************NOTE**************************************
  72. // NO SdFile calls are allowed while cache is used for raw writes
  73. //***************************************************************
  74. // clear the cache and use it as a 512 byte buffer
  75. uint8_t* pCache = (uint8_t*)sd.vol()->cacheClear();
  76. // fill cache with eight lines of 64 bytes each
  77. memset(pCache, ' ', 512);
  78. for (uint16_t i = 0; i < 512; i += 64) {
  79. // put line number at end of line then CR/LF
  80. pCache[i + 61] = '0' + (i/64);
  81. pCache[i + 62] = '\r';
  82. pCache[i + 63] = '\n';
  83. }
  84. cout << F("Start raw write of ") << file.fileSize()/1000UL << F(" KB\n");
  85. cout << F("Target rate: ") << RATE_KB_PER_SEC << F(" KB/sec\n");
  86. cout << F("Target time: ") << TEST_TIME_SEC << F(" seconds\n");
  87. // tell card to setup for multiple block write with pre-erase
  88. if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
  89. error("writeStart failed");
  90. }
  91. // init stats
  92. delay(1000);
  93. uint32_t dotCount = 0;
  94. uint32_t maxQueuePrint = 0;
  95. uint32_t maxWriteTime = 0;
  96. uint32_t minWriteTime = 9999999;
  97. uint32_t totalWriteTime = 0;
  98. uint32_t maxQueueSize = 0;
  99. uint32_t nWrite = 0;
  100. uint32_t b = 0;
  101. // write data
  102. uint32_t startTime = millis();
  103. while (nWrite < BLOCK_COUNT) {
  104. uint32_t nProduced = RATE_KB_PER_SEC*(millis() - startTime)/512UL;
  105. uint32_t queueSize = nProduced - nWrite;
  106. if (queueSize == 0) continue;
  107. if (queueSize > maxQueueSize) {
  108. maxQueueSize = queueSize;
  109. }
  110. if ((millis() - startTime - dotCount*DOT_TIME_MS) > DOT_TIME_MS) {
  111. if (maxQueueSize != maxQueuePrint) {
  112. cout << F("\nQ: ") << maxQueueSize << endl;
  113. maxQueuePrint = maxQueueSize;
  114. } else {
  115. cout << ".";
  116. if (++dotCount%10 == 0) {
  117. cout << endl;
  118. }
  119. }
  120. }
  121. // put block number at start of first line in block
  122. uint32_t n = b++;
  123. for (int8_t d = 5; d >= 0; d--) {
  124. pCache[d] = n || d == 5 ? n % 10 + '0' : ' ';
  125. n /= 10;
  126. }
  127. // write a 512 byte block
  128. uint32_t tw = micros();
  129. if (!sd.card()->writeData(pCache)) {
  130. error("writeData failed");
  131. }
  132. tw = micros() - tw;
  133. totalWriteTime += tw;
  134. // check for max write time
  135. if (tw > maxWriteTime) {
  136. maxWriteTime = tw;
  137. }
  138. if (tw < minWriteTime) {
  139. minWriteTime = tw;
  140. }
  141. nWrite++;
  142. }
  143. uint32_t endTime = millis();
  144. uint32_t avgWriteTime = totalWriteTime/BLOCK_COUNT;
  145. // end multiple block write mode
  146. if (!sd.card()->writeStop()) {
  147. error("writeStop failed");
  148. }
  149. cout << F("\nDone\n");
  150. cout << F("maxQueueSize: ") << maxQueueSize << endl;
  151. cout << F("Elapsed time: ") << setprecision(3)<< 1.e-3*(endTime - startTime);
  152. cout << F(" seconds\n");
  153. cout << F("Min block write time: ") << minWriteTime << F(" micros\n");
  154. cout << F("Max block write time: ") << maxWriteTime << F(" micros\n");
  155. cout << F("Avg block write time: ") << avgWriteTime << F(" micros\n");
  156. // close file for next pass of loop
  157. file.close();
  158. Serial.println();
  159. }