#include <ADC.h>
#include <DMAChannel.h>
#include <array>
// connect out_pin to adc_pin0 and adc_pin1, PWM output on out_pin will be measured
// via adc_pin0 and adc_pin1.
const uint8_t adc_pin0 = A9; // digital pin 23, on ADC0
const uint8_t adc_pin1 = A12; // digital pin 31, on ADC1
const uint8_t out_pin = 2;
ADC adc;
DMAChannel dma0;
DMAChannel dma1;
struct CapturePair {
uint16_t v_adc0;
uint16_t v_adc1;
};
std::array<volatile CapturePair, 4096> buffer;
volatile size_t write_pos = 0;
void setup() {
pinMode(adc_pin0, INPUT);
pinMode(adc_pin1, INPUT);
Serial.begin(9600);
delay(2000);
Serial.println("Starting");
adc.setAveraging(1);
adc.setResolution(12);
adc.setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED);
adc.setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED);
adc.adc0->analogRead(adc_pin0); // performs various ADC setup stuff
adc.adc1->analogRead(adc_pin1); // performs various ADC setup stuff
if(adc.adc0->fail_flag || adc.adc1->fail_flag) {
Serial.printf("ADC error, ADC0: %x ADC1: %x\n", adc.adc0->fail_flag, adc.adc1->fail_flag);
}
adc.adc0->stopPDB();
adc.adc1->stopPDB();
dma0.source((uint16_t&) ADC0_RA); // ADC result register
dma0.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC0);
dma0.destinationBuffer(&buffer[0].v_adc0, buffer.size() * sizeof(buffer[0]));
dma0.TCD->DOFF = 4;
dma0.TCD->CITER = buffer.size();
dma0.TCD->BITER = buffer.size();
dma0.enable();
adc.enableDMA(ADC_0);
dma1.source((uint16_t&) ADC1_RA); // ADC result register
dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1);
dma1.destinationBuffer(&buffer[0].v_adc1, buffer.size() * sizeof(buffer[0]));
dma1.TCD->DOFF = 4;
dma1.TCD->CITER = buffer.size();
dma1.TCD->BITER = buffer.size();
dma1.enable();
adc.enableDMA(ADC_1);
adc.adc0->setHardwareTrigger();
adc.adc1->setHardwareTrigger();
// enable PDB
SIM_SCGC6 |= SIM_SCGC6_PDB;
// Sample at 10'000 Hz
constexpr uint32_t pdb_trigger_frequency = 10000;
constexpr uint32_t mod = (F_BUS / pdb_trigger_frequency);
static_assert(mod <= 0x10000, "Prescaler required.");
PDB0_MOD = (uint16_t)(mod-1);
PDB0_CH0C1 = PDB_CHnC1_TOS_1 | PDB_CHnC1_EN_1; // PDB triggers ADC0 SC1A
PDB0_CH1C1 = PDB_CHnC1_TOS_1 | PDB_CHnC1_EN_1; // PDB triggers ADC1 SC1A
PDB0_SC = ADC_PDB_CONFIG | PDB_SC_PRESCALER(0) | PDB_SC_MULT(0) | PDB_SC_LDOK;
// PWM output on out_pin for testing purposes.
analogWriteFrequency(out_pin, 5000);
analogWrite(out_pin, 120);
// Kick off ADC conversion.
PDB0_SC = ADC_PDB_CONFIG | PDB_SC_PRESCALER(0) | PDB_SC_MULT(0) | PDB_SC_SWTRIG; // start
}
void loop() {
Serial.print("Current Buffer index DMA is writing to: ");
noInterrupts();
size_t buffer_idx0 = (((uint16_t*) dma0.destinationAddress()) - &buffer[0].v_adc0) / 2;
size_t buffer_idx1 = (((uint16_t*) dma1.destinationAddress()) - &buffer[0].v_adc1) / 2;
interrupts();
Serial.print(buffer_idx0);
Serial.print(" ");
Serial.println(buffer_idx1);
// Print first 64 measurements in buffer.
for(size_t i = 0; i < 64; i++) {
Serial.printf("[%4u, %4u]", buffer[i].v_adc0, buffer[i].v_adc1);
if(i % 8 == 7) Serial.println();
else Serial.print(" ");
}
Serial.println();
if(adc.adc0->fail_flag || adc.adc1->fail_flag) {
Serial.printf("ADC error, ADC0: %x ADC1: %x\n", adc.adc0->fail_flag, adc.adc1->fail_flag);
}
delay(1000);
}