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.

TM4C1294NCPDT: Increase sampling rate of the ADC

Part Number: TM4C1294NCPDT


Hello,

I am trying to reach the mentioned sampling rate of 1 MHz for the ADC on the TM4C1294NCPDT board. But, all I can reach is upto 50 kHz for each channel (I am using 4 channels). I am using a timer to trigger the ADC sequence and take data. I also have some processing going on in between the timer interrupts.

Whenever I try to set the sampling rate more than 50kHz, the code doesn't work and when I watch the variables using expression tab in CCS, it would give some garbage values.

Please, let me know where I am going wrong and how to reach the maximum sampling rate as it would helpful to me. I have attached my code below.

Regards,

Sourav

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/interrupt.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"

	#define TOT_CHN 4
	#define UP_WIN 70
	#define LOW_WIN 10
	#define TOT_WIN UP_WIN+LOW_WIN
	#define SAMPLING_RATE 50000

    uint32_t pui32ADC0Value[TOT_CHN];
    uint32_t cnt[TOT_CHN];
    volatile uint32_t read_data[TOT_CHN][120]; volatile uint32_t ci = 0;
    volatile uint16_t ub,l,m,p = 0; volatile uint16_t lb = 100-LOW_WIN;
    volatile uint16_t y[TOT_CHN]={100,100,100,100}; volatile uint16_t k[TOT_CHN];
    volatile uint32_t saved_data[TOT_CHN][100]; volatile uint32_t sample[TOT_CHN];
    volatile bool read[TOT_CHN] = {true,true,true,true};

//volatile uint32_t write = 0;

int
main(void)
{
    uint32_t ui32SysClock;

    ui32SysClock = SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                       SYSCTL_OSC_MAIN |
                                       SYSCTL_USE_PLL |
                                       SYSCTL_CFG_VCO_480), 120000000);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

//    SysCtlPeripheralReset(SYSCTL_PERIPH_ADC0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

//    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);

    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 30);

//    GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_2);

    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_TIMER, 0);
//    ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_ALWAYS, 0);

    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

    ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH1);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH2);
    ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH3 | ADC_CTL_IE |
                                                ADC_CTL_END);

    TimerLoadSet(TIMER0_BASE, TIMER_A, ui32SysClock/SAMPLING_RATE);

    TimerControlTrigger(TIMER0_BASE, TIMER_A, true);

    IntMasterEnable();

    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    IntEnable(INT_TIMER0A);

    ADCSequenceEnable(ADC0_BASE, 1);

    ADCIntClear(ADC0_BASE, 1);

    TimerEnable(TIMER0_BASE, TIMER_A);

    //SysCtlDelay(ui32SysClock/6);

    while(1)
    {
//    	GPIOPinWrite(GPIO_PORTN_BASE,GPIO_PIN_2, 4);

        for(l=0;l<TOT_CHN;l++){
            if(k[l]>=TOT_WIN){k[l]=0;}
        }

    	for(l=0;l<TOT_CHN;l++){
    	    if(read_data[l][ub]>=500 && read[l]==true){
    		    m=lb;read[l]=false;y[l]=0;sample[l]=ci;
    		    for(p=0;p<10;p++){
    			    saved_data[l][k[l]]=read_data[l][m+1];k[l]++;
    			    m++;
    			    if(m>=100){m=0;}
    		    }
    		    cnt[l]++;
    	    }
    	}
    	if(ub>=100){ub=0;}
    	if(lb>=100){lb=0;}
    	if(ci>100000){ci=0;}
//    	SysCtlDelay(200000);

//    	GPIOPinWrite(GPIO_PORTN_BASE,GPIO_PIN_2, 1);

//    	SysCtlDelay(200000);
    }
}

void
Timer0IntHandler(void)
{

//	GPIOPinWrite(GPIO_PORTN_BASE,GPIO_PIN_2, 4);

	ub++;lb++;ci++;

	TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

//	ADCProcessorTrigger(ADC0_BASE, 1);

	while(!ADCIntStatus(ADC0_BASE, 1, false))
	{
	}

	ADCIntClear(ADC0_BASE, 1);

	ADCSequenceDataGet(ADC0_BASE, 1, pui32ADC0Value);
	for(l=0;l<TOT_CHN;l++){
	    read_data[l][ub]=pui32ADC0Value[l];
	    read[l]=true;
	}
	for(l=0;l<TOT_CHN;l++){
	    if(y[l]<UP_WIN){
	        saved_data[l][k[l]]=read_data[l][ub];
	        k[l]++;y[l]++;read[l]=false;
	    }
	}

//	GPIOPinWrite(GPIO_PORTN_BASE,GPIO_PIN_2, 1);
}

  

  • Even though SysCtlClockFreqSet() uses the parameter SYSCTL_CFG_VCO_480, the VCO is set to 240MHz to avoid the issues of erratum SYSCTL#22. Therefore use a divider of 15 in the function ADCClockConfigSet() to configure the ADC for 1 MSPS (million samples per second). In the code you configured the sequencer to convert 4 channels. That means each channel is sampled at a rate of 250KHz (1MHz/4). Since to achieve this rate the ADC is running continuously you should just configure the sequence to use ADC_TRIGGER_ALWAYS. Finally, your processing needs to keep up with the rate of the incoming data.
  • Hi Bob,

    Thanks I could achieve the max sampling rate following your recommendations. But, the part in the while loop seems to be slowing down things. It takes almost 1/150 ms for the code in the while loop to execute even the system clock is set at max 120 MHz. It would be helpful if you can give any general ideas to speed up the code.
    Also, the some of the variables values are not behaving as expected. Like, sample variable I have defined for all 4 channels but for the 1st channel it is showing always 0 in the watch expression tab. Is something I can do to avoid such errors.

    Regards,
    Sourav
  • The problem with being stuck in the "while" loop is that you use the timer to start the ADC and to generate the interrupt. In the timer interrupt routine you need to wait for the four ADC conversions to complete. Instead, use the timer to start the ADC, but use the last step of the ADC sequence to generate the interrupt. I have attached an example that uses the timer to start the ADC. It is a bit more complicated because it uses the uDMA to read the ADC instead of the CPU. Maybe it will help you.

    /cfs-file/__key/communityserver-discussions-components-files/908/7380.ADCwDMA.zip

  • Thank you very much.

    Regards,
    Sourav