Luc 93312ff8b5
Idf 5.1.4/Arduino 3.0.4 porting for esp32 (#1046)
* Update WebSocket library
* Update SSDP library
* Update TFT_eSPI library
* Update EspLuaEngine library
* Update SDFat library
* Change to pioarduino
* Make ESP3DMessageFIFO and ESP3DMessage  more thread safe
* Fix sanity checks for BT
* Add some C6 support
* Refactor ethernet code
* Split Ethernet Sta / WiFi sta ESP Commands  and settings
* Simplify wait and wdtFeed code
* Set C3 with 4MB by default in platformio.ini
* Apply Disable brown out only on ESP32 to avoid crash e.g:ESP32S3
* Add missing entries in platformio.ini
2024-09-05 16:27:47 +08:00

215 lines
5.7 KiB
C++

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