TeensySdioLogger.ino 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Test Teensy SDIO with write busy in a data logger demo.
  2. //
  3. // The driver writes to the uSDHC controller's FIFO then returns
  4. // while the controller writes the data to the SD. The first sector
  5. // puts the controller in write mode and takes about 11 usec on a
  6. // Teensy 4.1. About 5 usec is required to write a sector when the
  7. // controller is in write mode.
  8. #include "SdFat.h"
  9. #include "RingBuf.h"
  10. // Use Teensy SDIO
  11. #define SD_CONFIG SdioConfig(FIFO_SDIO)
  12. // Interval between points for 25 ksps.
  13. #define LOG_INTERVAL_USEC 40
  14. // Size to log 10 byte lines at 25 kHz for more than ten minutes.
  15. #define LOG_FILE_SIZE 10*25000*600 // 150,000,000 bytes.
  16. // Space to hold more than 800 ms of data for 10 byte lines at 25 ksps.
  17. #define RING_BUF_CAPACITY 400*512
  18. #define LOG_FILENAME "SdioLogger.csv"
  19. SdFs sd;
  20. FsFile file;
  21. // RingBuf for File type FsFile.
  22. RingBuf<FsFile, RING_BUF_CAPACITY> rb;
  23. void logData() {
  24. // Initialize the SD.
  25. if (!sd.begin(SD_CONFIG)) {
  26. sd.initErrorHalt(&Serial);
  27. }
  28. // Open or create file - truncate existing file.
  29. if (!file.open(LOG_FILENAME, O_RDWR | O_CREAT | O_TRUNC)) {
  30. Serial.println("open failed\n");
  31. return;
  32. }
  33. // File must be pre-allocated to avoid huge
  34. // delays searching for free clusters.
  35. if (!file.preAllocate(LOG_FILE_SIZE)) {
  36. Serial.println("preAllocate failed\n");
  37. file.close();
  38. return;
  39. }
  40. // initialize the RingBuf.
  41. rb.begin(&file);
  42. Serial.println("Type any character to stop");
  43. // Max RingBuf used bytes. Useful to understand RingBuf overrun.
  44. size_t maxUsed = 0;
  45. // Min spare micros in loop.
  46. int32_t minSpareMicros = INT32_MAX;
  47. // Start time.
  48. uint32_t logTime = micros();
  49. // Log data until Serial input or file full.
  50. while (!Serial.available()) {
  51. // Amount of data in ringBuf.
  52. size_t n = rb.bytesUsed();
  53. if ((n + file.curPosition()) > (LOG_FILE_SIZE - 20)) {
  54. Serial.println("File full - quitting.");
  55. break;
  56. }
  57. if (n > maxUsed) {
  58. maxUsed = n;
  59. }
  60. if (n >= 512 && !file.isBusy()) {
  61. // Not busy only allows one sector before possible busy wait.
  62. // Write one sector from RingBuf to file.
  63. if (512 != rb.writeOut(512)) {
  64. Serial.println("writeOut failed");
  65. break;
  66. }
  67. }
  68. // Time for next point.
  69. logTime += LOG_INTERVAL_USEC;
  70. int32_t spareMicros = logTime - micros();
  71. if (spareMicros < minSpareMicros) {
  72. minSpareMicros = spareMicros;
  73. }
  74. if (spareMicros <= 0) {
  75. Serial.print("Rate too fast ");
  76. Serial.println(spareMicros);
  77. break;
  78. }
  79. // Wait until time to log data.
  80. while (micros() < logTime) {}
  81. // Read ADC0 - about 17 usec on Teensy 4, Teensy 3.6 is faster.
  82. uint16_t adc = analogRead(0);
  83. // Print spareMicros into the RingBuf as test data.
  84. rb.print(spareMicros);
  85. rb.write(',');
  86. // Print adc into RingBuf.
  87. rb.println(adc);
  88. if (rb.getWriteError()) {
  89. // Error caused by too few free bytes in RingBuf.
  90. Serial.println("WriteError");
  91. break;
  92. }
  93. }
  94. // Write any RingBuf data to file.
  95. rb.sync();
  96. file.truncate();
  97. file.rewind();
  98. // Print first twenty lines of file.
  99. Serial.println("spareMicros,ADC0");
  100. for (uint8_t n = 0; n < 20 && file.available();) {
  101. int c = file.read();
  102. if (c < 0) {
  103. break;
  104. }
  105. Serial.write(c);
  106. if (c == '\n') n++;
  107. }
  108. Serial.print("fileSize: ");
  109. Serial.println((uint32_t)file.fileSize());
  110. Serial.print("maxBytesUsed: ");
  111. Serial.println(maxUsed);
  112. Serial.print("minSpareMicros: ");
  113. Serial.println(minSpareMicros);
  114. file.close();
  115. }
  116. void clearSerialInput() {
  117. for (uint32_t m = micros(); micros() - m < 10000;) {
  118. if (Serial.read() >= 0) {
  119. m = micros();
  120. }
  121. }
  122. }
  123. void setup() {
  124. Serial.begin(9600);
  125. while (!Serial) {}
  126. // Go faster or log more channels. ADC quality will suffer.
  127. // analogReadAveraging(1);
  128. }
  129. void loop() {
  130. clearSerialInput();
  131. Serial.println("Type any character to start");
  132. while (!Serial.available()) {};
  133. clearSerialInput();
  134. logData();
  135. }