chipKIT® Development Platform

Inspired by Arduino™

AD converter UNO32 (MPLAB)

Created Tue, 24 Sep 2013 09:06:18 +0000 by quentinumons


quentinumons

Tue, 24 Sep 2013 09:06:18 +0000

Hi everyone,

I'm new and this is my first topic, be kind with me :-) I'm trying to develop an AD converter on my UNO32 using MPLAB. The code is very basic: I read a simple sinusoidal signal on my analog entry AN12 or AN14 and I put the result on hyperTerminal. But I have some troubles. When I put the sinusoid signal on AN12 and nothing on AN14, I still have signal on AN14 (on hyperterminal in fact). It's like if there is a dependency between the two input... this must surely come from the ADC configuration but I do not see where...

here is the code :

// Include Header Files
#include "p32mx320f128h.h"
#include "config.h"
#include "plib.h"
#include "time.h"
#include "math.h"
#include "outcompare.h"
#include <stdio.h>
#include "string.h"
#include "uart.h"
#include <stdio.h>
#define _UART1

#define LED LATFbits.LATF0 
#define LED2 LATGbits.LATG6 

volatile float time_UART =0;
volatile int flagprint = 0;

unsigned int channel4;  // conversion result as read from result buffer   
unsigned int channel5;  // conversion result as read from result buffer   
unsigned int offset;    // buffer offset to point to the base of the idle buffer 

//-------------------------------------------------------------------------------

// Function interrupt for loop print : 
 void __ISR(_TIMER_1_VECTOR, ipl2) _Timer1Handler(void) // rated at 100 Hz
	{
  	 mT1ClearIntFlag(); // clear the interrupt flag
		time_UART=time_UART+0.1; 	
		flagprint = 1;
		LED = !LED; 
	}

//-------------------------------------------------------------------------------
int main(void)
{
	unsigned int period = 31250; 	// prescaler@256 so loop period is 10ms
	unsigned long int result;
	char buffer2[50];

	// Configure the system performance
	SYSTEMConfigPerformance(SYSCLK); 

	// Configure pin I/O
	TRISFbits.TRISF0 = 0; 		// LED = output
	TRISGbits.TRISG6 = 0; 		// LED = output
	LED = 0;					// initialize at 0
	LED2 = 0;					// initialize at 0
	
	TRISBbits.TRISB12 = 1;		// AN12 = output
	TRISBbits.TRISB14 = 1;		// AN14 = output

//-------------------------------------------------------------------------------
	// "Print" loop
	OpenTimer1(T1_ON | T1_PS_1_256 | T1_SOURCE_INT, period); 
	ConfigIntTimer1(T1_INT_ON | T1_INT_PRIOR_2);

	// enable device multi-vector interrupts
        INTEnableSystemMultiVectoredInt();
	
//-------------------------------------------------------------------------------

	// Configure UART1 :  
	U1BRG = 21; //Set Baud rate : system_clock/2 /(16*beaud_rate_desired) -1 (here 115200)
	U1STA = 0;
	U1MODE = 0x8000; 			//Enable Uart for 8-bit data
	//no parity, 1 STOP bit
	U1STASET = 0x1400;     		//Enable Transmit and Receive

//-------------------------------------------------------------------------------    

CloseADC10();   // ensure the ADC is off before setting the configuration   
   
    // define setup parameters for OpenADC10   
    // Turn module on | ouput in integer | trigger mode auto | enable autosample   
    #define PARAM1  ADC_MODULE_ON | ADC_FORMAT_INTG | ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON   
   
    // ADC ref external | disable offset test | disable scan mode | perform 2 samples | use dual buffers | use alternate mode   
    #define PARAM2  ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_2 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON   
   
 
    // use ADC internal clock | set sample time   
    #define PARAM3  ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_15   
   
    // do not assign channels to scan   
    #define PARAM4  SKIP_SCAN_ALL   
   
    // set AN4 and AN5 as analog inputs   
    #define PARAM5  ENABLE_AN12_ANA | ENABLE_AN14_ANA   


     // use ground as neg ref for A | use AN12 for input A | use ground as neg ref for A | use AN14 for input A   
   
     // configure to sample AN12 & AN14   
    SetChanADC10( ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN12 |  ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN14); // configure to sample AN12 & AN14   
    
   OpenADC10( PARAM1, PARAM2, PARAM3, PARAM4, PARAM5 ); // configure ADC using parameter define above   
   
    EnableADC10(); // Enable the ADC  

// the results of the conversions are available in channel4 and channel5   

	putsUART1("\033[H\033[J"); 		// clear screen 
	putsUART1("-- ADC converter - A/D continuous + data recovery every 10 ms --\n");
	putsUART1("\r Time  A4  A5 \n");
    while (1)   
    {   
         // determine which buffer is idle and create an offset   
        offset = 8 * ((~ReadActiveBufferADC10() & 0x01)); 
         // read the result of channel 4 conversion from the idle buffer
        channel4 = ReadADC10(offset);         
         // read the result of channel 5 conversion from the idle buffer 
        channel5 = ReadADC10(offset + 1);      
			if(flagprint == 1)					
				{	
					LED2 = 1; 
					while(BusyUART1()); 		// Wait till the UART transmitter is free. 
					sprintf(buffer2,"\r \n %.2f  %d  %d",time_UART, channel4, channel5); 
				 	putsUART1(buffer2);
					LED2 = 0;
					flagprint = 0;
				}	
    }   
   
    return 0;   
}

