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.

Having a hard time getting ADC to do more than 71 ksps

I am just not quite understanding how to get the ADC14 to sample at its top speed.  I would like to get something in the neighborhood of 1MSPS, but I ma having a hard time getting even 1/10 of the way there. 

The program that I am using is based on the adc14_single_conversion_repeat.c example.  I added in a few lines to echo ACLK and MCLK to P4.2 and P4.3 and a line of code to flip the LED bit on each conversion. 

The code is below, if anyone is willing to look.  Hopefully there is an amusing error in there.  I have tried various clocks for the MAP_ADC14_initModule() call etc., but I get the same results.

Thanks,

mike hogan

/* DriverLib Includes */
#include "driverlib.h"

/* Standard Includes */
#include <stdint.h>

#include <stdbool.h>

/* Statics */
static volatile uint16_t curADCResult;
static volatile float normalizedADCRes;

int main(void)
{
    /* Halting the Watchdog  */
    MAP_WDT_A_holdTimer();

    // Set P1.0 to output direction
    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0 );

    P4DIR |= BIT2 | BIT3;
    P4SEL0 |= BIT2 | BIT3;                         // Output ACLK & MCLK
    P4SEL1 &= ~(BIT2 | BIT3);

    /* Initializing Variables */
    curADCResult = 0;

    /* Setting DCO to 48MHz  */
    MAP_PCM_setPowerState(PCM_AM_LDO_VCORE1);
    MAP_CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_48);

    /* Enabling the FPU for floating point operation */
    MAP_FPU_enableModule();
    MAP_FPU_enableLazyStacking();

    /* Initializing ADC (MCLK/1/1) */
    MAP_ADC14_enableModule();
    MAP_ADC14_initModule(ADC_CLOCKSOURCE_MCLK, ADC_PREDIVIDER_1, ADC_DIVIDER_1,  0);
            
    /* Configuring GPIOs (5.5 A0) */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN5,  GPIO_TERTIARY_MODULE_FUNCTION);

    /* Configuring ADC Memory */
    MAP_ADC14_configureSingleSampleMode(ADC_MEM0, true);
    MAP_ADC14_configureConversionMemory(ADC_MEM0, ADC_VREFPOS_AVCC_VREFNEG_VSS, ADC_INPUT_A0, false);

    /* Configuring Sample Timer */
    MAP_ADC14_enableSampleTimer(ADC_AUTOMATIC_ITERATION);

    /* Enabling/Toggling Conversion */
    MAP_ADC14_enableConversion();
    MAP_ADC14_toggleConversionTrigger();

    /* Enabling interrupts */
    MAP_ADC14_enableInterrupt(ADC_INT0);
    MAP_Interrupt_enableInterrupt(INT_ADC14);
    MAP_Interrupt_enableMaster();

    while (1)
    {
        MAP_PCM_gotoLPM0();
    }
    
}

/* ADC Interrupt Handler. This handler is called whenever there is a conversion
 * that is finished for ADC_MEM0.
 */
void adc_isr(void)
{
    uint64_t status = MAP_ADC14_getEnabledInterruptStatus();
    MAP_ADC14_clearInterruptFlag(status);

    if (ADC_INT0 & status)
    {
        curADCResult = MAP_ADC14_getResult(ADC_MEM0);
        normalizedADCRes = (curADCResult * 3.3) / 16384;

       // MAP_ADC14_toggleConversionTrigger();

        // Toggle P1.0 output for simple measurement of conversion speed
        GPIO_toggleOutputOnPin( GPIO_PORT_P1, PIO_PIN0);
    }
}

  • Hi Michael!

    The reason for your "slow" conversion rate is your interrupt service routine. If you want to do conversions at very high sample rates you will have to use the DMA controller to fetch your ADC results without CPU intervention. Although the MSP432 can run at 48MHz, this is not fast enough to sample with 1MSPS and having all the overhead that comes from the ISR. The DMA works in hardware and needs (almost) no CPU power.

    And there is another thing you should not do:

    normalizedADCRes = (curADCResult * 3.3) / 16384;

    ...you do calculations inside the ISR. This slows down your processing speed even more. The MSP432 has a floating point unit (try to avoid floating point calculations on a processor without FPU), but it works against your goal of high sample rates.

    So you should try to get familiar with the DMA controller.

    Dennis

  • Thanks!  I will see how much I gain by eliminating the calculation.

    The code is for reading a CCD, and I need to coordinate the samples with a clock signal, so I am not quite sure how to do that with DMA .. I'll see if I can figure out how to echo a sample-clock signal to one of the external pins .. Or maybe I need to use a completely different approach

  • Michael Hogan said:
    normalizedADCRes = (curADCResult * 3.3) / 16384;

    The floating point constant 3.3 is implicitly double-precision (64-bit) which will cause the compiler to generate double-precision calculations.

    The Cortex-M4F only supports single-precision (32-bit) calculations in hardware, which means any double-precision calculations have to be done in software which is slower.

    If you change the floating point constant to single-precision by adding a "f" suffix that should allow the compiler to generate single-precision calculations using the hardware floating point and thus run faster:

     normalizedADCRes = (curADCResult * 3.3f) / 16384;

  • Good catch, Chester!
  • Thanks -- I took out the FP calculation and it's up to about 165ksps, which may be good enough for what I am doing.

**Attention** This is a public forum