/* Adapted code take from Pedvides ADC library:Example for triggering the ADC with PDB
DMA channel added to store samples directy.
DMA isr changed such that only one single write cycle to samples[] is performed
*/
#include <ADC.h>
#include <DMAChannel.h>
const int MeasurementPin = A4; // ADC0
//const int MeasurementPin2 = A2; // ADC1
uint16_t samples[16384];
ADC *adc = new ADC(); // adc object;
DMAChannel dma; // dma Channel
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(MeasurementPin, INPUT);
//pinMode(MeasurementPin2, INPUT);
Serial.begin(9600);
while (!Serial);
Serial.println("Begin setup");
dmaInit();
///// ADC0 ////
// reference can be ADC_REF_3V3, ADC_REF_1V2 (not for Teensy LC) or ADC_REF_EXT.
//adc->setReference(ADC_REF_1V2, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2
adc->setReference(ADC_REF_3V3, ADC_0);
adc->setAveraging(4); // set number of averages
adc->setResolution(12); // set bits of resolution
// it can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED_16BITS, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED
// see the documentation for more information
adc->setConversionSpeed(ADC_HIGH_SPEED_16BITS); // change the conversion speed
// it can be ADC_VERY_LOW_SPEED, ADC_LOW_SPEED, ADC_MED_SPEED, ADC_HIGH_SPEED or ADC_VERY_HIGH_SPEED
adc->setSamplingSpeed(ADC_HIGH_SPEED_16BITS); // change the sampling speed
adc->enableInterrupts(ADC_0); // it's necessary to enable interrupts for PDB to work (why?)
adc->enableDMA(ADC_0); // enable DMA requrest; ADC0_SC2 |= | ADC_SC2_ADTRG | ADC_SC2_DMAEN;
adc->analogRead(MeasurementPin, ADC_0); // call this to setup everything before the pdb starts
////// ADC1 /////
//#if ADC_NUM_ADCS>1
// adc->setReference(ADC_REF_3V3, ADC_1);
// adc->setAveraging(4, ADC_1); // set number of averages
// adc->setResolution(12, ADC_1); // set bits of resolution
// adc->setConversionSpeed(ADC_HIGH_SPEED_16BITS, ADC_1); // change the conversion speed
// adc->setSamplingSpeed(ADC_HIGH_SPEED_16BITS, ADC_1); // change the sampling speed
// adc->enableInterrupts(ADC_1);
// adc->enableDMA(ADC_1); // enable DMA requrest; ADC1_SC2 |= | ADC_SC2_ADTRG | ADC_SC2_DMAEN;
// adc->analogRead(MeasurementPin2, ADC_1); // call this to setup everything before the pdb starts
//#endif
Serial.println("End setup");
}
char c = 0;
int value;
int value2;
void loop() {
if (Serial.available()) {
c = Serial.read();
if (c == 's') { // start pdb, before pressing enter write the frequency in Hz
uint32_t freq = Serial.parseInt();
Serial.print("Start pdb with frequency ");
Serial.print(freq);
Serial.println(" Hz.");
adc->adc0->stopPDB();
adc->adc0->startPDB(freq); //frequency in Hz
//#if ADC_NUM_ADCS>1
// adc->adc1->stopPDB();
// adc->adc1->startPDB(freq); //frequency in Hz
//#endif
} else if (c == 'p') { // pbd stats
Serial.print("Prescaler:");
Serial.println( (PDB0_SC & 0x7000) >> 12 , HEX);
Serial.print("Mult:");
Serial.println( (PDB0_SC & 0xC) >> 2, HEX);
} else if (c == 'r') { // reset
adc->adc0->stopPDB();
//#if ADC_NUM_ADCS>1
// adc->adc1->stopPDB();
//#endif
dma.detachInterrupt();
dma.disable();
} else if (c == 'd') { // send Data to serial monitor, 16 samples just to see some data.
for (int i = 0; i < 16; i++) {
Serial.println(samples[i]);
}
Serial.println("");
}
}
/* fail_flag contains all possible errors,
They are defined in ADC_Module.h as
ADC_ERROR_OTHER
ADC_ERROR_CALIB
ADC_ERROR_WRONG_PIN
ADC_ERROR_ANALOG_READ
ADC_ERROR_COMPARISON
ADC_ERROR_ANALOG_DIFF_READ
ADC_ERROR_CONT
ADC_ERROR_CONT_DIFF
ADC_ERROR_WRONG_ADC
ADC_ERROR_SYNCH
You can compare the value of the flag with those masks to know what's the error.
*/
if (adc->adc0->fail_flag) {
Serial.print("ADC0 error flags: 0x");
Serial.println(adc->adc0->fail_flag, HEX);
if (adc->adc0->fail_flag == ADC_ERROR_COMPARISON) {
adc->adc0->fail_flag &= ~ADC_ERROR_COMPARISON; // clear that error
Serial.println("Comparison error in ADC0");
}
}
//#if ADC_NUM_ADCS>1
// if (adc->adc1->fail_flag) {
// Serial.print("ADC1 error flags: 0x");
// Serial.println(adc->adc1->fail_flag, HEX);
// if (adc->adc1->fail_flag == ADC_ERROR_COMPARISON) {
// adc->adc1->fail_flag &= ~ADC_ERROR_COMPARISON; // clear that error
// Serial.println("Comparison error in ADC1");
// }
// }
//#endif
//digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
//delay(100);
}
void dmaInit() {
dma.source(*(uint16_t*) &ADC0_RA);
dma.destinationBuffer(samples, sizeof(samples));
dma.attachInterrupt(dma_isr);
dma.interruptAtCompletion();
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC0);
dma.enable();
}
void adc0_isr() {
Serial.print("adc0 isr: ");
Serial.println(millis());
}
//#if ADC_NUM_ADCS>1
//void adc1_isr() {
// Serial.print("adc1 isr: ");
// Serial.println(millis());
//}
//#endif
// pdb interrupt is enabled in case you need it.
void pdb_isr(void) {
PDB0_SC &= ~PDB_SC_PDBIF; // clear interrupt
Serial.print("pdb isr: ");
Serial.println(millis());
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
}
//void dma_isr() {
// Serial.print("dma isr: ");
// Serial.println(millis());
// dma.clearInterrupt();
// for (int i = 0; i < 16; i++) {
// Serial.println(samples[i]);
// }
// Serial.println("");
//}
void dma_isr() {
adc->adc0->stopPDB();
//#if ADC_NUM_ADCS>1
// adc->adc1->stopPDB();
//#endif
dma.detachInterrupt();
dma.disable();
}