This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADC12 and DMA Sampling - Slower than expected

Other Parts Discussed in Thread: MSP430F5636

I am using an MSP430F5636 to do some high speed sampling of 4 different ADC pins.  My code is below.

void sample( void ){
   unsigned int i,k;
   unsigned int an[4] = {13,15,12,14};
   int c[4][40];

    for(k=0;k<4;k++) {
		// Setup ADC12
		ADC12CTL0 &= ~ADC12ENC;
		ADC12CTL0 = ADC12SHT0_0+ADC12ON;
		ADC12CTL1 = ADC12SHS_1+ADC12CONSEQ_2+ADC12SSEL_3+ADC12DIV_3; // Repeated single transfer, SMCLK/4 = 4MHz
		ADC12MCTL0 = ADC12SREF_0+an[k];
		
        while (ADC12CTL1 & BUSY);              // Wait if ADC12 core is active

        // Setup DMA0
		DMACTL0 = DMA0TSEL_24;                    // ADC12IFGx triggered
		DMACTL4 = DMARMWDIS;                      // Read-modify-write disable
		DMA0CTL = DMADT_4+DMADSTINCR_3;	  // rpt single transfer, inc dst
		DMA0SZ = 40;                               
		DMA0SA = (unsigned int) &ADC12MEM0;	  // DMA source
		DMA0DA = (unsigned int) c[k];			  // DMA destination


		// Timer setup for ADC sample rate
		TA0CTL = 0;
		TA0CTL &= ~TAIFG;        
        TA0CCTL1 = OUTMOD_4;                     // set timer A to start A to D sampling in rising edge	
		TA0R = 0;
		TA0CCR0 = 0x10;		// 16MHz/0x10 = 1MHz
		TA0CCR1 = 0x08;
        TA0CTL = TACLR + TASSEL_2 + MC_1;          // clear, smclock, up, start	

		P9OUT |= BIT6;		// Timing bit

		// Start the conversion
		DMA0CTL |= DMAEN;
		ADC12CTL0 |= ADC12ENC;
		
		while (!(DMA0CTL & DMAIFG));	// Wait for 40 samples
		
		P9OUT &= ~BIT6;		// Timing bit

		DMA0CTL = 0;			// Disable DMA
		ADC12CTL0 &= ~ADC12ENC;	// Disable ADC conversion
    }
}

OUTMOD_4 should set the ADC sampling for each subsequent sample at 2us (1MHz/2 = 500KHz, 1/500KHz = 2us).  This means that 40 samples should be around 40 * 2 = 80us.  In reality, when monitoring P9.6 with an oscilloscope I am measuring about 21.6 ms for 40 samples.  This takes a lot longer than I expect.

At this point, I'm assuming that the ADC can't sample as quickly as I want it to.  Using SMCLK = 16MHz, and dividing that by 4 for the ADC gives 4MHz for the ADC clock.  Using the equation shown in the datasheet for calculating ADC12 conversion time (13 × ADC12DIV × 1/fADC12CLK) and adding another 4 clock cycles to it for the sample and hold time, results in 4.25us.  4.25us*40 = 170us, which still isn't what I'm seeing but implies that I'm setting something up wrong.

My questions are these:

What is the maximum possible sample rate I can expect to see using DMA?

Am I setting something up incorrectly in my code that causes it to act differently than I want it to?

I know the code isn't setup in the most efficient manner, but I'm just trying to get something working at this point.

  • It appears that I had two possible problems.  

    1: The timer was interrupting faster than the ADC can handle (this is stated as a bad idea in the errata sheet)

    2: Running the code in debug mode was somehow causing the ADC/DMA operation to run orders of magnitude slower.

    Can an expert out there confirm or deny what I've found?

  • Without knowing your clock system setup, it is difficult to analyze timing problems. :)

     However, assuming 4MHz ADC12CLK, one conversion takes 13+SHT ADC clock cycles. You don’t set SHP, so the ADC12SHT setting is ignored. Instead the pulse duration of the timer determines the cycle time, and after this, another 13 ADC12CLK cycle s= 3.25µs are required for the conversion. Since you use OUTMOD_4 (toggle), one timer cycle (1µs) is used for sampling, then the ADC converts, and ignores the next 3.25 pulses from the timer. So basically, I’d expect a conversion to take place every 6µs.

    Suggestions:

    - Set ADC12SHP. This alone won’t reduce the conversion time
    - set CCR0 to 68. This gives 4.3125µs cycle time (one tick more than needed, to be sure). Configure CCR1 for SET/RESET or RESET/SET mode, to get a trigger on each cycle.

    - If you don’t need full 12 bit resolution, you may go for 10 or 8 bit. This saves 2 or 4 clock cycles during conversion, speeding things up a bit more (only 15/13 clock cycles required for conversion = 3.75/3.25µs for each conversion)

    Not setting SHP but using the SET/RESET mode for controlling the sampling time may lead to faster conversions, but it would also mean that the sampling time (the time to charge the sampling capacitor) will be <1µs. Depending on signal source impedance, even 1µs is quite short, maybe (way) too short.

    Another option would be to raise the ADC12 clock. When using AVCC as reference, 5MHz can be used without reducing precision - if you can live with reduced precision, you can go as high as 6MHz. In your case, using ADC12DIV_2 would give 5.33MHz and therefore a 33% speedup.

    Running the system under debugger control may affect the clock system.

  • Thank you for the explanation of SHT and SHP.  For whatever reason, those two values didn't correlate to me.

    Jens-Michael Gross said:

    - set CCR0 to 68. This gives 4.3125µs cycle time (one tick more than needed, to be sure). Configure CCR1 for SET/RESET or RESET/SET mode, to get a trigger on each cycle.

    In my testing, I noticed that I start running into issues when I set the Timer to trigger the ADC any faster than about 4us.  To quote the erratasheet: "Subsequent ADC conversions are halted if a new ADC conversion is triggered while ADC is busy. ADC conversions are triggered manually or by a timer."  It suggests setting the timer interval to be longer than the ADC sample/conversion time.

    Also in my testing, using debug mode will substantially increase the time it takes to collect 40 samples on each of the 4 ADC input pins.  I have not seen my issues occur if I run a release version of the firmware.

  • Jacob Preston said:
    In my testing, I noticed that I start running into issues when I set the Timer to trigger the ADC any faster than about 4us.

    Yes, that’s why I said that 4.3125µs would be good. A conversion takes 4.25µs. Which are 68 timer ticks or a CCR0 value of 67. One more to be sure.
    If you try to trigger faster than every 4.25µs, you’ll get into trouble.

    When running under debugger control, the debugger my halt the CPU to update register or memory view. You won’t see the CPU stop, but it takes quite some time (for an MCU) to fetch the data, so it may slow down things significantly.

**Attention** This is a public forum