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/ADC
- static 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");
- }
|