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.

CCS/TM4C1294NCPDT: ADC TIMMER TRIGGER CONFIGURATION

Part Number: TM4C1294NCPDT

Tool/software: Code Composer Studio

Hello! I'm quite new using this plataform and i'm having problems on using a timmer triggered ADC convertion. Can someone help me to find out what is wrong in my code?

//Inclusão de Arquivos/Bibliotecas
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "driverlib/adc.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "utils/uartstdio.h"
#include "driverlib/timer.h"

static uint32_t ADC0Value[1];
static int var = 1;
static int cont = 0;

void InitConsole(void)
{

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); 

	GPIOPinConfigure(GPIO_PA0_U0RX); 
	GPIOPinConfigure(GPIO_PA1_U0TX); 

	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); 

	UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); 

	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); 

	UARTStdioConfig(0, 115200, 16000000);
}

void InitADC(void)
{
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); 

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); 
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE))
	{
	}
	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2);
	SysCtlDelay(80u);


	ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 5);
	SysCtlDelay(10u);

	IntDisable(INT_ADC0SS0);
	ADCIntDisable(ADC0_BASE, 3);
	ADCSequenceDisable(ADC0_BASE, 3);

	ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_TIMER, 0); 

	ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_CH0 | ADC_CTL_IE | ADC_CTL_END);

	ADCIntClear(ADC0_BASE, 3); 
	IntEnable(INT_ADC0SS3);
	ADCIntEnable(ADC0_BASE, 3);
	ADCSequenceEnable(ADC0_BASE, 3); 

}

void InitGPIO(void)
{
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION); 
	while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPION))
	{
	}

	GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1, 0X03); 
}


void InitTimer0 (void)
{
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

	TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC);

	TimerLoadSet(TIMER0_BASE, TIMER_B, SysCtlClockGet() / 1000);

	TimerControlTrigger(TIMER0_BASE, TIMER_B, true);

	TimerIntEnable(TIMER0_BASE, TIMER_TIMB_TIMEOUT);

	IntMasterEnable();

	TimerEnable(TIMER0_BASE, TIMER_B);
}

void ADC0SS3IntHandler(void)
{

	cont+=2;
	ADCIntClear(ADC0_BASE, 3);

	ADCSequenceDataGet(ADC0_BASE, 3, ADC0Value);
}


