Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 19 of 19

Thread: Teensy 3.1 ADC with DMA

  1. #1
    Junior Member
    Join Date
    Jan 2014
    Posts
    12

    Unhappy Teensy 3.1 ADC with DMA

    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?

  2. #2
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    what sustained and what burst samples/sec do you need (considering how fast the samples can be "consumed".)

  3. #3
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,369
    Quote Originally Posted by digi.ctrl View Post
    Have anybody used Teensy 3.1 ADC with DMA?
    The audio library has an input object that uses the ADC with DMA. It configures for 44100 Hz and averaging 8 samples in the ADC.

    https://github.com/PaulStoffregen/Audio

    The ADC might be able to run faster than 320 ksamples/sec at lower resolution, but I do not believe it's capable of 1 Msample/sec.

  4. #4
    Junior Member
    Join Date
    Jan 2014
    Posts
    12
    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?

  5. #5
    Senior Member
    Join Date
    Jul 2013
    Posts
    272
    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.

  6. #6
    Junior Member
    Join Date
    Jan 2014
    Posts
    12
    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.

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,369
    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.

  8. #8
    Junior Member
    Join Date
    Jan 2014
    Posts
    12
    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?

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,369
    Quote Originally Posted by digi.ctrl View Post
    When it is running in continuous mode, can ADC data can be stored at every EOC with DMA?
    I have not tried to use it in that mode (yet). Seems like it ought to work.

  10. #10
    Junior Member
    Join Date
    Jan 2014
    Posts
    12
    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 by digi.ctrl; 01-28-2014 at 09:56 AM.

  11. #11
    Junior Member
    Join Date
    Jan 2014
    Posts
    12

    Unhappy

    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
    }

  12. #12
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    885
    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.

  13. #13
    Senior Member
    Join Date
    Jul 2013
    Posts
    272
    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.

  14. #14
    Junior Member
    Join Date
    Jan 2014
    Posts
    12
    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 by digi.ctrl; 01-29-2014 at 10:42 AM.

  15. #15
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    885
    Quote Originally Posted by digi.ctrl View Post
    Well, I have set ADC continuous mode at the end of setupADC() by
    ADC0_SC3 |= ADC_SC3_ADCO;
    and ADC0_SC1A = channel;
    I cannot spot these lines in the setupADC() you posted.
    Quote Originally Posted by digi.ctrl View Post
    The mistake was that I have not set ADC0_SC1A = channel at the end of setupADC().
    Isn't that a contradiction to what you said in the previous sentence? I don't understand your post, really...

  16. #16
    Junior Member
    Join Date
    Jan 2014
    Posts
    12
    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.

  17. #17
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    885
    Ah, I understand. Make sure you can process your ADC data as fast as it comes in, otherwise you'll lose samples.

  18. #18
    Junior Member
    Join Date
    Mar 2014
    Location
    Utah
    Posts
    1
    Can you please post the final version of your code? Thanks!

  19. #19
    Junior Member
    Join Date
    Aug 2016
    Posts
    4
    Can you explain why have you used HARDWARE AVG , CNT = 160000/AVG and 160000000 / t ?
    Thanks




    Quote Originally Posted by digi.ctrl View Post
    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?

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •