PIC18F4520 ADC Conversion in MC18 – How to Guide


I have a dilemma.

I need to read ADC values from PIC18F4520. My configuration, and code, is as follows:

#define OSC INTIO67
int adc_result = 0;

void main(void)
    OSSCON = 0x70; //Set it as 8Mhz.
    OSCTUNEbits.PLLEN = 1; //Enable PLL 4x multiplier, thus we have 32 Mhz internal clock.

    //Set PORTA direction ports as input
    TRISA = 0xFF;

    OpenADC( ADC_FOSC_32      &
         ADC_RIGHT_JUST   &
         ADC_CH0          &
         ADC_REF_VDD_VSS  &
         ADC_INT_OFF, ADC_5ANA);

    while (1) {
        while (BusyADC());
        adc_result = ReadADC();

The issue is this:

  1. When I run it in MPLAB v8.x, my reading is slightly off, and terminates my debugging.
  2. I can't debug the PIC again since I get errors like "Cannot enter debug mode."

How do I fix those issues? Also, is my ADC configuration correct (seeing that ADC requires a clock to do ADC conversion) with my internal clock? Is this correct to set the clock signal to 32 MHz.

I am programming using PicKit2 (with the black button).

Best Answer

You are not setting the clock signal of the ADC to 32MHz. The parameter ADC_FOSC_32 divides the clock by 32 (see page 225 of the datasheet). This ensures, together with the aquisition time select bits (ADC_4_TAD in your case), the minimum (/maximum) A/D aquisiton time (see page 359). When you hurt these requirements you will not get valid/accurate results.

With the equations given on page 228 you can do the math and verify, that the requirements are met.

Some other points:

  • In your code you are never starting the ADC conversion by calling ConvertADC.
  • You are configurating port a as output by setting TRISA = 0x0; but you want it to be configured as input (as your comment is saying). TRISA = 0xFF; would configure all pins on port a as input.

To expand a bit on the aquisiton time (\$T_{AD}\$): This time is needed for the internal circuitry to probably charge. When this time is too short, you will get no/bad results.

For 32Mhz (without divisor) \$T_{AD}\$ would be 31ns. That is too fast. At least 0.7us are required for the ADC to work probably. So you select a proper divisor to get \$T_{AD}\$ above 0.7us. A divisor of 32 will do it here, \$T_{AD} = 1\$us > 0.7us.