17.5.2 CVD Scan of All Analog Inputs Using a Custom Processing Sequence Defined in Software

In the following example, the ITC is initialized to perform CVD scans of all AN pins. In each scan, a new ITCTX pin is selected by DMA.
#include <xc.h>

// All pins CVD results.
// 32 ITCAN pins are scanned for 32 different ITCTX pins settings.
long result[32][32]; 

long* pointer; // Used to store the results.
long cvd_counter; // CVD scans counter.
long tx_counter; // TX settings counter.

// OPTIONAL
// ITCTX pins selections for each CVD scan.
// Moved by DMA after each scan in ITCTXA register.
unsigned long cvd_tx_pins[32] = {
0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x100, 
0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000,
0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000,
0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1
};

int main(){

    PLL1CONbits.ON = 1;
    OSCCTRLbits.PLL1EN = 1;
    while(OSCCTRLbits.PLL1RDY == 0);   
    
    PLL1DIVbits.PLLFBDIV = 100; // VCO = 800 MHz
    PLL1DIVbits.PLLPRE = 1;
    PLL1DIVbits.POSTDIV1 = 4;
    PLL1DIVbits.POSTDIV2 = 1;
    PLL1CONbits.DIVSWEN = 1;
    while(PLL1CONbits.DIVSWEN == 1);    
    PLL1CONbits.NOSC = 1; // FRC
    PLL1CONbits.OSWEN = 1;
    while(PLL1CONbits.OSWEN == 1);        
    PLL1CONbits.FOUTSWEN = 1;
    while(PLL1CONbits.FOUTSWEN == 1);
    PLL1CONbits.PLLSWEN = 1;
    while(PLL1CONbits.PLLSWEN == 1);
    while(PLL1CONbits.CLKRDY == 0);


    // CPU clock 200MHz
    CLK1CONbits.ON = 1;
    CLK1CONbits.NOSC = 5; // PLL1
    CLK1CONbits.OSWEN = 1;
    while(CLK1CONbits.OSWEN == 1); 
    while(CLK1CONbits.CLKRDY == 0);
    
    // ADC (Generator 6) clock 200 MHz
    CLK6CONbits.ON = 1;
    CLK6CONbits.NOSC = 5; // PLL1
    CLK6CONbits.OSWEN = 1;
    while(CLK6CONbits.OSWEN == 1); 
    while(CLK6CONbits.CLKRDY == 0);

    // Initialize ADC 3 for operation with ITC
    AD3CH5CON1bits.MODE = 0; // single conversion
    AD3CH5CON1bits.IRQSEL = 0; // each conversion interrupt
    AD3CH5CON1bits.PINSEL = 5; // AD3AN5 is connected to CVD capacitors array
    AD3CH5CON1bits.NINSEL = 0; // VSS
    AD3CH5CON1bits.SAMC = 0; // small balance time
    AD3CH5CON1bits.TRG1SRC = 12; // trigger for ITC
    AD3CONbits.ON = 1; // enable ADC 3
    while (AD3ONbits.ADRDY == 0); // wait for ready

    
    // OPTIONAL
    // Initialize DMA channel to update ITCTX pins by
    // ADC 2 list #0 interrupt after each scan
    // (optional, may be used for 2D CVD).
    DMALOW = 0; // any address
    DMAHIGH = -1UL; // any address
    DMA0CHbits.SIZE = 2; // 32 bits
    DMA0CHbits.TRMODE = 1; // repeated one shot
    DMA0CHbits.DAMODE = 0; // not incremented
    DMA0CHbits.SAMODE = 1; // take next data each transfer
    DMA0CHbits.RELOADC = 1; // reload counter
    DMA0CHbits.RELOADS = 1; // reload source
    DMA0CHbits.CHEN = 1; // enable channel
    DMA0SELbits.CHSEL = 66; // trigger DMA from ADC 2 interrupt
    DMA0DST = (unsigned long)&ITCTXA; // update pins in ITCTXA register 
    DMA0SRC = (unsigned long)&cvd_tx_pins[0];
    DMA0CNT = 32; // 32 ITCTX pins updates before rollover
    DMACONbits.ON = 1; // enable DMA    
   
    ITCTXA = 0x1; // start from TX0 pin

    // List 0 will be processed by sequence number 5
    ITCLS0SEQbits.DATASEQ = 5;
    // Each sequence will be executed 4 times per record
    ITCLS0SEQbits.ACCNUM = 4-1;
    ITCLS0SEQbits.ACCMODE = 1; // back to back

    // Use all 16 acquisition commands for one sequence
    ITCSDATAMAPbits.SPLIT0 = 0;
    ITCSDATAMAPbits.SPLIT1 = 0;
    ITCSDATAMAPbits.SPLIT2 = 0;
    ITCSDATAMAPbits.SPLIT3 = 0;

    // Assign sequence to number 5 to be processed by list 0
    ITCSDATAMAPbits.DATASEQ0 = 5;
    ITCSDATAMAPbits.DATASEQ1 = 5;
    ITCSDATAMAPbits.DATASEQ2 = 5;
    ITCSDATAMAPbits.DATASEQ3 = 5;

    // Split 16 math commands in 2 sequences
    ITCSMATHMAPbits.SPLIT0 = 2;
    ITCSMATHMAPbits.SPLIT1 = 2;
    ITCSMATHMAPbits.SPLIT2 = 2;
    ITCSMATHMAPbits.SPLIT3 = 2;

    // First 8 sequence steps are assigned to math sequence # 5
    ITCSMATHMAPbits.MATHSEQ0 = 5;
    ITCSMATHMAPbits.MATHSEQ1 = 5;

    // Second 8 sequence steps are assigned to math sequence # 6
    ITCSMATHMAPbits.MATHSEQ2 = 6;
    ITCSMATHMAPbits.MATHSEQ3 = 6;

    
    // CVD ACQUISITION SEQUENCE
    // Command 0
    ITCSDATACMD0bits.CHRG = 1; // charge CVD capacitor
    ITCSDATACMD0bits.PC0 = 1; // drive 0 to discharge sensor on AN pin
    ITCSDATACMD0bits.PCA = 2; // drive 1 on pins selected in ITCTXA register
    ITCSDATACMD0bits.LOOP = 1; // wait for timer A in ITCLS0TMR register
    // Command 1
    ITCSDATACMD1bits.BAL = 1; // connect CVD capacitor to AN pin (balance)
    ITCSDATACMD1bits.PC0 = 3; // tri-state AN pin
    ITCSDATACMD1bits.PCA = 2; // drive 1 on pins selected in ITCTXA register
    ITCSDATACMD1bits.LOOP = 2; // wait for timer B in ITCLS0TRM register
    // Command 2
    ITCSDATACMD2bits.PC0 = 3; // tri-state AN pin    
    ITCSDATACMD2bits.PCA = 2; // drive 1 on pins selected in ITCTXA register    
    ITCSDATACMD2bits.BAL = 1; // Balance switch must be closed when CONV = 1    
    ITCSDATACMD2bits.CONV = 1; // start conversion
    ITCSDATACMD2bits.LOOP = 4; // wait for end of conversion 
    ITCSDATACMD2bits.MSEQ = 5; // math sequence # 5 
    ITCSDATACMD2bits.MSTART = 1; // start the math sequence
    
    // Command 3
    ITCSDATACMD3bits.DISCHRG = 1; // discharge CVD capacitor
    ITCSDATACMD3bits.PC0 = 2; // drive 1 to charge sensor on AN pin
    ITCSDATACMD3bits.PCA = 1; // drive 0 on pins selected in ITCTXA register
    ITCSDATACMD3bits.LOOP = 1; // wait for timer A in ITCLS0TMR register
    // Command 4
    ITCSDATACMD4bits.BAL = 1; // connect CVD capacitor to AN pin (balance)
    ITCSDATACMD4bits.PC0 = 3; // tri-state AN pin
    ITCSDATACMD4bits.PCA = 1; // drive 0 on pins selected in ITCTXA register
    ITCSDATACMD4bits.LOOP = 2; // wait for timer B in ITCLS0TRM register
    // Command 5
    ITCSDATACMD5bits.PC0 = 3; // tri-state AN pin
    ITCSDATACMD5bits.PCA = 1; // drive 0 on pins selected in ITCTXA register
    ITCSDATACMD5bits.BAL = 1; // Balance switch must be closed when CONV = 1
    ITCSDATACMD5bits.CONV = 1; // start conversion
    ITCSDATACMD5bits.LOOP = 4; // wait for end of conversion 
    ITCSDATACMD5bits.MSEQ = 6; // math sequence # 6 
    ITCSDATACMD5bits.MSTART = 1; // start the first math sequence
    ITCSDATACMD5bits.END = 1; // last command, end of the sequence
    
    // CVD MATH SEQUENCES
    // MATH "-"/Sample B
    ITCSMATHCMD0bits.FIRST = 1; // AIN is zero for the first accumulation
    ITCSMATHCMD0bits.AIN = 3; // ADC result
    ITCSMATHCMD0bits.BIN = 1; // Accumulator B
    ITCSMATHCMD0bits.F = 3; // "-"
    ITCSMATHCMD0bits.ACCB = 1; // latch result in Accumulator B
    ITCSMATHCMD0bits.WM = 2; // never write record
    ITCSMATHCMD0bits.WMOV = 1; // overwrite WM bits in ITCLS0CON register
    ITCSMATHCMD0bits.END = 1; // last command, end of sequence
    
    // MATH "+"/Sample A    
    ITCSMATHCMD8bits.AIN = 3; // ADC result
    ITCSMATHCMD8bits.BIN = 1; // Accumulator B
    ITCSMATHCMD8bits.F = 2; // "+"
    ITCSMATHCMD8bits.ACCB = 1; // latch result in Accumulator B
    ITCSMATHCMD8bits.WM = 0; // always write to ITCRES register
    ITCSMATHCMD8bits.WMOV = 1; // overwrite WM bits in ITCLS0CON register
    ITCSMATHCMD8bits.END = 1; // last command, end of sequence
    
    // Set CVD capacitor to 10pF 
    ITCCON1bits.CVDEN = 1;
    ITCLS0SEQbits.CVDCAP = 4;
                
    // AN pins are grounded (LAT = 0) when idle
   TRISAbits.TRISA0 = 0; //CVDAN0
   TRISAbits.TRISA1 = 0; //CVDAN1
   TRISAbits.TRISA2 = 0; //CVDAN2
   TRISAbits.TRISA3 = 0; //CVDAN3
   TRISAbits.TRISA4 = 0; //CVDAN4
   TRISAbits.TRISA5 = 0; //CVDAN5    
   TRISAbits.TRISA6 = 0; //CVDAN6
   TRISAbits.TRISA7 = 0; //CVDAN7
   TRISAbits.TRISA8 = 0; //CVDAN8
   TRISAbits.TRISA9 = 0; //CVDAN9
   TRISBbits.TRISB0 = 0; //CVDAN10    
   TRISBbits.TRISB1 = 0; //CVDAN11
   TRISBbits.TRISB2 = 0; //CVDAN12
   TRISBbits.TRISB3 = 0; //CVDAN13
   TRISBbits.TRISB4 = 0; //CVDAN14
   TRISBbits.TRISB5 = 0; //CVDAN15    
   TRISBbits.TRISB6 = 0; //CVDAN16    
   TRISBbits.TRISB7 = 0; //CVDAN17        
   TRISAbits.TRISA10 = 0; //CVDAN18 
   TRISAbits.TRISA11 = 0; //CVDAN19     
   TRISBbits.TRISB8 = 0; //CVDAN20            
   TRISBbits.TRISB9 = 0; //CVDAN21            
   TRISBbits.TRISB10 = 0; //CVDAN22            
   TRISBbits.TRISB11 = 0; //CVDAN23                
   TRISAbits.TRISA12 = 0; //CVDAN24         
   TRISAbits.TRISA13 = 0; //CVDAN25         
   TRISAbits.TRISA14 = 0; //CVDAN26             
   TRISAbits.TRISA15 = 0; //CVDAN27                 
   TRISBbits.TRISB12 = 0; //CVDAN28    
   TRISBbits.TRISB13 = 0; //CVDAN29    
   TRISBbits.TRISB14 = 0; //CVDAN30    
   TRISBbits.TRISB15 = 0; //CVDAN31           
   
    // Assign CVDAN pins to the records 
    ITCREC0bits.PIN0 = 0; // CVDAN0 pin
    ITCREC0bits.PIN1 = 1;
    ITCREC1bits.PIN2 = 2;
    ITCREC1bits.PIN3 = 3;
    ITCREC2bits.PIN4 = 4;
    ITCREC2bits.PIN5 = 5;
    ITCREC3bits.PIN6 = 6;
    ITCREC3bits.PIN7 = 7;
    ITCREC4bits.PIN8 = 8;
    ITCREC4bits.PIN9 = 9;
    ITCREC5bits.PIN10 = 10;
    ITCREC5bits.PIN11 = 11;
    ITCREC6bits.PIN12 = 12;
    ITCREC6bits.PIN13 = 13;
    ITCREC7bits.PIN14 = 14;
    ITCREC7bits.PIN15 = 15;
    ITCREC8bits.PIN16 = 16;
    ITCREC8bits.PIN17 = 17;
    ITCREC9bits.PIN18 = 18;
    ITCREC9bits.PIN19 = 19;
    ITCREC10bits.PIN20 = 20;
    ITCREC10bits.PIN21 = 21;
    ITCREC11bits.PIN22 = 22;
    ITCREC11bits.PIN23 = 23;
    ITCREC12bits.PIN24 = 24;
    ITCREC12bits.PIN25 = 25;
    ITCREC13bits.PIN26 = 26;
    ITCREC13bits.PIN27 = 27;
    ITCREC14bits.PIN28 = 28;
    ITCREC14bits.PIN29 = 29;
    ITCREC15bits.PIN30 = 30;
    ITCREC15bits.PIN31 = 31; // CVDAN31 pin

    // Set timers for the acquisition sequences (A and B are used only)
    ITCLS0TMRbits.TMRA = 16; // charge/discharge
    ITCLS0TMRbits.TMRB = 32; // balance   
    

    ITCCON2bits.CLKSEL = 1; // Clock from Generator 6 (200MHz)
    ITCCON2bits.CLKDIV = 4; // Divide by 8 to get 25 MHz ADC clock

    // One trigger scans all records.
    // One interrupt is generated after scan
    ITCLS0CONbits.MODE = 5; 
    ITCLS0CONbits.WM = 0; // always write to ITCRES registers
    ITCLS0CONbits.TRGSRC = 0; // software trigger
    ITCLS0CONbits.RECCNT = 32; // 32 records are in list 0
    ITCLS0CONbits.DMAEN = 1; // enable DMA triggers
    ITCLS0CONbits.TRGEN = 1; // trigger enable

    ITCCON1bits.SIGN = 1; // signed format is required for CVD
    ITCCON1bits.ON = 1; // enable ADC 2
    ITCLS0CONbits.SAMP = 1; // arm trigger
    while(ITCSTATbits.DRDY == 0);

    while(1){ // scan in infinite loop
        
        for(tx_counter=0; tx_counter<32; tx_counter++){
            _ITCIF = 0; // clear ITC interrupt flag 
            ITCLS0CONbits.SAMP = 0; // trigger scan
            while(_ITCIF == 0); // wait for the scan is done
            ITCLS0CONbits.SAMP = 1; // arm for the next scan
            pointer = (long*)&ITCRES0; 
            // store the results
            for(cvd_counter=0; cvd_counter<32; cvd_counter++){
                result[tx_counter][cvd_counter] = *pointer++;
            }
        }
    }
    return 1;
}