Code Examples

Last modified by Microchip on 2026/03/31 10:50

Click Play ► to listen to the commentary.

Information

Note: These examples are from the dsPIC33AK512MPS512 Family Data Sheet (DS70005591B).  Check the latest data sheet for updates.

Content

Single Sample Conversion

In Example 17-4, a software trigger is used to start a single conversion.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <xc.h>
// The channel output
long result = 0;
int main()
{
// Set up clock for 40Msps operation
clock_ADC_for_40Msps_from_PLL2();
// In this example channel 1 will be used.
// Software trigger will start a conversion.
AD5CH0CON1bits.TRG1SRC = 1;
// Use a single ended input.
AD5CH0CON1bits.DIFF = 0;
// Select the AN0 analog positive input/pin for the signal.
AD5CH0CON1bits.PINSEL = 0;
// Select the ANN0 (Vss) analog negative input/pin for the signal.
AD5CH0CON1bits.NINSEL = 0;
// Select signal sampling time (6.5 TADs = 81nS).
AD5CH0CON1bits.SAMC = 3;
// Enable ADC.
AD5CONbits.ON = 1;
// Wait when ADC will be ready/calibrated.
while (AD5CONbits.ADRDY == 0);
// Trigger channel #1 in software and wait for the result.
while (1) {
// Trigger channel # 1.
AD5SWTRGbits.CH0TRG = 1;
// Wait for a conversion ready flag.
while (AD5STATbits.CH0RDY == 0);
// Read result. It will clear the conversion ready flag.
result = AD5CH0DATA;
 }
return 1;
}

Back to Top

Windowed Conversion

In Example 17-5, the conversion results are accumulated until the RA4 pin is at the high level. The conversions are triggered from the internal Analog-to-Digital Converter (ADC) timer.

