/*******************************************************
Peak to Peak voltage measurement
ADC collection controlled by ADC timer for no jitter
and precise sample timing.
This simple test program assumes that the input signal
has been shifted and scaled to fit within the 0.0 to
3.3V range of the T4.0 ADC
For testing purposes, the program was run with input from
a signal generator with a 50-Ohm output impedance
Results were compared with an 18-year-old Tek TDS210
digital oscilloscope.
MJB 3/23/2021
***************************************************************/
#include <ADC.h>
// instantiate a new ADC object
ADC *adc = new ADC(); // adc object;
const char compileTime [] = "\n\nPk-Pk test Compiled on " __DATE__ " " __TIME__;
const int admarkpin = 1;
const int ledpin = 13;
const uint adcpin = A9;
// ADMARKHI and ADMARKLO are used to observe ADC Collectiom timing on oscilloscope
#define ADMARKHI digitalWriteFast(admarkpin, HIGH);
#define ADMARKLO digitalWriteFast(admarkpin, LOW);
#define LEDON digitalWriteFast(ledpin, HIGH); // Also marks IRQ handler timing
#define LEDOFF digitalWriteFast(ledpin, LOW);
#define ADCMAX 4096 // for 12-bit samples
float vRef = 3.298; // measured for my T4.0
float pk_pkSamples[1000];
uint16_t numsamples;
// keep the sample rate out of the 300 to 400KHz band
#define DEFAULTRATE 298000
volatile bool sampling = false;
volatile uint16_t adcmax, adcmin;
void setup() {
Serial.begin(9600);
delay(500);
Serial.println(compileTime);
pinMode(admarkpin, OUTPUT);
pinMode(ledpin, OUTPUT);
pinMode(adcpin, INPUT_DISABLE);
adc->adc0->setAveraging(1 ); // set number of averages
adc->adc0->setResolution(12); // set bits of resolution
adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED); // change the conversion speed
adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED); // change the sampling speed
ADCSetFrequency(DEFAULTRATE);
}
void loop() {
// put your main code here, to run repeatedly:
char ch;
if (Serial.available()) {
ch = Serial.read();
if (ch == '0')Pk_PkDisplay(10, 1);
if (ch == '1')Pk_PkDisplay(10, 10);
if (ch == '2')Pk_PkDisplay(10, 100);
if (ch == 'a')ADCSetFrequency(210000);
if (ch == 'b')ADCSetFrequency(290000);
if (ch == 'c')ADCSetFrequency(420000);
}
}
/*****************************************************
This is the ADC timer interrupt handler
The ISR runs in about 75nSec on T4.1 at 600MHz
when collecting max and min data
******************************************************/
void adc0_isr() {
uint16_t adc_val;
ADMARKHI
if (sampling) {
// Collect ADC value and update the ADC Histogram data
adc_val = adc->adc0->readSingle();
if (adc_val >= adcmax) adcmax = adc_val;
if (adc_val <= adcmin) adcmin = adc_val;
#if defined(__IMXRT1062__) // Teensy 4.0
asm("DSB");
#endif
} // end of if( sampling)
ADMARKLO;
}
// Set the ADC Sample timer to the desired frequency
void ADCSetFrequency(uint32_t freq){
// Now start the ADC timer. It runs continuously, but we don't always collect the data
sampling = false;
adc->adc0->stopTimer();
delay(2);
adc->adc0->startSingleRead(adcpin); // call this to setup everything before the Timer starts, differential is also possible
delay(1);
adc->adc0->readSingle();
adc->adc0->startTimer(freq); //frequency in Hz
adc->adc0->enableInterrupts(adc0_isr);
Serial.printf("\nADC0 timer rate set to %lu\n", adc->adc0->getTimerFrequency());
}
// Display 10 samples of Pk-Pk data
void Pk_PkDisplay(uint16_t nsamples, uint16_t msec) {
uint16_t i;
for (i = 0; i < nsamples; i++) {
pk_pkSamples[i] = GetPk_Pk(msec);
}
Serial.printf("\nSample Data with %u mSec window:\n", msec);
for (i = 0; i < nsamples; i++) {
Serial.printf("%6.3f\t",pk_pkSamples[i]);
}
Serial.println();
}
// Collect max and min data for msec milliseconds
// then calculate pk-pk volts;
float GetPk_Pk(uint16_t msec) {
uint16_t pkpkcounts;
float volts;
sampling = false;
// now reset adcmax and adcmin, then start the ADC collection timer
adcmax = 0; adcmin = ADCMAX;
sampling = true;
delay(msec); // collect max and min for requested milliseconds
sampling = false;
pkpkcounts = adcmax - adcmin;
volts = vRef * pkpkcounts / ADCMAX;
return volts;
}