123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- // Test of Teensy exFAT DMA ADC logger.
- // This is mainly to test use of RingBuf in an ISR.
- // This example only supports pins on the first ADC.
- // it has only been tested on Teensy 3.6 and 4.1.
- // You should modify it for serious use as a data logger.
- //
- #include "ADC.h"
- #include "DMAChannel.h"
- #include "FreeStack.h"
- #include "RingBuf.h"
- #include "SdFat.h"
- // Pin must be on first ADC.
- #define ADC_PIN A0
- // 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)
- ADC adc;
- DMAChannel dma(true);
- SdFs sd;
- FsFile file;
- // Ping-pong DMA buffer.
- DMAMEM static uint16_t __attribute__((aligned(32))) dmaBuf[2][256];
- // Count of DMA interrupts.
- volatile size_t dmaCount;
- // RingBuf for 512 byte sectors.
- RingBuf<FsFile, RING_BUF_SIZE> rb;
- // Shared between ISR and background.
- volatile size_t maxBytesUsed;
- // Overrun error for write to RingBuf.
- volatile bool overrun;
- //------------------------------------------------------------------------------
- // ISR for DMA.
- static void isr() {
- if (!overrun) {
- // Clear cache for buffer filled by DMA to insure read from DMA memory.
- arm_dcache_delete((void*)dmaBuf[dmaCount & 1], 512);
- // Enable RingBuf functions to be called in ISR.
- rb.beginISR();
- if (rb.write(dmaBuf[dmaCount & 1], 512) == 512) {
- dmaCount++;
- if (rb.bytesUsed() > maxBytesUsed) {
- maxBytesUsed = rb.bytesUsed();
- }
- } else {
- overrun = true;
- }
- // End use of RingBuf functions in ISR.
- rb.endISR();
- }
- dma.clearComplete();
- dma.clearInterrupt();
- #if defined(__IMXRT1062__)
- // Handle clear interrupt glitch in Teensy 4.x!
- asm("DSB");
- #endif // defined(__IMXRT1062__)
- }
- //------------------------------------------------------------------------------
- #if defined(__IMXRT1062__) // Teensy 4.x
- #define SOURCE_SADDR ADC1_R0
- #define SOURCE_EVENT DMAMUX_SOURCE_ADC1
- #else
- #define SOURCE_SADDR ADC0_RA
- #define SOURCE_EVENT DMAMUX_SOURCE_ADC0
- #endif
- //------------------------------------------------------------------------------
- static void init(uint8_t pin) {
- dma.begin();
- dma.attachInterrupt(isr);
- 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();
- adc.adc0->enableDMA();
- adc.adc0->startContinuous(pin);
- }
- //------------------------------------------------------------------------------
- void stopDma() {
- adc.adc0->disableDMA();
- 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(',');
- // Test read with: template <typename Type>bool read(Type* data).
- rb.read(&data);
- 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 (!rb.sync()) {
- Serial.println("sync() failed");
- file.close();
- return;
- }
- if (!file.truncate()) {
- sd.errorHalt("truncate failed");
- }
- if (overrun) {
- Serial.println("Overrun ERROR!!");
- }
- Serial.print("dmsCount ");
- Serial.println(dmaCount);
- Serial.print("RingBufSize ");
- Serial.println(RING_BUF_SIZE);
- Serial.print("maxBytesUsed ");
- Serial.println(maxBytesUsed);
- Serial.print("fileSize ");
- file.printFileSize(&Serial);
- Serial.println();
- 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) {
- do {
- delay(10);
- } while (Serial.read() >= 0);
- 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);
- }
- // Try for max speed.
- adc.adc0->setAveraging(1);
- adc.adc0->setResolution(10);
- adc.adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED);
- adc.adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED);
- runTest(ADC_PIN);
- waitSerial("Type any character to run test again");
- }
|