I've recently started playing with the Teensy 3.6 and Arduino IDE configured as a 'USB Serial' device at 180MHz, optimized 'Faster'. I am trying to put together a Time of Flight acoustic measuring system which needs quick and well timed analog measurements. So, naturally I've been using Pedvide's ADC library with PDB. So far so good, just measuring the analog write pin to test. Teensy seems to have no trouble keeping up with many hundreds of KSPS. My problem comes from trying to log the data. I'm trying to send the data over USB to my laptop so I can start to run the analysis. I have set up the ADC library to 10 bit measurements, and unless I throttle the sampling frequency to 10 Ksps I cannot get all the data to my computer. I figure that with 2 bytes for data and 1 byte for delimiting per sample, I should be able to transfer at least 300 Ksps, but I drop a lot of data across the USB unless the speed is quite slow. Below is the Teensy Code (many thanks to all the excellent forum posts about ADC):
For completeness, here is the Python Code (3.7) I am using to catch the data, note that I also attempted this with some other serial monitors (TyCommander among them) and this has been consistently the best for me:
I have also increased the number of NUM_USB_BUFFERS in usb_desc.h to 16 and the number of TX_PACKET_LIMIT in usb_serial.c to 32.
I am wondering if there is something I can do to get at least 250 Ksps over USB?
I guess that the USB transfers are colliding with the ADC ISRs. I have tried to run down other possible issues. I have attempted this on both windows and linux, used the USB data transfer tools Paul provided on PJRC website (just north of 1 MB/s as expected), Serial.write instead of serial.println, different numbers of usb buffers and TX packet limits, changed the interrupt priority of ISRs and PDB, I can certainly make things worse, but I can't seem to get better. What is getting me is that the data loss is generally 1-3% across a range of speeds. The data loss gets worse as the sampling speed increases which makes sense, but it doesn't get much worse.
Here are some results of number of samples transmitted vs received:
Rx.............Tx...........%
---- ............----.........----
10000........10000......1
29900........30000......0.997
49500........50000......0.99
99000........100000....0.99
246000......250000....0.984
295000......300000....0.983
302000......310000....0.974
323500......330000....0.980
340000......350000....0.971
These are rounded and general averages of a number of runs. Mostly I was running at 300 Ksps, and these percentages are the same whether I sample for 1 second or 100 seconds. The losses are random throughout the run.
If anyone has any feedback I would appreciate it. Thanks in advance.
Code:
#include <ADC.h>
#include <RingBuffer.h>
// connect out_pin to adc_pin, PWM output on out_pin will be measured
// via adc_pin.
const uint8_t adc_pin = A9;
const uint8_t out_pin = 2;
ADC adc;
RingBuffer *buffer = new RingBuffer;
volatile size_t write_pos = 0;
volatile size_t read_pos = 0;
bool flag = false;
bool quitFlag = false;
volatile uint32_t Counter = 0;
uint32_t readCounter = 0;
volatile uint16_t adc_val = 0;
const uint32_t pdb_trigger_frequency = 300000;
const uint32_t seconds = 100;
uint32_t numSamples = pdb_trigger_frequency * seconds;
void setup() {
pinMode(adc_pin, INPUT);
Serial.begin(9600);
delay(3000);
Serial.println("Starting");
adc.setAveraging(1);
adc.setResolution(10);
adc.setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED);
adc.setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED);
adc.adc0->analogRead(adc_pin); // performs various ADC setup stuff
analogWriteFrequency(out_pin, 5000);
analogWrite(out_pin, 128);
delay(2000);
Serial.println(millis());
adc.enableInterrupts(ADC_0);
//NVIC_SET_PRIORITY(IRQ_ADC0,0);
//NVIC_SET_PRIORITY(IRQ_PDB,2);
adc.adc0->resetError();
adc.adc0->stopPDB();
adc.adc0->startPDB(pdb_trigger_frequency);
}
void loop() {
if(readCounter < Counter){
adc_val = buffer->read();
Serial.println(adc_val);
readCounter++;
}
else{
if (quitFlag == true){
Serial.println("OVER");
Serial.end(); //Does nothing
quitFlag = false;
}
}
}
//void yield(){}
void adc0_isr() {
if(Counter<numSamples){
buffer->write(adc.adc0->readSingle());
}
else{
adc.adc0->stopPDB();
adc.disableInterrupts(ADC_0);
adc.adc0->readSingle();
quitFlag = true;
}
Counter++;
}
void pdb_isr(void) {
PDB0_SC &=~PDB_SC_PDBIF; // clear interrupt
}
For completeness, here is the Python Code (3.7) I am using to catch the data, note that I also attempted this with some other serial monitors (TyCommander among them) and this has been consistently the best for me:
Code:
import time
flag = 1
with open('logFile', 'w') as log:
time.sleep(1)
# Don't fight the Kernal, wait some seconds for prepare device
with open("/dev/ttyACM0", "r") as readBuff:
while flag:
ans = readBuff.readline()
if ans:
if ans[:-1] == "OVER":
flag = 0
else:
log.write(ans[:])
readBuff.close()
log.close()
I have also increased the number of NUM_USB_BUFFERS in usb_desc.h to 16 and the number of TX_PACKET_LIMIT in usb_serial.c to 32.
I am wondering if there is something I can do to get at least 250 Ksps over USB?
I guess that the USB transfers are colliding with the ADC ISRs. I have tried to run down other possible issues. I have attempted this on both windows and linux, used the USB data transfer tools Paul provided on PJRC website (just north of 1 MB/s as expected), Serial.write instead of serial.println, different numbers of usb buffers and TX packet limits, changed the interrupt priority of ISRs and PDB, I can certainly make things worse, but I can't seem to get better. What is getting me is that the data loss is generally 1-3% across a range of speeds. The data loss gets worse as the sampling speed increases which makes sense, but it doesn't get much worse.
Here are some results of number of samples transmitted vs received:
Rx.............Tx...........%
---- ............----.........----
10000........10000......1
29900........30000......0.997
49500........50000......0.99
99000........100000....0.99
246000......250000....0.984
295000......300000....0.983
302000......310000....0.974
323500......330000....0.980
340000......350000....0.971
These are rounded and general averages of a number of runs. Mostly I was running at 300 Ksps, and these percentages are the same whether I sample for 1 second or 100 seconds. The losses are random throughout the run.
If anyone has any feedback I would appreciate it. Thanks in advance.