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.

ADC sampling at 240kHz

Part Number: EK-TM4C123GXL

EDIT: Removed Sleep(), as it is irrelevant to the question.

EDIT: Included relevant pre-processor definitions and cleaned up code representation.

EDIT: Fixed SysTick initialization, which did not affect the issue.

I am trying to collect data via the ADC at 240 kHz, and am not sure if I am setting up the clock and timer up correctly... I've been inputting a 10kHz sine wave, and getting data that looks like it's much higher frequency (about 100 kHz). Can someone either verify my config code below, or explain precisely how SysCtlClockSet() and TimerLoadSet() work (as in, how the numbers input to them convert to clock and timer frequency)?

When I run SysCtlClockGet(), I get 80 MHz, the maximum clock frequency. In order to look at the input, I have been putting the samples into a global uint32_t dataBuffer and graphing it.

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <math.h>

#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/timer.h"

#include "inc/hw_adc.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"

//*****************************************************************************
//
// Preprocessor Definitions
// ## Adjust Parameters Here!! ##
//
//*****************************************************************************

// Programmer-Designed Parameters (do not touch)
#define SAMPLE_RATE 240000      // Hz

#define ADC_SEQUENCER 3

#define DEBUG
//#undef DEBUG

//*****************************************************************************
//
// Global Variables
//
//*****************************************************************************

// Debugging variables
#ifdef DEBUG
int gBufferIndex;
static uint32_t gDataBuffer[400];
#endif

//*****************************************************************************
//
// Initialization/Configuration Functions
//
//*****************************************************************************

// Initialize global variables. //
void InitGVariables()
{
#ifdef DEBUG
    // Initialize debugging variables.
    gBufferIndex = 0;
#endif
}

// Initialize clock and timer. //
void InitTiming()
{
    // Initialize clock.
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

    // Configure and enable timer.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0));
    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet()/SAMPLE_RATE);
    TimerEnable(TIMER0_BASE, TIMER_A);
    TimerControlTrigger(TIMER0_BASE, TIMER_A, true);

#ifdef DEBUG
    // Initialize SysTick.
    SysTickPeriodSet(10000000);
    SysTickEnable();
#endif
}

// Initialize GPIO pins. //
void InitGPIO()
{
    // Configure analog input pin.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE));
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3); // Pin 3 corresponds to channel 0.
}

// Initialize ADC. //
void InitADC()
{
    // Configure ADC sequencer.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0));
    ADCSequenceConfigure(ADC0_BASE, ADC_SEQUENCER, ADC_TRIGGER_TIMER, 0);
    ADCSequenceStepConfigure(ADC0_BASE, ADC_SEQUENCER, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);

    // Enable ADC interrupt.
    IntEnable(INT_ADC0SS3);
    ADCIntEnable(ADC0_BASE, ADC_SEQUENCER);
    IntMasterEnable();

    // Enable ADC sequencer.
    ADCSequenceEnable(ADC0_BASE, ADC_SEQUENCER);
}

//*****************************************************************************
//
// Interrupt Handlers
//
//*****************************************************************************

// Handle an ADC interrupt. //
void ADC0Seq3IntHandler()
{
#ifdef DEBUG
    uint32_t numCycles = SysTickValueGet();
#endif

    // Clear interrupt and get sample
    ADCIntClear(ADC0_BASE, ADC_SEQUENCER);
    uint32_t sample;
    ADCSequenceDataGet(ADC0_BASE, ADC_SEQUENCER, &sample);

    // Process data sample.

#ifdef DEBUG
    gBufferIndex = (gBufferIndex + 1) % 400;
    gDataBuffer[gBufferIndex] = sample;

    numCycles = SysTickValueGet() - numCycles;
    uint32_t clockRate = SysCtlClockGet();
#endif
}

//*****************************************************************************
//
// The main function.
//
//*****************************************************************************
int main(void)
{
    // Initialize everything.
    InitGVariables();
    InitTiming();
    InitGPIO();
    InitADC();

    while(1);
}

  • Laura Brandt said:
    (1) Collect data via the ADC at 240 kHz.

    Laura Brandt said:
    (3) Have the processor sleep between samples (rather than running a continual while(1) loop)

    Why!?

    Even assuming 0 processing that's only a few microseconds sleep. Also sleeping and waking will take time.

    Laura Brandt said:
    I am not sure if I am setting up the clock and timer up correctly... I've been inputting a 10kHz sine wave, and getting data that looks like it's much higher frequency (about 100 kHz).

    Get it to work without sleep first. Then you can measure the actual idle time left after processing and see if there is any reason to hare off in this direction

    Robert

  • That is a good point. I increased the sampling rate and never re-evaluated the sleeping idea.

    That said, I have reverted back to a while(1) loop, and it doesn't affect the issue. I still have a strange output from my ADC. I am hopeful that it is simply a silly timing issue that comes from me not fully understanding SysCtlClockSet() and TimerLoadSet(). I mostly copied and then modified code from examples.
  • One thing missing from your code presentation is the definition of SAMPLE_RATE.

    BTW if you use rich formatting and the code past icon </> the code is much easier to read.

    Robert
  • I have included more of my code, hopefully everything relevant is there now.
    Also, I swear that my original code has a terminating new line!

    As you can tell, I don't have much experience. Sorry for the confusion and undue time spent.
  • Laura Brandt said:
    SysTickPeriodSet(16777216);

    That value exceeds by "1" - the 24 bit (max) of SysTick.      Not a likely cause of your issue - yet deserves mention.

    Poster Robert is advocating your employ of, "KISS" which most always, "Speeds, Eases & Enhances" your development efforts.

    You've questioned the operation of (both) Timer & SysTick - "KISS" would have you "toggle" a simple GPIO upon the expiration of each - and your scope would then easily enable "period measurement."