Teensy 3.1 ADC with DMA

digi.ctrl

Member
I am very new to Teensy. I have received my Teensy 3.1 recently. I have used analogRead for reading analog input. I need to read analog input at its fastest speed. I understand, DMA would be the only option. I have used DMA with Arduino Due to run at 1 MBPS using help from here . Have anybody used Teensy 3.1 ADC with DMA?
 
what sustained and what burst samples/sec do you need (considering how fast the samples can be "consumed".)
 
I have used a very simple code to find sampling rate of the ADC at 16 bit resolution and at different hardware average count (1 to 32).

Code:
#define RES  16
// change HARDWARE AVG to 1, 2, 4, 8, 16, 32
#define AVG  2
#define CNT  160000 / AVG


void setup() {
  Serial.begin(115200);
  analogReadResolution(RES);
  analogReadAveraging(AVG);
  analogReference(0);
}


void loop() {
  int t = micros();
  int a0;

  for(int i = 0; i < CNT ; i++){
    a0 = analogRead(A0);             // read data
  }

  t = micros() - t;
  Serial.print("ADC sampling rate (AVG "); Serial.print(AVG); Serial.print(") = ");
  Serial.print(160000000 / t); Serial.println(" kSPS");
}

The output for hardware average count (1, 2, 4, 8, 16 and 32) is as below
Code:
ADC sampling rate (AVG 1) = 215 kSPS
ADC sampling rate (AVG 2) = 159 kSPS
ADC sampling rate (AVG 4) = 319 kSPS
ADC sampling rate (AVG 8) = 353 kSPS
ADC sampling rate (AVG 16) = 368 kSPS
ADC sampling rate (AVG 32) = 377 kSPS

Surprisingly, with hardware average of 2, the ADC works slow. The sampling rate should be more if the ADC is configured at free-running mode. But I do not know, what registers to use for this configuration. After this I would like to use DMA and free-running mode. Can anyone help in this line?
 
For the Teensy 3.0, using continuous mode I get:
ADC resolution Measurement frequency Num. averages
16 bits 325.500 kHz 1
12 bits 345.620 kHz 1
10 bits 364.230 kHz 1
8 bits 772.274 kHz 1

but this doesn't include time to actually do something with the measurement.
 
By default Teensy 3.1 is running with Continuous Conversion (free-running) Enabled (check ADCx_SC3, x = 0 & 1). Strangely, setting High-Speed Configuration mode (ADHSC bit in ADCx_CFG2) reduces the sampling rate. So, probably conversion rate cannot be improved much. I would like to use ADC DMA to run ADC in the background.
 
