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;
}
