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: Problems with ADC accuracy

Part Number: TM4C1294NCPDT
Hi,
I'm doing some tests with EK-TM4C1294XL evaluation board using its ADC but the captured samples are too inaccurate, as you can see in the histogram bellow. 
I would like to know what are your opinions about the possible reasons to this happening. 
Bellow you can see the code I'm using and other related files.

The code is bellow :

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


void adc_init(void);
void Timer0ISR(void);
void ConfigureTimer(void);



/*keep the value of clock */
uint32_t g_ui32SysClock;

uint32_t adc0_values[10000];

typedef enum my_states{
	SAMPLING,
	DISABLE_SAMPLING,
	END_FLAG,
	IDLE
}State_t;


int main(void) {

	/* control variables */
	State_t current_state = SAMPLING;
	uint32_t amostra_adc_0[1];
	uint32_t counter = 0;

	/* Set the clocking to run at 120MHz */
	g_ui32SysClock= SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
	                    SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
	                    SYSCTL_CFG_VCO_480), 120000000);
	adc_init();
	ConfigureTimer();

	while(1){
		switch(current_state){
			case SAMPLING:
				while(!ADCIntStatus(ADC0_BASE,3,false));

				/* Cleaning after aquisition*/
				ADCIntClear(ADC0_BASE,3);
				/* Taking the samples*/
				ADCSequenceDataGet(ADC0_BASE, 3,amostra_adc_0);
				/* Cleaning the interruption flag*/
				ADCIntClear(ADC0_BASE,3);

				//passing values through the variables
				adc0_values[counter] = amostra_adc_0[0];

				counter++;

				if(counter == 10000){
					current_state = DISABLE_SAMPLING;
				}
				else{
					current_state = SAMPLING;
				}

				break;
			case DISABLE_SAMPLING:

				//the problem is here!!!!
				SysCtlPeripheralDisable(SYSCTL_PERIPH_TIMER0);
				current_state = END_FLAG;
				break;

			case END_FLAG:
				//here I'm turning on a led to flag the end
				SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
				GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_1);
				GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, GPIO_PIN_1);
				current_state = IDLE;
				break;

			case IDLE:
				break;

		}
	}
	
	return 0;
}

void adc_init(void){
	/* Enabling the Peripheral ADC0 */
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);

	/* Enabling Port E in order to read the values in ADC0 */
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);

	/* Selecting the pins to read ADC0 Values */
	GPIOPinTypeADC(GPIO_PORTE_BASE,
			(GPIO_PIN_0));

	/* Configuring Sample Sequence 3 in ADC0 */
	ADCSequenceConfigure(ADC0_BASE,3,
			ADC_TRIGGER_PROCESSOR, 0);

	/*Configure steps in ADC0*/
	ADCSequenceStepConfigure(ADC0_BASE, 3,
			0, (ADC_CTL_CH3 | ADC_CTL_IE | ADC_CTL_END));
	/*END*/

	/* Enable the sample sequence in ADC0 */
	ADCSequenceEnable(ADC0_BASE, 3);

	/*cleaning the interrupt flag */
	ADCIntClear(ADC0_BASE, 3);
}


void Timer0ISR(void){
	/* cleaning the timer interruptions for timer 0 module in full-with mode */
	TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
	ADCProcessorTrigger(ADC0_BASE,3);
}


void ConfigureTimer(void){
    /* enabling the timer 0 peripheral */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

    /* Allow the use of the processor interrupts */
    IntMasterEnable();

    /* configurating the TIMER to use a 32bit periodic timer */
    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

    /* setting the timer load value */
    /* we're using only timer A cause we want a 32 bit timer */
    /* here we've 1ms */
    TimerLoadSet(TIMER0_BASE, TIMER_A, g_ui32SysClock/1000);

    /* here we're setting the ISR to timer 0 */
    TimerIntRegister(TIMER0_BASE,TIMER_A,Timer0ISR);

    /* allowing interruptions for timer 0 */
    /* we use only timera because we're using full-with mode */
    IntEnable(INT_TIMER0A);

    /* enabling the interruptions for timer0 in full-with mode */
    /* It appears when timeout situation is got */
    /* again, using timer A because we're using full-with mode */
    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    /* Enabling Timer */
	TimerEnable(TIMER0_BASE, TIMER_A);
}

 
  • I suspect the "inaccuracy" is due to electrical noise. On the EK-TM4C129XL the A to D supply and (by default) the reference supply are tied to the digital supply. Also, the board is not designed with a good way to bring in shielded signals to the A to D inputs.
  • Bob, thank for answering! Is there something that I can do in order to reduce the noise, without use the hardware or software average?
  • Without adding hardware filtering, the only thing I can think of is to take multiple measurements and select the mode (value that occurs most often). This only works if the signal changes very slowly and takes longer (more time and more CPU interaction) .
  • Jamelly Ferreira said:
    something to do ... to reduce the noise, without use the hardware or software average?

    Bob's comments are seconded - yet I'm not convinced that, "Giving up on hardware" (per your quote) is a wise choice.    

    If you'll allow (some) addition of external hardware:

    • a small value, ceramic cap (0.01µF) as close to the MCU's ADC input pin(s) as possible, usually improves ADC results.
    • You should also make the effort to (reasonably) mate the output impedance of your Analog Voltage Source to the MCU's ADC input impedance.
    • If feeling (really) adventurous you may impose a small ferrite bead between MCU's VDDA and the board's VDD.   (small cap there would help, as well.)

    Should you seek to (minimize) disturbance to your MCU board - both those ceramic caps & impedance matching should be implemented as close to your Eval board's input header as possible.    Unfortunately the ferrite bead works best when "kissing" VDDA.

    This vendor (and others) provide such Eval Boards at (very) low cost - to attract greatest interest/use.    Often - (necessary) fine details are bypassed to minimize board size & cost...