// Get timing histograms for ADC Timer with and without SD Card writing.
// Targeted to T4.1 at 600MHz Compiled with ARDUINO 1.8.15 and TD 1.54
// mborgerson 7/9/2021
#include "SdFat.h"
#include <TimeLib.h>
SdFs sd;
FsFile outfile;
const int ledpin = 13;
const int tmpin = 30;
#define TMLOW digitalWriteFast(tmpin, LOW);
#define TMHIGH digitalWriteFast(tmpin, HIGH);
#define LEDON digitalWriteFast(ledpin, HIGH);
#define LEDOFF digitalWriteFast(ledpin, LOW);
#define SD_CONFIG SdioConfig(FIFO_SDIO)
#define TMHISTOMAX 40960
#define ADCMAX 4096 // for 12-bit samples
#include <ADC.h>
#include <ADC_util.h>
const int readpin = A9; // My 2.5V precision reference
ADC *adc = new ADC(); // adc object;
#define SAMPRATE 20000
#define AVERAGING 4
#define RESOLUTION 12
uint8_t sdcbuffer[32*1024]; // 32K SD card buffer
uint32_t tm_histobuffer[TMHISTOMAX]; // for timing intervals up to 40.96mSec
uint32_t adc_histobuffer[ADCMAX];
const char compileTime [] = "ADC Timer histogram Compiled on " __DATE__ " " __TIME__;
void setup() {
delay(500);
Serial.begin(115200);
delay(1000);
// activate ARM cycle counter
ARM_DEMCR |= ARM_DEMCR_TRCENA; // Assure Cycle Counter active
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
pinMode(tmpin, OUTPUT);
pinMode(ledpin, OUTPUT);
pinMode(readpin, INPUT_DISABLE);
delay(2500);
Serial.print("\n\n");
Serial.println(compileTime);
setSyncProvider(getTeensy3Time);
if (timeStatus() != timeSet) {
Serial.println("Unable to sync with the RTC");
} else {
Serial.println("RTC has set the system time");
Serial.print("Initializing SD card...");
}
if (!sd.begin(SD_CONFIG)) {
Serial.println("\nSD initialization failed.\n");
} else Serial.println("initialization done.");
if (sd.fatType() == FAT_TYPE_EXFAT) {
Serial.println("Type is exFAT");
} else {
Serial.printf("Type is FAT%d\n", int16_t(sd.fatType()));
}
// set date time callback function
SdFile::dateTimeCallback(dateTime);
adc->adc0->setAveraging(AVERAGING); // set number of averages
adc->adc0->setResolution(RESOLUTION); // set bits of resolution
adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // change the conversion speed
adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // change the sampling speed
}
elapsedMillis blocktimer;
volatile uint32_t byteswritten;
volatile uint32_t totalsamples;
volatile uint32_t lastcycles;
void loop() {
char ch;
if (Serial.available()) {
ch = Serial.read();
if (ch == 'n') GetHistoData(false);
if (ch == 'f') GetHistoData(true);
if (ch == 'a') ShowADCHisto();
if (ch == 'd') sd.ls(LS_SIZE | LS_DATE | LS_R);
}
}
/*****************************************************************************
Read the Teensy RTC and return a time_t (Unix Seconds) value
******************************************************************************/
time_t getTeensy3Time() {
return Teensy3Clock.get();
}
/*
User provided date time callback function.
See SdFile::dateTimeCallback() for usage.
*/
void dateTime(uint16_t* date, uint16_t* time) {
// use the year(), month() day() etc. functions from timelib
// return date using FAT_DATE macro to format fields
*date = FAT_DATE(year(), month(), day());
// return time using FAT_TIME macro to format fields
*time = FAT_TIME(hour(), minute(), second());
}
volatile uint16_t maxidx;
volatile uint32_t tmax;
// This ISR runs in about 100nSec on T4.1 at 600MHz.
// It doesn't actually save the data, but only updates
// timing and adc histogram values
void adc0_isr() {
uint32_t tmdiff, thiscycles;
uint16_t adc_val;
LEDON;
thiscycles = ARM_DWT_CYCCNT;
tmdiff = thiscycles - lastcycles;
if (tmdiff >= TMHISTOMAX) tmdiff = TMHISTOMAX - 1;
lastcycles = thiscycles;
if(tmdiff > tmax) {
tmax = tmdiff;
maxidx = totalsamples;
}
totalsamples++;
// signal the main loop to write a 16KB block every 8192 samples
// call readSingle() to clear the interrupt.
// and update the ADC Histogram data
adc_val = adc->adc0->readSingle();
if (adc_val >= 4095) adc_val = 4095;
// Skip the first two samples, as they often have
// weird timing values. Update histogram data
if(totalsamples > 2){
tm_histobuffer[tmdiff]++;
adc_histobuffer[adc_val]++;
}
#if defined(__IMXRT1062__) // Teensy 4.0
asm("DSB");
#endif
LEDOFF;
}
// get timing and ADC histogram data, optionally writing to SD card while
// collecting.
void GetHistoData(bool writesdc) {
bool sdfileopen = false;
byteswritten = 0;
totalsamples = 0;
uint32_t numtowrite;
uint16_t seccount = 0;
elapsedMillis dmillis;
memset(adc_histobuffer, 0, sizeof(adc_histobuffer)); // clear adc histogram counts
memset(tm_histobuffer, 0, sizeof(tm_histobuffer)); // clear timing histogram counts
if (writesdc) {
sdfileopen = outfile.open("dummyfile.dxx", O_RDWR | O_CREAT | O_TRUNC);
}
ShowSetup(writesdc);
delay(10); // wait for usb serial to finish
adc->adc0->stopTimer();
adc->adc0->startSingleRead(readpin); // call this to setup everything before the Timer starts, differential is also possible
maxidx = 0;
tmax = 0;
delay(1);
adc->adc0->readSingle();
dmillis = 0;
// now start the ADC collection timer
adc->adc0->startTimer(SAMPRATE); //frequency in Hz
lastcycles = ARM_DWT_CYCCNT;
adc->adc0->enableInterrupts(adc0_isr);
// Write out the elapsed seconds during collection
// The USB Serial writes occasionally block ADC interrupts
// for a microsecond or so.
do {
if (dmillis > 1000) {
seccount++;
dmillis = 0;
Serial.printf("%4u: %lu\n", seccount, totalsamples);
}
// write an appropriate number of bytes from SD Buffer
if(byteswritten < (totalsamples *2)){
if (writesdc) {
numtowrite = (totalsamples * 2) - byteswritten;
if (sdfileopen)outfile.write(sdcbuffer, numtowrite); // Write bytes when needed
byteswritten += numtowrite;
}
} // end of if(byteswritten < (totalsamples *2)
} while (totalsamples < 1000000); // stop after 1 million samples
adc->adc0->stopTimer();
if (writesdc) {
if (sdfileopen)outfile.close();
Serial.printf("%6.2f MBytes written to SD Card.\n", (float)byteswritten / (1000000));
}
Serial.println("Collection complete.");
ShowTmHisto();
}
void ShowSetup(bool writesdc) {
Serial.printf("Collecting Data ");
if (writesdc) {
Serial.printf("with SD Card Writes \n");
} else {
Serial.println("with no SD Card writes\n");
}
}
void ShowTmHisto(void) {
uint32_t i;
Serial.println("Timing Histogram Data in ARM Cycle Counts");
for (i = 0; i < TMHISTOMAX; i++) {
if (tm_histobuffer[i] > 0) {
Serial.printf("%5lu %lu\n", i, tm_histobuffer[i]);
}
}
Serial.println();
Serial.printf("Maximum at sample %lu\n",maxidx);
}
void ShowADCHisto(void) {
uint32_t i;
Serial.println("ADC Histogram Data in Counts");
for (i = 0; i < ADCMAX; i++) {
if (adc_histobuffer[i] > 0) {
Serial.printf("%5lu %lu\n", i, adc_histobuffer[i]);
}
}
Serial.println();
}