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: ADC sampling frequency and clock

Part Number: TM4C1294NCPDT

Hi, 

This is namha. 

I want to increase the ADC sampling frequency to over 1Mhz. But the frequency above 600kHz does not increase.

I'm using ADC0 and ADC1 two modules at the same time, I'm using timer0 as a trigger, and I'm working with polling.

And here are some questions.

1. Why does not the sampling frequency increase by more than 1Mhz?

2. I would like to run the ADC clock at 32Mhz using an external oscillator. Can I use the API as shown below?

  What does 'ADC_CLOCK_SRC_PLL' mean? 

ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 15); // Configure the ADC to use PLL at 480 MHz divided by 15 to get an ADC clock of 32 MHz
ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 15); // Configure the ADC to use PLL at 480 MHz divided by 15 to get an ADC clock of 32 MHz.

3. What does 'ADC_REF_EXT_3V' mean in the code below?

ADCReferenceSet(ADC0_BASE,ADC_REF_EXT_3V)

Below is my code.

------------------------------------------------------------ function ------------------------------------------------------------------------

void ADCInit()
{
uint32_t samplePeriod = 0;
//Initialize ADC
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //ADC0 peripheral
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1); //ADC1 peripheral
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // ADC Trigger
SysCtlDelay(10);

ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 15); // Configure the ADC to use PLL at 480 MHz divided by 15 to get an ADC
// clock of 32 MHz.
ADCClockConfigSet(ADC1_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 15); // Configure the ADC to use PLL at 480 MHz divided by 15 to get an ADC
// clock of 32 MHz.
SysCtlDelay(10); // Time for the clock configuration to set

//Pins used for ADC channels
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);
ADCSequenceConfigure(ADC0_BASE, ADC_SEQUENCE_NUMBER, ADC_TRIGGER_TIMER, 0);
ADCSequenceConfigure(ADC1_BASE, ADC_SEQUENCE_NUMBER, ADC_TRIGGER_TIMER, 0);

ADCSequenceStepConfigure(ADC0_BASE, ADC_SEQUENCE_NUMBER, 0, ADC_CTL_D | ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); // Differtial mode, Timer0 Trigger
ADCSequenceStepConfigure(ADC1_BASE, ADC_SEQUENCE_NUMBER, 0, ADC_CTL_D | ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END); // Differtial mode, Timer0 Trigger
ADCHardwareOversampleConfigure(ADC0_BASE, g_ui32AdcOverSamplingNumber);
ADCHardwareOversampleConfigure(ADC1_BASE, g_ui32AdcOverSamplingNumber);

ADCIntClear(ADC0_BASE, ADC_SEQUENCE_NUMBER); // ADC0 interrupt flag clear
ADCIntClear(ADC1_BASE, ADC_SEQUENCE_NUMBER); // ADC1 interrupt flag clear

TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC);
samplePeriod = g_ui32SysClock / 800000; // calculate timerperiod for 500KHz

TimerLoadSet(TIMER0_BASE, TIMER_A, samplePeriod - 1); // sampling frequency
TimerEnable(TIMER0_BASE, TIMER_A);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
TimerControlStall(TIMER0_BASE, TIMER_A, true); //Assist in debug by stalling timer at breakpoints

ADCReferenceSet(ADC0_BASE,ADC_REF_EXT_3V); // ADC0 External Reference Voltage setting
ADCReferenceSet(ADC1_BASE,ADC_REF_EXT_3V); // ADC0 External Reference Voltage setting
ADCSequenceEnable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
ADCSequenceEnable(ADC1_BASE, ADC_SEQUENCE_NUMBER);
}

void ADCAcquire_Org(uint32_t ADCDataLength)
{
uint32_t ui32ADCCurrentIndex = 0;

ADCEnable(); // ADC Start
//GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, GPIO_PIN_0);
for(ui32ADCCurrentIndex=0; ui32ADCCurrentIndex < ADCDataLength/2; ui32ADCCurrentIndex++)
{
ADCIntClear(ADC0_BASE, ADC_SEQUENCE_NUMBER);
ADCIntClear(ADC1_BASE, ADC_SEQUENCE_NUMBER);
while(!ADCIntStatus(ADC0_BASE, ADC_SEQUENCE_NUMBER, 0));
while(!ADCIntStatus(ADC1_BASE, ADC_SEQUENCE_NUMBER, 0));

g_ui16AdcRawData[2*ui32ADCCurrentIndex + 0] = (q15_t)HWREG(ADC0_BASE + ADC_O_SSFIFO3);
g_ui16AdcRawData[2*ui32ADCCurrentIndex + 1] = (q15_t)HWREG(ADC1_BASE + ADC_O_SSFIFO3);
}
//GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0);
ADCDisable(); // ADC Stop
}

