| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 | // Test of Teensy exFAT DMA ADC logger.// This is mainly to test use of RingBuf in an ISR.// You should modify it for serious use as a data logger.//#include "DMAChannel.h"#include "SdFat.h"#include "FreeStack.h"#include "RingBuf.h"// 400 sector RingBuf - could be larger on Teensy 4.1.const size_t RING_BUF_SIZE = 400*512;// Preallocate 8GiB file.const uint64_t PRE_ALLOCATE_SIZE = 8ULL << 30;// Use FIFO SDIO.#define SD_CONFIG SdioConfig(FIFO_SDIO)DMAChannel dma(true);SdFs sd;FsFile file;//------------------------------------------------------------------------------// Ping-pong DMA buffer.DMAMEM static uint16_t __attribute__((aligned(32))) dmaBuf[2][256];size_t dmaCount;// RingBuf for 512 byte sectors.RingBuf<FsFile, RING_BUF_SIZE> rb;// Shared between ISR and background.volatile size_t maxBytesUsed;volatile bool overrun;//------------------------------------------------------------------------------//ISR.static void isr() {  if (rb.bytesFreeIsr() >= 512 && !overrun) {    rb.memcpyIn(dmaBuf[dmaCount & 1], 512);    dmaCount++;    if (rb.bytesUsed() > maxBytesUsed) {      maxBytesUsed = rb.bytesUsed();    }  } else {    overrun = true;  }  dma.clearComplete();  dma.clearInterrupt();#if defined(__IMXRT1062__)  // Handle clear interrupt glitch in Teensy 4.x!  asm("DSB");#endif  // defined(__IMXRT1062__)}//------------------------------------------------------------------------------// Over-clocking will degrade quality - use only for stress testing.void overclock() {#if defined(__IMXRT1062__) // Teensy 4.0  ADC1_CFG  =    // High Speed Configuration    ADC_CFG_ADHSC |    // Sample period 3 clocks    ADC_CFG_ADSTS(0) |    // Input clock    ADC_CFG_ADIV(0) |    // Not selected - Long Sample Time Configuration    // ADC_CFG_ADLSMP |    // 12-bit    ADC_CFG_MODE(2) |    // Asynchronous clock    ADC_CFG_ADICLK(3);#else // defined(__IMXRT1062__)  // Set 12 bit mode and max over-clock  ADC0_CFG1 =    // Clock divide select, 0=direct, 1=div2, 2=div4, 3=div8    ADC_CFG1_ADIV(0) |    // Sample time configuration, 0=Short, 1=Long    // ADC_CFG1_ADLSMP |    // Conversion mode, 0=8 bit, 1=12 bit, 2=10 bit, 3=16 bit    ADC_CFG1_MODE(1) |    // Input clock, 0=bus, 1=bus/2, 2=OSCERCLK, 3=async    ADC_CFG1_ADICLK(0);  ADC0_CFG2 = ADC_CFG2_MUXSEL | ADC_CFG2_ADLSTS(3);#endif  // defined(__IMXRT1062__)}//------------------------------------------------------------------------------#if defined(__IMXRT1062__) // Teensy 4.0#define SOURCE_SADDR ADC1_R0#define SOURCE_EVENT DMAMUX_SOURCE_ADC1#else#define SOURCE_SADDR ADC0_RA#define SOURCE_EVENT DMAMUX_SOURCE_ADC0#endif//------------------------------------------------------------------------------// Should replace ADC stuff with calls to Teensy ADC library.// https://github.com/pedvide/ADCstatic void init(uint8_t pin) {  uint32_t adch;	uint32_t i, sum = 0;	// Actually, do many normal reads, to start with a nice DC level	for (i=0; i < 1024; i++) {		sum += analogRead(pin);	}#if defined(__IMXRT1062__) // Teensy 4.0  // save channel  adch = ADC1_HC0 & 0x1F;  // Continuous conversion , DMA enable  ADC1_GC = ADC_GC_ADCO | ADC_GC_DMAEN;  // start conversion  ADC1_HC0 = adch;#else  // defined(__IMXRT1062__) // Teensy 4.0  // save channel  adch = ADC0_SC1A & 0x1F;  // DMA enable  ADC0_SC2 |= ADC_SC2_DMAEN;  // Continuous conversion enable  ADC0_SC3 = ADC_SC3_ADCO;  // Start ADC  ADC0_SC1A = adch; #endif  // defined(__IMXRT1062__) // Teensy 4.0	// set up a DMA channel to store the ADC data 	dma.attachInterrupt(isr);	dma.begin();  dma.source((volatile const signed short &)SOURCE_SADDR);  dma.destinationBuffer((volatile uint16_t*)dmaBuf, sizeof(dmaBuf));  dma.interruptAtHalf();  dma.interruptAtCompletion();	dma.triggerAtHardwareEvent(SOURCE_EVENT);	dma.enable();}//------------------------------------------------------------------------------void stopDma() {#if defined(__IMXRT1062__) // Teensy 4.0  ADC1_GC = 0;#else  // defined(__IMXRT1062__)  ADC0_SC3 = 0;#endif  // defined(__IMXRT1062__)  dma.disable();}//------------------------------------------------------------------------------void printTest(Print* pr) {  if (file.fileSize() < 1024*2) {    return;  }  file.rewind();  rb.begin(&file);  // Could readIn RING_BUF_SIZE bytes and write to a csv file in a loop.  if (rb.readIn(2048) != 2048) {    sd.errorHalt("rb.readIn failed");  }  uint16_t data;  for (size_t i = 0; i < 1024; i++) {    pr->print(i);    pr->print(',');    rb.memcpyOut(&data, 2);    pr->println(data);  }}//------------------------------------------------------------------------------void runTest(uint8_t pin) {  dmaCount = 0;  maxBytesUsed = 0;  overrun = false;  do {    delay(10);  } while (Serial.read() >= 0);  if (!file.open("IsrLoggerTest.bin", O_CREAT | O_TRUNC | O_RDWR)) {    sd.errorHalt("file.open failed");  }  if (!file.preAllocate(PRE_ALLOCATE_SIZE)) {    sd.errorHalt("file.preAllocate failed");  }  rb.begin(&file);  Serial.println("Type any character to stop\n");  init(pin);  uint32_t samplingTime = micros();  while (!overrun && !Serial.available()) {    size_t n = rb.bytesUsed();    if ((n + file.curPosition()) >= (PRE_ALLOCATE_SIZE - 512)) {      Serial.println("File full - stopping");      break;    }    if (n >= 512) {      if (rb.writeOut(512) != 512) {        Serial.println("writeOut() failed");        file.close();        return;      }    }  }  stopDma();  samplingTime = (micros() - samplingTime);  if (!file.truncate()) {    sd.errorHalt("truncate failed");  }  if (overrun) {    Serial.println("Overrun ERROR!!");  }  Serial.print("RingBufSize ");  Serial.println(RING_BUF_SIZE);  Serial.print("maxBytesUsed ");  Serial.println(maxBytesUsed);  Serial.print("fileSize ");  Serial.println((uint32_t)file.fileSize());  Serial.print(0.000001*samplingTime);  Serial.println(" seconds");  Serial.print(1.0*file.fileSize()/samplingTime, 3);  Serial.println(" MB/sec\n");  printTest(&Serial);  file.close();}//------------------------------------------------------------------------------void waitSerial(const char* msg) {  uint32_t m = micros();  do {    if (Serial.read() >= 0) {      m = micros();    }  } while (micros() - m < 10000);  Serial.println(msg);  while (!Serial.available()) {}  Serial.println();}//------------------------------------------------------------------------------void setup() {  Serial.begin(9600);  while (!Serial) {    yield();  }  waitSerial("Type any character to begin");  Serial.print("FreeStack: ");  Serial.println(FreeStack());}//------------------------------------------------------------------------------void loop() {  if (!sd.begin(SD_CONFIG)) {    sd.initErrorHalt(&Serial);  }//analogReadAveraging(1);//analogReadResolution(12);//overclock(); // 3 Msps on Teensy 3.6 - requires high quality card.  runTest(A0);  waitSerial("Type any character to run test again");}
 |