19.4 Application Example
In CVD Scan of All CVDANx Inputs, the ITC is initialized to perform CVD scans of all CVDANx pins. For each scan, a new CVDTXx pin is selected by DMA.
CVD Scan of All CVDANx Inputs
#include <xc.h>
// All pins CVD results.
// 32 CVD pins scans for 32 different CVDTXx 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
// CVDTXx pins selections for each CVD scan.
// Moved by DMA after each scan to 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,
0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1
};
int main(){
// Initialize Oscillators
// PLL1 initialization
PLL1CONbits.ON = 1;
OSCCTRLbits.PLL1EN = 1;
while(OSCCTRLbits.PLL1RDY == 0);
PLL1CONbits.FSCMEN = 1; // disable clock fail monitor
VCO1DIVbits.INTDIV = 1; // 1:2 = 320MHz
PLL1DIVbits.PLLFBDIV = 80; // VCO = 640 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);
// clock CPU from PLL
CLK1CONbits.NOSC = 5; // PLL1
CLK1CONbits.OSWEN = 1;
while(CLK1CONbits.OSWEN == 1);
while(CLK1CONbits.CLKRDY == 0);
// ADC high speed clock (Generator 6), should be 320 MHz for 80MHz operation
CLK6CONbits.ON = 1;
CLK6CONbits.NOSC = 7; // PLL1 VCO divider
CLK6CONbits.OSWEN = 1;
while(CLK6CONbits.OSWEN == 1);
while(CLK6CONbits.CLKRDY == 0);
// OPTIONAL
// Initialize DMA channel to update CVDTXx pins by
// ITC 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 = 106; // trigger DMA from ITC list 0
DMA0SRC = (unsigned long)&ITCTXA; // update pins in ITCTXA register
DMA0DST = (unsigned long)&cvd_tx_pins[0];
DMA0CNT = 32; // 32 CVDTXx pins updates before rollover
DMACONbits.ON = 1; // enable DMA
ITCLS0CONbits.DMAEN = 1; // Enable DMA triggers from List 0
ITCTXA = 0x1; // start from CVDTX0 pin
// Initialize ADC5 for ITC clock and conversions
AD5CH5CON1bits.MODE = 0; // single conversion
AD5CH5CON1bits.IRQSEL = 0; // each conversion
AD5CH5CON1bits.PINSEL = 5; // AN5
AD5CH5CON1bits.NINSEL = 0; // VSS
AD5CH5CON1bits.SAMC = 0; // small sampling time
AD5CH5CON1bits.TRG1SRC = 26; // trigger for Touch Controller
AD5CONbits.ON = 1; // enable ADC5
while(AD5CONbits.ADRDY == 0);
// Use all 16 acquisition commands for one sequence
SDATAMAPbits.SPLIT0 = 0;
SDATAMAPbits.SPLIT1 = 0;
SDATAMAPbits.SPLIT2 = 0;
SDATAMAPbits.SPLIT3 = 0;
// List 0 will be processed by sequence number 5
ITCLS0SEQbits.DATASEQ = 5;
// Assign sequence to number 5 to be processed by list 0
SDATAMAPbits.DATASEQ0 = 5;
SDATAMAPbits.DATASEQ1 = 5;
SDATAMAPbits.DATASEQ2 = 5;
SDATAMAPbits.DATASEQ3 = 5;
// Split 16 math commands in 2 sequences
SMATHMAPbits.SPLIT0 = 2;
SMATHMAPbits.SPLIT1 = 2;
SMATHMAPbits.SPLIT2 = 2;
SMATHMAPbits.SPLIT3 = 2;
// List 0 will be processed by two math sequences number 5
ITCLS0SEQbits.MATHSEQ = 5;
// List 0 will accumulate result.
// Each sequence will be executed 4 times per record
ITCLS0SEQbits.ACCEN = 1;
ITCLS0SEQbits.ACCCNT = 2;
// First 8 steps sequence called when
// SECOND0 bit = 0 in SnMATHCMDx register
// The sequence will be executed several times per record
// (accumulation mode)
SMATHMAPbits.MATHSEQ0 = 5;
SMATHMAPbits.MATHSEQ1 = 5;
SMATHMAPbits.SECOND0 = 0;
SMATHMAPbits.SECOND1 = 0;
SMATHMAPbits.ACC0 = 1;
SMATHMAPbits.ACC1 = 1;
// Second 8 steps sequence called when
// SECOND bit = 1 in SnMATHCMDx register
// The sequence will be executed several times per record
// (accumulation mode)
SMATHMAPbits.MATHSEQ2 = 5;
SMATHMAPbits.MATHSEQ3 = 5;
SMATHMAPbits.SECOND2 = 1;
SMATHMAPbits.SECOND3 = 1;
SMATHMAPbits.ACC2 = 1;
SMATHMAPbits.ACC3 = 1;
// CVD ACQUISITION SEQUENCE
// Command 0
SDATACMD0bits.CHRG = 1; // charge CVD cpasitor
SDATACMD0bits.PC0 = 1; // drive 0 to discharge sensor on CVDANx pin
SDATACMD0bits.PCA = 1; // drive 0 on pins selected in ITCTXA register
SDATACMD0bits.PCB = 2; // drive 1 on pins selected in ITCTXB register
SDATACMD0bits.LOOP = 1; // wait for timer A in ITCLSxTMR register
// Command 1
// break before make, disconnect everything
SDATACMD1bits.PC0 = 3; // tri-state CVDANx pin
SDATACMD1bits.PCA = 1; // drive 0 on pins selected in ITCTXA register
SDATACMD1bits.PCB = 2; // drive 1 on pins selected in ITCTXB register
// Command 2
SDATACMD2bits.BAL = 1; // connect CVD capacitor to CVDANx pin (balance)
SDATACMD2bits.PC0 = 3; // tri-state CVDANx pin
SDATACMD2bits.PCA = 1; // drive 0 on pins selected in ITCTXA register
SDATACMD2bits.PCB = 2; // drive 1 on pins selected in ITCTXB register
SDATACMD2bits.LOOP = 2; // wait for timer B in ITCLSxTRM register
// Command 3
SDATACMD3bits.CONV = 1; // start conversion
SDATACMD3bits.LOOP = 4; // wait for end of conversion
SDATACMD3bits.PC0 = 3; // tri-state CVDANx pin
SDATACMD3bits.PCA = 1; // drive 0 on pins selected in ITCTXA register
SDATACMD3bits.PCB = 2; // drive 1 on pins selected in ITCTXB register
SDATACMD3bits.MSTART = 1; // start the first math sequence
// Command 4
SDATACMD4bits.DISCHRG = 1; // discharge CVD capacitor
SDATACMD4bits.PC0 = 2; // drive 1 to charge sensor on CVDANx pin
SDATACMD4bits.PCA = 2; // drive 1 on pins selected in ITCTXA register
SDATACMD4bits.PCB = 1; // drive 0 on pins selected in ITCTXB register
SDATACMD4bits.LOOP = 1; // wait for timer A in ITCLSxTMR register
// Command 5
// break before make, disconnect everything
SDATACMD5bits.PC0 = 3; // tri-state
SDATACMD5bits.PCA = 2; // drive 1 on pins selected in ITCTXA register
SDATACMD5bits.PCB = 1; // drive 0 on pins selected in ITCTXB register
// Command 6
SDATACMD6bits.BAL = 1; // connect CVD capacitor to CVDANx pin (balance)
SDATACMD6bits.PC0 = 3; // tri-state CVDANx pin
SDATACMD6bits.PCA = 2; // drive 1 on pins selected in ITCTXA register
SDATACMD6bits.PCB = 1; // drive 0 on pins selected in ITCTXB register
SDATACMD6bits.LOOP = 2; // wait for timer B in ITCLSxTRM register
// Command 7
SDATACMD7bits.CONV = 1; // start conversion
SDATACMD7bits.LOOP = 4; // wait for end of conversion
SDATACMD7bits.PC0 = 3; // tri-state CVDANx pin
SDATACMD7bits.PCA = 2; // drive 1 on pins selected in ITCTXA register
SDATACMD7bits.PCB = 1; // drive 0 on pins selected in ITCTXB register
SDATACMD7bits.MSTART = 1; // start the first math sequence
SDATACMD7bits.SECOND = 1; // second math sequence
SDATACMD7bits.END = 1; // last command, end of the sequence
// CVD MATH SEQUENCES
// MATH "-"/Sample B
SMATHCMD0bits.AIN = 3; // ADC result
SMATHCMD0bits.BIN = 1; // Accumulator B
SMATHCMD0bits.F = 3; // "-"
SMATHCMD0bits.ACCB = 1; // latch result in Accumulator B
SMATHCMD0bits.WM = 2; // never write record
SMATHCMD0bits.WMOV = 1; // overwrite WM bits in ITCLSxCON register
SMATHCMD0bits.END = 1; // last command, end of sequence
// MATH "+"/Sample A
SMATHCMD8bits.AIN = 3; // ADC result
SMATHCMD8bits.BIN = 1; // Accumulator B
SMATHCMD8bits.F = 2; // "+"
SMATHCMD8bits.ACCB = 1; // latch result in Accumulator B
SMATHCMD8bits.WM = 0; // always write to ITCRESx register
SMATHCMD8bits.WMOV = 1; // overwrite WM bits in ITCLSxCON register
SMATHCMD8bits.END = 1; // last command, end of sequence
// Set CVD capacitor to 10pF
ITCCON1bits.CVDEN = 1;
ITCLS0SEQbits.CVDCAP = 8;
// Assign CVDANx 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
// All CVDANx pins should drive low when idle
_TRISA0 = 0; _LATA0 = 0; // RA0/CVDAN0
_TRISA1 = 0; _LATA1 = 0; // RA1/CVDAN1
_TRISA2 = 0; _LATA2 = 0; // RA2/CVDAN2
_TRISA3 = 0; _LATA3 = 0; // RA3/CVDAN3
_TRISA4 = 0; _LATA4 = 0; // RA4/CVDAN4
_TRISA5 = 0; _LATA5 = 0; // RA5/CVDAN5
_TRISA6 = 0; _LATA6 = 0; // RA6/CVDAN6
_TRISA7 = 0; _LATA7 = 0; // RA7/CVDAN7
_TRISA8 = 0; _LATA8 = 0; // RA8/CVDAN8
_TRISA9 = 0; _LATA9 = 0; // RA9/CVDAN9
_TRISA10 = 0; _LATA10 = 0; // RA10/CVDAN10
_TRISA11 = 0; _LATA11 = 0; // RA11/CVDAN11
_TRISA12 = 0; _LATA12 = 0; // RA12/CVDAN12
_TRISA13 = 0; _LATA13 = 0; // RA13/CVDAN13
_TRISA14 = 0; _LATA14 = 0; // RA14/CVDAN14
_TRISA15 = 0; _LATA15 = 0; // RA15/CVDAN15
_TRISB0 = 0; _LATB0 = 0; // RB0/CVDAN16
_TRISB1 = 0; _LATB1 = 0; // RB1/CVDAN17
_TRISB2 = 0; _LATB2 = 0; // RB2/CVDAN18
_TRISB3 = 0; _LATB3 = 0; // RB3/CVDAN19
_TRISB4 = 0; _LATB4 = 0; // RB4/CVDAN20
_TRISB5 = 0; _LATB5 = 0; // RB5/CVDAN21
_TRISB6 = 0; _LATB6 = 0; // RB6/CVDAN22
_TRISB7 = 0; _LATB7 = 0; // RB7/CVDAN23
_TRISB8 = 0; _LATB8 = 0; // RB8/CVDAN24
_TRISB9 = 0; _LATB9 = 0; // RB9/CVDAN25
_TRISB10 = 0; _LATB10 = 0; // RB10/CVDAN26
_TRISB11 = 0; _LATB11 = 0; // RB11/CVDAN27
_TRISB12 = 0; _LATB12 = 0; // RB12/CVDAN28
_TRISB13 = 0; _LATB13 = 0; // RB13/CVDAN29
_TRISB14 = 0; _LATB14 = 0; // RB14/CVDAN30
_TRISB15 = 0; _LATB15 = 0; // RB15/CVDAN31
// Set timers for the acquisition sequences (A and B are used only)
ITCLS0TMRbits.TMRA = 16; // charge/discharge
ITCLS0TMRbits.TMRB = 32; // balance
// One trigger scans all records.
// One interrupt is generated after scan
ITCLS0CONbits.MODE = 5;
ITCLS0CONbits.WM = 0; // always write to ITCRESx registers
ITCLS0CONbits.SSRC = 0; // trigger on 1 to 0 transition of SAMP bit
ITCLS0CONbits.RECCNT = 31; // 32 records are in list 0
ITCLS0CONbits.TRGEN = 1; // trigger enable
ITCCON1bits.SIGN = 1; // signed format is required for CVD
ITCCON1bits.ON = 1; // enable ITC
ITCLS0CONbits.SAMP = 1; // arm to trigger
asm volatile(“repeat #128 \n nop”); // at least TAD delay
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;
}