I'm still not entirely sure how to effectively send the binary data in chunks once the buffer is full. Should this be done in chunks or as soon as they become available?
After banging my forehead for a while I saw that there is an issue associated with the RingBufferDMA and ADC_1 (https://github.com/pedvide/ADC/issues/34). Basically, the correct DMA/ADC pair was not being assigned in the pedvide code. In case this serves someone else I'll pass it on:
Cheers.
Code:
/*
* It doesn't work for Teensy LC yet!
* Added example for two pins on ADC_0 and ADC_1
* Added a couple of lines to ensure the correct DMA setup on ADC_1
*/
#include "ADC_Module.h"
#include "ADC.h"
#include "RingBufferDMA.h"
const uint8_t readPin = A9;
const uint8_t readPin1 = A12; // digital pin 31, on ADC1
ADC *adc = new ADC(); // adc object
// Define the array that holds the conversions here.
// buffer_size must be a power of two.
// The buffer is stored with the correct alignment in the DMAMEM section
// the +0 in the aligned attribute is necessary b/c of a bug in gcc.
const uint8_t buffer_size = 8;
DMAMEM static volatile int16_t __attribute__((aligned(buffer_size+0))) buffer[buffer_size];
// use dma with ADC0
RingBufferDMA *dmaBuffer = new RingBufferDMA(buffer, buffer_size, ADC_0);
#if ADC_NUM_ADCS>1
const int buffer_size1 = 8;
DMAMEM static volatile int16_t __attribute__((aligned(buffer_size1+0))) buffer1[buffer_size1];
// use dma with ADC1
RingBufferDMA *dmaBuffer1 = new RingBufferDMA(buffer1, buffer_size1, ADC_1);
#endif // defined
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(readPin, INPUT); //pin 23 single ended
pinMode(readPin1, INPUT); //pin on ADC_1
Serial.begin(9600);
// reference can be ADC_REFERENCE::REF_3V3, ADC_REFERENCE::REF_1V2 (not for Teensy LC) or ADC_REF_EXT.
//adc->setReference(ADC_REFERENCE::REF_1V2, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2
adc->setAveraging(8); // set number of averages
adc->setResolution(12); // set bits of resolution
// always call the compare functions after changing the resolution!
//adc->enableCompare(1.0/3.3*adc->getMaxValue(ADC_0), 0, ADC_0); // measurement will be ready if value < 1.0V
//adc->enableCompareRange(1.0*adc->getMaxValue(ADC_1)/3.3, 2.0*adc->getMaxValue(ADC_1)/3.3, 0, 1, ADC_1); // ready if value lies out of [1.0,2.0] V
// enable DMA and interrupts
adc->enableDMA(ADC_0);
// ADC interrupt enabled isn't mandatory for DMA to work.
adc->enableInterrupts(ADC_0);
#if ADC_NUM_ADCS>1
adc->setAveraging(8, ADC_1); // set number of averages
adc->setResolution(12, ADC_1); // set bits of resolution
adc->enableDMA(ADC_1);
adc->enableInterrupts(ADC_1);
#endif
}
char c=0;
void loop() {
if (Serial.available()) {
c = Serial.read();
if(c=='s') { // start dma
Serial.println("Start DMA");
dmaBuffer->start(&dmaBuffer_isr);
} else if(c=='d') { // start dma
Serial.println("Start DMA 1");
dmaBuffer1->start(&dmaBuffer1_isr);
dmaBuffer1->dmaChannel->disable();//added to get around the ring buffer issue: https://github.com/pedvide/ADC/issues/34
dmaBuffer1->dmaChannel->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1); // start DMA channel when ADC finishes a conversion
dmaBuffer1->dmaChannel->enable();
} else if(c=='c') { // start conversion
Serial.print("Conversion: ");
adc->analogRead(readPin, ADC_0);
} else if(c=='v') { // start conversion
Serial.print("Conversion: ");
adc->analogRead(readPin1, ADC_1);
} else if(c=='p') { // print buffer
printBuffer();
} else if(c=='l') { // toggle led
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
} else if(c=='r') { // read
Serial.print("read(): ");
Serial.println(dmaBuffer->read());
} else if(c=='f') { // full?
Serial.print("isFull(): ");
Serial.println(dmaBuffer->isFull());
} else if(c=='e') { // empty?
Serial.print("isEmpty(): ");
Serial.println(dmaBuffer->isEmpty());
}
}
//digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
delay(100);
}
void dmaBuffer_isr() {
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
Serial.println("******dmaBuffer_isr");
// update the internal buffer positions
dmaBuffer->dmaChannel->clearInterrupt();
}
void dmaBuffer1_isr() {
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
Serial.println("******dmaBuffer1_isr");
// update the internal buffer positions
dmaBuffer1->dmaChannel->clearInterrupt();
}
// it can be called everytime a new value is converted. The DMA isr is called first
void adc0_isr(void) {
//int t = micros();
Serial.println("ADC0_ISR"); //Serial.println(t);
adc->adc0->readSingle(); // clear interrupt
}
// it can be called everytime a new value is converted. The DMA isr is called first
#if ADC_NUM_ADCS>1
void adc1_isr() {
//int t = micros();
Serial.println("ADC1_ISR"); //Serial.println(t);
adc->adc1->readSingle();
//digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN) );
}
#endif
void printBuffer() {
Serial.println("Buffer: Address, Value");
uint8_t i = 0;
// we can get this info from the dmaBuffer object, even though we should have it already
volatile int16_t* buffer = dmaBuffer->buffer();
for (i = 0; i < dmaBuffer->size(); i++) {
Serial.print(uint32_t(&buffer[i]), HEX);
Serial.print(", ");
Serial.println(buffer[i]);
}
}