That's very strange, where the averaging doesn't correspond to the speed. Looks like I have another thing to investigate.... (I'd added to a long list of stuff)

Later this year I am planning to add an official API in Teensyduino for rapid ADC usage, but with Arduino-style ease of use. I'm hoping to collaborate with the Arduino Team on this, and they've shown a little interest in the conversations we've had so far. Certainly it would benefit them, since Arduino Due has a really fast ADC.
 
Paul, you have used hardware trigger in audio library for sampling at a specific rate. When it is running in continuous mode, can ADC data can be stored at every EOC with DMA?
 
Making Sample time Short (ADC_CFG1_ADLSMP = 0), I am getting for hardware average of 32 - 16 bit and 8 bit
Code:
ADC sampling rate (AVG 32) = 464 kSPS
ADC sampling rate (AVG 32) = 1299 kSPS
 
Last edited:
I am trying to use DMA when the ADC is running in continuous mode. But, there seems to be some problem.
I am using part of the code from Audio.cpp. I have used software trigger and continuous mode for ADC. Also DMA request is enabled for ADC. The DMA setup code is as in Audio.cpp (line 1003 onwards). I am not getting any trigger to the dma_ch2_isr. What's wrong?

Code:
#define AUDIO_BLOCK_SAMPLES 1024

DMAMEM static uint16_t analog_rx_buffer[AUDIO_BLOCK_SAMPLES];
uint16_t dc_average;

void setupADC(int pin)
{
	uint32_t i, sum=0;

	// pin must be 0 to 13 (for A0 to A13)
	// or 14 to 23 for digital pin numbers A0-A9
	// or 34 to 37 corresponding to A10-A13
	if (pin > 23 && !(pin >= 34 && pin <= 37)) return;

	// Configure the ADC and run at least one software-triggered
	// conversion.  This completes the self calibration stuff and
	// leaves the ADC in a state that's mostly ready to use
	analogReadRes(16);
	analogReference(INTERNAL); // range 0 to 1.2 volts
	//analogReference(DEFAULT); // range 0 to 3.3 volts
	analogReadAveraging(8);
	// Actually, do many normal reads, to start with a nice DC level
	for (i=0; i < 1024; i++) {
		sum += analogRead(pin);
	}
	dc_average = sum >> 10;

	// set the programmable delay block to trigger the ADC at 44.1 kHz

	// enable the ADC for DMA
	ADC0_SC2 |= ADC_SC2_DMAEN;

	// set up a DMA channel to store the ADC data
//	SIM_SCGC7 |= SIM_SCGC7_DMA;
//	SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
	DMA_CR = 0;
	DMA_TCD2_SADDR = &ADC0_RA;
	DMA_TCD2_SOFF = 0;
	DMA_TCD2_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
	DMA_TCD2_NBYTES_MLNO = 2;
	DMA_TCD2_SLAST = 0;
	DMA_TCD2_DADDR = analog_rx_buffer;
	DMA_TCD2_DOFF = 2;
	DMA_TCD2_CITER_ELINKNO = sizeof(analog_rx_buffer) / 2;
	DMA_TCD2_DLASTSGA = -sizeof(analog_rx_buffer);
	DMA_TCD2_BITER_ELINKNO = sizeof(analog_rx_buffer) / 2;
	DMA_TCD2_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
	DMAMUX0_CHCFG2 = DMAMUX_DISABLE;
	DMAMUX0_CHCFG2 = DMAMUX_SOURCE_ADC0 | DMAMUX_ENABLE;
	DMA_SERQ = 2;
	NVIC_ENABLE_IRQ(IRQ_DMA_CH2);
}

void dma_ch2_isr(void)
{
	digitalWriteFast(3, HIGH);
	DMA_CINT = 2;
	digitalWriteFast(3, LOW);
}

void setup()
{
        setupADC(14);  //A0
}

void loop()
{
        // do nothing
}
 
I never used the Teensy 3 ADC, so I'm possibly not on the right track here: Do you actually ever start an ADC conversion after DMA has been configured? You say that it's supposed to run in continuous mode, but in your code you take 1024 "normal" ADC readings and then configure DMA for the ADC. Do you reconfigure your ADC afterwards? If not, there won't be any covnersion complete flag that could trigger DMA.
 
As christoph says, at no point in the code you start the ADC!
At the end of the setupADC(pin) you have to set the flag for continuous operation (I don't remember now in which register it is) and write to the ADC_SC1A to start the measurements.
 
Well, I have set ADC continuous mode at the end of setupADC() by
ADC0_SC3 |= ADC_SC3_ADCO;
and ADC0_SC1A = channel;

With this change too DMA request does not start (no toggling of pin 3). But if I do repeated analogRead() in loop() it triggers the dma_ch2_isr.

Thanks Pedvide, it is working!. The mistake was that I have not set ADC0_SC1A = channel at the end of setupADC().
 
Last edited:
These lines were not there in the posted setupADC(). I included them later on. Even though the sequence of those lines posted was correct, but whil testing I wrote them in reverse order. When corrected DMA started working. It seems ADC sampling rate improves a little with DMA.
 
Ah, I understand. Make sure you can process your ADC data as fast as it comes in, otherwise you'll lose samples.
 
Can you explain why have you used HARDWARE AVG , CNT = 160000/AVG and 160000000 / t ?
Thanks




I have used a very simple code to find sampling rate of the ADC at 16 bit resolution and at different hardware average count (1 to 32).

Code:
#define RES  16
// change HARDWARE AVG to 1, 2, 4, 8, 16, 32
#define AVG  2
#define CNT  160000 / AVG


void setup() {
  Serial.begin(115200);
  analogReadResolution(RES);
  analogReadAveraging(AVG);
  analogReference(0);
}


void loop() {
  int t = micros();
  int a0;

  for(int i = 0; i < CNT ; i++){
    a0 = analogRead(A0);             // read data
  }

  t = micros() - t;
  Serial.print("ADC sampling rate (AVG "); Serial.print(AVG); Serial.print(") = ");
  Serial.print(160000000 / t); Serial.println(" kSPS");
}

The output for hardware average count (1, 2, 4, 8, 16 and 32) is as below
Code:
ADC sampling rate (AVG 1) = 215 kSPS
ADC sampling rate (AVG 2) = 159 kSPS
ADC sampling rate (AVG 4) = 319 kSPS
ADC sampling rate (AVG 8) = 353 kSPS
ADC sampling rate (AVG 16) = 368 kSPS
ADC sampling rate (AVG 32) = 377 kSPS

Surprisingly, with hardware average of 2, the ADC works slow. The sampling rate should be more if the ADC is configured at free-running mode. But I do not know, what registers to use for this configuration. After this I would like to use DMA and free-running mode. Can anyone help in this line?
 
Back
Top