Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

AnalogBinLogger.ino 24KB

pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 10 gadiem
pirms 8 gadiem
pirms 8 gadiem
pirms 10 gadiem
pirms 8 gadiem
pirms 8 gadiem
pirms 10 gadiem
pirms 10 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. /**
  2. * This program logs data from the Arduino ADC to a binary file.
  3. *
  4. * Samples are logged at regular intervals. Each Sample consists of the ADC
  5. * values for the analog pins defined in the PIN_LIST array. The pins numbers
  6. * may be in any order.
  7. *
  8. * Edit the configuration constants below to set the sample pins, sample rate,
  9. * and other configuration values.
  10. *
  11. * If your SD card has a long write latency, it may be necessary to use
  12. * slower sample rates. Using a Mega Arduino helps overcome latency
  13. * problems since 13 512 byte buffers will be used.
  14. *
  15. * Each 512 byte data block in the file has a four byte header followed by up
  16. * to 508 bytes of data. (508 values in 8-bit mode or 254 values in 10-bit mode)
  17. * Each block contains an integral number of samples with unused space at the
  18. * end of the block.
  19. *
  20. * Data is written to the file using a SD multiple block write command.
  21. */
  22. #ifdef __AVR__
  23. #include <SPI.h>
  24. #include "SdFat.h"
  25. #include "FreeStack.h"
  26. #include "AnalogBinLogger.h"
  27. //------------------------------------------------------------------------------
  28. // Analog pin number list for a sample. Pins may be in any order and pin
  29. // numbers may be repeated.
  30. const uint8_t PIN_LIST[] = {0, 1, 2, 3, 4};
  31. //------------------------------------------------------------------------------
  32. // Sample rate in samples per second.
  33. const float SAMPLE_RATE = 5000; // Must be 0.25 or greater.
  34. // The interval between samples in seconds, SAMPLE_INTERVAL, may be set to a
  35. // constant instead of being calculated from SAMPLE_RATE. SAMPLE_RATE is not
  36. // used in the code below. For example, setting SAMPLE_INTERVAL = 2.0e-4
  37. // will result in a 200 microsecond sample interval.
  38. const float SAMPLE_INTERVAL = 1.0/SAMPLE_RATE;
  39. // Setting ROUND_SAMPLE_INTERVAL non-zero will cause the sample interval to
  40. // be rounded to a a multiple of the ADC clock period and will reduce sample
  41. // time jitter.
  42. #define ROUND_SAMPLE_INTERVAL 1
  43. //------------------------------------------------------------------------------
  44. // ADC clock rate.
  45. // The ADC clock rate is normally calculated from the pin count and sample
  46. // interval. The calculation attempts to use the lowest possible ADC clock
  47. // rate.
  48. //
  49. // You can select an ADC clock rate by defining the symbol ADC_PRESCALER to
  50. // one of these values. You must choose an appropriate ADC clock rate for
  51. // your sample interval.
  52. // #define ADC_PRESCALER 7 // F_CPU/128 125 kHz on an Uno
  53. // #define ADC_PRESCALER 6 // F_CPU/64 250 kHz on an Uno
  54. // #define ADC_PRESCALER 5 // F_CPU/32 500 kHz on an Uno
  55. // #define ADC_PRESCALER 4 // F_CPU/16 1000 kHz on an Uno
  56. // #define ADC_PRESCALER 3 // F_CPU/8 2000 kHz on an Uno (8-bit mode only)
  57. //------------------------------------------------------------------------------
  58. // Reference voltage. See the processor data-sheet for reference details.
  59. // uint8_t const ADC_REF = 0; // External Reference AREF pin.
  60. uint8_t const ADC_REF = (1 << REFS0); // Vcc Reference.
  61. // uint8_t const ADC_REF = (1 << REFS1); // Internal 1.1 (only 644 1284P Mega)
  62. // uint8_t const ADC_REF = (1 << REFS1) | (1 << REFS0); // Internal 1.1 or 2.56
  63. //------------------------------------------------------------------------------
  64. // File definitions.
  65. //
  66. // Maximum file size in blocks.
  67. // The program creates a contiguous file with FILE_BLOCK_COUNT 512 byte blocks.
  68. // This file is flash erased using special SD commands. The file will be
  69. // truncated if logging is stopped early.
  70. const uint32_t FILE_BLOCK_COUNT = 256000;
  71. // log file base name. Must be six characters or less.
  72. #define FILE_BASE_NAME "analog"
  73. // Set RECORD_EIGHT_BITS non-zero to record only the high 8-bits of the ADC.
  74. #define RECORD_EIGHT_BITS 0
  75. //------------------------------------------------------------------------------
  76. // Pin definitions.
  77. //
  78. // Digital pin to indicate an error, set to -1 if not used.
  79. // The led blinks for fatal errors. The led goes on solid for SD write
  80. // overrun errors and logging continues.
  81. const int8_t ERROR_LED_PIN = 3;
  82. // SD chip select pin.
  83. const uint8_t SD_CS_PIN = SS;
  84. //------------------------------------------------------------------------------
  85. // Buffer definitions.
  86. //
  87. // The logger will use SdFat's buffer plus BUFFER_BLOCK_COUNT additional
  88. // buffers. QUEUE_DIM must be a power of two larger than
  89. //(BUFFER_BLOCK_COUNT + 1).
  90. //
  91. #if RAMEND < 0X8FF
  92. #error Too little SRAM
  93. //
  94. #elif RAMEND < 0X10FF
  95. // Use total of two 512 byte buffers.
  96. const uint8_t BUFFER_BLOCK_COUNT = 1;
  97. // Dimension for queues of 512 byte SD blocks.
  98. const uint8_t QUEUE_DIM = 4; // Must be a power of two!
  99. //
  100. #elif RAMEND < 0X20FF
  101. // Use total of five 512 byte buffers.
  102. const uint8_t BUFFER_BLOCK_COUNT = 4;
  103. // Dimension for queues of 512 byte SD blocks.
  104. const uint8_t QUEUE_DIM = 8; // Must be a power of two!
  105. //
  106. #elif RAMEND < 0X40FF
  107. // Use total of 13 512 byte buffers.
  108. const uint8_t BUFFER_BLOCK_COUNT = 12;
  109. // Dimension for queues of 512 byte SD blocks.
  110. const uint8_t QUEUE_DIM = 16; // Must be a power of two!
  111. //
  112. #else // RAMEND
  113. // Use total of 29 512 byte buffers.
  114. const uint8_t BUFFER_BLOCK_COUNT = 28;
  115. // Dimension for queues of 512 byte SD blocks.
  116. const uint8_t QUEUE_DIM = 32; // Must be a power of two!
  117. #endif // RAMEND
  118. //==============================================================================
  119. // End of configuration constants.
  120. //==============================================================================
  121. // Temporary log file. Will be deleted if a reset or power failure occurs.
  122. #define TMP_FILE_NAME "tmp_log.bin"
  123. // Size of file base name. Must not be larger than six.
  124. const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
  125. // Number of analog pins to log.
  126. const uint8_t PIN_COUNT = sizeof(PIN_LIST)/sizeof(PIN_LIST[0]);
  127. // Minimum ADC clock cycles per sample interval
  128. const uint16_t MIN_ADC_CYCLES = 15;
  129. // Extra cpu cycles to setup ADC with more than one pin per sample.
  130. const uint16_t ISR_SETUP_ADC = PIN_COUNT > 1 ? 100 : 0;
  131. // Maximum cycles for timer0 system interrupt, millis, micros.
  132. const uint16_t ISR_TIMER0 = 160;
  133. //==============================================================================
  134. SdFat sd;
  135. SdBaseFile binFile;
  136. char binName[13] = FILE_BASE_NAME "00.bin";
  137. #if RECORD_EIGHT_BITS
  138. const size_t SAMPLES_PER_BLOCK = DATA_DIM8/PIN_COUNT;
  139. typedef block8_t block_t;
  140. #else // RECORD_EIGHT_BITS
  141. const size_t SAMPLES_PER_BLOCK = DATA_DIM16/PIN_COUNT;
  142. typedef block16_t block_t;
  143. #endif // RECORD_EIGHT_BITS
  144. block_t* emptyQueue[QUEUE_DIM];
  145. uint8_t emptyHead;
  146. uint8_t emptyTail;
  147. block_t* fullQueue[QUEUE_DIM];
  148. volatile uint8_t fullHead; // volatile insures non-interrupt code sees changes.
  149. uint8_t fullTail;
  150. // queueNext assumes QUEUE_DIM is a power of two
  151. inline uint8_t queueNext(uint8_t ht) {
  152. return (ht + 1) & (QUEUE_DIM -1);
  153. }
  154. //==============================================================================
  155. // Interrupt Service Routines
  156. // Pointer to current buffer.
  157. block_t* isrBuf;
  158. // Need new buffer if true.
  159. bool isrBufNeeded = true;
  160. // overrun count
  161. uint16_t isrOver = 0;
  162. // ADC configuration for each pin.
  163. uint8_t adcmux[PIN_COUNT];
  164. uint8_t adcsra[PIN_COUNT];
  165. uint8_t adcsrb[PIN_COUNT];
  166. uint8_t adcindex = 1;
  167. // Insure no timer events are missed.
  168. volatile bool timerError = false;
  169. volatile bool timerFlag = false;
  170. //------------------------------------------------------------------------------
  171. // ADC done interrupt.
  172. ISR(ADC_vect) {
  173. // Read ADC data.
  174. #if RECORD_EIGHT_BITS
  175. uint8_t d = ADCH;
  176. #else // RECORD_EIGHT_BITS
  177. // This will access ADCL first.
  178. uint16_t d = ADC;
  179. #endif // RECORD_EIGHT_BITS
  180. if (isrBufNeeded && emptyHead == emptyTail) {
  181. // no buffers - count overrun
  182. if (isrOver < 0XFFFF) {
  183. isrOver++;
  184. }
  185. // Avoid missed timer error.
  186. timerFlag = false;
  187. return;
  188. }
  189. // Start ADC
  190. if (PIN_COUNT > 1) {
  191. ADMUX = adcmux[adcindex];
  192. ADCSRB = adcsrb[adcindex];
  193. ADCSRA = adcsra[adcindex];
  194. if (adcindex == 0) {
  195. timerFlag = false;
  196. }
  197. adcindex = adcindex < (PIN_COUNT - 1) ? adcindex + 1 : 0;
  198. } else {
  199. timerFlag = false;
  200. }
  201. // Check for buffer needed.
  202. if (isrBufNeeded) {
  203. // Remove buffer from empty queue.
  204. isrBuf = emptyQueue[emptyTail];
  205. emptyTail = queueNext(emptyTail);
  206. isrBuf->count = 0;
  207. isrBuf->overrun = isrOver;
  208. isrBufNeeded = false;
  209. }
  210. // Store ADC data.
  211. isrBuf->data[isrBuf->count++] = d;
  212. // Check for buffer full.
  213. if (isrBuf->count >= PIN_COUNT*SAMPLES_PER_BLOCK) {
  214. // Put buffer isrIn full queue.
  215. uint8_t tmp = fullHead; // Avoid extra fetch of volatile fullHead.
  216. fullQueue[tmp] = (block_t*)isrBuf;
  217. fullHead = queueNext(tmp);
  218. // Set buffer needed and clear overruns.
  219. isrBufNeeded = true;
  220. isrOver = 0;
  221. }
  222. }
  223. //------------------------------------------------------------------------------
  224. // timer1 interrupt to clear OCF1B
  225. ISR(TIMER1_COMPB_vect) {
  226. // Make sure ADC ISR responded to timer event.
  227. if (timerFlag) {
  228. timerError = true;
  229. }
  230. timerFlag = true;
  231. }
  232. //==============================================================================
  233. // Error messages stored in flash.
  234. #define error(msg) {sd.errorPrint(F(msg));fatalBlink();}
  235. //------------------------------------------------------------------------------
  236. //
  237. void fatalBlink() {
  238. while (true) {
  239. if (ERROR_LED_PIN >= 0) {
  240. digitalWrite(ERROR_LED_PIN, HIGH);
  241. delay(200);
  242. digitalWrite(ERROR_LED_PIN, LOW);
  243. delay(200);
  244. }
  245. }
  246. }
  247. //==============================================================================
  248. #if ADPS0 != 0 || ADPS1 != 1 || ADPS2 != 2
  249. #error unexpected ADC prescaler bits
  250. #endif
  251. //------------------------------------------------------------------------------
  252. // initialize ADC and timer1
  253. void adcInit(metadata_t* meta) {
  254. uint8_t adps; // prescaler bits for ADCSRA
  255. uint32_t ticks = F_CPU*SAMPLE_INTERVAL + 0.5; // Sample interval cpu cycles.
  256. if (ADC_REF & ~((1 << REFS0) | (1 << REFS1))) {
  257. error("Invalid ADC reference");
  258. }
  259. #ifdef ADC_PRESCALER
  260. if (ADC_PRESCALER > 7 || ADC_PRESCALER < 2) {
  261. error("Invalid ADC prescaler");
  262. }
  263. adps = ADC_PRESCALER;
  264. #else // ADC_PRESCALER
  265. // Allow extra cpu cycles to change ADC settings if more than one pin.
  266. int32_t adcCycles = (ticks - ISR_TIMER0)/PIN_COUNT - ISR_SETUP_ADC;
  267. for (adps = 7; adps > 0; adps--) {
  268. if (adcCycles >= (MIN_ADC_CYCLES << adps)) {
  269. break;
  270. }
  271. }
  272. #endif // ADC_PRESCALER
  273. meta->adcFrequency = F_CPU >> adps;
  274. if (meta->adcFrequency > (RECORD_EIGHT_BITS ? 2000000 : 1000000)) {
  275. error("Sample Rate Too High");
  276. }
  277. #if ROUND_SAMPLE_INTERVAL
  278. // Round so interval is multiple of ADC clock.
  279. ticks += 1 << (adps - 1);
  280. ticks >>= adps;
  281. ticks <<= adps;
  282. #endif // ROUND_SAMPLE_INTERVAL
  283. if (PIN_COUNT > sizeof(meta->pinNumber)/sizeof(meta->pinNumber[0])) {
  284. error("Too many pins");
  285. }
  286. meta->pinCount = PIN_COUNT;
  287. meta->recordEightBits = RECORD_EIGHT_BITS;
  288. for (int i = 0; i < PIN_COUNT; i++) {
  289. uint8_t pin = PIN_LIST[i];
  290. if (pin >= NUM_ANALOG_INPUTS) {
  291. error("Invalid Analog pin number");
  292. }
  293. meta->pinNumber[i] = pin;
  294. // Set ADC reference and low three bits of analog pin number.
  295. adcmux[i] = (pin & 7) | ADC_REF;
  296. if (RECORD_EIGHT_BITS) {
  297. adcmux[i] |= 1 << ADLAR;
  298. }
  299. // If this is the first pin, trigger on timer/counter 1 compare match B.
  300. adcsrb[i] = i == 0 ? (1 << ADTS2) | (1 << ADTS0) : 0;
  301. #ifdef MUX5
  302. if (pin > 7) {
  303. adcsrb[i] |= (1 << MUX5);
  304. }
  305. #endif // MUX5
  306. adcsra[i] = (1 << ADEN) | (1 << ADIE) | adps;
  307. adcsra[i] |= i == 0 ? 1 << ADATE : 1 << ADSC;
  308. }
  309. // Setup timer1
  310. TCCR1A = 0;
  311. uint8_t tshift;
  312. if (ticks < 0X10000) {
  313. // no prescale, CTC mode
  314. TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10);
  315. tshift = 0;
  316. } else if (ticks < 0X10000*8) {
  317. // prescale 8, CTC mode
  318. TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
  319. tshift = 3;
  320. } else if (ticks < 0X10000*64) {
  321. // prescale 64, CTC mode
  322. TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11) | (1 << CS10);
  323. tshift = 6;
  324. } else if (ticks < 0X10000*256) {
  325. // prescale 256, CTC mode
  326. TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12);
  327. tshift = 8;
  328. } else if (ticks < 0X10000*1024) {
  329. // prescale 1024, CTC mode
  330. TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
  331. tshift = 10;
  332. } else {
  333. error("Sample Rate Too Slow");
  334. }
  335. // divide by prescaler
  336. ticks >>= tshift;
  337. // set TOP for timer reset
  338. ICR1 = ticks - 1;
  339. // compare for ADC start
  340. OCR1B = 0;
  341. // multiply by prescaler
  342. ticks <<= tshift;
  343. // Sample interval in CPU clock ticks.
  344. meta->sampleInterval = ticks;
  345. meta->cpuFrequency = F_CPU;
  346. float sampleRate = (float)meta->cpuFrequency/meta->sampleInterval;
  347. Serial.print(F("Sample pins:"));
  348. for (uint8_t i = 0; i < meta->pinCount; i++) {
  349. Serial.print(' ');
  350. Serial.print(meta->pinNumber[i], DEC);
  351. }
  352. Serial.println();
  353. Serial.print(F("ADC bits: "));
  354. Serial.println(meta->recordEightBits ? 8 : 10);
  355. Serial.print(F("ADC clock kHz: "));
  356. Serial.println(meta->adcFrequency/1000);
  357. Serial.print(F("Sample Rate: "));
  358. Serial.println(sampleRate);
  359. Serial.print(F("Sample interval usec: "));
  360. Serial.println(1000000.0/sampleRate, 4);
  361. }
  362. //------------------------------------------------------------------------------
  363. // enable ADC and timer1 interrupts
  364. void adcStart() {
  365. // initialize ISR
  366. isrBufNeeded = true;
  367. isrOver = 0;
  368. adcindex = 1;
  369. // Clear any pending interrupt.
  370. ADCSRA |= 1 << ADIF;
  371. // Setup for first pin.
  372. ADMUX = adcmux[0];
  373. ADCSRB = adcsrb[0];
  374. ADCSRA = adcsra[0];
  375. // Enable timer1 interrupts.
  376. timerError = false;
  377. timerFlag = false;
  378. TCNT1 = 0;
  379. TIFR1 = 1 << OCF1B;
  380. TIMSK1 = 1 << OCIE1B;
  381. }
  382. //------------------------------------------------------------------------------
  383. void adcStop() {
  384. TIMSK1 = 0;
  385. ADCSRA = 0;
  386. }
  387. //------------------------------------------------------------------------------
  388. // Convert binary file to csv file.
  389. void binaryToCsv() {
  390. uint8_t lastPct = 0;
  391. block_t buf;
  392. metadata_t* pm;
  393. uint32_t t0 = millis();
  394. char csvName[13];
  395. StdioStream csvStream;
  396. if (!binFile.isOpen()) {
  397. Serial.println(F("No current binary file"));
  398. return;
  399. }
  400. binFile.rewind();
  401. if (!binFile.read(&buf , 512) == 512) {
  402. error("Read metadata failed");
  403. }
  404. // Create a new csv file.
  405. strcpy(csvName, binName);
  406. strcpy(&csvName[BASE_NAME_SIZE + 3], "csv");
  407. if (!csvStream.fopen(csvName, "w")) {
  408. error("open csvStream failed");
  409. }
  410. Serial.println();
  411. Serial.print(F("Writing: "));
  412. Serial.print(csvName);
  413. Serial.println(F(" - type any character to stop"));
  414. pm = (metadata_t*)&buf;
  415. csvStream.print(F("Interval,"));
  416. float intervalMicros = 1.0e6*pm->sampleInterval/(float)pm->cpuFrequency;
  417. csvStream.print(intervalMicros, 4);
  418. csvStream.println(F(",usec"));
  419. for (uint8_t i = 0; i < pm->pinCount; i++) {
  420. if (i) {
  421. csvStream.putc(',');
  422. }
  423. csvStream.print(F("pin"));
  424. csvStream.print(pm->pinNumber[i]);
  425. }
  426. csvStream.println();
  427. uint32_t tPct = millis();
  428. while (!Serial.available() && binFile.read(&buf, 512) == 512) {
  429. if (buf.count == 0) {
  430. break;
  431. }
  432. if (buf.overrun) {
  433. csvStream.print(F("OVERRUN,"));
  434. csvStream.println(buf.overrun);
  435. }
  436. for (uint16_t j = 0; j < buf.count; j += PIN_COUNT) {
  437. for (uint16_t i = 0; i < PIN_COUNT; i++) {
  438. if (i) {
  439. csvStream.putc(',');
  440. }
  441. csvStream.print(buf.data[i + j]);
  442. }
  443. csvStream.println();
  444. }
  445. if ((millis() - tPct) > 1000) {
  446. uint8_t pct = binFile.curPosition()/(binFile.fileSize()/100);
  447. if (pct != lastPct) {
  448. tPct = millis();
  449. lastPct = pct;
  450. Serial.print(pct, DEC);
  451. Serial.println('%');
  452. }
  453. }
  454. if (Serial.available()) {
  455. break;
  456. }
  457. }
  458. csvStream.fclose();
  459. Serial.print(F("Done: "));
  460. Serial.print(0.001*(millis() - t0));
  461. Serial.println(F(" Seconds"));
  462. }
  463. //------------------------------------------------------------------------------
  464. // read data file and check for overruns
  465. void checkOverrun() {
  466. bool headerPrinted = false;
  467. block_t buf;
  468. uint32_t bgnBlock, endBlock;
  469. uint32_t bn = 0;
  470. if (!binFile.isOpen()) {
  471. Serial.println(F("No current binary file"));
  472. return;
  473. }
  474. if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
  475. error("contiguousRange failed");
  476. }
  477. binFile.rewind();
  478. Serial.println();
  479. Serial.println(F("Checking overrun errors - type any character to stop"));
  480. if (!binFile.read(&buf , 512) == 512) {
  481. error("Read metadata failed");
  482. }
  483. bn++;
  484. while (binFile.read(&buf, 512) == 512) {
  485. if (buf.count == 0) {
  486. break;
  487. }
  488. if (buf.overrun) {
  489. if (!headerPrinted) {
  490. Serial.println();
  491. Serial.println(F("Overruns:"));
  492. Serial.println(F("fileBlockNumber,sdBlockNumber,overrunCount"));
  493. headerPrinted = true;
  494. }
  495. Serial.print(bn);
  496. Serial.print(',');
  497. Serial.print(bgnBlock + bn);
  498. Serial.print(',');
  499. Serial.println(buf.overrun);
  500. }
  501. bn++;
  502. }
  503. if (!headerPrinted) {
  504. Serial.println(F("No errors found"));
  505. } else {
  506. Serial.println(F("Done"));
  507. }
  508. }
  509. //------------------------------------------------------------------------------
  510. // dump data file to Serial
  511. void dumpData() {
  512. block_t buf;
  513. if (!binFile.isOpen()) {
  514. Serial.println(F("No current binary file"));
  515. return;
  516. }
  517. binFile.rewind();
  518. if (binFile.read(&buf , 512) != 512) {
  519. error("Read metadata failed");
  520. }
  521. Serial.println();
  522. Serial.println(F("Type any character to stop"));
  523. delay(1000);
  524. while (!Serial.available() && binFile.read(&buf , 512) == 512) {
  525. if (buf.count == 0) {
  526. break;
  527. }
  528. if (buf.overrun) {
  529. Serial.print(F("OVERRUN,"));
  530. Serial.println(buf.overrun);
  531. }
  532. for (uint16_t i = 0; i < buf.count; i++) {
  533. Serial.print(buf.data[i], DEC);
  534. if ((i+1)%PIN_COUNT) {
  535. Serial.print(',');
  536. } else {
  537. Serial.println();
  538. }
  539. }
  540. }
  541. Serial.println(F("Done"));
  542. }
  543. //------------------------------------------------------------------------------
  544. // log data
  545. // max number of blocks to erase per erase call
  546. uint32_t const ERASE_SIZE = 262144L;
  547. void logData() {
  548. uint32_t bgnBlock, endBlock;
  549. // Allocate extra buffer space.
  550. block_t block[BUFFER_BLOCK_COUNT];
  551. Serial.println();
  552. // Initialize ADC and timer1.
  553. adcInit((metadata_t*) &block[0]);
  554. // Find unused file name.
  555. if (BASE_NAME_SIZE > 6) {
  556. error("FILE_BASE_NAME too long");
  557. }
  558. while (sd.exists(binName)) {
  559. if (binName[BASE_NAME_SIZE + 1] != '9') {
  560. binName[BASE_NAME_SIZE + 1]++;
  561. } else {
  562. binName[BASE_NAME_SIZE + 1] = '0';
  563. if (binName[BASE_NAME_SIZE] == '9') {
  564. error("Can't create file name");
  565. }
  566. binName[BASE_NAME_SIZE]++;
  567. }
  568. }
  569. // Delete old tmp file.
  570. if (sd.exists(TMP_FILE_NAME)) {
  571. Serial.println(F("Deleting tmp file"));
  572. if (!sd.remove(TMP_FILE_NAME)) {
  573. error("Can't remove tmp file");
  574. }
  575. }
  576. // Create new file.
  577. Serial.println(F("Creating new file"));
  578. binFile.close();
  579. if (!binFile.createContiguous(TMP_FILE_NAME, 512 * FILE_BLOCK_COUNT)) {
  580. error("createContiguous failed");
  581. }
  582. // Get the address of the file on the SD.
  583. if (!binFile.contiguousRange(&bgnBlock, &endBlock)) {
  584. error("contiguousRange failed");
  585. }
  586. // Use SdFat's internal buffer.
  587. uint8_t* cache = (uint8_t*)sd.vol()->cacheClear();
  588. if (cache == 0) {
  589. error("cacheClear failed");
  590. }
  591. // Flash erase all data in the file.
  592. Serial.println(F("Erasing all data"));
  593. uint32_t bgnErase = bgnBlock;
  594. uint32_t endErase;
  595. while (bgnErase < endBlock) {
  596. endErase = bgnErase + ERASE_SIZE;
  597. if (endErase > endBlock) {
  598. endErase = endBlock;
  599. }
  600. if (!sd.card()->erase(bgnErase, endErase)) {
  601. error("erase failed");
  602. }
  603. bgnErase = endErase + 1;
  604. }
  605. // Start a multiple block write.
  606. if (!sd.card()->writeStart(bgnBlock, FILE_BLOCK_COUNT)) {
  607. error("writeBegin failed");
  608. }
  609. // Write metadata.
  610. if (!sd.card()->writeData((uint8_t*)&block[0])) {
  611. error("Write metadata failed");
  612. }
  613. // Initialize queues.
  614. emptyHead = emptyTail = 0;
  615. fullHead = fullTail = 0;
  616. // Use SdFat buffer for one block.
  617. emptyQueue[emptyHead] = (block_t*)cache;
  618. emptyHead = queueNext(emptyHead);
  619. // Put rest of buffers in the empty queue.
  620. for (uint8_t i = 0; i < BUFFER_BLOCK_COUNT; i++) {
  621. emptyQueue[emptyHead] = &block[i];
  622. emptyHead = queueNext(emptyHead);
  623. }
  624. // Give SD time to prepare for big write.
  625. delay(1000);
  626. Serial.println(F("Logging - type any character to stop"));
  627. // Wait for Serial Idle.
  628. Serial.flush();
  629. delay(10);
  630. uint32_t bn = 1;
  631. uint32_t t0 = millis();
  632. uint32_t t1 = t0;
  633. uint32_t overruns = 0;
  634. uint32_t count = 0;
  635. uint32_t maxLatency = 0;
  636. // Start logging interrupts.
  637. adcStart();
  638. while (1) {
  639. if (fullHead != fullTail) {
  640. // Get address of block to write.
  641. block_t* pBlock = fullQueue[fullTail];
  642. // Write block to SD.
  643. uint32_t usec = micros();
  644. if (!sd.card()->writeData((uint8_t*)pBlock)) {
  645. error("write data failed");
  646. }
  647. usec = micros() - usec;
  648. t1 = millis();
  649. if (usec > maxLatency) {
  650. maxLatency = usec;
  651. }
  652. count += pBlock->count;
  653. // Add overruns and possibly light LED.
  654. if (pBlock->overrun) {
  655. overruns += pBlock->overrun;
  656. if (ERROR_LED_PIN >= 0) {
  657. digitalWrite(ERROR_LED_PIN, HIGH);
  658. }
  659. }
  660. // Move block to empty queue.
  661. emptyQueue[emptyHead] = pBlock;
  662. emptyHead = queueNext(emptyHead);
  663. fullTail = queueNext(fullTail);
  664. bn++;
  665. if (bn == FILE_BLOCK_COUNT) {
  666. // File full so stop ISR calls.
  667. adcStop();
  668. break;
  669. }
  670. }
  671. if (timerError) {
  672. error("Missed timer event - rate too high");
  673. }
  674. if (Serial.available()) {
  675. // Stop ISR calls.
  676. adcStop();
  677. if (isrBuf != 0 && isrBuf->count >= PIN_COUNT) {
  678. // Truncate to last complete sample.
  679. isrBuf->count = PIN_COUNT*(isrBuf->count/PIN_COUNT);
  680. // Put buffer in full queue.
  681. fullQueue[fullHead] = isrBuf;
  682. fullHead = queueNext(fullHead);
  683. isrBuf = 0;
  684. }
  685. if (fullHead == fullTail) {
  686. break;
  687. }
  688. }
  689. }
  690. if (!sd.card()->writeStop()) {
  691. error("writeStop failed");
  692. }
  693. // Truncate file if recording stopped early.
  694. if (bn != FILE_BLOCK_COUNT) {
  695. Serial.println(F("Truncating file"));
  696. if (!binFile.truncate(512L * bn)) {
  697. error("Can't truncate file");
  698. }
  699. }
  700. if (!binFile.rename(sd.vwd(), binName)) {
  701. error("Can't rename file");
  702. }
  703. Serial.print(F("File renamed: "));
  704. Serial.println(binName);
  705. Serial.print(F("Max block write usec: "));
  706. Serial.println(maxLatency);
  707. Serial.print(F("Record time sec: "));
  708. Serial.println(0.001*(t1 - t0), 3);
  709. Serial.print(F("Sample count: "));
  710. Serial.println(count/PIN_COUNT);
  711. Serial.print(F("Samples/sec: "));
  712. Serial.println((1000.0/PIN_COUNT)*count/(t1-t0));
  713. Serial.print(F("Overruns: "));
  714. Serial.println(overruns);
  715. Serial.println(F("Done"));
  716. }
  717. //------------------------------------------------------------------------------
  718. void setup(void) {
  719. if (ERROR_LED_PIN >= 0) {
  720. pinMode(ERROR_LED_PIN, OUTPUT);
  721. }
  722. Serial.begin(9600);
  723. // Read the first sample pin to init the ADC.
  724. analogRead(PIN_LIST[0]);
  725. Serial.print(F("FreeStack: "));
  726. Serial.println(FreeStack());
  727. // Initialize at the highest speed supported by the board that is
  728. // not over 50 MHz. Try a lower speed if SPI errors occur.
  729. if (!sd.begin(SD_CS_PIN, SD_SCK_MHZ(50))) {
  730. sd.initErrorPrint();
  731. fatalBlink();
  732. }
  733. }
  734. //------------------------------------------------------------------------------
  735. void loop(void) {
  736. // Read any Serial data.
  737. do {
  738. delay(10);
  739. } while (Serial.available() && Serial.read() >= 0);
  740. Serial.println();
  741. Serial.println(F("type:"));
  742. Serial.println(F("c - convert file to csv"));
  743. Serial.println(F("d - dump data to Serial"));
  744. Serial.println(F("e - overrun error details"));
  745. Serial.println(F("r - record ADC data"));
  746. while(!Serial.available()) {
  747. SysCall::yield();
  748. }
  749. char c = tolower(Serial.read());
  750. if (ERROR_LED_PIN >= 0) {
  751. digitalWrite(ERROR_LED_PIN, LOW);
  752. }
  753. // Read any Serial data.
  754. do {
  755. delay(10);
  756. } while (Serial.available() && Serial.read() >= 0);
  757. if (c == 'c') {
  758. binaryToCsv();
  759. } else if (c == 'd') {
  760. dumpData();
  761. } else if (c == 'e') {
  762. checkOverrun();
  763. } else if (c == 'r') {
  764. logData();
  765. } else {
  766. Serial.println(F("Invalid entry"));
  767. }
  768. }
  769. #else // __AVR__
  770. #error This program is only for AVR.
  771. #endif // __AVR__