TeensySdioLogger.ino 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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 "RingBuf.h"
  9. #include "SdFat.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. }
  82. // Read ADC0 - about 17 usec on Teensy 4, Teensy 3.6 is faster.
  83. uint16_t adc = analogRead(0);
  84. // Print spareMicros into the RingBuf as test data.
  85. rb.print(spareMicros);
  86. rb.write(',');
  87. // Print adc into RingBuf.
  88. rb.println(adc);
  89. if (rb.getWriteError()) {
  90. // Error caused by too few free bytes in RingBuf.
  91. Serial.println("WriteError");
  92. break;
  93. }
  94. }
  95. // Write any RingBuf data to file.
  96. rb.sync();
  97. file.truncate();
  98. file.rewind();
  99. // Print first twenty lines of file.
  100. Serial.println("spareMicros,ADC0");
  101. for (uint8_t n = 0; n < 20 && file.available();) {
  102. int c = file.read();
  103. if (c < 0) {
  104. break;
  105. }
  106. Serial.write(c);
  107. if (c == '\n') n++;
  108. }
  109. Serial.print("fileSize: ");
  110. Serial.println((uint32_t)file.fileSize());
  111. Serial.print("maxBytesUsed: ");
  112. Serial.println(maxUsed);
  113. Serial.print("minSpareMicros: ");
  114. Serial.println(minSpareMicros);
  115. file.close();
  116. }
  117. void clearSerialInput() {
  118. for (uint32_t m = micros(); micros() - m < 10000;) {
  119. if (Serial.read() >= 0) {
  120. m = micros();
  121. }
  122. }
  123. }
  124. void setup() {
  125. Serial.begin(9600);
  126. while (!Serial) {
  127. }
  128. // Go faster or log more channels. ADC quality will suffer.
  129. // analogReadAveraging(1);
  130. }
  131. void loop() {
  132. clearSerialInput();
  133. Serial.println("Type any character to start");
  134. while (!Serial.available()) {
  135. }
  136. clearSerialInput();
  137. logData();
  138. }