void ADCEnable()

{
ADCIntEnable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
ADCIntEnable(ADC1_BASE, ADC_SEQUENCE_NUMBER);
}

void ADCDisable()
{
ADCIntDisable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
ADCIntDisable(ADC1_BASE, ADC_SEQUENCE_NUMBER);
}

------------------------------------------------------------ main------------------------------------------------------------------------

int main(void)
{

 g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), TM4C129_MAIN_CLK);

FPUEnable();
FPULazyStackingEnable();

.

.

.

.

 IntMasterEnable(); // 20190312_LNH, Global Interrupt Enable

while(1)
{
ADCAcquire_Org(FFT_POINTS); // 20190312_LNH

arm_q15_to_float(g_ui16AdcRawData, g_ui32AdcRawData, FFT_POINTS); // 20190312_LNH, integer to float change.
for(i = 0; i < FFT_POINTS; i++) g_ui32AdcRawData[i] = g_ui32AdcRawData[i] * FloatScale; // 20190312_LNH, scaling for integer to float
delay_ms(1); // 20190312_LNH
}

    

  • Sorry. I forgot one thing. ADCInit () is in main().
  • Hello Namha,

    This topic came up a while ago and one of our engineers found the solution to get the ADC running up to 2MSPS, please see this thread in which he provided the full code required to get the ADC operating at above 1MSPS: e2e.ti.com/.../2545036
  • Hi Ralph, 

    Before posting my issue, I reviewed and applied the issue you recommended.But there was no change.

    Is there any other solution?

  • Hello Namha,

    Can you post your latest code with the fixes Bob had suggested so I can review?
  • void ADCInit()
    {
    	uint32_t samplePeriod = 0;
    	//Initialize ADC
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //ADC0 peripheral
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1); //ADC1 peripheral
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); // ADC Trigger
    	SysCtlDelay(80u);
    
    	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 5);
    	SysCtlDelay(10); // Time for the clock configuration to set
    
    	IntDisable(INT_ADC0SS3);
    	IntDisable(INT_ADC1SS3);
    	ADCIntDisable(ADC0_BASE, 0u);
    	ADCIntDisable(ADC1_BASE, 0u);
    	ADCSequenceDisable(ADC0_BASE,0u);
    	ADCSequenceDisable(ADC1_BASE,0u);
    	// With sequence disabled, it is now safe to load the new configuration parameters
    
    	//Pins used for ADC channels
    	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);
    	ADCSequenceConfigure(ADC0_BASE, ADC_SEQUENCE_NUMBER, ADC_TRIGGER_TIMER, 0); // Priority 0
    	ADCSequenceConfigure(ADC1_BASE, ADC_SEQUENCE_NUMBER, ADC_TRIGGER_TIMER, 1); // Priority 1
    	ADCSequenceStepConfigure(ADC0_BASE, ADC_SEQUENCE_NUMBER, 0, ADC_CTL_D | ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END); // Differential mode, Timer0 Trigger
    	ADCSequenceStepConfigure(ADC1_BASE, ADC_SEQUENCE_NUMBER, 0, ADC_CTL_D | ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END); // Differential mode, Timer0 Trigger
    
    	TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC);
    
    	samplePeriod = g_ui32SysClock / 800000; // calculate timerperiod for 500KHz
    	TimerLoadSet(TIMER0_BASE, TIMER_A, samplePeriod - 1); // sampling frequency
    	TimerEnable(TIMER0_BASE, TIMER_A);
    	TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    	TimerControlStall(TIMER0_BASE, TIMER_A, true); //Assist in debug by stalling timer at breakpoints
    
    	ADCReferenceSet(ADC0_BASE,ADC_REF_EXT_3V); // ADC0 External Reference Voltage setting
    	ADCReferenceSet(ADC1_BASE,ADC_REF_EXT_3V); // ADC0 External Reference Voltage setting
    	ADCSequenceEnable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    	ADCSequenceEnable(ADC1_BASE, ADC_SEQUENCE_NUMBER);
    	ADCIntClear(ADC0_BASE, ADC_SEQUENCE_NUMBER); // ADC0 interrupt flag clear
    	ADCIntClear(ADC1_BASE, ADC_SEQUENCE_NUMBER); // ADC1 interrupt flag clear
    	IntEnable(INT_ADC0SS3);
    	IntEnable(INT_ADC1SS3);
    }
    
    void ADCEnable()
    {
    	ADCIntEnable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    	ADCIntEnable(ADC1_BASE, ADC_SEQUENCE_NUMBER);
    }
    
    void ADCDisable()
    {
    	ADCIntDisable(ADC0_BASE, ADC_SEQUENCE_NUMBER);
    	ADCIntDisable(ADC1_BASE, ADC_SEQUENCE_NUMBER);
    
    }
    
    ======================================================== main ==============================================================
    
    		int main(void)
    {
    	int i; 
    	g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), TM4C129_MAIN_CLK); // TM4C129_MAIN_CLK = 120000000
    
    
    	FPUEnable();
    	FPULazyStackingEnable();
    
    	.
    
    	.
    
    	.
    
    	ADCInit();
    
    	ADCEnable(); // for test ADC Function
    
    	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0);
    
    	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 0);
    	IntMasterEnable(); // 20190312_LNH, Global Interrupt Enable
    
    	while(1)
    	{
    
    	}
    }
    
    void ADC0SS3IntHandler(void)
    {
    	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, GPIO_PIN_0); // LED toggle
    	g_ui16AdcRawData[2*ui32ADCCurrentIndex_0 + 0] = (q15_t)HWREG(ADC0_BASE + ADC_O_SSFIFO3);
    	ui32ADCCurrentIndex_0++;
    	HWREG(ADC0_BASE + ADC_O_ISC) = 1 << 0; // ADC Interrupt Status and Clear
    	// ADCIntClear(ADC0_BASE, 0);
    	if(ui32ADCCurrentIndex_0 >= 2048)
    	{
    		GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_0, 0); // LED toggle
    		//HWREG(GPIO_PORTD_BASE + GPIO_PIN_0) = 0x00;
    		ui32ADCCurrentIndex_0 = 0;
    	}
    }
    
    void ADC1SS3IntHandler(void)
    {
    	g_ui16AdcRawData[2*ui32ADCCurrentIndex_1 + 0] = (q15_t)HWREG(ADC1_BASE + ADC_O_SSFIFO3);
    	ui32ADCCurrentIndex_1++;
    	HWREG(ADC1_BASE + ADC_O_ISC) = 1 << 0; // ADC Interrupt Status and Clear
    	if(ui32ADCCurrentIndex_1 >= 2048)
    	{
    		ui32ADCCurrentIndex_1 = 0;
    	}
    }

    Hi Ralph , 

    he above codes are those using Bob's code. 

    The interrupt method using samplesquence was tested with tm4c123 a few months ago. At that time, only ADC0SS3IntHandler worked and ADC1SS3IntHandlers did not work. The tm4c1294 that I tested this time is also the same result.

    ADC0 and 1 sample sequence interrupt can not operate at the same time?

    I want to ensure that the ADC0 and ADC1 two modules simultaneously have sampling frequencies above 1Mhz.

  • Hello Namha,

    I need to consult with Bob on the part about being able to get both modules running at 1 MHz. In theory since one module can get to 2MSPS, I would think two are capable of running at 1MSPS, but there may be some limiting factor I am not aware of. Also I am not sure if you can trigger both modules off the same timer.

    As far as the speeds you are see, couple comments:

    1) TimerEnable(TIMER0_BASE, TIMER_A); should be used to trigger the ADC's, so I would recommend calling that at the end of the setup.

    2) The ISR you have is pretty ADC0 has a lot going on, and that is going to slow down the processing. Bob specifically used an extremely slim ISR to maintain a high sample rate (2MSPS in his case) and I am concerned you have too much going on for this if you want to run both modules at 1MSPS. Given you are trying to do pretty high speed readings here, I think you need to trim down your ISR to the bare minimum.

    See if you can at least get ADC0 sped up to 1MSPS by trimming down the ISR (perhaps start w/ removing LED toggle?)
  • Hello Namha,

    I spoke w/ Bob and he doesn't think there would any reason both ADC's can't run at your desired speeds simultaneously. Let's try and simplify this a little first, as mentioned I want you to see if you can get the ADC0 speed up to your levels. Can you please try the changes and get ADC0 working at 1MSPS?

    Then when done, also test if you run only ADC1 and not ADC0, that you also can get ADC1 at 1 MSPS. If both of these are running at your desired rate, then try and use them both together again and if that ends up still having issues, then we can investigate from there at least knowing that the individual ADC modules on their own work as expected.