#include <xc.h>
// The channel output from primary accumulator.
volatile long result = 0;
// The number of accumulated samples.
volatile long number_of_accumulated_samples;
int main(){
 _TRISC8 = 0;
 _ANSELC8 = 0;
//Set up clock for 40Msps operation
clock_ADC_for_40Msps_from_PLL2();

// RF1/RP82 pin is a trigger input.
// Switch to a digital input.
ANSELFbits.ANSELF1 = 0;
// Make an input.
TRISFbits.TRISF1 = 1;
// Map external pin trigger to RF1/RP82.
_ADTRG31R = 82;
// In this example channel 0 will be used.
// Set limit for the accumulated samples number.
AD5CH0CNTbits.CNT = 0xffff;
// Window conversion mode.
AD5CH0CON1bits.MODE = 1;
// Accumulation will be started/stopped from an external pin.
AD5CH0CON1bits.TRG1SRC = 31;
// Logic LOW on RF1/RP82 will trigger conversion
AD5CH0CON1bits.TRG1POL = 1;
// Trigger all conversions from the ADC repeat timer.
AD5CH0CON1bits.TRG2SRC = 3;
// Select the AN0 analog positive input/pin.
AD5CH0CON1bits.PINSEL = 0;
// Select signal sampling time (6.5 TADs = 81nS).
AD5CH0CON1bits.SAMC = 3;
// Set period of the triggers timer (63 is maximum).
AD5CONbits.RPTCNT = 60;
// Interrupt when AD5CH0DATA is updated
AD5CH0CON1bits.IRQSEL = 1;
// Enable ADC.
AD5CONbits.ON = 1;
// Wait when ADC will be ready/calibrated.
while(AD5CONbits.ADRDY == 0);
// Enable interrupt;
_AD5CH0IF = 0;
 _AD5CH0IE = 1;

// Channel 0 is converted and results are accumulated until the RF1 pin is
high.
// On transition from high to low an interrupt is generated.
while(1);

return 1;
}
void __attribute__((interrupt)) _AD5CH0Interrupt(){
 _LATC8 ^= 1;

// Read result in accumulator and clear CH3RDY flag.
result = AD5CH0DATA;
 number_of_accumulated_samples = AD5CH0CNTbits.CNTSTAT;
 result /= number_of_accumulated_samples;

// Clear interrupt f

Back to Top

Integration Conversion

In Example 17-6, the conversions are started by a software trigger and continued by back-to-back triggers until the number of conversions is less than set in the AD1CNT7 register.

#include <xc.h>
// The channel output.
long result = 0;
int main(){

//Set up clock for 40Msps operation
clock_ADC_for_40Msps_from_PLL2();

 _TRISC8 = 0;
 _ANSELC8 = 0;

// In this example channel 15 will be used.
// Integration conversion mode.
AD5CH0CON1bits.MODE = 2;
// Set number of conversions accumulated to 123.
AD5CH0CNT = 123;
// Software trigger will start a conversions.
AD5CH0CON1bits.TRG1SRC = 1;
// Re-trigger back to back.
AD5CH0CON1bits.TRG2SRC = 2;
// Select the AN0 analog positive input/pin.
AD5CH0CON1bits.PINSEL = 0;
// Select signal sampling time (6.5 TADs = 81nS).
AD5CH0CON1bits.SAMC = 3;
// Enable ADC.
AD5CONbits.ON = 1;
// Wait when ADC will be ready/calibrated.
while(AD5CONbits.ADRDY == 0);
// Trigger channel #15 in software and wait for the 123 samples
// accumulated result.
while(1){
// Trigger channel # 0.
AD5SWTRGbits.CH0TRG = 1;
// Wait for a conversion ready flag.
while(AD5STATbits.CH0RDY == 0);
// Read oversampling result. It will clear the conversion ready flag.
result = AD5CH0DATA;

 _LATC8 ^= 1;
 }
return 1;
}

Back to Top

Oversampling

In Example 17-7, the conversions are started by a software trigger and continued by back-to-back triggers. The number of accumulated conversion results is set to 16. The oversampling process cannot be interrupted by other channel conversions because the ACCBRST bit is set.

#include <xc.h>
// The channel output.
long result = 0;
int main(){
//Set up clock for 40Msps operation
clock_ADC_for_40Msps_from_PLL2();

 _TRISC8 = 0;
 _ANSELC8 = 0;

// In this example channel 0 will be used.
// Oversampling conversion mode.
AD5CH0CON1bits.MODE = 3;
// Set number of conversions accumulated to 16.
AD5CH0CON1bits.ACCNUM = 1;
// The oversampling if started cannot be interrupted
// by a high priority channels conversion requests.
AD5CH0CON2bits.ACCBRST = 1;
// Software trigger will start a conversions.
AD5CH0CON1bits.TRG1SRC = 1;
// Re-trigger back to back.
AD5CH0CON1bits.TRG2SRC = 2;
// Select the AN0 analog positive input/pin.
AD5CH0CON1bits.PINSEL = 0;
// Select signal sampling time (6.5 TADs = 81nS).
AD5CH0CON1bits.SAMC = 3;
// Enable ADC.
AD5CONbits.ON = 1;
// Wait when ADC will be ready/calibrated.
while(AD5CONbits.ADRDY == 0);
// Trigger channel #0 in software and wait for the 16 samples
// oversampling result.

while(1){
// Trigger channel # 0.
AD5SWTRGbits.CH0TRG = 1;
// Wait for a conversion ready flag.
while(AD5STATbits.CH0RDY == 0);
// Read oversampling result. It will clear the conversion ready flag.
result = AD5CH0DATA;

 _LATC8 ^= 1;
 }
return 1;
}

Back to Top

Multiple Scans

In Example 17-9, three channels are scanned. To scan these channels, they are triggered from the same trigger source.

#include <xc.h>
volatile long channel_2_an1;
volatile long channel_4_an2;
volatile long channel_6_an3;
// Define peripheral clock frequency.
#define FCY (150000000UL) // 150MHz
// Define the CCP1 timer frequency.
#define TIMER_FREQUENCY (100UL) // 1kHz
int main(){

//Set up clock for 40Msps operation
clock_ADC_for_40Msps_from_PLL2();

 _TRISC8 = 0;
 _ANSELC8 = 0;

// In this example channels ## 2, 4 and 6 will be scanned.
// To scan channels they must be triggered from one source.
// The channel with lowest number (#2) will be converted first.
// The channel with highest number (#6) will be converted last.

// CHANNEL 2
// Single conversion mode.
AD1CH2CON1bits.MODE = 0;
// CCP1 Timer starts conversion (same for all scanned channels).
AD1CH2CON1bits.TRG1SRC = 0b100000;
// Select the AN1 analog input/pin for the channel #2.
AD1CH2CON1bits.PINSEL = 1;
// Select signal sampling time (6.5 TADs = 81nS).
AD1CH2CON1bits.SAMC = 3;

// CHANNEL 4
// Single conversion mode.
AD1CH4CON1bits.MODE = 0;
// CCP1 Timer starts conversion (same for all scanned channels).
AD1CH4CON1bits.TRG1SRC = 0b100000;
// Select the AN2 analog input/pin for the channel #4.
AD1CH4CON1bits.PINSEL = 2;
// Select signal sampling time (8.5 TADs = 106nS).
AD1CH4CON1bits.SAMC = 4;

// CHANNEL 6
// Single conversion mode.
AD1CH6CON1bits.MODE = 0;
// CCP1 Timer starts conversion (same for all scanned channels).
AD1CH6CON1bits.TRG1SRC = 0b100000;
// Select the AN3 analog input/pin for the channel #6.
AD1CH6CON1bits.PINSEL = 3;
// Select signal sampling time (10.5 TADs = 131nS).
AD1CH6CON1bits.SAMC = 5;
// Enable ADC.
AD1CONbits.ON = 1;
// Wait when ADC will be ready/calibrated.
while(AD1CONbits.ADRDY == 0);

// Configure CCP1 Timer to trigger all channels (to scan).
CCP1CON1bits.MOD = 0;
// Set 32-bit timer.
CCP1CON1bits.T32 = 1;
// Set period.
CCP1PR = FCY/TIMER_FREQUENCY;
// Run timer.
CCP1CON1bits.ON = 1;

// Enable channel # 6 interrupt.
// This channel is processed last and all other channels results
// will be ready in the channel #6 ISR.
_AD1CH6IE = 1;

while(1);

return 1;
}
// Channel # 6 interrupt (processed last). All channels
// results in the scan are available here.
void __attribute__((interrupt)) _AD1CH6Interrupt(){
 _LATC8 ^= 1;
 channel_2_an1 = AD1CH2DATA;
 channel_4_an2 = AD1CH4DATA;
channel_6_an3 = AD1CH6DATA;
_AD1CH6IF = 0;
}

Back to Top

Data Channel Comparator

In Example 17-8, the comparator interrupt is generated each time the conversion result is outside of a window.

#include <xc.h>
// The channel output.
long result = 0;
int main(){

//Set up clock for 40Msps operation
clock_ADC_for_40Msps_from_PLL2();

 _TRISC8 = 0;
 _ANSELC8 = 0;

// In this example channel 0 will be used.
// Select single conversion mode.
AD5CH0CON1bits.MODE = 0;
// Software trigger will start a conversion.
AD5CH0CON1bits.TRG1SRC = 1;
// Select the AN0 analog positive input/pin for the signal.
AD5CH0CON1bits.PINSEL = 0;
// Select signal sampling time (6.5 TADs = 81nS).
AD5CH0CON1bits.SAMC = 3;
// Enable the comparator for this channel.
// Use channel data value in ADnDATAx register for comparison
AD5CH0CON2bits.CMPVAL = 1;
// Select out of bounds mode.
AD5CH0CON2bits.CMPMOD = 1;
// 1 comparison matching the criteria will trigger comparator event
AD5CH0CON2bits.ADCMPCNT = 1;
// Select low limit. To generate comparator event when AD5CH0DATA < 1024.
AD5CH0CMPLO = 1024;
// Select high limit. To generate comparator event when AD5CH0DATA > 3072.
AD5CH0CMPHI = 3072;
// Enable comparator interrupt.
_AD5CMP0IE = 1;
// Enable ADC.
AD5CONbits.ON = 1;
// Wait when ADC will be ready/calibrated.
while(AD5CONbits.ADRDY == 0);
// Trigger channel #0 in software and wait for the result.
while(1) {
 _LATC8 = 0;
// Trigger channel # 0.
AD5SWTRGbits.CH0TRG = 1;
// Wait for a conversion ready flag.
while(AD5STATbits.CH0RDY == 0);
// Read result. It will clear the conversion ready flag.
result = AD5CH0DATA;
 }
return 1;
}
void __attribute__((interrupt)) _AD5CMP0Interrupt(){
// Process the comparator event here.
// Clear the comparator event flag.
AD5CMPSTATbits.CH0FLG = 0;
// Clear the comparator flag.
_AD5CMP0IF = 0;

 _LATC8 ^= 1;
}

Back to Top

Data Channel Filter

In Example 17-10, the second order low-pass filter is implemented using the second accumulator.

#include <xc.h>
// VARIABLES OF THE SOFTWARE PART OF THE FILTER.
// These global variables are used in an interrupt.
// That's why they must be declared as "volatile".
// Input for the software part of the filter's first stage.
volatile long ch7_current_1 = 0;
// Input delayed for the first stage.
volatile long ch7_previous_1 = 0;
// Input for the software part of the filter's second stage.
volatile long ch7_current_2 = 0;
// Input delayed for the second stage.
High-Performance dsPIC33A Core with Floating-Point Unit, High-Speed ADCs, High-Speed PWM, Crypto Acc...
40 MSPS Analog-to-Digital Converter (ADC)
 Data Sheet
© 2025 Microchip Technology Inc. and its subsidiaries
DS70005591B - 1445
volatile long ch7_previous_2 = 0;
// The filter output.
volatile long filtered_result = 0;
// Define peripheral clock frequency.
#define FCY (150000000UL) // 150MHz
// Define the CCP1 timer frequency.
#define TIMER_FREQUENCY (100UL) // 1kHz
int main()
{
//Set up clock for 40Msps operation
clock_ADC_for_40Msps_from_PLL2();

 _TRISC8 = 0;
 _ANSELC8 = 0;

// The device has 2 channels with the secondary
// accumulator implemented: ## 6 and 7.
// This example will use channel #7.
// Enable accumulators roll-over to enable the secondary accumulator.
AD1CH7CON2bits.ACCRO = 1;
// Select integration sampling mode.
AD1CH7CON1bits.MODE = 2;
// CCP1 Timer starts conversions (1kHz frequency).
AD1CH7CON1bits.TRG1SRC = 32;
// CCP1 Timer re-triggers (1kHz frequency).
AD1CH7CON1bits.TRG2SRC = 32;
// Select the AN1 analog input/pin for the signal to be filtered.
AD1CH7CON1bits.PINSEL = 1;
// Select signal sampling time (6.5 TADs = 81nS).
AD1CH7CON1bits.SAMC = 3;
// Set number of conversions = 8 for the filter (sub-sampler).
// The CH7RDY bit will be set after 8 conversions.
// The conversions frequency is 1kHz defined by CCP1 Timer period.
// The signal maximum frequency is in twice less = 500 Hz.
// The filter cut-off frequency is 500kHz/8 = 62.5 Hz.
AD1CH7CNT = 8;
// Interrupt when AD1CH7DATA is updated
AD1CH7CON1bits.IRQSEL = 1;
// Enable ADC.
AD1CONbits.ON = 1;
// Wait when ADC will be ready/calibrated.
while(AD1CONbits.ADRDY == 0);

// Configure CCP1 Timer to trigger the channel # 7.
CCP1CON1bits.MOD = 0;
// Set 32-bit timer.
CCP1CON1bits.T32 = 1;
// Set period.
CCP1PR = FCY/TIMER_FREQUENCY;
// Run timer.
CCP1CON1bits.ON = 1;

// Enable channel # 7 interrupt.
_AD1CH7IE = 1;
// The AN1 pin filtered result is available in the channel # 19 interrupt.
while(1);

return 1;
}
// Channel # 7 interrupt.
// Called when integration is finished (every AD1CH7CNT = 8 conversions).
void __attribute__((interrupt)) _AD1CH7Interrupt(){

long primary_accumulator;

// Clear interrupt flag. If the interrupt is persistent then
// to clear the flag it is required to read the ADC channel
// result register first.
primary_accumulator = AD1CH7DATA;
 _AD1CH7IF = 0;

// Process software part of the filter.
ch7_current_1 = AD1CH7ACC;
 ch7_current_2 = ch7_previous_1 - ch7_current_1;
 ch7_previous_1 = ch7_current_1;
 filtered_result = ch7_previous_2 - ch7_current_2;
 ch7_previous_2 = ch7_current_2;
// Divide by 1:(8*8) or 1:64 or shift right by 6
filtered_result >>= 6;
 _LATC8 ^= 1;
}