Simultaneous Sampling of 4 ADC Channels with PIC24E

No matter how fast we advance in this digital era, the world is still analog in nature. In many industrial applications, an engineer needs to measure a continuous-time signal and store/process it digitally. For this reason, most microcontrollers have Analog-to-Digital Converter (ADC) modules as standard peripherals.

When several ADC channels (each equipped with a sample-and-hold unit) are available to the user, new products commonly provide 2 options for sampling: simultaneous, or sequential. The difference is shown in Figure 1.

Figure 1 simultaneous v.s. sequential sampling

The simultaneous sampling scheme on the left is useful, for example, when accurate phase information is needed. This can be done in the PIC24EP256MC202 by using 4 S&H channels. The tradeoff is that accuracy is limited to 10-bit for such configuration. According to Microchip datasheet, if you need 12-bit ADC, only one S&H channel can be used. So the sequential sampling at right is the only option for 12-bit ADC configuration.

The tricky part is perhaps on how to configure the ADC properly for simultaneous sampling of 4 channels. In this article we provide the C code example and show the result sent via USB-to-serial communication.

The hardware setup is simple. The analog inputs AN0 – AN3 are connected to the wipers of 4 variable resistors. The voltages are read, converted, and sent to hyperterminal when a push-button switch is activated. Issuing a command “READV” in the console yields the same result.

Of course, for this simple experiment, it does not make any difference whether to use either one of the two sampling schemes in Figure 1 since timing is not an issue.


First, we initialize the pins AN0/RA0, AN1/RA1,AN2,RB0, AN3/RB1 to be analog inputs. This can be written as in initialization function

ANSELA=0x0003;  // use only AN0-AN1 as analog
ANSELB=0x0003;  // use only AN2 - AN3 (RB0,RB1) as analog
// input pins
_TRISA0 = 1;  // analog AN0
_TRISA1 = 1;  // analog AN1
_TRISB0 = 1;  // AN2
_TRISB1 = 1;  // AN3

Then we configure the ADC registers as follows. Refer to Section 16. Analog-to-Digital Converter (ADC) of PIC24E Family Reference Manual (FRM) for details. The last statement turns on the ADC module.

/* Initialize and enable ADC module */
AD1CON1 = 0x000C; // Enable simultaneous sampling and auto-sample
AD1CON2 = 0x0300; // Sample 4 channels
AD1CON3 = 0x000F;
AD1CON4 = 0x0000;
AD1CSSH = 0x0000;
AD1CSSL = 0x0000;
AD1CHS0bits.CH0SA = 3; // Select AN3 for CH0 +ve input
AD1CHS0bits.CH0NA = 0; // Select Vref- for CH0 -ve input
AD1CHS123bits.CH123SA = 0; // Select AN0 for CH1 +ve input
    			// Select AN1 for CH2 +ve input
    		// Select AN2 for CH3 +ve inputAD1CHS123bits.CH123NA = 0; // Select Vref- for CH1/CH2/CH3 -ve inputs
AD1CON1bits.ADON = 1;

That’s it. Even though the configuration process is somewhat more involved than older PIC microcontroller, we eventually manage to make it work as desired.

Reading the ADC Buffers

Now the last part is to read from the 4 ADC buffers. We define a global array somewhere at the top of source file.

int ADCValues[4] = {0, 0, 0, 0};

and implement a function to read 4 voltage values to the array after the conversion process is finished

 void readAdc(void)
        AD1CON1bits.SAMP = 0; // Start the conversions
        while (!_AD1IF); // Wait for all 4 conversions to complete
        _AD1IF = 0; // Clear conversion done status bit
        ADCValues[0] = ADC1BUF1; // Read the AN0 conversion result
        ADCValues[1] = ADC1BUF2; // Read the AN1 conversion result
        ADCValues[2] = ADC1BUF3; // Read the AN2 conversion result
        ADCValues[3] = ADC1BUF0; // Read the AN3 conversion result

Pay attention to the connection between ANx and ADC1BUFy. It is quite easy to make mistake here; i.e., ADCBUF0 contains the result from AN3, not AN0. See the ADC Block Diagram from Microchip datasheet or FRM for further understanding.

Figure 2 shows some output data values in hyperterminal console when the 4 VRs are adjusted randomly. The values are directly from 10-bit ADC buffers without converting to voltage. The maximum readout of 1023 corresponds to 3.3 Volts.

Figure 2 ADC value readouts in hyperterminal program



Comments are closed.