// ********************************************************************************************* // PIC32MZ Family 12.5msps Interleaved ADC sample code example // // SUMMARY: // TARGET CPU: PIC32MZxxEFxx >= 100 pin // OSC INPUT TYPE = 24 MHz Clock oscillator (EC Mode) // SYSCLK=200 MHz // PBCLK = 100 MHz // ADC TAD = SYSCLK / 4 = 50 MHz = 20ns // ADC SAMC=3 TAD // Interleaved ADC SAMPLE RATE = 12.5msps(max) // INTERLEAVED ADCS // ADC 0: 12bit mode, ADCTRG1 Output Compare 1 // ADC 1: 12bit mode, ADCTRG1 Output Compare 3 // ADC 2: 12bit mode, ADCTRG1 Output Compare 5 // ADC 3: 12bit mode, ADCTRG1 Timer3 // // interleaved ADC0/1/2/3 with AN0/AN1/AN2/AN3 inputs respectively // (12.5 msps combined throughput rate) // // USER NOTE: // Although the number of interleaved ADC's the user wishes to use is selectable, it is required // "FOR THIS CODE ONLY" that those ADCx modules be sequential starting from AN0 to the last sequential // ANx to be used for interleaving. In different code than below, any combination of interleaved ADC are allowed // // NOTE: (FYI only) // A user could configure the PIC32MZ to have multiple sets of // interleaved ADC's to measure multiple different analog input streams like: // ----------------------------- EXAMPLE 1 CONFIGURATION ----------------------------- // 1) AN0-AN1 pair with triggers OC5 and TMR3 @ 6.25msps(max) // 2) AN2-AN3 pair with triggers OC1 and TMR5 @ 6.25msps(max) // ----------------------------- EXAMPLE 2 CONFIGURATION ----------------------------- // 3) ADC0-ADC2 (3) ADCs with triggers OC1, OC3 and TMR5 @ 8.333333 msps(max) combined // 4) ADC3-ADC4 (2) ADCs with triggers OC5 and TMR3 @ 6.25msps(max) // ----------------------------- EXAMPLE 3 CONFIGURATION ----------------------------- // 5) ADC0-ADC3 (4) ADCs with triggers OC1, OC3, OC5 and TMR3 @ 12.5msps(max) combined // ********************************************************************************************* // // ********************************************************************************************* // USER NOTE: // Although the number of interleaved ADC's the user wishes to use is selectable in this code // example, it is required "FOR THIS CODE ONLY" that those ADCx modules be sequential starting // from AN0 to the last sequential ANx to be used for interleaving. // In a user’s own original code however they can define any combination // of ADC's they prefer. // // **************************************************************************** // F I L E I N C L U D E S // **************************************************************************** #include #include #include #include // **************************************************************************** // C O N F I G U R A T I O N W O R D S // **************************************************************************** // //---------------------------------------------------------- // DEVCFG0 //---------------------------------------------------------- #pragma config DEBUG = OFF #pragma config JTAGEN = OFF #pragma config ICESEL = ICS_PGx2 #pragma config TRCEN = OFF #pragma config BOOTISA = MIPS32 #pragma config FECCCON = OFF_UNLOCKED #pragma config FSLEEP = OFF #pragma config DBGPER = PG_ALL #pragma config SMCLR = MCLR_NORM #pragma config SOSCGAIN = GAIN_2X #pragma config SOSCBOOST = ON #pragma config POSCGAIN = GAIN_2X #pragma config POSCBOOST = ON #pragma config EJTAGBEN = NORMAL #pragma config CP = OFF //---------------------------------------------------------- // DEVCFG1 //---------------------------------------------------------- #pragma config FNOSC = SPLL #pragma config DMTINTV = WIN_127_128 #pragma config FSOSCEN = OFF #pragma config IESO = OFF #pragma config POSCMOD = EC //24 Mhz External clock osc #pragma config OSCIOFNC = OFF #pragma config FCKSM = CSECME #pragma config WDTPS = PS1048576 #pragma config WDTSPGM = STOP #pragma config FWDTEN = OFF #pragma config WINDIS = NORMAL #pragma config FWDTWINSZ = WINSZ_25 #pragma config DMTCNT = DMT31 #pragma config FDMTEN = OFF //---------------------------------------------------------- // DEVCFG2 // EC Ext OSC in =24Mhz // SYSCLK=200Mhz, PBxCLK=100Mhz //---------------------------------------------------------- #pragma config FPLLIDIV = DIV_3 #pragma config FPLLRNG = RANGE_5_10_MHZ #pragma config FPLLICLK = PLL_POSC #pragma config FPLLMULT = MUL_50 #pragma config FPLLODIV = DIV_2 #pragma config UPLLFSEL = FREQ_24MHZ //---------------------------------------------------------- // DEVCFG3 //---------------------------------------------------------- #pragma config USERID = 0x0ADC #pragma config FMIIEN = OFF #pragma config FETHIO = OFF #pragma config PGL1WAY = OFF #pragma config PMDL1WAY = OFF #pragma config IOL1WAY = OFF #pragma config FUSBIDIO = OFF //---------------------------------------------------------- // BF1SEQ0 //---------------------------------------------------------- #pragma config TSEQ = 0x0000 #pragma config CSEQ = 0xFFFF // ************************************************************************************************* // U S E R D E F I N E S // Note: User must configure as required // ************************************************************************************************* #define TAD_TRIGGER_SOURCE_SPACING 4 // TAD trigger spacing value from ADC Table 13 or 15 accordingly w/12bit & 4 interleaved ADCs #define INTERLEAVED_ADC_COUNT 4 // Number of interleaved ADC (Cannot be <2 or >4). Changing this value will // automatically scale the number of interleaved ADC and triggers utilized in this code. #define ADC_DMA_BUFF_SIZE 2048 //ADC DMA buffer size // // ************************************************************************************************* // EQUATION #1: (Assumptions: INTERLEAVED_ADC_COUNT=4) // (Fastest Triggering possible) // TAD_TRIGGER_SOURCE_SPACING(min) = // = ((SAMC(min) + (((#bits Resolution+1) + ADJ) * TAD)) / INTERLEAVED_ADC_COUNT) // = (3+12+1) + ADJ) * TAD)) / 4 ADCs) // = (16 + ADJ) * TAD)) / 4 ADCs // = (16 + 0) * TAD)) / 4 ADCs // = 4.0 TAD (minimum trigger spacing possible) // // NOTE: "ADJ" term = A user selected whole number adjustment factor between 0-4 // that must yield a Minimum TAD Trigger interval that equates to an exact // multiple of a ˝ TAD. This represents the minimum TAD_TRIGGER_SOURCE_SPACING // and therefore the fastest throughput possible. Additional TAD_TRIGGER_SOURCE_SPACING // and hence ADC Throughput Rates are possible in ˝ TAD trigger spacing increments. // (See examples 1-3 below) // // NOTE: Once the minimum, TAD trigger spacing possible is determined, the user can configure for any // additional sampling frequency required if needed in 0.5 TAD trigger spacing increments. // // Example 1: (INTERLEAVED_ADC_COUNT=4) // TAD_TRIGGER_SOURCE_SPACING(min) = 4 // interleaved ADC Throughput rate = TAD clock freq / TAD_TRIGGER_SOURCE_SPACING // = 50Mhz / 4.0(min) // = 12.5msps // // Example 2: (INTERLEAVED_ADC_COUNT=4) // TAD_TRIGGER_SOURCE_SPACING = 4.5 // interleaved ADC Throughput rate = TAD clock freq / TAD_TRIGGER_SOURCE_SPACING // = 50Mhz / 4.5 // = 11.111111msps // // Example 3: (INTERLEAVED_ADC_COUNT=4) // TAD_TRIGGER_SOURCE_SPACING = 5.0 // interleaved ADC Throughput rate = TAD clock freq / TAD_TRIGGER_SOURCE_SPACING // = 50Mhz / 5.0 // = 10msps // // ************************************************************************************************* // // ************************************************************************************************* // P R O G R A M D E F I N E S // (User Do Not Change) // Note: // TAD_TRIGGER_SOURCE_SPACING is multiplied by (2) because // OCx and TMR3 trigger source time base is 2x faster than an ADC TAD clock. // 2 TMR3 clocks = 1 ADC TAD Clock // ************************************************************************************************** // ------------------------------------------------------------------------------------------------------------------ // NOTE: Remember that the peripheral trigger clock frequency is 2x TAD clock frequency. // This is why the 2x. The -1 is because the Si peripheral triggers are always // on (match+1), so to compensate for correct timing subtract 1. // #define ADC_TRIG (TAD_TRIGGER_SOURCE_SPACING * 2) // #define OC1_ADC_TRIG (ADC_TRIG - 1) // #define OC3_ADC_TRIG ((2 * ADC_TRIG) - 1) // #define OC5_ADC_TRIG ((3 * ADC_TRIG) - 1) // #define T3_ADC_TRIG ((INTERLEAVED_ADC_COUNT * ADC_TRIG) - 1) // #define ADC0_IRQ 59 //PIC32MZxxEFxx ADC0 Data_0 IRQ number #define ADC1_IRQ 60 //PIC32MZxxEFxx ADC1 Data_1 IRQ number #define ADC2_IRQ 61 //PIC32MZxxEFxx ADC2 Data_2 IRQ number #define ADC3_IRQ 62 //PIC32MZxxEFxx ADC3 Data_3 IRQ number #define VirtAddr_TO_PhysAddr(v) ((unsigned long)(v) & 0x1FFFFFFF) #if ((INTERLEAVED_ADC_COUNT < 2) | (INTERLEAVED_ADC_COUNT > 4)) #error INTERLEAVED_ADC_COUNT error, it is either less than 2 or greater than 4 #endif // ************************************************************************************************* // F U N C T I O N P R O T O T Y P E S // ************************************************************************************************* void init_ADC(void); void init_DMA(void); void init_TMR3(void); // ************************************************************************************************* // G L O B A L V A R I A B L E S // ************************************************************************************************* uint32_t __attribute__((coherent)) adc_bufA[INTERLEAVED_ADC_COUNT * ADC_DMA_BUFF_SIZE]; uint32_t __attribute__((coherent)) adc_bufB[INTERLEAVED_ADC_COUNT * ADC_DMA_BUFF_SIZE]; uint32_t adc_buf_index = 0; bool adc_dma_buf_full_flg = 0; // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // $ M A I N R O U T I N E $ // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ int main(void) { // ****************************************************************************** // CPU Performance Optimization: // ****************************************************************************** register unsigned long tmp_cache; //KSEG0 cache enable asm("mfc0 %0,$16,0" : "=r"(tmp_cache)); tmp_cache = (tmp_cache & ~7) | 3; asm("mtc0 %0,$16,0" :: "r" (tmp_cache)); PRECONbits.PFMWS=2; //Flash wait states = 2 CPU clock cycles @ 200Mhz PRECONbits.PREFEN = 2; //Enable predictive prefetch for CPU instructions and CPU data PRISSbits.PRI7SS = 7; //DMA Interrupt with priority level of 7 uses Shadow Set 7 PRISSbits.PRI6SS = 6; //Interrupt with priority level of 6 uses Shadow Set 6 PRISSbits.PRI5SS = 5; //Interrupt with priority level of 5 uses Shadow Set 5 PRISSbits.PRI4SS = 4; //Interrupt with priority level of 4 uses Shadow Set 4 PRISSbits.PRI3SS = 3; //Interrupt with priority level of 3 uses Shadow Set 3 PRISSbits.PRI2SS = 2; //Interrupt with priority level of 2 uses Shadow Set 2 INTCONbits.MVEC = 1; //Enable multi-vector interrupts __builtin_mtc0(12,0,(__builtin_mfc0(12,0) | 0x0001)); // Global Interrupt Enable // ****************************************************************************** // * Disable all ANx pins that are enabled by default on reset // ****************************************************************************** ANSELACLR = 0xFFFF; //Disable all analog ANx input pins ANSELBCLR = 0xFFFF; //Disable all analog ANx input pins ANSELCCLR = 0xFFFF; //Disable all analog ANx input pins ANSELDCLR = 0xFFFF; //Disable all analog ANx input pins ANSELECLR = 0xFFFF; //Disable all analog ANx input pins ANSELFCLR = 0xFFFF; //Disable all analog ANx input pins ANSELGCLR = 0xFFFF; //Disable all analog ANx input pins ANSELHCLR = 0xFFFF; //Disable all analog ANx input pins ANSELJCLR = 0xFFFF; //Disable all analog ANx input pins // ****************************************************************************** // Initialize and enable ADC(s) followed by ADC trigger sources 2nd // ****************************************************************************** init_ADC(); //Initialize and enable interleaved ADCs first before PWM ADC triggers are enabled while(1) { if(adc_dma_buf_full_flg) //If current DMA buffer is full { adc_dma_buf_full_flg = 0; //Clr DMA buff full flag //*********************************************************************** // In main(), "adc_buf_index" represents the current active buffer being // filled as the companion buffer is already full. //*********************************************************************** if(adc_buf_index == 0) //if "adc_bufA" active then "adc_bufB" full { //----------------------------------------------------------------------------------------------------------------------- // User must process here previously filled ADC DMA Buffer B ptr starting at "adc_bufB" //----------------------------------------------------------------------------------------------------------------------- } else //if "adc_bufB" active then "adc_bufA" full { //----------------------------------------------------------------------------------------------------------------------- // User must process here previously filled ADC DMA Buffer A ptr starting at "adc_bufA" //----------------------------------------------------------------------------------------------------------------------- } } //******************************************************* //* USERS OTHER MAIN CODE GOES HERE //******************************************************* } } // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // $ F U N C T I O N S U B - R O U T I N E S $ // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // ********************************************************************************* // * init_ADC(void) // * I N T E R L E A V E D A D C I N I T I L I Z A T I O N R O U T I N E // * Used analog inputs if: // * INTERLEAVED_ADC_COUNT = 2 (Analog inputs, AN0 and AN1 only) // * INTERLEAVED_ADC_COUNT = 3 (Analog inputs, AN0, AN1 and AN2 only) // * INTERLEAVED_ADC_COUNT = 4 (Analog inputs, AN0, AN1, AN2 and AN3 only) // ********************************************************************************* // ********************************************************************************* // These steps are already done in this code example, this is just a reminder // to the user for any new original code development. // // CAUTION:(Required) // 1) The user SHOULD always set the minimum sampling time of each Class_1 ADC // equal to 3TAD as defined by ADCxTIME. // 2) The user should insure that the selected trigger source time base clock rate is // exactly 2x faster than the ADC clock TAD rate. This will provide the highest // timing resolution along with the most sampling rate options as defined in // Table 13 or 15 accordingly in this app note. // 3) The user selected trigger sources have to be able to be mapped to a single // synchronized time base. // For example: // a) TMR3 & OCx (x=1,3,5 PIC32MZxxxx) // b) TMR3 & OCx (x=1-4 PIC32MKxxGPxx) // c) PTMRx & TRIGx ( x=1-12 PIC32MKxxMCxx PWM) // d) PTMRx & STRIGx ( x=1-12 PIC32MKxxMCxx PWM) // 4) In a same group of interleaved ADC’s a user “MUST NOT” use two separate timer trigger sources. // Example: ADC0, ADC1 and ADC2 are being used in an interleaved group. // Trigger sources can be any combination of valid ADC OCx edge triggered sources synchronized to a SINGLE TMRx. // It would not be allowed to use in the same group of interleaved ADCs OCx, TMR3 & TMR5 for example. // Separate TMRx in different interleaved ADC groups is OK. // 5 If using the DMA for the ADC the user “MUST” use SYSCLK as the ADC // source clock, (i.e. ADCCON3). // 6) User must configure ADC for 512 TAD warm-up time // (ADCANCONbits.WKUPCLKCNT = 0x9) "BEFORE" enabling ADC. // 7) Users SW must wait for ADC BANGAP and ADC warm-up time "AFTER" // enabling ADC and before activating the ADC trigger sources. // 8) ADC must always be initialized 1st “BEFORE” activating the ADC trigger sources // // NOTE: Failure to follow these recommendations will result in inaccurate ADC // data acquisition and poor performance. //****************************************************************************** void init_ADC(void) { ADC0CFG = DEVADC0; //Load ADC0 Calibration values ADC1CFG = DEVADC1; //Load ADC1 Calibration values ADC2CFG = DEVADC2; //Load ADC2 Calibration values ADC3CFG = DEVADC3; //Load ADC3 Calibration values ADC4CFG = DEVADC4; //Load ADC4 Calibration values ADC7CFG = DEVADC7; //Load ADC7 Calibration values ADCANCONbits.WKUPCLKCNT = 0x9; // ADC Warm up delay = (512 * TADx) ADCCON1bits.AICPMPEN = 0; //Disable ADC charge pump CFGCONbits.IOANCPEN = 0; //Disable ADC I/O charge pump // ****************************************************************************** // * If using the DMA the user MUST use SYSCLK as the ADC source clock // ****************************************************************************** ADCCON1bits.FSSCLKEN = 1; //Fast synchronous SYSCLK to ADC control clock is enabled ADCCON3bits.ADCSEL = 1; // Select ADC input clock source = SYSCLK 200Mhz ADCCON3bits.CONCLKDIV = 1; // Analog-to-Digital Control Clock (TQ) Divider = SYSCLK/2 // ****************************************************************************** // * ADC0 Module setup: // * TAD = SYSCLK/4, 12bit, SAMC=3TAD, OC1 Trigger // ****************************************************************************** ANSELBSET = 0x1; //Enable analog AN0 input ADC0TIMEbits.ADCDIV = 1; // ADCx Clock Divisor, Divide by 2, 50Mhz ADC0TIMEbits.SAMC = 1; // 3 TAD (Hardware enforced sample time) ADC0TIMEbits.SELRES = 3; // ADC0 12bit resolution mode ADCTRG1bits.TRGSRC0 = 8; // Set AN0 to trigger from OC1 ADCANCONbits.ANEN0 = 1; // Enable ADC0 analog bias/logic ADCCON3bits.DIGEN0 = 1; // Enable ADC0 digital logic ADCGIRQEN1bits.AGIEN0 = 1; //Enb ADC0 AN0 interrupts for DMA // ****************************************************************************** // * ADC1 Module setup: // * TAD = SYSCLK/4, 12bit, SAMC=3TAD // * if(INTERLEAVED_ADC_COUNT == 2) TMR3 trigger else OC3 Trigger // ****************************************************************************** ANSELBSET = 0x2; //Enable analog AN1 input ADC1TIMEbits.ADCDIV = 1; // ADCx Clock Divisor, Divide by 2, 50Mhz ADC1TIMEbits.SAMC = 1; // 3 TAD ADC1TIMEbits.SELRES = 3; // ADC1 12bit resolution mode if(INTERLEAVED_ADC_COUNT == 2) ADCTRG1bits.TRGSRC1 = 6; // Set ADC1 to trigger from TMR3 else ADCTRG1bits.TRGSRC1 = 9; // Set ADC1 to trigger from OC3 ADCANCONbits.ANEN1 = 1; // Enable ADC1 analog bias/logic ADCCON3bits.DIGEN1 = 1; // Enable ADC1 digital logic ADCGIRQEN1bits.AGIEN1 = 1; //Enb ADC1 AN1 interrupts for DMA // ****************************************************************************** // * ADC2 Module setup: // * TAD = SYSCLK/4, 12bit, SAMC=3TAD, OC5 Trigger // * if(INTERLEAVED_ADC_COUNT == 3) TMR3 trigger else OC5 Trigger // ****************************************************************************** if(INTERLEAVED_ADC_COUNT > 2) { ANSELBSET = 0x4; //Enable analog AN2 input ADC2TIMEbits.ADCDIV = 1; // ADCx Clock Divisor, Divide by 2, 50Mhz ADC2TIMEbits.SAMC = 1; // 3 TAD ADC2TIMEbits.SELRES = 3; // ADC2 12bit resolution mode if(INTERLEAVED_ADC_COUNT == 3) ADCTRG1bits.TRGSRC2 = 6; // Set ADC2 to trigger from TMR3 else ADCTRG1bits.TRGSRC2 = 10; // Set ADC2 to trigger from OC5 ADCANCONbits.ANEN2 = 1; // Enable ADC2 analog bias/logic ADCCON3bits.DIGEN2 = 1; // Enable ADC2 digital logic ADCGIRQEN1bits.AGIEN2 = 1; //Enb ADC2 AN2 interrupts for DMA } // ****************************************************************************** // * ADC3 Module setup: // * if(INTERLEAVED_ADC_COUNT == 4) // * TAD = SYSCLK/4, 12bit, SAMC=3TAD, TMR3 Trigger // ****************************************************************************** if(INTERLEAVED_ADC_COUNT > 3) { ANSELBSET = 0x8; //Enable analog AN3 input ADC3TIMEbits.ADCDIV = 1; // ADCx Clock Divisor, Divide by 2, 50Mhz ADC3TIMEbits.SAMC = 1; // 3 TAD ADC3TIMEbits.SELRES = 3; // ADC3 12bit resolution mode ADCTRG1bits.TRGSRC3 = 6; // Set ADC3 to trigger from TMR3 ADCANCONbits.ANEN3 = 1; // Enable ADC3 analog bias/logic ADCCON3bits.DIGEN3 = 1; // Enable ADC3 digital logic ADCGIRQEN1bits.AGIEN3 = 1; //Enb ADC3 AN3 interrupts for DMA } ADCCON1bits.ON = 1; // Turn the ADC on // ****************************************************************************** // * Waiting for ADC warm-up time and ADC bandgap reference to stabilize // ****************************************************************************** while(!ADCCON2bits.BGVRRDY); // Wait until the reference voltage is ready while(!ADCANCONbits.WKRDY0); // Wait until ADC0 is ready while(!ADCANCONbits.WKRDY1); // Wait until ADC1 is ready if(INTERLEAVED_ADC_COUNT > 2) while(!ADCANCONbits.WKRDY2); // Wait until ADC2 is ready if(INTERLEAVED_ADC_COUNT > 3) while(!ADCANCONbits.WKRDY3); // Wait until ADC3 is ready ADCDATA0; // Read ADC data to make sure that data ready bits are clear. ADCDATA1; // ADCDATA2; // ADCDATA3; // init_DMA(); //Initialize DMA init_TMR3(); //Initialize and enable ADC interleaved triggers } // *************************************************************** // * D M A I N I T I A L I Z A T I O N R O U T I N E * // *************************************************************** void init_DMA(void) { // ********************************************************** // * Set the DMA trigger source. Each interrupt on the indicated // * ADC_DATA_VECTOR begins a DMA transfer. // ********************************************************** if(INTERLEAVED_ADC_COUNT == 2)DCH0ECONbits.CHSIRQ = ADC1_IRQ; //DMA_TRIGGER_ADC0_DATA0; if(INTERLEAVED_ADC_COUNT > 2)DCH0ECONbits.CHSIRQ = ADC2_IRQ; //DMA_TRIGGER_ADC2_DATA2; if(INTERLEAVED_ADC_COUNT > 3)DCH0ECONbits.CHSIRQ = ADC3_IRQ; //DMA_TRIGGER_ADC3_DATA3; // ********************************************************** // * Enable DMA Channel Start IRQ. // ********************************************************** DCH0ECONbits.SIRQEN = 1; //DMA Chan_0 Start IRQ Enable // ********************************************************** // * Set DMA Source Starting Address // ********************************************************** DCH0SSA = (uint32_t) VirtAddr_TO_PhysAddr((const void *)&ADCDATA0); // ********************************************************** // * Set DMA Source Size in bytes // ********************************************************** if(INTERLEAVED_ADC_COUNT == 2) DCH0SSIZ = 8; // ADC0 + ADC1, 4+4bytes = 8bytes if(INTERLEAVED_ADC_COUNT > 2) DCH0SSIZ = 12; //ADC0 + ADC1 + ADC2 = 12bytes if(INTERLEAVED_ADC_COUNT > 3) DCH0SSIZ = 16; //ADC0 + ADC1 + ADC2 + ADC3 = 16bytes // ********************************************************** // * Set DMA Destination Starting Address // ********************************************************** DCH0DSA = (uint32_t) VirtAddr_TO_PhysAddr((const void *)&adc_bufA[0]); // ********************************************************** // * Set DMA Destination Size // ********************************************************** DCH0DSIZ = (uint16_t) INTERLEAVED_ADC_COUNT*(ADC_DMA_BUFF_SIZE)*sizeof(adc_bufA[0]); // ********************************************************** // * Set Cell Size // ********************************************************** DCH0CSIZ = (uint16_t) sizeof(adc_bufA[0]); DCH0INTbits.CHDDIF = 0; //Clr Chan Dest Done Int Flg DCH0INTbits.CHDDIE = 1; //Enable DMA Destination Interrupt // ********************************************************** // * Enable DMA channel 0 // ********************************************************** DCH0CONbits.CHEN = 1; //DMA Chan 0 enable // ********************************************************** // * Enable DMA and DMA interrupts // ********************************************************** IFS4bits.DMA0IF = 0; //Clr DMA Chan0 int flg IPC33bits.DMA0IP = 7; //Set DMA Chan0 int priority 7 IPC33bits.DMA0IS = 3; //Set DMA Chan0 sub priority 3 IEC4bits.DMA0IE = 1; //Enable DMA Chan0 interrupt DMACONbits.ON = 1; //Enb DMA } // ********************************************************************************* // * I N T E R L E A V E D A D C T R I G G E R I N I T I A L I Z A T I O N // ********************************************************************************* void init_TMR3(void) { // ***************************************************************************** // * AN0-ANx Interleaved Triggers: (x=1-3) // * Same analog input connected to all interleaved ANx inputs w/staggered triggers: // ***************************************************************************** PR3 = T3_ADC_TRIG; //ADC3 TRM3 Trigger throughput rate // ****************************************************************************** // * ADC0 Trigger setup: // * TMR3 = OC1 time base, continuous pulse // ****************************************************************************** CFGCONbits.OCACLK = 0; // OC1CONbits.OCTSEL = 1; //Timer"y" is clk source for OC1 module OC1CONbits.OCM = 5; //Init OC1 low; gen continuous output pulses OC1R = OC1_ADC_TRIG; //ADC0 OC1 Trigger throughput rate OC1RS = OC1_ADC_TRIG+2; OC1CONSET = 0x8000; // Enable OC1 // ****************************************************************************** // * ADCx Trigger setup: // * TMR3 = OC3 time base, continuous pulse // ****************************************************************************** if(INTERLEAVED_ADC_COUNT > 2) { OC3CONbits.OCTSEL = 1; //Timer"y" is clk source for OC3 module OC3CONbits.OCM = 5; //Init OC3 low; gen continuous output pulses OC3R = OC3_ADC_TRIG; //ADC1 OC3 Trigger throughput rate OC3RS = OC3_ADC_TRIG+2; OC3CONSET = 0x8000; // Enable OC3 } // ****************************************************************************** // * ADCy Trigger setup: // * TMR3 = OC5 time base, continuous pulse // ****************************************************************************** if(INTERLEAVED_ADC_COUNT > 3) { OC5CONbits.OCTSEL = 1; //Timer"y" is clk source for OC5 module OC5CONbits.OCM = 5; //Init OC5 low; gen continuous output pulses OC5R = OC5_ADC_TRIG; //ADC2 OC5 Trigger throughput rate OC5RS = OC5_ADC_TRIG+2; OC5CONSET = 0x8000; // Enable OC5 } T3CONSET = 0x8000; //Start TMR3 } //End TMR3 Subroutine // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // $ I N T E R R U P T S E R V I C E R O U T I N E S $ // $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ // ************************************************************************************************* // D M A I S R (Interrupt Service Routine) // ************************************************************************************************* void __attribute__((interrupt(ipl7auto), vector(_DMA0_VECTOR), aligned(16), nomips16)) isr () { IFS4bits.DMA0IF = 0; //Clr DMA Chan 0 int flg DCH0INTbits.CHDDIF = 0; //Clr DMA dest done flg adc_dma_buf_full_flg = 1; //Current DMA buffer is full if(adc_buf_index == 0) //if "adc_bufA" full, change DMA dest to "adc_bufB" { DCH0DSA = (uint32_t) VirtAddr_TO_PhysAddr((const void *)&adc_bufB[0]); adc_buf_index = 1; } else //if "adc_bufB" full, change DMA dest to "adc_bufA" { DCH0DSA = (uint32_t) VirtAddr_TO_PhysAddr((const void *)&adc_bufA[0]); adc_buf_index = 0; } DCH0CONbits.CHEN = 1; //DMA Chan 0 enable }