thank you for your response and sorry for my english, I'm french...

Quentin


majenko

Tue, 24 Sep 2013 14:34:31 +0000

Is AN14 left floating when there is no signal applied? If so, then yes I would expect it to give an echo of the signal from AN12.

I wrote a bit about the problem on the Arduino forums, and here it is copied for you:

It's all to do with the way the ADC works. It uses a method known as "sample and hold". There is a small capacitor in the input, and the ADC "samples" the input voltage into that capacitor, then "holds" it there while it converts that stored voltage into a digital value. With nothing connected to an input pin, when the multiplexer switches the capacitor to sample that input, there will still be some of the old charge left in it - couple that with noise picked up by the pin, and you get a rough trace influenced by the previous channel that had any real input.

One good trick with this kind of ADC is to have one input dedicated as a purging input. Connect it to ground through a small resistor (say 100 ohms) and sample that channel in between each channel you are interested in. This ensures that the S&H capacitor is purged of residual charge between readings. The resistor is important to reduce current flow, but you want it small enough that the capacitor discharges in a reasonable time. Yes, you could short it direct to ground, but then you run the risk of too much current being drawn through the pin and killing the IO port (what happens if the pin gets switched to output and high? pop).

For instance, compare these two graphs. 4 channels, sampled in the order red, green, glue, magenta. The red channel has input, the others don't.

In this image all the other inputs are just floating and read in order. [attachment=1]bad1.png[/attachment] However, in this image an extra channel is linked to ground, with a 10Ω resistor in this case (though that may be a bit small TBH) and is read in between each of the other channels. You can see how each channel has less and less of the charge from the red channel left in it. [attachment=0]good1.png[/attachment]


quentinumons

Wed, 25 Sep 2013 13:45:05 +0000

Hello Majenko,

Thank you for your answer! And no, there is nothing on AN14 when there is no signal applied... I wanted to see if there was something like you told me and so I tried with MPIDE. But it works well... here the code i'm using :

void setup() {
  Serial.begin(9600);
}

void loop() {
  int sensorValue = analogRead(A4);   // A4 = AN12
  int sensorValue2 = analogRead(A5);  // A5 = AN14
  Serial.println(sensorValue, DEC);
  Serial.println(sensorValue2, DEC);
}

And when I put signal on A4 and nothing on A5, I have something for the first one and 0 for the second...