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.

TM4C123: Trouble in implementing ADC function



Hello, I am Sky.

I am struggling with implementing an ADC function on TM4C123.

I would like to make an ADC function which satisfies four conditions:

1) acquire two channels of ADC signals from ADC0_BASE, ADC1_BASE concurrently

2) synchronize with specific sampling rate (e.g., 200khz) using TIMER (not PWM)

3) use oversampling (4x) mode and calculate average values of them

4) use differential mode

Fortunately, I found well-defined two documents as below:

Ref 1. ADC Oversampling Techniques for Stellaris® Family Microcontrollers

(http://www.ti.com/lit/an/spma001a/spma001a.pdf)

Ref 2. C:\ti\TivaWare_C_Series-2.1.3.156\examples\peripherals\adc\differential.c

They gives me information on oversampling(4x), average values, and differential mode well.

However, I faced with a few questions,

Q1) My program hangs on ADCIntStatus command.

When I write the code on Ref 2,

it hangs on a line "while(!ADCIntStatus(ADC0_BASE, 3, false))".

I don't know how to fix it.

Q2) How can I manipulate sampling time of ADC using Timer?

In order to synchronize with Timer0 (not PWM), I used this command.

ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_TIMER, 0);

(When I refer to another manual which named "TivaWare™ Peripheral Driver Library", it explains that

"ADC_TRIGGER_TIMER - A trigger generated by a timer; configured with TimerControlTrigger().")

And then, I follow an example of 5 page of (Ref 1).

However, it seems that defined sampling rate of the Timer doesn't work.

How can I run ADC conversion with desired sampling rate which is defined by Timer?

For better understanding of my problem, I would like to attach my source code below:

=====================================================================

    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    uint32_t sequence_number = 3;

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_ADC0))
    {
    }
    SysCtlDelay(10);

    ADCIntEnable(ADC0_BASE, sequence_number);
    ADCSequenceDisable(ADC0_BASE, sequence_number);

    ADCSequenceConfigure(ADC0_BASE, sequence_number, ADC_TRIGGER_TIMER, 0);
    ADCSoftwareOversampleConfigure(ADC0_BASE, sequence_number, 4);
    ADCSoftwareOversampleStepConfigure(ADC0_BASE, sequence_number, 0, (ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END));
    ADCSequenceEnable(ADC0_BASE, sequence_number);
    ADCIntEnable(ADC0_BASE, sequence_number);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0))
    {
    }
    SysCtlDelay(10);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_B_PERIODIC);
    TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 1000);
    TimerEnable(TIMER0_BASE, TIMER_A);

    while(1)
    {
        ADCProcessorTrigger(ADC0_BASE, sequence_number);
        while(!ADCIntStatus(ADC0_BASE, sequence_number, false))
        {
	}
	uint32_t g_ulAverage;
	ADCSoftwareOversampleDataGet(ADC0_BASE, sequence_number, &g_ulAverage, 4);

	GPIO_toggle(Board_LED0);
    }

=====================================================================

Please give me a solution.

Thanks in advance.

-Sky

+ Nov 16, 2016

As Amit Ashara suggested, I will update my posting after remove ADCProcessorTrigger command.

  • Hello Sky

    If you are using Timer Trigger then ADCProcessorTrigger API must not be used. There is a known issue where if the ADC is triggered while it is converting, the ADC shall not complete the conversion process.
  • Sky Kim said:
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);

    Is parameter, "SYSCTL_SYSDIV_1" proper when using the PLL?   (suspect that this MCU requires a divide of 2.5 (minimum)...)

  • Hello cb1

    Another excellent point...
  • Thank you, Sir.

    Easy when Robert, f.m., Chester (et moi) may "cherry-pick" - and deal w/1/1000 of your load...
  • Hello guys,

    Finally, I can control my ADC function.
    I can adjust sampling rate as I want, and it works well.
    Thanks for your kindness!

    Here is my source code.


    uint32_t ADCSequenceNumber = 0;
    uint16_t ADCSamplingRateKhz = 200;
    uint32_t ADCNumOfSamples = 4096;

    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

    //Initialize ADC
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); //Pin for ADC input
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //ADC peripheral
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1); //ADC peripheral
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    //Pins used for ADC channels
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0); //set GPIO_E3 for channel 1
    ADCSequenceConfigure(ADC0_BASE, ADCSequenceNumber, ADC_TRIGGER_TIMER, 0); //sequencer 0
    ADCSequenceConfigure(ADC1_BASE, ADCSequenceNumber, ADC_TRIGGER_TIMER, 0); //sequencer 0
    ADCSequenceStepConfigure(ADC0_BASE, ADCSequenceNumber, 0, ADC_CTL_D | ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);
    ADCSequenceStepConfigure(ADC1_BASE, ADCSequenceNumber, 0, ADC_CTL_D | ADC_CTL_CH2 | ADC_CTL_IE | ADC_CTL_END);

    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
    TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet()/(1000*ADCSamplingRateKhz));
    TimerEnable(TIMER0_BASE, TIMER_A);
    TimerControlTrigger(TIMER0_BASE,TIMER_A,true);

    ADCSequenceEnable(ADC0_BASE, ADCSequenceNumber);
    ADCSequenceEnable(ADC1_BASE, ADCSequenceNumber);
    ADCIntEnable(ADC0_BASE, ADCSequenceNumber);
    ADCIntEnable(ADC1_BASE, ADCSequenceNumber);


    //Enable ADC
    ADCIntClear(ADC0_BASE, ADCSequenceNumber);
    ADCIntClear(ADC1_BASE, ADCSequenceNumber);
    ADCIntEnable(ADC0_BASE, ADCSequenceNumber);
    ADCIntEnable(ADC1_BASE, ADCSequenceNumber);

    uint32_t data0[4096];
    uint32_t data1[4096];

    for(ADCCurrentIndex=0; ADCCurrentIndex < ADCNumOfSamples; ADCCurrentIndex++)
    {
    ADCIntClear(ADC0_BASE, ADCSequenceNumber);
    ADCIntClear(ADC1_BASE, ADCSequenceNumber);
    while(!ADCIntStatus(ADC0_BASE, ADCSequenceNumber, 0));
    while(!ADCIntStatus(ADC1_BASE, ADCSequenceNumber, 0));

    uint32_t num1 = ADCSequenceDataGet(ADC0_BASE, ADCSequenceNumber, &data0[ADCCurrentIndex]);
    uint32_t num2 = ADCSequenceDataGet(ADC1_BASE, ADCSequenceNumber, &data1[ADCCurrentIndex]);
    }

    ADCIntDisable(ADC0_BASE, ADCSequenceNumber);
    ADCIntDisable(ADC1_BASE, ADCSequenceNumber);