Why do some analog pins on my PIC32 report zero when disconnected and others report non-zero?

StackOverflow https://stackoverflow.com/questions/7645812

  •  06-02-2021
  •  | 
  •  

Question

I am using a PIC32MX534F064L (datasheet), and trying to read several of its analog pins (marked AN0 to AN15).

With none of those pins connected to anything, I expect to read a value of zero. Instead on AN0 through AN5 I read values between 650 and 900. Only from the rest (AN6 through AN15) I get a value of zero.

When each of the pins is connected to a source, they report correctly. Each of the pins, AN0 through AN15 will report 0 for 0.0V, and 1023 for 3.3V.

I've tried sampling the values in pairs, and each separately. Whether sampled together or apart, AN0 will report non-zero values (usually around 700-800), and AN13 will report 0.

My first thought was that I somehow failed to properly set up the ADC. Here's my code:

#include <stdio.h>
#include <plib.h>

unsigned int an0;
unsigned int offset;
char buffer[100];

int main(void)
{
  SYSTEMConfigPerformance(72000000L);
  CloseADC10();

  #define ADC_CONFIG1 ADC_MODULE_ON | ADC_FORMAT_INTG | \
                      ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON
  #define ADC_CONFIG2 ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | \
                      ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_2 | \
                      ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON
  #define ADC_CONFIG3 ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_15
  #define ADC_CONFIGSCAN SKIP_SCAN_ALL
  #define ADC_CONFIGPORT ENABLE_AN0_ANA

  SetChanADC10( ADC_CH0_NEG_SAMPLEA_NVREF | ADC_CH0_POS_SAMPLEA_AN0 );
  OpenADC10( ADC_CONFIG1, ADC_CONFIG2, ADC_CONFIG3, \
             ADC_CONFIGPORT, ADC_CONFIGSCAN );
  EnableADC10();

  while ( ! mAD1GetIntFlag() ) { }

  while (1)
  {
    offset = 8 * ((~ReadActiveBufferADC10() & 0x01));
    an0 =  ReadADC10(offset);
    sprintf(buffer, "AN0 = %u", an0);
  }

  return 0;
}

Looking in the PIC's datasheet, I noticed two things:

  1. The pins AN0 to AN5, the ones mis-reporting non-zero values, are also CNx pins. These pins are "Change Notification" pins, that are meant to raise an interrupt when the value on the pins changes.

  2. There is a "weak pull-up" that can be enabled on all CNx pins.

So I tried disabling the "weak pull-up" by using this line:

mCNClose();

Which disables all the CNx pins and their pull-ups. Sadly, this did not help. And when I checked the value of the CN-pull-up-register (CNPUE

What else can I try? Am I doing something wrong in my code?

Was it helpful?

Solution

Well, your expectation is wrong!

The minimum input resistance for source should be only few kilo ohms check datasheet. If ADC pins is floating (not connected) the unpredicted value of internal parasitic current will cause that measuring value will be bigger than 0. Remember the ADC sample capacitor has only few pF capacity so floating pins can oscillate in wide voltage range also from external EM (electromagnetic) influences. So, connect at least 1M resistors to pull down voltage on ADC pin, the resistance of pull down resistor is depended of ADC sample time. If ADC sample time is short than decrease the pull down value of resistor.

EDIT: Check datasheet page 214 parameter AD17: Recommended Impedance of Analog Voltage Source is 5 KOhms. And AD15 say that that max. Leakage Current on ADC input pins can be +/-0.61 uA.

OTHER TIPS

It's probably just noise, since the inputs are high impedance when nothing is connected. Try grounding the inputs (connect to 0V) as an experiment - the values should then be close to 0. If you need the inputs to be zero when nothing is connected then connect a pull-down resistor to each input (between input and 0V) to lower the impedance - a value of 10k ohms should do it.

Do not leave pins unconnected! The unconnected pin is essentially an antenna which could pick up voltages outside of the Vss and Vdd range. Section 2.10 of the datasheet says to not leave any pins unconnected (or if you do, configure them as outputs and drive them low.)

If you want to test your A2D, you can configure the pin as a digital output (the analog setting only overrides the digital input) and then drive it high and low to test.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top