int main(void)
{

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


	InitGPIO();
	InitConsole();
	InitADC();
	InitTimer0();

	while(1)

	{

		UARTprintf("AIN0 = %d\t", ADC0Value[0]);
		GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1, var);

		UARTprintf("VAR = %d\n",var);

		SysCtlDelay(10000000);

		if(var == 4)
			var = 1;
		else
			var*=2;
	}
}

  • Hello Tiago,

    Your ADC clock configuration looks to be off. For TM4C129x parts the clock frequency for the ADC after dividing must be between 16 and 32 MHz. So if you are using the VCO from the PLL as indicated by your API then, then you should device by a value between 15 and 30 in order to fall into this range as the VCO is running at 480MHz.

    You can read further details about how ADCClockConfigSet should be used in the DriverLib User's Guide.
  • Hello Ralph,

    I made this change as you suggested, but i'm still getting wrong measures from my ADC.

    Now i'm using this configuration:

    //ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 24);

    And already tried the one that's above.

    It seems to be unstable, even when there is a fixed input the converted values are varying a lot. Can you help me with this issue?

    Thanks in advance!
  • Hello Tiago,

    Ah so you are getting wrong measurements now? I had thought it wasn't working period. That is quite a different situation then.

    Can you explain what you are measuring, and any sources of impedance that would affect the input impedance of the ADC pin?
  • Tiago Texeira said:
    It (poster's ADC value) seems to be unstable, even when there is a fixed input - the converted values are varying a lot.

    What's a 'lot?'    For any such 'mixed signal device' - the 3 lsb are likely to suffer jitter.    (You must be precise in your descriptions.)

    As its summer - my firm's intern staff had a crack at 'your assistance.'     They found:

    • IntDisable(INT_ADC0SS0);    and that followed (later) by:

    • IntEnable(INT_ADC0SS3);     (they note that (some) consistency would prove useful)

    • You've elected ADC Sequence #3 - which performs (only) a single conversion.     At this early stage - would it not prove (more) useful - for you to choose Sequence #0 - which enables, '8 'back to back' conversions?     This proves so as those (additional) 7 conversion results (all upon the SAME Channel) - are sure to provide further insights - so helpful to such ADC troubleshooting.   (i.e. 'MORE' data - most always - trumps 'less' data!)
    • As always here - and as Vendor's Ralph well noted - no description of your, 'Analog Input Signal's 'particulars' arrived.    To gain the best performance - the, 'Output characteristics' of your analog signal - must match (as closely as possible) the 'Input characteristics' - of the MCU's ADC.    (such fine detail is provided w/in the MCU manual - both in the ADC Section - and later - w/in the 'Electrical Specs.')
    • You've chosen a Timer Trigger of the ADC operating at 1millisecond (mS) intervals.    Yet you've employed a UART - to display signal results - and (most always) the 'slowness of the UART's data rate' - will intrude into that 1mS, Timer Triggered Interval!    What then?    Has that NOT COMPROMISED your measurement?    When testing - 'KISS' dictates that you, 'REDUCE DATA RATES' (as well as ADC Conversion Rates) so that you, 'Give the device the best odds - of success!'     It is suggested that you increase the time - between ADC conversions!   (but that hits - yet another - and (possibly) a 'deadly'  SNAG!)
    • You've chosen a half-timer (16 bits) AND a 120MHz System Clock - AND desire a 1mS (repetitive) Timer Trigger.    Yet - under the conditions of 120MHz system clock - and 16 Timer Bits - your Timer (at best) can accommodate intervals (no larger) than ~546µS!     Thus - the Timer is (likely) being 'triggered' at a different rate - than you wanted!    (that proves so as the excess Timer Load Value 'over-flows' the Timer's 16 bit capacity - resulting in a 65K 'value subtraction.'      This appears the 'most grievous' of your 'Code Issues!'
    • Rather than 'Invite the complications of the Timer Trigger - the (Old standby)  'ADC Processor Trigger' - may be called at  far LESSER (i.e. Safer RATES - and when coupled w/the 'Move to Sequence 0 (achieving 8 conversions - of the SAME CHANNEL (back to back to back etc.)) - such should provide the 'most likely' (and EASED) 'Path - to your ADC Success!'     (courtesy - as always, 'KISS!')

    To 'best match' your signal - to the requirements of the ADC - in general:

    • minimize the length of 'wire leads' - should those be employed - to provide the analog signal.    (if separation IS required - consider the use of a shielded cable - w/one side of the cable's shield grounded)
    • insure that 'GND' is made common (i.e. both MCU Gnd and your analog signal's Gnd - ARE solidly connected!)    (this SO OFTEN is missed!)
    • introduce the most stable - and pure - DC Level to the ADC.    (unlikely to result from 'tapping' to the MCU's VDD!)
    • Should your MCU provide a 'separate Analog VDD & Analog GND' - properly exploit those (signal stabilizing) power inputs.    Apply the highest quality reference voltage to Analog VDD!
    • most always - the impedance match is 'assisted' by buffering your analog signal through an Op-Amp - configured as a 'voltage follower.'
    • the addition of a small value, ceramic capacitor (0.01µF) installed as close as possible to the MCU's ADC pin - also often improves results
    • keep your analog signal as far as possible from obvious 'noise sources, high currents, and fast switching signals' - each likely to add (unwanted) jitter to your signal  (again - 'short' shielded cable assists)
    • and of course - insure that your analog signal remains - at ALL TIMES - w/in the ADC's input signal specifications.

    [edit/UPDATE]   Credit Vendor's Charles for his keen observation: 

    Poster's use of this function, 'TimerLoadSet(TIMER0_BASE, TIMER_B, SysCtlClockGet() / 1000);'  which included a parameter (which my staff identified as too large - to be accommodated w/in a 16 bit register - suffers yet (another) and (possibly) more significant weakness!     Even though MANY code examples reveal 'SysCtlClockGET() (or Set)' - its use is RESERVED for TM4C123 devices - ONLY!    Such is an 'unfortunate reality' - introduced with the arrival of the TM4C129 family!     An entirely different function must be employed - and those past labels (abandoned) - when the '129 is deployed!

    The young staff - so thoughtful & detailed - would SO MUCH ... LOVE to see their 'Contribution LIKED' - and for (unexplained) reasons - such has been denied...    (So great and 'Motivation KILLING' ... and Pitiful that!)

  • Hello cb1,

    Thanks for mentioning the SysCtlClockGet(), I missed that as well. I was informed from another colleague of the same.

    Tiago, please remove the SysCtlClockGet() call and input the clock frequency based on the output of SysCtlClockFreqSet (many users store this as a variable for ease of reference).
  • Hi Ralph,

    Thank you - and it should be (again) noted that poster's 'preliminary' choice of '1mS' - as the ADC's 'Sequenced Conversion Call' rate, proves:

    • impossible to achieve w/in the split timer's, 16 bit register capacity, when clocked from a 120MHz source
    • in all probability is 'FAR TOO FAST' for poster's initial, 'Test/Verify.'     'KISS' directs the slowest, easily achievable rate - which 'vastly heightens the odds of poster success!'
    • use of the Timer - as ADC trigger - adds (another) element of risk - thus violates 'KISS.'     Instead - old standby, 'ADC processor trigger' should be employed  - at least until ADC success results.

    Soon departing (intern) staff (school starts next week) have provided a 'rich guide' of tech items - worthy of poster's time & consideration.    (even (others) arriving here - should benefit from this dedicated group's focus & effort...)

  • Hello! Thank you all so much for your time and effort to help me!

    It was all about the clock configuration, I made some modifications in order to set it correctly, including removing the SysCtlClockGet().

    Here is my code after the modifications:


    //Inclusão de Arquivos/Bibliotecas
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_ints.h"
    #include "driverlib/adc.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/uart.h"
    #include "utils/uartstdio.h"
    #include "driverlib/timer.h"

    //Definição de variáveis
    #define NUMBER_OF_INTS 32000


    int cont = 0;
    int i = 0;
    int ADC_FREQKHZ = 30;
    uint32_t SysClock = 0;
    uint32_t ADC0Value[2];
    uint32_t DATA_ADC0[NUMBER_OF_INTS];
    uint32_t DATA_ADC1[NUMBER_OF_INTS];

    void InitConsole(void)
    {

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); 

    GPIOPinConfigure(GPIO_PA0_U0RX); 
    GPIOPinConfigure(GPIO_PA1_U0TX); 

    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); 

    UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); 

    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    UARTStdioConfig(0, 115200, 16000000); 
    }

    void InitADC(void)
    {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); //Habilita o canal ADC0

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); //Habilita a porta E

    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3 | GPIO_PIN_2); 
    //GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    SysCtlDelay(80u);


    //ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 10);
    //ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PLL | ADC_CLOCK_RATE_FULL, 24);
    SysCtlDelay(10u);

    IntDisable(INT_ADC0SS0);
    ADCIntDisable(ADC0_BASE, 0);
    ADCSequenceDisable(ADC0_BASE, 0);

    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0); 

    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
    ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1 | ADC_CTL_IE | ADC_CTL_END);

    ADCHardwareOversampleConfigure(ADC0_BASE, 8);

    ADCIntClear(ADC0_BASE, 0); //Define a flag para iniciar as conversões
    IntEnable(INT_ADC0SS0);
    ADCIntEnable(ADC0_BASE, 0);
    ADCSequenceEnable(ADC0_BASE, 0); //Habilita o canal 0

    }

    void InitGPIO(void)
    {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION); //Habilita o GPION
    GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2); 
    GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0 | GPIO_PIN_1, 0X02); 
    }


    void InitTimer0 (void)
    {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC);

    TimerLoadSet(TIMER0_BASE, TIMER_B, SysClock/(1000*ADC_FREQKHZ));

    TimerControlTrigger(TIMER0_BASE, TIMER_B, true);

    TimerIntEnable(TIMER0_BASE, TIMER_TIMB_TIMEOUT);

    IntMasterEnable();

    TimerEnable(TIMER0_BASE, TIMER_B);
    }

    void ADC0SS0IntHandler(void)
    {
    cont+=1;
    ADCIntClear(ADC0_BASE, 0);
    ADCSequenceDataGet(ADC0_BASE, 0, ADC0Value);
    //UARTprintf("AIN0 = %d\n", ADC0Value[0]);
    DATA_ADC0[cont] = ADC0Value[0]; //PE3
    DATA_ADC1[cont] = ADC0Value[1]; //PE2

    if(cont >= NUMBER_OF_INTS)
    {
    IntDisable(INT_ADC0SS0);
    ADCIntDisable(ADC0_BASE, 0);
    ADCSequenceDisable(ADC0_BASE, 0);
    ADCIntClear(ADC0_BASE, 0);
    }

    }


    int main(void)
    {

    SysClock = SysCtlClockFreqSet(SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480, 40000000); 
    InitGPIO();

    InitConsole();
    InitADC();
    InitTimer0();


    cont = 0;

    while(1)
    {
    if(cont >= NUMBER_OF_INTS)
    {
    cont = 0;
    for(i==0;i<=NUMBER_OF_INTS;i++)
    {
    UARTprintf("Sample %d: %d\t%d\n", i, DATA_ADC0[i], DATA_ADC1[i]);
    SysCtlDelay(10000);
    }

    }
    }
    }

  • Thank you - my group (and surely this vendor) are pleased that you've persisted - and succeeded!

    Yet may we ask - what is the 'expected  Timer-Triggered, ADC rate' - achieved via:

    "TimerLoadSet(TIMER0_BASE, TIMER_B, SysClock/(1000*ADC_FREQKHZ));"

    You may have noted that staff (earlier) identified  '~564µS'  as the maximum value - containable w/in the Timer's 16 bit Register - when driven from a 120MHz clock source!      Are you certain that your "new implementation' indeed 'fits' - w/in those 16 Timer bits?

    We have just noted - FAR DOWN your code listing - that you (appear) to have reduced System Clock to 40MHz.     That should expand your 16 bit Timer Register to a 1.5mS (max) capacity.    (assuming 'everything else' - remains constant.)    Such DOES NOT - prove the case!   (we only later - discovered!)

    Instead - you define, 'ADC_FREQKHZ' as 30' - thus we believe your final (3rd) parameter w/in TimerLoadSet() is (now) 30,000.     (which btw - fits NICELY w/in a 65K Timer Register - is this (30K) correct?)

    And - kindly do describe the variance of your ADC measurements - when feeding a 'fixed input signal level' to your ADC.    (two channels are (now) being converted...)    It is expected that the 3 lsb of the ADC's conversion value - will reveal 'jitter' - characteristic of (any) MCU's ADC...

    Finally - you've not (yet) adopted staff's (earlier post) suggestion - of  employing 'ALL EIGHT STEPS' - w/in 'ADC Sequence 0!'      Would not 8 (back to back) ADC Measures (of the SAME ADC Channel) - prove of (even) greater value?     (variations w/in such 'rapid conversions' may (likely) reveal - 'improper MATCH' - between your analog signal's output - and the ADC's input.    Such proves of value ... does it not?