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.

181 lines
5.1KB

  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 one block every MICROS_PER_BLOCK.
  7. *
  8. * If a high quality SanDisk card is used with this program
  9. * no overruns occur and the maximum block write time is
  10. * under 2000 micros.
  11. *
  12. * Note: Apps should create a very large file then truncates it
  13. * to the length that is used for a logging. It only takes
  14. * a few seconds to erase a 500 MB file since the card only
  15. * marks the blocks as erased; no data transfer is required.
  16. */
  17. #include <SPI.h>
  18. #include "SdFat.h"
  19. #include "FreeStack.h"
  20. // SD chip select pin
  21. const uint8_t chipSelect = SS;
  22. // number of blocks in the contiguous file
  23. const uint32_t BLOCK_COUNT = 10000UL;
  24. // time to produce a block of data
  25. const uint32_t MICROS_PER_BLOCK = 10000;
  26. // file system
  27. SdFat sd;
  28. // test file
  29. SdFile file;
  30. // file extent
  31. uint32_t bgnBlock, endBlock;
  32. // Serial output stream
  33. ArduinoOutStream cout(Serial);
  34. //------------------------------------------------------------------------------
  35. // store error strings in flash to save RAM
  36. #define error(s) sd.errorHalt(F(s))
  37. //------------------------------------------------------------------------------
  38. // log of first overruns
  39. #define OVER_DIM 20
  40. struct {
  41. uint32_t block;
  42. uint32_t micros;
  43. } over[OVER_DIM];
  44. //------------------------------------------------------------------------------
  45. void setup(void) {
  46. Serial.begin(9600);
  47. // Wait for USB Serial
  48. while (!Serial) {
  49. SysCall::yield();
  50. }
  51. }
  52. //------------------------------------------------------------------------------
  53. void loop(void) {
  54. // Read any extra Serial data.
  55. do {
  56. delay(10);
  57. } while (Serial.available() && Serial.read() >= 0);
  58. // F stores strings in flash to save RAM
  59. cout << F("Type any character to start\n");
  60. while (!Serial.available()) {
  61. SysCall::yield();
  62. }
  63. cout << F("FreeStack: ") << FreeStack() << endl;
  64. // initialize the SD card at SPI_FULL_SPEED for best performance.
  65. // try SPI_HALF_SPEED if bus errors occur.
  66. if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
  67. sd.initErrorHalt();
  68. }
  69. // delete possible existing file
  70. sd.remove("RawWrite.txt");
  71. // create a contiguous file
  72. if (!file.createContiguous(sd.vwd(), "RawWrite.txt", 512UL*BLOCK_COUNT)) {
  73. error("createContiguous failed");
  74. }
  75. // get the location of the file's blocks
  76. if (!file.contiguousRange(&bgnBlock, &endBlock)) {
  77. error("contiguousRange failed");
  78. }
  79. //*********************NOTE**************************************
  80. // NO SdFile calls are allowed while cache is used for raw writes
  81. //***************************************************************
  82. // clear the cache and use it as a 512 byte buffer
  83. uint8_t* pCache = (uint8_t*)sd.vol()->cacheClear();
  84. // fill cache with eight lines of 64 bytes each
  85. memset(pCache, ' ', 512);
  86. for (uint16_t i = 0; i < 512; i += 64) {
  87. // put line number at end of line then CR/LF
  88. pCache[i + 61] = '0' + (i/64);
  89. pCache[i + 62] = '\r';
  90. pCache[i + 63] = '\n';
  91. }
  92. cout << F("Start raw write of ") << file.fileSize() << F(" bytes at\n");
  93. cout << 512000000UL/MICROS_PER_BLOCK << F(" bytes per second\n");
  94. cout << F("Please wait ") << (BLOCK_COUNT*MICROS_PER_BLOCK)/1000000UL;
  95. cout << F(" seconds\n");
  96. // tell card to setup for multiple block write with pre-erase
  97. if (!sd.card()->writeStart(bgnBlock, BLOCK_COUNT)) {
  98. error("writeStart failed");
  99. }
  100. // init stats
  101. uint16_t overruns = 0;
  102. uint32_t maxWriteTime = 0;
  103. uint32_t t = micros();
  104. uint32_t tNext = t;
  105. // write data
  106. for (uint32_t b = 0; b < BLOCK_COUNT; b++) {
  107. // write must be done by this time
  108. tNext += MICROS_PER_BLOCK;
  109. // put block number at start of first line in block
  110. uint32_t n = b;
  111. for (int8_t d = 5; d >= 0; d--) {
  112. pCache[d] = n || d == 5 ? n % 10 + '0' : ' ';
  113. n /= 10;
  114. }
  115. // write a 512 byte block
  116. uint32_t tw = micros();
  117. if (!sd.card()->writeData(pCache)) {
  118. error("writeData failed");
  119. }
  120. tw = micros() - tw;
  121. // check for max write time
  122. if (tw > maxWriteTime) {
  123. maxWriteTime = tw;
  124. }
  125. // check for overrun
  126. if (micros() > tNext) {
  127. if (overruns < OVER_DIM) {
  128. over[overruns].block = b;
  129. over[overruns].micros = tw;
  130. }
  131. overruns++;
  132. // advance time to reflect overrun
  133. tNext = micros();
  134. } else {
  135. // wait for time to write next block
  136. while(micros() < tNext);
  137. }
  138. }
  139. // total write time
  140. t = micros() - t;
  141. // end multiple block write mode
  142. if (!sd.card()->writeStop()) {
  143. error("writeStop failed");
  144. }
  145. cout << F("Done\n");
  146. cout << F("Elapsed time: ") << setprecision(3)<< 1.e-6*t;
  147. cout << F(" seconds\n");
  148. cout << F("Max write time: ") << maxWriteTime << F(" micros\n");
  149. cout << F("Overruns: ") << overruns << endl;
  150. if (overruns) {
  151. uint8_t n = overruns > OVER_DIM ? OVER_DIM : overruns;
  152. cout << F("fileBlock,micros") << endl;
  153. for (uint8_t i = 0; i < n; i++) {
  154. cout << over[i].block << ',' << over[i].micros << endl;
  155. }
  156. }
  157. // close file for next pass of loop
  158. file.close();
  159. Serial.println();
  160. }