• AVR Freaks

Hot!PIC32MZ EF ADC usage methods

Author
WaltR
Super Member
  • Total Posts : 3812
  • Reward points : 0
  • Joined: 2003/11/07 12:38:21
  • Status: offline
2020/03/07 08:22:39 (permalink)
4.67 (3)

PIC32MZ EF ADC usage methods

The ADC module in the PIC32MZ EF has a mind bogging number of registers. The Data Sheet is very brief but Section 22 of the Family Reference Manual has more detail and some code examples. It can be found here:
http://ww1.microchip.com/...eviceDoc/60001344B.pdf

I am using a PIC32MZ2048EFM144 on a Curiosity PIC32MZ EF 2.0 Development Board.
Comments in code examples refer to the Headers on this Dev board.  
One method of using the ADCs that is Not explained in a Manual operation like how ADC operation is done in PIC16s and PIC18s. That is Start Sampling then do Conversion, then Read ADC Data.
The Data sheet has a hint in the notes under register ADCCON3.

ADCCON3:
    bit 9 SAMP: Class 2 and Class 3 Analog Input Sampling Enable bit(1,2,3,4)
          1 = The ADC S&H amplifier is sampling
          0 = The ADC S&H amplifier is holding
    bit 8 RQCNVRT: Individual ADC Input Conversion Request bit
          This bit and its associated ADINSEL<5:0> bits enable the user to
          individually request an analog-to-digital conversion of an analog
          input through software.
    1 = Trigger the conversion of the selected ADC input as specified by the
          ADINSEL<5:0> bits
    0 = Do not trigger the conversion
          Note: This bit is automatically cleared in the next ADC clock cycle.
    bit 5-0 ADINSEL<5:0>: Analog Input Select bits
        These bits select the analog input to be converted when the RQCNVRT bit is set.
        111111 = Reserved
       ....
        101101 = Reserved
        101100 = MAX_AN_INPUT + 2 = IVTEMP
        101011 = MAX_AN_INPUT + 1 = IVREF
        101010 = MAX_AN_INPUT = AN[MAX_AN_INPUT]
       .....
        000001 = AN1
        000000 = AN0
 Note 1: The SAMP bit has the highest priority and setting this bit will keep the S&H circuit in Sample mode until the
    bit is cleared. Also, usage of the SAMP bit will cause settings of SAMC<9:0> bits (ADCCON2<25:16>) to
    be ignored.
  2: The SAMP bit only connects Class 2 and Class 3 analog inputs to the shared ADC, ADC7. All Class 1
    analog inputs are not affected by the SAMP bit.
  3: The SAMP bit is not a self-clearing bit and it is the responsibility of application software to first clear this bit
    and only after setting the RQCNVRT bit to start the analog-to-digital conversion.
  4: Normally, when the SAMP and RQCNVRT bits are used by software routines, all TRGSRCx<4:0> bits
    and STRGSRC<4:0> bits should be set to '00000' to disable all external hardware triggers and prevent
    them from interfering with the software-controlled sampling command signal SAMP and with the
    software-controlled trigger RQCNVRT.

Figure 22-5 in “PIC32 Family Reference Manual” shows the effect of the SAMP & RQCNVRT bit ever though Figure 22-5's example timing is due to a Trigger.
The code to do this follows. This function selects input AN29 on the shared ADC7, Starts teh pin Sampling, delays to allow the ADC's input cap to charge then starts the conversion. The 'while' loop waits for the conversion to finish then reads and returns the ADC data.

unsigned int read_ADC_AN29 (void)
{
    ADCCON3bits.ADINSEL = 29;       // AN29, Ard A1, pin RA1
    ADCCON3bits.SAMP = 1;           // start sampling pin
    Wait_200ns();                   // Input C sampling time
    ADCCON3bits.RQCNVRT = 1;        // start conversion
    ADCCON3bits.SAMP = 0;           // now release Sample
    while (ADCCON3bits.RQCNVRT);    // wait for conversion to finish
    return ADCDATA29;
}

This is very close to an ADC Get  function on a PIC16 or PIC18. The major difference is that each analog input has its own data register. Therefore one cannot write a universal function to Sample/convert/read. Instead write a function for Each analog input to be used.
One thing I found using this method is the very first conversion returns 0x0000. Not sure why yet but doing a call to the read_ADC function in 'main' before going into the 'main loop' fixes this.
Minimal code in Main.c

#define LED_R_T       LATBINV = 0x0080; // RB7 0b0000 0000 1000 0000
void main(void) {

        SYSTEM_Initialize();    // setup all CPU, pins, etc as needed
    Wait_100ms();
    init_ADC();
    Wait_100ms();
    // warm up?
        adc_buf[0] = read_ADC_AN29();

    while(1)                        // Main Loop
            {
        Wait_500ms();
                LED_R_T;                    // blink Red LED
        adc_buf[0] = read_ADC_AN29();            // Get ADC value of AN29
                UART2_Hex16_Out((uint16_t)adc_buf[0]);    // output ADC value in hex format on UART2
    }
}

I have UART2 setup as a simple Async output to a Terminal program on the PC.
I use TRM5 to do fixed, blocking delays. I find this is an easy method. The delay code is:

void Wait_200ns (void)
{
    T5CON = 0x8000;                     // TCKPS 1:1
    PR5 = 0x0013;                       // 19d
    TMR5 = 0x0;                         // reset timer
    IFS0CLR= _IFS0_T5IF_MASK;           // clear IF
    while(!IFS0bits.T5IF);
}
void Wait_100ms (void)
{
    T5CON = 0x8070;             // TCKPS 1:256
    PR5 = 0x970F;               // 38671d
    TMR5 = 0x0;                 // reset timer
    IFS0CLR= _IFS0_T5IF_MASK;  // clear IF
    while(!IFS0bits.T5IF);      // wait for PR match
}
void Wait_500ms (void)
{
    int i;
    for (i=0;i<5;i++){
        Wait_100ms();
    }
}


What about setting up the ADC modules? I saved this for last since it is nearly the same as the examples in the “PIC32 Family Reference Manual”. There are still many register that must be setup.
Here is the minimum setup needed if  ONLY using the shared ADC7.

void init_ADC( void)
{
    // Must ensure register PMD1<0> is cleared to enable ADC module
    
    ADC0CFG = DEVADC0;    // copy calibration
    ADC1CFG = DEVADC1;
    ADC2CFG = DEVADC2;
    ADC3CFG = DEVADC3;
    ADC4CFG = DEVADC4;
    ADC7CFG = DEVADC7;

    /* Configure ADCCON1 */
    ADCCON1 = 0;
    ADCCON1bits.SELRES = 3;      // ADC7 resolution is 12 bits
    ADCCON1bits.STRGSRC = 0; // No scan trigger
    
    /* Configure ADCCON2 */
    ADCCON2 = 0;
    ADCCON2bits.SAMC = 5;       // ADC7 sampling time = 7 * TAD7 = 141ns
    ADCCON2bits.ADCDIV = 1;     // ADC7 clock freq is half of control clock (TQ) = TAD7

    /* Global setting */
    ADCCON3 = 0;
    ADCCON3bits.VREFSEL = 0;       // Select AVDD and AVSS as reference source
    ADCCON3bits.ADCSEL = 1;        // Select input clock source = SYSCLK
    ADCCON3bits.CONCLKDIV = 1;     // Control clock (TQ) frequency is half of input clock
                                            // TQ output to ADCDIVx
    // SYSCLK = 198MHz
    // TQ = 10.1 nsec (99MHz)
    // TAD = 20.2ns
    
    /* No selection for dedicated ADC modules, no presync trigger, not sync sampling */
    ADCTRGMODE = 0;

    /* Select ADC input mode */
    ADCIMCON1 = 0; // all unsigned data format & Single ended mode

    /* Configure ADCGIRQENx */
    ADCGIRQEN1 = 0; // No interrupts are used.
    ADCGIRQEN2 = 0;

    /* Early interrupt */
    ADCEIEN1 = 0; // No early interrupt
    ADCEIEN2 = 0;
    
    /* Configure ADCCSSx ADC COMMON SCAN SELECT REGISTER */
    ADCCSS1 = 0; // Clear all bits  - No scanning is used
    ADCCSS2 = 0; // clear all bits
      
    /* Configure ADCCMPCONx */
    ADCCMPCON1 = 0; // No digital comparators are used. Setting the ADCCMPCONx
    ADCCMPCON2 = 0; // register to '0' ensures that the comparator is disabled.
    ADCCMPCON3 = 0; // Other registers are ?don't care?.
    ADCCMPCON4 = 0;
    ADCCMPCON5 = 0;
    ADCCMPCON6 = 0;
    
    /* Configure ADCFLTRx */
    ADCFLTR1 = 0; // No oversampling filters are used.
    ADCFLTR2 = 0;
    ADCFLTR3 = 0;
    ADCFLTR4 = 0;
    ADCFLTR5 = 0;
    ADCFLTR6 = 0;
    
    // Setup Manual SAMP/CONV: AN0-42
    // not needed. Set SAMP-RQCNVRT in function that does manual convert

    /* Initialize warm up time register */
    ADCANCON = 0;
    ADCANCONbits.WKUPCLKCNT = 5; // Wakeup exponent = 32 * TADx
    
    /* Turn the ADC on */
    ADCCON1bits.ON = 1;
    
    /* Wait for voltage reference to be stable */
    while(!ADCCON2bits.BGVRRDY);   // Wait until the reference voltage is ready
    while(ADCCON2bits.REFFLT);     // Wait if there is a fault with the reference voltage

    // Enable clock to the module.
    ADCCON3bits.DIGEN7 = 1;         // Enable ADC7
    ADCANCONbits.ANEN7 = 1;         // Enable clock, ADC7
    
    while( !ADCANCONbits.WKRDY7 );  // Wait until ADC7 is ready

    /* Setup pins for ADC input */
        
    ANSELASET = 0x0002;     // AN29, Ard A1, pin RA1
    TRISASET = 0x0002;
    // add for other analog inputs desired

}

There is still a lot of registers setup and still requires the Warm up to wait for all to be ready.
The examples show only one analog input. to use additional analog inputs simply ensure the ANSELx & TRISx register are properly set then write read_ADC_ANx() function s for each analog input pin to be read.
This method is Blocking but perfectly fine for taking ADC reading non-frequently.  There is another method I plan to write up in the next post.
That's about it. All the information is in the data sheets and the PIC32 Family Reference Manual. It needs to be read very carefully and many times.



#1

16 Replies Related Threads

    MisterHemi
    Super Member
    • Total Posts : 276
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/03/07 13:55:54 (permalink)
    0
    Hopefully someone will have an answer for you soon. I have used the PIC32MZ ADC but it's been a while.
     
    When I have a chance i'll see if I can post my code from the version 1 board to the version 2 board, as I have both.
     
    I do remember what I did was just basic ADC conversion without using all of the optional parameters for the ADC but it worked fine for my simple purposes at the time (just periodically reading the value of some pots).

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS Mojave (10.14.6) and MPLAB X IDE v5.30
     
    Curiosity PIC32MZ EF 1 & 2, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #2
    MisterHemi
    Super Member
    • Total Posts : 276
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/03/07 14:03:21 (permalink)
    0
    This is some older code I wrote but here is how I initialized the ADC on the PIC32MZ. I think if I were to update it i'd probably change or fix some things but maybe this would be helpful/useful for you.
     

     
    void initADC(void)
    {
    /* Calibrate the ADCs by using these values contained in the DEVADC registers */
    ADC0CFG = DEVADC0; // Load the calibration numbers into the ADCs
    ADC1CFG = DEVADC1;
    ADC2CFG = DEVADC2;
    ADC3CFG = DEVADC3;
    ADC4CFG = DEVADC4;
    ADC7CFG = DEVADC7;

    // Configure ADCCON1 register
    ADCCON1 = 0; // No ADCCON1 features are enabled

    /* Configure ADCCON2 */
    ADCCON2 = 0; // We are only going to use class-1 inputs, so no settings required here

    /* Initialize warm up time register */
    ADCANCON = 0;
    ADCANCONbits.WKUPCLKCNT = 5; // Wakeup exponent = 32 * TADx

    /* Clock settings */
    ADCCON3 = 0;
    ADCCON3bits.ADCSEL = 1; // Set the ADC clock to use SYSCLK
    ADCCON3bits.CONCLKDIV = 1; // Control clock frequency is half of the input clock
    ADCCON3bits.VREFSEL = 0; // Set AVDD (+3.3v) and AVSS (0v/GND) as the Reference voltage sources

    /* Select ADC sample time and conversion clock */
    ADC0TIMEbits.ADCDIV = 1; // ADC0 clock frequency is half
    ADC0TIMEbits.SAMC = 5; // ADC0 sampling time = 5 *TAD2
    ADC0TIMEbits.SELRES = 3; // ADC0 resolution is 12 bits

    /* Select analog input for ADC modules, no pre-sync trigger, not sync sampling */
    ADCTRGMODEbits.SH2ALT = 0; // ADC2 = AN2
    ADCTRGMODEbits.SH3ALT = 0; // ADC3 = AN3

    /* Select the ADC input mode */
    // AN2 Configuration (Class 1)
    ADCIMCON1bits.SIGN2 = 0; // The channel is to use Unsigned Data mode
    ADCIMCON1bits.DIFF2 = 0; // The ADC channel is using SIngle-ended mode

    // AN3 Configuration (Class 1)
    ADCIMCON1bits.SIGN3 = 0; // The channel is to use Unsigned Data mode
    ADCIMCON1bits.DIFF3 = 0; // The ADC channel is using SIngle-ended mode

    /* Configure ADCGIRQENx */
    ADCGIRQEN1 = 0; // No interrupts are used
    ADCGIRQEN2 = 0;

    /* Configure ADCCSSx */
    ADCCSS1 = 0;
    ADCCSS2 = 0;

    /* Configure ADCCMPCONx */
    ADCCSS1 = 0;
    ADCCSS2 = 0;

    /* Configure ADCCMPCONx */
    ADCCMPCON1 = 0; // No digital comparators are used. Setting the ADCCMPCONx
    ADCCMPCON2 = 0; // register to '0' ensures that the comparator is disabled.
    ADCCMPCON3 = 0; // Other registers are ?don't care?.
    ADCCMPCON4 = 0;
    ADCCMPCON5 = 0;
    ADCCMPCON6 = 0;

    /* Configure ADCCLTRx */
    ADCFLTR1 = 0; // No oversampling filters are used.
    ADCFLTR2 = 0;
    ADCFLTR3 = 0;
    ADCFLTR4 = 0;
    ADCFLTR5 = 0;
    ADCFLTR6 = 0;

    /* Set up the trigger sources */
    ADCTRGSNSbits.LVL2 = 0; // Edge trigger
    ADCTRGSNSbits.LVL3 = 0; // Edge trigger
    ADCTRG1bits.TRGSRC2 = 1; // Set AN2 to trigger from software
    ADCTRG1bits.TRGSRC3 = 1; // Set AN3 to trigger from software

    /* Early interrupt */
    ADCEIEN1 = 0; // No early interrupt
    ADCEIEN2 = 0;

    /* Turn the ADC on */
    ADCCON1bits.ON = 1;

    /* Wait for voltage references to be stable */
    while (!ADCCON2bits.BGVRRDY);// Wait until the reference voltage is ready
    while (ADCCON2bits.REFFLT); // Wait if there is a fault with the reference voltage

    /* Enable clock to analog circuit */
    ADCANCONbits.ANEN2 = 1; // Enable the clock to the analog bias
    ADCANCONbits.ANEN3 = 1; // Enable the clock to the analog bias

    /* Wait for ADC to be ready */
    while (!ADCANCONbits.WKRDY2); // Wait until ADC2 is ready
    while (!ADCANCONbits.WKRDY3); // Wait until ADC3 is ready

    /* Enable the ADC module */
    ADCCON3bits.DIGEN2 = 1; // Enable ADC2
    ADCCON3bits.DIGEN3 = 1; // Enable ADC3

    }

     
    Then when I wanted to read a value I used something like this:

    /* Trigger a conversion */
    ADCCON3bits.GSWTRG = 1;

    /* Wait for conversions to complete */
    while (ADCDSTAT1bits.ARDY2 == 0); // Wait for AN2 conversion

    /* Fetch the conversion results */
    analog2 = ADCDATA2;

     
    You might want to add a time out, etc.
     
     

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS Mojave (10.14.6) and MPLAB X IDE v5.30
     
    Curiosity PIC32MZ EF 1 & 2, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #3
    WaltR
    Super Member
    • Total Posts : 3812
    • Reward points : 0
    • Joined: 2003/11/07 12:38:21
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/03/07 18:19:19 (permalink)
    0
    Hopefully someone will have an answer for you soon. I have used the PIC32MZ ADC but it's been a while.

    I did not have a Question. I posted a 'HOW TO' since when I started on this PIC32's ADC and searched the forum found many questions but no good answers.
     
    I looked at the code you posted and you are using the Global Software trigger. Whereas my example uses the 'SAMP' then 'RQCNVRT' bits for a Manual conversion of one ADC input at a time.
     
    Adding Time-out to the 'wait for conversion' is a good idea.
     
     
     
    post edited by WaltR - 2020/03/08 06:23:44
    #4
    MisterHemi
    Super Member
    • Total Posts : 276
    • Reward points : 0
    • Joined: 2017/11/02 12:24:21
    • Location: Commerce, CA USA
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/03/07 19:00:10 (permalink)
    0
    Sorry, I misunderstood your post but I think we agree that it isn't straightforward from some of the examples.

    My configuration:
    MacBook Pro (Retina, 15-inch, Mid 2015) with MacOS Mojave (10.14.6) and MPLAB X IDE v5.30
     
    Curiosity PIC32MZ EF 1 & 2, PIC24F Curiosity, XPRESS EVAL BOARD (PIC16F18855), SAMA5D3 Xplained and various custom boards.
    #5
    WaltR
    Super Member
    • Total Posts : 3812
    • Reward points : 0
    • Joined: 2003/11/07 12:38:21
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/03/08 06:21:05 (permalink)
    0
    MisterHemi
    Sorry, I misunderstood your post but I think we agree that it isn't straightforward from some of the examples.



    Exactly why I started this thread. My idea is to post examples of various ways to use the ADC in the PIC32MZ EF that are not covered in the FRM.
     
    Thanks for adding the code you came up with. My next subject is setting up and using the Global Software Trigger like you did.
    #6
    Joel QO
    New Member
    • Total Posts : 27
    • Reward points : 0
    • Joined: 2014/09/28 11:52:38
    • Location: 0
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/03/10 11:01:55 (permalink)
    0
    WaltR

    There is still a lot of registers setup and still requires the Warm up to wait for all to be ready.
    The examples show only one analog input. to use additional analog inputs simply ensure the ANSELx & TRISx register are properly set then write read_ADC_ANx() function s for each analog input pin to be read.
    This method is Blocking but perfectly fine for taking ADC reading non-frequently.  There is another method I plan to write up in the next post.
    That's about it. All the information is in the data sheets and the PIC32 Family Reference Manual. It needs to be read very carefully and many times.







    Hi, WaltR
     
    I'm using also the PIC32MZ2048EFM144 and I'm trying to read through the AN49 pin in a custom board. This pin is on the shared ADC4.
     
    I have a doubt about the value that I should assign to the ADINSEL bits. Should I assign the channel number value? The multiplexer selector? Or is it something else?
     
    I appreciate your help. Thank you ahead.
    #7
    WaltR
    Super Member
    • Total Posts : 3812
    • Reward points : 0
    • Joined: 2003/11/07 12:38:21
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/03/11 09:09:02 (permalink)
    0
    1- ADC4 is Not consider shared. It is ADC7 that is 'shared'. Terminology is important.
    However, ADC4 has an Alternative input that is AN49.
     
    In the Data sheet & FRM section 22 it does state that the first 5 ADCs, 0 -4, are always named ADC0-ADC4 (AN0-AN4) even if the alternate input (AN45-AN49) is used.
     
    So you must select this alternate input in register: ADCTRGMODE, bits 25-24 = 0b01 (This did take me a few minutes to find in the data sheet). Then use the ADINSEL set to AN4 as this can be used for any ADCs (this is the example I have in post #1 above). Then read ADCDATA4.
     
    This is covered in Section 22.4.4.4 of the FRM.
    Good question and why I started this thread. Hope this helps.
    post edited by WaltR - 2020/03/12 19:35:21
    #8
    ACPUK
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2020/03/31 18:52:16
    • Location: 0
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/01 19:00:14 (permalink)
    0
    Hi all and thank you to WaltR for your thread.
    So after many years of PIC dev, I admit defeat with the PIC32MZ(EF) ADC, therefore I have joined this forum in response to your topic.
    For this new project, I have switched from my usual PIC32MX choice to the PIC32MZ2048EFH144 as I require 33 channels on ADC.
    I am using MicroC for PIC32, and Microelectronica’s Fusion dev board. All AN pins are currently pulled high to Vss for testing. PIC is running from a 24MHz clock SPLL = 200MHZ, ADCs are running from SPPL DIV 10 (20MHz.)
    My understanding is
    AN0 is on ADC0
    AN1 is on ADC1
    AN2 is on ADC2
    AN3 is on ADC3
    AN4 is on ADC4
    AN5 to AN42 is on ADC7
    I am trying to scan all channels from AN0 through AN31, all single-ended. However, after spending much time checking the SFRs I am at a loss.
    The odd thing is, I am only getting data in the associated ADCDATAx for every 4th channel, AN0, AN4, AN8, AN12, AN16, AN20, AN24 and AN28
     
    I have also tried, as a test, to load ADINSEL to invoke manual channel by channel conversions: -
    for(Ch=0; Ch<=31; Ch++){
    ADCCON3bits.ADINSEL = Ch
    while(!ADCCON3bits.SAMP);
     ADCCON3bits.RQCNVRT =1;
    }
    I get the same result as when I set GSWTRG to invoke a scan.
    All expected ADCDSTAT bits set when and as expected.
    One set of SFRs that are confusing me are the ADCTRG1: to ADCTRG3:
    These set the Trigger Source for Conversion for AN0 through to AN11 !
    Why is this AN0 to AN11? Where AN5 + are Class 3 therefor no ‘special’ triggers, I’m confused…
     
    So I post my code below, If anybody has the time to have a look, I would be most grateful.
     
     #define SAMPLE_TIME 5
     #define ADC_CLOCK_DIV 5 // ADCDIV 10 20MHz
     Config_Internal_ACD()
    {
      char error =0;
       /* Load Calobration*/
      ADC0CFG = DEVADC0;
      ADC1CFG = DEVADC1;
      ADC2CFG = DEVADC2;
      ADC3CFG = DEVADC3;
      ADC4CFG = DEVADC4;
      ADC7CFG = DEVADC7;


      ADCCON1 = 0x0; //Clear the SFR, this sets DMA Biffer size to 1
      ADCCON1bits.STRGLVL = 2; //Scan trigger is high level sensitive. Once STRIG mode is selected (TRGSRCx<4:0> in the ADCTRGx
                                      //register), the scan trigger will continue for all selected analog inputs, until the STRIG option is removed.
      ADCCON1bits.IRQVS =0b000; //0 X Interrupt Vector Shift bits
      ADCCON1bits.FSPBCLKEN =1; //Fast synchronous peripheral clock to ADC control clock is ENABLED
      ADCCON1bits.FSSCLKEN =0; //Fast synchronous system clock to ADC control clock is disabled
      ADCCON1bits.CVDEN =0; //Capacitive Voltage Division is Desabled
      ADCCON1bits.AICPMPEN =0; //Analog input charge pump is disabled as the digerence between Vrefh - Vrefl is grater than 2.145 volts
      ADCCON1bits.SIDL =0; // Continue operation in Idle mode
      ADCCON1bits.ON =0; // ADC is enabled, needs enabled later
      //Scan Trigger Source Select bits
      //00010 = Global level software trigger (GLSWTRG)
      //00001 = Global software trigger (GSWTRG) is self-cleared on the next clock cycle
      //00000 = No Trigger
      ADCCON1bits.STRGSRC =1; // Global software trigger (GSWTRG) is self-cleared on the next clock cycle.
      ADCCON1bits.SELRES =3; // 12 bit resolution
      ADCCON1bits.FRACT =0; // Interger Data output (0=- Unsigned, 1=Fractional)
      ADCCON1bits.TRBSLV =0; // ADC1 is Turbo Slave
      ADCCON1bits.TRBMST =0; // ADC0 is turbo master
      ADCCON1bits.TRBEN =0; // Turbo mode is disabled, we dont need it

      ADCCON2bits.ADCDIV =4; // ADC7 clock freq is 1/10 of control clock 20MHz
      ADCCON2bits.ADCEIS =0; // Shared ADC Early Interrupt Select bits, 000 = The data ready interrupt is generated 1 ADC module clock prior to end of conversion

      ADCCON2bits.ADCEIOVR =1; // Early interrupt generation is overridden and interrupt generation is controlled by the ADCGIRQEN1 and ADCGIRQEN2 registers
      ADCCON2bits.EOSIEN =1; // End of Scan Interrupt Enable bit, Interrupt will be generated when EOSRDY bit is set
      ADCCON2bits.REFFLTIEN =0; // Band Gap/VREF Voltage Fault Interrupt Enable bit, No interrupt is generated when the REFFLT bit is set
      ADCCON2bits.BGVRIEN =0; // Band Gap/VREF Voltage Ready Interrupt Enable bit, No interrupt is generated when the BGVRRDY bit is set
      ADCCON2bits.SAMC =SAMPLE_TIME; // ADC7 sampling time = 5 * TAD7
      //ADCCON2bits.EOSRDY End of scan Interups Status bit
      //ADCCON2bits.REFFLT Band Gap/VREF/AVDD BOR Fault Status bit

      // Initialize warm up time register
      ADCANCON = 0;
      ADCANCONbits.WKUPCLKCNT = 0xA; // Wakeup exponent = 32 * TADx


      ADCCON3bits.ADINSEL =0; // Analog Input Select bits for manual convertion
      ADCCON3bits.GSWTRG =1; // Global Software Trigger bit, enabled
      ADCCON3bits.GLSWTRG =0; // Global Level Software Trigger bit, disabled
      ADCCON3bits.RQCNVRT =0; // Individual ADC Input Conversion Request bit
                                        // This bit and its associated ADINSEL<5:0> bits enable the user to individually request an analog-to-digital
                                        // conversion of an analog input through software.
      /*
      Note 1: The SAMP bit has the highest priority and setting this bit will keep the S&H circuit in Sample mode until the
      bit is cleared. Also, usage of the SAMP bit will cause settings of the SAMC<9:0> bits (ADCCON2<25:16>)
      to be ignored.
      2: The SAMP bit only connects Class 2 and Class 3 analog inputs to the shared ADC. All Class 1 analog
      inputs are not affected by the SAMP bit.
      3: The SAMP bit is not a self-clearing bit and it is the responsibility of application software to first clear this bit
      and only after setting the RQCNVRT bit to start the analog-to-digital conversion.
      4: Normally, when the SAMP and RQCNVRT bits are used by software routines, all TRGSRCx<4:0> bits and
      STRGSRC<4:0> bits should be set to ‘00000’ to disable all external hardware triggers and prevent them
      from interfering with the software-controlled sampling command signal SAMP and with the
      software-controlled trigger RQCNVRT.
      */
      ADCCON3bits.SAMP =1; //Class 2 and Class 3 Analog Input Sampling Enable bit(1,2,3,4)
                                         //1 = The ADC S&H amplifier is sampling
                                         //0 = The ADC S&H amplifier is holding
      //ADCCON3bits.UPDRDY ADC Update Ready Status bit
      ADCCON3bits.TRGSUSP =0; // Trigger Suspend bit
      ADCCON3bits.VREFSEL =0; // Voltage Reference (VREF) Input Selection bits,000 AVDD AVss

      ADCCON3bits.DIGEN0 =0; // ADC0 Digital Enable bit, disabled for now
      ADCCON3bits.DIGEN1 =0; // ADC1 Digital Enable bit, disabled for now
      ADCCON3bits.DIGEN2 =0; // ADC2 Digital Enable bit, disabled for now
      ADCCON3bits.DIGEN3 =0; // ADC3 Digital Enable bit, disabled for now
      ADCCON3bits.DIGEN4 =0; // ADC4 Digital Enable bit, disabled for now
      ADCCON3bits.DIGEN7 =0; // ADC7 Digital Enable bit, disabled for now

      ADCCON3bits.CONCLKDIV =ADC_CLOCK_DIV; // ADC7 clock freq is 1/10 of control clock 20MHz
      ADCCON3bits.ADCSEL =SAMPLE_TIME; // Analog-to-Digital Clock Source (TCLK) bits, Peripheral bus clock (PBCLK), Paripheral bus IS SPPL (System closck 200MHz)
      /* Setup timing*/
      ADC0TIMEbits.ADCDIV =ADC_CLOCK_DIV; // ADC0 clock frequency is 1/10 20MHz
      ADC0TIMEbits.SAMC =SAMPLE_TIME; // ADC0 sampling time = 5 * TAD0
      ADC0TIMEbits.SELRES =3; // ADC0 resolution is 12 bits

      ADC1TIMEbits.ADCDIV =ADC_CLOCK_DIV; // ADC1 clock frequency is 1/10 20MHz
      ADC1TIMEbits.SAMC =SAMPLE_TIME; // ADC1 sampling time = 5 * TAD0
      ADC1TIMEbits.SELRES =3; // ADC1 resolution is 12 bits

      ADC2TIMEbits.ADCDIV =ADC_CLOCK_DIV; // ADC2 clock frequency is 1/10 20MHz
      ADC2TIMEbits.SAMC =SAMPLE_TIME; // ADC2 sampling time = 5 * TAD0
      ADC2TIMEbits.SELRES =3; // ADC2 resolution is 12 bits

      ADC3TIMEbits.ADCDIV =ADC_CLOCK_DIV; // ADC3 clock frequency is 1/10 20MHz
      ADC3TIMEbits.SAMC =SAMPLE_TIME; // ADC3 sampling time = 5 * TAD0
      ADC3TIMEbits.SELRES =3; // ADC3 resolution is 12 bits

      ADC4TIMEbits.ADCDIV =4; // ADC4 clock frequency is 1/10 20MHz
      ADC4TIMEbits.SAMC =5; // ADC4 sampling time = 5 * TAD0
      ADC4TIMEbits.SELRES =3; // ADC4 resolution is 12 bits



      /* Select analog input for ADC modules, no presync trigger, not sync sampling */
      ADCTRGMODE = 0; // ADC0 = AN0
      /* Select ADC input mode */
      ADCIMCON1 =0x0; // Set AN0 to AN15 to Singal ended and Unsigned Data Mode
      ADCIMCON2 =0x0; // Set AN16 to AN31 to Singal ended and Unsigned Data Mode
      ADCIMCON3 =0x0; // Set AN32 to AN47 to Singal ended and Unsigned Data Mode

      // ADC Global Interrupt Enable Register 1
      ADCGIRQEN1 =0x0; // Disable AN0 to AN31 Interupts
      ADCGIRQEN2 =0x0; // Disable AN32 to AN63 Interupts
      /* Early interrupt */
      ADCEIEN1 = 0; // No early interrupt
      ADCEIEN2 = 0;
      /* Configure ADCCSSx */


      //ADCDSTAT1: ADC Data Ready Status Register 1
      //ADCDSTAT2: ADC Data Ready Status Register 2
      /* Configure ADCCMPCONx */
      ADCCMPCON1 = 0; // No digital comparators are used. Setting the ADCCMPCONx
      ADCCMPCON2 = 0; // register to '0' ensures that the comparator is disabled.
      ADCCMPCON3 = 0; // Other registers are ‘don't care’.
      ADCCMPCON4 = 0;
      ADCCMPCON5 = 0;
      ADCCMPCON6 = 0;

      //ADCCMPENx: ADC Digital Comparator
      ADCCMPEN1 =0x0; // Disable comparitors
      ADCCMPEN2 =0x0; // Disable comparitors
      ADCCMPEN3 =0x0; // Disable comparitors
      ADCCMPEN4 =0x0; // Disable comparitors
      ADCCMPEN5 =0x0; // Disable comparitors
      ADCCMPEN6 =0x0; // Disable comparitors

      //ADCFLTRx: ADC Digital Filter
      ADCFLTR1 =0x0; // Disable Digital Filtering
      ADCFLTR2 =0x0; // Disable Digital Filtering
      ADCFLTR3 =0x0; // Disable Digital Filtering
      ADCFLTR4 =0x0; // Disable Digital Filtering
      ADCFLTR5 =0x0; // Disable Digital Filtering
      ADCFLTR6 =0x0; // Disable Digital Filtering

      /* Set up the trigger sources */
      ADCTRGSNS =0xFFFFFFFF; //Analog input is sensitive to the high level of its trigger (level sensitivity implies retriggering as long as

    /* Set up the trigger sources */
      ADCTRG1bits.TRGSRC0 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG1bits.TRGSRC1 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG1bits.TRGSRC2 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG1bits.TRGSRC3 =3; //Global software edge Trigger (GSWTRG)

      ADCTRG2bits.TRGSRC4 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG2bits.TRGSRC5 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG2bits.TRGSRC6 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG2bits.TRGSRC7 =3; //Global software edge Trigger (GSWTRG)

      ADCTRG3bits.TRGSRC8 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG3bits.TRGSRC9 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG3bits.TRGSRC10 =3; //Global software edge Trigger (GSWTRG)
      ADCTRG3bits.TRGSRC11 =3; //Global software edge Trigger (GSWTRG)
       /* Turn the ADC on */
      ADCCON1bits.ON = 1;
      /* Wait for voltage reference to be stable */
      //While_Timeout_10ms = 0;
      //while(!ADCCON2bits.BGVRRDY || While_Timeout_10ms > 5); // Wait until the reference voltage is ready
      while(!ADCCON2bits.BGVRRDY);
      if(!ADCCON2bits.BGVRRDY)
      {
        //Report_Status(PMS_STATE,INTERNAL_ADC,REF_VOLT_TIMEOUT);
        return 1;
      }
      else
      {
        //Report_Status(PMS_STATE,INTERNAL_ADC,REF_VOLT_STABLE);

      /* Enable clock to analog circuit */
      ADCANCONbits.ANEN0 = 1; // Enable the clock to analog bias ADC0
      ADCANCONbits.ANEN1 = 1; // Enable the clock to analog bias ADC1
      ADCANCONbits.ANEN2 = 1; // Enable the clock to analog bias ADC2
      ADCANCONbits.ANEN3 = 1; // Enable the clock to analog bias ADC3
      ADCANCONbits.ANEN4 = 1; // Enable the clock to analog bias ADC4
      ADCANCONbits.ANEN7 = 1; // Enable, ADC7

        //While_Timeout_10ms = 0;
        //while(ADCCON2bits.REFFLT|| While_Timeout_10ms > 5); // Wait if there is a fault with the reference voltage
        while(ADCCON2bits.REFFLT);
        
        if(ADCCON2bits.REFFLT)
        {
        //Report_Status(PMS_STATE,INTERNAL_ADC,REF_VOLT_FAULT);
        return 1;
        }
        //Report_Status(PMS_STATE,INTERNAL_ADC,REF_VOLT_STABLE);

      }

      //While_Timeout_10ms = 0;
      //while(!ADCANCONbits.WKRDY0 && While_Timeout_10ms >2); // Wait until ADC0 is ready
      while(!ADCANCONbits.WKRDY0);
          
          if(!ADCANCONbits.WKRDY0)
             {
              //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_0_TIME);
              error =error &0b10;
              }
          else
        //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_0_UP);
      //While_Timeout_10ms = 0;
      //while(!ADCANCONbits.WKRDY1 && While_Timeout_10ms >2); // Wait until ADC1 is ready
        while(!ADCANCONbits.WKRDY1);
          if(!ADCANCONbits.WKRDY1)
             {
              //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_1_TIME);
              error =error &0b100;
              }
          else
        //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_1_UP);
      //While_Timeout_10ms = 0;
      //while(!ADCANCONbits.WKRDY2 && While_Timeout_10ms >2); // Wait until ADC2 is ready
        while(!ADCANCONbits.WKRDY2);
          if(!ADCANCONbits.WKRDY2)
             {
              //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_2_TIME);
              error =error &0b1000;
              }
          else
       // Report_Status(PMS_STATE,INTERNAL_ADC,ACD_2_UP);
      //While_Timeout_10ms = 0;
      //while(!ADCANCONbits.WKRDY3 && While_Timeout_10ms >2); // Wait until ADC3 is ready
        while(!ADCANCONbits.WKRDY3);
          if(!ADCANCONbits.WKRDY3)
             {
              //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_3_TIME);
              error =error &0b10000;
              }
          else
        //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_3_UP);
      //While_Timeout_10ms = 0;
      //while(!ADCANCONbits.WKRDY4 && While_Timeout_10ms >2); // Wait until ADC4 is ready
        while(!ADCANCONbits.WKRDY4);
          if(!ADCANCONbits.WKRDY4)
             {
              //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_3_TIME);
              //error =error &0b100000;
              }
          else
        //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_4_UP);
      //While_Timeout_10ms = 0;
      //while(!ADCANCONbits.WKRDY7 && While_Timeout_10ms >2); // Wait until ADC5 is ready
        while(!ADCANCONbits.WKRDY7);
          if(!ADCANCONbits.WKRDY7)
             {
              //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_3_TIME);
              error =error &0b1000000;
              }
          else
        //Report_Status(PMS_STATE,INTERNAL_ADC,ACD_7_UP);
       /* Enable the ADC module */
      ADCCON3bits.DIGEN0 = 1; // Enable ADC0
      ADCCON3bits.DIGEN1 = 1; // Enable ADC1
      ADCCON3bits.DIGEN2 = 1; // Enable ADC2
      ADCCON3bits.DIGEN3 = 1; // Enable ADC3
      ADCCON3bits.DIGEN4 = 1; // Enable ADC4
      ADCCON3bits.DIGEN7 = 1; // Enable ADC7


     return error;
    }

    void Scan_Internal_ADC()
    {
     // count = 0;
     /* Trigger a conversion */

    //for(count=0; count<=30; count++)
    //{
    //ADCCON3bits.ADINSEL = count;
    // ADCCON3bits.SAMP = 1;
    // while(!ADCCON3bits.SAMP);
    // ADCCON3bits.RQCNVRT =1;
    // while (ADCCON3bits.RQCNVRT);
    // ADCCON3bits.SAMP = 0;
    // delay_ms(50);*/
    //ADCCON3bits.GSWTRG = 1;


    //while (ADCDSTAT1bits.ARDY4 == 0);
    /* Trigger a conversion */


    /* Wait the conversions to complete */
    /*while (ADCDSTAT1bits.ARDY0 == 0);

    while (ADCDSTAT1bits.ARDY1 == 0);

    while (ADCDSTAT1bits.ARDY2 == 0);*/
    /* fetch the result */
    }



    void Init_MCU()
    {
     /* Make all outputs off*/
     LATA = 0;
     LATB = 0;
     LATC = 0;
     LATD = 0;
     LATE = 0;
     LATF = 0;
     LATG = 0;
     LATH = 0;

     JTAGEN_bit = 0;
     Unlock_IOLOCK();
     PPS_Mapping_NoLock(_RPD3,_INPUT,_C1RX);
     PPS_Mapping_NoLock(_RPD2,_OUTPUT,_C1TX);
     PPS_Mapping_NoLock(_RPB8,_INPUT,_C2RX);
     PPS_Mapping_NoLock(_RPB6,_OUTPUT,_C2TX);
     PPS_Mapping_NoLock(_RPC14,_OUTPUT,_SDO1);
     PPS_Mapping_NoLock(_RPF1,_INPUT,_SDI1);
     PPS_Mapping_NoLock(_RPD0, _OUTPUT, _OC1);
     PPS_Mapping_NoLock(_RPD1, _OUTPUT, _OC2);
     PPS_Mapping_NoLock(_RPF4, _OUTPUT, _OC3);
     Lock_IOLOCK();
    //TRIS ANSEL CSS
                                                 ADCCSS2 =0;
      TRISAbits.TRISA0 =1; ANSELABits.ANSA0 =1; ADCCSS1bits.CSS24 =1; //AN24 COM_5V_2_IMON_AN24
      TRISAbits.TRISA1 =1; ANSELABits.ANSA1 =0; ADCCSS1bits.CSS29 =0;//EN1_5V_M85
      TRISAbits.TRISA2 =0; //ESC_5_ENABLE_C_P-M85
      TRISAbits.TRISA3 =0; //ESC_6_ENABLE_C_P-M86
      TRISAbits.TRISA4 =0; //ESC_2_ENABLE_C_P-M87
      TRISAbits.TRISA5 =1; ANSELABits.ANSA5 =0;ADCCSS2bits.CSS34 =0;//E1_INTB-M2
      TRISAbits.TRISA6 =0; //SPI1_cs_4-M129
      TRISAbits.TRISA7 =0; //SPI1_CS_5-M130
      TRISAbits.TRISA9 =1; ANSELABits.ANSA9 =1; ADCCSS1bits.CSS27 =1;//AN27 GEAR_4_IMON_AN27
      TRISAbits.TRISA10 =1; ANSELABits.ANSA10 =1; ADCCSS1bits.CSS28 =1;//AN28 ST_1_VS_AN28
      TRISAbits.TRISA14 =0; //SCL_1-M95
    //TRISAbits.TRISA15 =1; //SDA_1-M96

      TRISbbits.TRISB0 =1; ANSELBBits.ANSB0 =1; ADCCSS1bits.CSS0 =1;//AN0 IRE_5V_IMON_AN0
      TRISBbits.TRISB1 =1; ANSELBBits.ANSB1 =1; ADCCSS1bits.CSS1 =1;//AN1 FIR_12V_IMON_AN1
      TRISBbits.TRISB2 =1; ANSELBBits.ANSB2 =1; ADCCSS1bits.CSS2 =1;//AN2 FIRE_24V_IMON_AN2
      TRISBbits.TRISB3 =1; ANSELBBits.ANSB3 =1; ADCCSS1bits.CSS3 =1;//AN3 GIMBAL_24V_IMON_AN3
      TRISBbits.TRISB4 =1; ANSELBBits.ANSB4 =1; ADCCSS1bits.CSS4 =1;//AN4 P_CAM_IMON_AN4
      TRISBbits.TRISB5 =1; //GP2_24V-M48
      TRISBbits.TRISB6 =1; //PGEC2
      TRISBbits.TRISB7 =1; //PGED2
      TRISBbits.TRISB8 =1; //CAN_2_RX
      TRISBbits.TRISB9 =1; //GP2_24V-M48
      TRISBbits.TRISB10 =1; ANSELBBits.ANSB5 =1; ADCCSS1bits.CSS5 =1;//AN5 GEAR_1_IMON_AN5
      TRISBbits.TRISB11 =1; ANSELBBits.ANSB6 =1; ADCCSS1bits.CSS6 =1;//AN6 ST_2_VS_AN6
      TRISBbits.TRISB12 =1; ANSELBBits.ANSB7 =1; ADCCSS1bits.CSS7 =1;//AN7 ST_3_VS_AN7
      TRISBbits.TRISB13 =1; ANSELBBits.ANSB8 =1; ADCCSS1bits.CSS8 =1;//AN8 ST_4_VS_AN8
      TRISBbits.TRISB14 =1; ANSELBBits.ANSB9 =1; ADCCSS1bits.CSS9 =1;//AN9 GEAR_2_IMON_AN9
      TRISBbits.TRISB15 =1; ANSELBBits.ANSB14 =1; ADCCSS1bits.CSS14 =1;//AN14 GEAR_2_IMON_AN9

      TRISCbits.TRISC1 =1; ANSELCBits.ANSC1 =1; ADCCSS1bits.CSS22 =1;//AN22 RADIO_IMON_AN22
      TRISCbits.TRISC2 =1; ANSELCBits.ANSC2 =1; ADCCSS1bits.CSS21 =1;//AN21 LED_2_IMON_AN21
      TRISCbits.TRISC3 =1; ANSELCBits.ANSC3 =1; ADCCSS1bits.CSS20 =1;//AN20 LIDAR_12V_2_IMON_AN20
      TRISCbits.TRISC4 =1; ANSELCBits.ANSC4 =1; ADCCSS1bits.CSS19 =1;//AN19 LIDAR_12V_1_IMON_AN19
      TRISCbits.TRISC12 =1; //CLKI
      TRISCbits.TRISC13 =0; //ST_1_OR_EN-M105
      TRISCbits.TRISC14 =0; //SDO1-M106
      TRISCbits.TRISC15 =1; // UNUSED

      TRISDbits.TRISD0 =0; //ST_1_DRIVE_C_P-M104
      TRISDbits.TRISD1 =1; // UNUSED
      TRISDbits.TRISD2 =0; //CAN_1_TX-M110
      TRISDbits.TRISD3 =1; //CAN_1_Rx-M111
      TRISDbits.TRISD4 =1; //ALERT_A_5V-M118
      TRISDbits.TRISD5 =0; //ST_2_DRIVE_C_P-M119
      TRISDbits.TRISD6 =0; //ETXEN-M120
      TRISDbits.TRISD7 =1; // UNUSED
      TRISDbits.TRISD9 =1; //PSM_3.3V_PG_1-M97
      TRISDbits.TRISD10 =1; //PSM_3.3V_PG_2-M98
      TRISDbits.TRISD11 =1; //EMDC-M99
      TRISDbits.TRISD12 =1; //IC_VDD_FALT-M112
      TRISDbits.TRISD13 =1; //IC_VDD_PG-M113
      TRISDbits.TRISD14 =0; //ST_4_OR_EN-M69
      TRISDbits.TRISD15 =0; //EXT_OR_EN-M70

      TRISEbits.TRISE0 =1; // UNUSED
      TRISEbits.TRISE1 =1; // UNUSED
      TRISEbits.TRISE2 =1; // UNUSED
      TRISEbits.TRISE3 =1; // UNUSED
      TRISEbits.TRISE4 =1; ANSELEBits.ANSE4 =1; ADCCSS1bits.CSS18 =1; //AN18 AFE_5V_2_IMON_AN18
      TRISEbits.TRISE5 =1; ANSELEBits.ANSE5 =1; ADCCSS1bits.CSS17 =1;//AN17 AFE_5V_1_IMON_AN17
      TRISEbits.TRISE6 =1; ANSELEBits.ANSE5 =1; ADCCSS1bits.CSS16 =1;//AN16 IC_VDD_IMON_AN16-M4
      TRISEbits.TRISE7 =1; ANSELEBits.ANSE7 =1; ADCCSS1bits.CSS15 =1;//AN16 LED_1_IMON_AN15-M5
      TRISEbits.TRISE8 =1; ANSELEBits.ANSE8 =1; ADCCSS1bits.CSS25 =1;//AN25 ETH_5V_IMON_AN25-M23
      TRISEbits.TRISE9 =1; ANSELEBits.ANSE9 =1; ADCCSS1bits.CSS26 =1;//AN26 ENC_5V_IMON_AN26-M24

      TRISFbits.TRISF0 =1; // UNUSED
      TRISFbits.TRISF1 =1; //SDI1-M125
      TRISFbits.TRISF2 =1; //E1_INTA-M79
      TRISFbits.TRISF3 =0; //CAN_2_tx-M78
      TRISFbits.TRISF4 =0; //ST_3_DRIVE_C_P-M90 PWM3 / OC3
      TRISFbits.TRISF5 =0; //ST_4_DRIVE_C_P-M91 PWM4 / OC4
      TRISFbits.TRISF8 =0; //ESC_8_ENABLE_C_P-M80
      TRISFbits.TRISF12 =1; ANSELFBits.ANSF12 =1; ADCCSS1bits.CSS31 =1; //AN31 LIDAR_12V_3_IMON_AN31
      TRISFbits.TRISF13 =0; //EN_12V-M57

      TRISGbits.TRISG0 =0; //SPI1_CS_3-M128
      TRISGbits.TRISG1 =0; //SPI1_CS_2-M127
      TRISGbits.TRISG6 =1; ANSELGBits.ANSG6 =1; ADCCSS1bits.CSS14 =1; //AN14 SBC_5V_IMON_AN14
      TRISGbits.TRISG7 =1; ANSELGBits.ANSG7 =1; ADCCSS1bits.CSS13 =1; //AN13 FMU_5V_2_IMON_AN13
      TRISGbits.TRISG8 =1; ANSELGBits.ANSG8 =1; ADCCSS1bits.CSS12 =1; //AN12 FMU_5V_1_IMON_AN12
      TRISGbits.TRISG9 =1; ANSELGBits.ANSG9 =1; ADCCSS1bits.CSS11 =1; //AN11 COM_5V_1_IMON_AN11
      TRISGbits.TRISG12 =1; // UNUSED
      TRISGbits.TRISG13 =1; // UNUSED
      TRISGbits.TRISG14 =1; // UNUSED
      TRISGbits.TRISG15 =1; ANSELGBits.ANSG15 =1; ADCCSS1bits.CSS23 =1; //AN32 LIDAR_12V_1_IMON_AN23
    }


    void main() {
     Init_MCU();
     Config_Internal_ACD();
     
     while(1){
      ADCCON3bits.GSWTRG = 1;
      while(!ADCDSTAT1bits.ARDY31); // This should be the last conversion to complete
      delay_ms(500);
     }
    }
     
     
    Thanks and
    Best Regards
    Anthony
    #9
    ACPUK
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2020/03/31 18:52:16
    • Location: 0
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/02 12:53:18 (permalink)
    0
    As an update from my last post.
    http://ww1.microchip.com/downloads/en/DeviceDoc/PIC32MZ_EF_Family_Errata_DS80000663K.pdf
    Family Silicon Errata and Data Sheet Clarification
    Indicated ADC on this PIC does NOT work in De-bug mode.
    So I am now pushing the results out of UART1.
    Now ADC0,1,2,3 and 4 are working. However, ADC7 just produces random results from AN5 to AN31.
    No matter what the voltage is on the channels, the numbers are just nonsense.
    I have also tried a range of SAMC up to 255 for max sample time and beond 9 the PIC stops functioning totaly.
    ADCDIV all the way to 255 (1111111 = 254 * TQ = TAD) with the same results.
    #10
    WaltR
    Super Member
    • Total Posts : 3812
    • Reward points : 0
    • Joined: 2003/11/07 12:38:21
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/16 16:49:13 (permalink)
    0
    Sorry I did not see your post sooner. I need to ensure I have subscribed.
    This is a complex ADC system so it takes a bit to get it doing what you need.
    At least you are past the Errata issue- I almost always use the UART for debugging
     
    I assume you have read Section 22 of the Family Reference Manual. 22.3.2 cover scan.
    Class 1 and Class 2 inputs are triggered using STRIG selection in
    ADCTRGx register and Class 3 inputs are triggered using the STRGSRC<4:0> of
    ADCCON1<20:16> register.

     
    Looking at code I have written and tested- I did not try do a scan on class 3 ADC inputs, only Class 1 & 2 (ADC0 to 11). The Ref Manual implies Class 3 ADCS (12-53) should also work.
    NOTE: be careful with the Ref manual as this covers ALL PIC32MZ processors. For example the PIC32MZ2048EFM144 we are using does NOT have ADC DMA and I would not be surprised that the ADC Class ranges are different.
     
    Have you tried the Manual Sample/Read method I described above?
    I have tested this on ADC29, 38, 39 & 42. It would be worth while to ensur the AN inputs to the ADC7 work.
     
     
     
    #11
    ACPUK
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2020/03/31 18:52:16
    • Location: 0
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/16 17:24:15 (permalink)
    0
    Hi WaltR thanks for your reply. I have tried manual sample and read and got exactly the same results as I did with a scan.
    Yes, I have the ADCCON1bits.STRGSRC   =1; to trigger on GSWTRG and I have tried it on 2 also for GLSWTRG without self-clear. 
     My understanding is if set to 1 = GSWTRG, in code as you set GSWTRG, this will start a scan. I am waiting for the last ARDY (ARDY31) of interest as this should be the last bit to set in the reg once the scan is complete then I read the ADCDATAx.
    ADCCON3bits.GSWTRG = 1;
    while(!ADCDSTAT1bits.ARDY31);
    ADC_Result_1 = ADCDATA0; etc. 
     
    The results are totally random for every 4th read, the rest is always 0. If they were all random I would suspect the internal Vref to be faulty. 
    I am currently looking at an external AD7490 which is working but it seems mad to use two of these ICs which are more expensive than the PIC, each. 
     
    I have attached my results output. 
    Regards
    Anthony
     

    Attached Image(s)

    #12
    ACPUK
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2020/03/31 18:52:16
    • Location: 0
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/16 17:51:01 (permalink)
    0
    Sorry ignore that attached image, that was from Debug. I have checked I do get results all around the 600 mark.
    This does then question the Vref but this is set to ADCCON3bits.VREFSEL   =0; AVdd / AVss 
    #13
    ACPUK
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2020/03/31 18:52:16
    • Location: 0
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/16 17:54:10 (permalink)
    0
    Interesting Setting Vef to Internal changes the results AN5 to AN 32 = 0
    ADCCON3bits.VREFSEL   =0;
    AN10 = 0
    AN11 = 669
    AN12 = 669
    AN13 = 664
    AN14 = 658
    AN15 = 658
    AN16 = 661
    AN17 = 661
    AN18 = 659
    AN19 = 655
    AN20 = 651
    AN21 = 650
    AN22 = 658
    AN23 = 659
    AN24 = 655
    AN25 = 651
    AN26 = 651
    AN27 = 653
    AN28 = 652
    AN29 = 0
    AN30 = 0
    AN31 = 653
     
    ADCCON3bits.VREFSEL   =4;
    AN0 = 4095
    AN1 = 4095
    AN2 = 4095
    AN3 = 4095
    AN4 = 4095
    AN5 = 0
    AN6 = 0
    AN7 = 0
    AN8 = 0
    AN9 = 0
    AN10 = 0
    AN11 = 0
    AN12 = 0
    AN13 = 0
    AN14 = 0
    AN15 = 0
    AN16 = 0
    AN17 = 0
    AN18 = 0
    AN19 = 0
    AN20 = 0
    AN21 = 0
    AN22 = 0
    AN23 = 0
    AN24 = 0
    AN25 = 0
    AN26 = 0
    AN27 = 0
    AN28 = 0
    AN29 = 0
    AN30 = 0
    AN31 = 0
     
     
     
    #14
    WaltR
    Super Member
    • Total Posts : 3812
    • Reward points : 0
    • Joined: 2003/11/07 12:38:21
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/16 19:48:21 (permalink)
    0
    ADCCON3bits.VREFSEL   =4;

    This is NOT a valid setting.
    I use ADCCON3bits.VREFSEL   =0; since single ended input and works well enough.
     
    One other little bit- I do Read all the ANxx data registers to ensure the 'data ready' bits are clear.
    Otherwise the while(!ADCDSTAT1bits.ARDY31); will be true and fall through.
     
    Looking through my code I see a comment I made for the 'global trigger':
    // Convert all AN's setup for Class 2 - Global software trigger sources AN0-11 only: 
    // These convert is sequence, lowest AN number first (highest prioty)
    void read_ADC_7( unsigned int* ADCbuf)
    {
        ADCCON3bits.GSWTRG = 1;             // Start software trigger

        while(ADCDSTAT1bits.ARDY5 == 0);    // Wait until the measurement run
        ADCbuf[0] = ADCDATA5;               // measured data
        while(ADCDSTAT1bits.ARDY6 == 0);
        ADCbuf[1] = ADCDATA6;
        while(ADCDSTAT1bits.ARDY7 == 0);
        ADCbuf[2] = ADCDATA7;    
        while(ADCDSTAT1bits.ARDY8 == 0);
        ADCbuf[3] = ADCDATA8;    
        while(ADCDSTAT1bits.ARDY9 == 0);
        ADCbuf[4] = ADCDATA9;
        while(ADCDSTAT1bits.ARDY10 == 0);
        ADCbuf[5] = ADCDATA10;

        while(ADCDSTAT1bits.ARDY0 == 0);    // Wait until the measurement run
        ADCbuf[6] = ADCDATA0;               // measured data
        while(ADCDSTAT1bits.ARDY1 == 0);
        ADCbuf[7] = ADCDATA1;
        while(ADCDSTAT1bits.ARDY2 == 0);
        ADCbuf[8] = ADCDATA2;
        while(ADCDSTAT1bits.ARDY3 == 0);
        ADCbuf[9] = ADCDATA3;
    //    while(ADCDSTAT1bits.ARDY4 == 0);
    //    ADCbuf[10] = ADCDATA4;
    }

     
    I have not seen anything in your code that is wrong but this is tough.
    When I get a chance I will use your code and try it.
     
    #15
    WaltR
    Super Member
    • Total Posts : 3812
    • Reward points : 0
    • Joined: 2003/11/07 12:38:21
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/17 08:29:30 (permalink)
    0
    Modified code I an working on to do scan of AN5,6,7,8,9,10,29,38,39 & 42 (these are pined out to connectors on the Curiosity 2.0 board).
    All are working fine.
    One difference is that I setup the ADCCSS registers before enabling the ADCs in the ADC init.
     
    An anomaly I have seen but haven't explained is the first conversion/read returns zero. All conversions after are ok.
    I get around this by either taking an extra sample and ignoring the first or do a manual sample then the ones I need.
     
    Hers is the ADC code
    #include "adc.h"
    #include "uart2.h"

    // ADC0 -> AN0 (RB0)    <PGC1>
    //         AN45 (RB5) = Enet & GFX
    // ADC1 -> AN1 (RB1)    <PGD1>
    //         AN46 (RB6 = GFX)
    // ADC2 -> AN2 (RB2 = EXT ADC+) *
    //         AN47 (RB7)   <LED R>
    // ADC3 -> AN3 (RB3 = EXT MOSI) *
    //         AN48 (RB8)   <LED G>
    // ADC4 -> AN4 (RB4 = Ard A0) *
    //         AN49 (RB9)   <LED B>

    // ADC7 -> AN5 (RB10 = Bus1 AN)
    //         AN6 (RB11 = Bus2 AN)
    //         AN7 (RB12 = EXT ADC-)
    //         AN9 (RB14 = EXT SCK)
    //         AN10 (RB15 = EXT SS)
    //         AN11 (RG9 = Bus2 RX) <UART2RX>
    //         AN12 (RG8 = Bus2 MOSI)
    //         AN29 (RA1 = Ard A1)
    //         AN8 (RB13 = Ard A2)
    //         AN38 (RH0 = Ard A3)
    //         AN39 (RH1 = Ard A4)
    //         AN42 (RH6 = Ard A5)

    // Class 1 = AN0 to AN4 (AN45 to AN49)
    // Class 2 = AN5 to AN11
    // Class 3 = AN12 to AN44

    // PBCLK3 = 100MHz
    // SYSCLK = 200MHz
    // TAD = 20ns min
    // ADC PBxDIV<PBDIV>= 1
    // Timer3 PBxDIV<PBDIV>= 1
    // ADCCON3<ADCSEL>= SYSCLK
    // ADCCON3<CONCLKDIV>= 1
    // TQ= 10ns
    // ADCxTIME<ADCDIV>= 1
    // ADC CLOCK (TAD)= 20ns
    // ADCxTIME<SAMC> >= 3TAD
    // Ensure that the selected trigger source time base clock rate is twice
    //      faster than the ADC clock TAD rate.
    //
    // Configure ADC for 512 TAD warm-up time (the ADCANCON bits.WKUPCLKCNT = 0x9)
    //      before enabling ADC.
    //
    // Equation 1: ADC Conversion Cycle time
    //  ADC Conversion Cycle time = ((# bits resolution+1) * TAD)
    //  TAD = ADC sample & conversion clock period
    //
    // Equation 2: Minimum Interleaved ADC TAD Trigger Source Interval:
    //  = ((SAMC Sample Time (min) + Conversion Time + ADJ) * TAD) / # of interleaved ADCs used
    //  = (3TAD + (((#bits Resolution+1) + ADJ) * TAD)) / # of interleaved ADCs used
    //
    // ------------------------------------------------------------------------------
    // Manual SAMP/CONV
    //
    // ADCCON3:
    //    bit 9 SAMP: Class 2 and Class 3 Analog Input Sampling Enable bit(1,2,3,4)
    //          1 = The ADC S&H amplifier is sampling
    //          0 = The ADC S&H amplifier is holding
    //    bit 8 RQCNVRT: Individual ADC Input Conversion Request bit
    //          This bit and its associated ADINSEL<5:0> bits enable the user to
    //          individually request an analog-to-digital conversion of an analog
    //          input through software.
    //    1 = Trigger the conversion of the selected ADC input as specified by the
    //          ADINSEL<5:0> bits
    //    0 = Do not trigger the conversion
    //          Note: This bit is automatically cleared in the next ADC clock cycle.
    //    bit 5-0 ADINSEL<5:0>: Analog Input Select bits
    //        These bits select the analog input to be converted when the RQCNVRT bit is set.
    //        111111 = Reserved
    //        ???
    //        101101 = Reserved
    //        101100 = MAX_AN_INPUT + 2 = IVTEMP
    //        101011 = MAX_AN_INPUT + 1 = IVREF
    //        101010 = MAX_AN_INPUT = AN[MAX_AN_INPUT]
    //        ???
    //        000001 = AN1
    //        000000 = AN0
    //
    //
    // Note 1: The SAMP bit has the highest priority and setting this bit will keep the S&H circuit in Sample mode until the
    //    bit is cleared. Also, usage of the SAMP bit will cause settings of SAMC<9:0> bits (ADCCON2<25:16>) to
    //    be ignored.
    //  2: The SAMP bit only connects Class 2 and Class 3 analog inputs to the shared ADC, ADC7. All Class 1
    //    analog inputs are not affected by the SAMP bit.
    //  3: The SAMP bit is not a self-clearing bit and it is the responsibility of application software to first clear this bit
    //    and only after setting the RQCNVRT bit to start the analog-to-digital conversion.
    //  4: Normally, when the SAMP and RQCNVRT bits are used by software routines, all TRGSRCx<4:0> bits
    //    and STRGSRC<4:0> bits should be set to ?00000? to disable all external hardware triggers and prevent
    //    them from interfering with the software-controlled sampling command signal SAMP and with the
    //    software-controlled trigger RQCNVRT.

    // ----------------------------------------------------------------------------
    // Setup 2 ADC inputs to sample at same times
    // first samples TX sine
    // second samples RX sine
    // Use two adjacent ADC channels for DMA Ch0 access in one event
    //
    // AN2 & AN3 are on EXT connector
    // Data format is signed
    //
    // 1 cycle = 320 usec
    // sample 512 @ 1usec per (1Msps) = 512us
    // buffer size = 4 byte(32bit) x 2ADCs x 512 = 4096 bytes
    //  
    //
    // ADC7 is multiplex to slow inputs, pots, etc
    //

    void init_ADC( void)
    {
        // works after clearing PMD1<0>
        
        UART2_string_Out("ADC Init\n\r");
        
        ADC0CFG = DEVADC0;    // copy calibration
        ADC1CFG = DEVADC1;
        ADC2CFG = DEVADC2;
        ADC3CFG = DEVADC3;
        ADC4CFG = DEVADC4;
        ADC7CFG = DEVADC7;
        
    //    ADCCON1bits.AICPMPEN = 0; //Disable ADC charge pump
    //    CFGCONbits.IOANCPEN = 0;  //Disable ADC I/O charge pump

        /* Configure ADCCON1 */
        ADCCON1 = 0;
        ADCCON1bits.SELRES = 3;     // ADC7 resolution is 12 bits
        ADCCON1bits.STRGSRC = 1;    // Global software scan trigger
        ADCCON1bits.FSSCLKEN = 1;   // Fast synchronous SYSCLK to ADC control clock is enabled
        
        /* Configure ADCCON2 */
        ADCCON2 = 0;
        ADCCON2bits.SAMC = 5;   // ADC7 sampling time = 7 * TAD7 = 141ns
        ADCCON2bits.ADCDIV = 1; // ADC7 clock freq is half of control clock (TQ) = TAD7

        /* Global setting */
        ADCCON3 = 0;
        ADCCON3bits.VREFSEL = 0;   // Select AVDD and AVSS as reference source
        ADCCON3bits.ADCSEL = 1;    // Select input clock source = SYSCLK 200MHz
        ADCCON3bits.CONCLKDIV = 1; // Control clock (TQ) frequency is half of input clock
                                   // TQ output to ADCDIVx
        // SYSCLK = 198MHz
        // TQ = 10.1 nsec (99MHz)
        // TAD = 20.2ns
        
        /* ADC0 setup */
    //    ADC0TIMEbits.ADCDIV = 1;  // = 2 *TQ = TADx = 20ns
    //    ADC0TIMEbits.SAMC = 3;    // = 5* TADx = 100ns
    //    ADC0TIMEbits.SELRES = 3;  // = 12 bits (conv = 13 TADx = 260ns)
    //                              // samp + conv = 100 + 260 = 360ns
        
    //    ADC1TIMEbits.ADCDIV = 1;
    //    ADC1TIMEbits.SAMC = 3;
    //    ADC1TIMEbits.SELRES = 3;
        // ADC2 setup
        ADC2TIMEbits.ADCDIV = 1;
        ADC2TIMEbits.SAMC = 3;
        ADC2TIMEbits.SELRES = 3;
        ADCTRG1bits.TRGSRC2 = 6;    // trigger on TMR3 match
        // ADC3 setup
        ADC3TIMEbits.ADCDIV = 1;
        ADC3TIMEbits.SAMC = 3;
        ADC3TIMEbits.SELRES = 3;
        ADCTRG1bits.TRGSRC3 = 6;    // trigger on TMR3 match
        
    //    // ADC4 setup
    //    ANSELBSET = 0x0010;         // AN4 RB4   -Ard A0
    //    TRISBSET = 0x0010;
    //    ADC4TIMEbits.ADCDIV = 1;
    ////    ADC4TIMEbits.SAMC = 1;      // = 3* TADx = 60ns + 263 = 323ns
    ////    ADC4TIMEbits.SAMC = 3;      // = 5* TADx = 100ns + 260 = 360ns
    //    ADC4TIMEbits.SAMC = 5;      // = 7* TADx = 140ns + 260 = 400ns
    //    ADC4TIMEbits.SELRES = 3;
    //    ADCTRG2bits.TRGSRC4 = 6;    // ADC4 trigger on TMR3 match
    //    ADCANCONbits.ANEN4 = 1;
    //    ADCCON3bits.DIGEN4 = 1;
    //    ADCGIRQEN1bits.AGIEN4 = 1;  // ADC4 IF -> DMA transfer
        
        
        /* No selection for dedicated ADC modules, no presync trigger, not sync sampling */
        ADCTRGMODE = 0;             // ADC2 = AN2, ADC3 = AN3, ADC4 = AN4
    //    ADCTRGMODEbits.SH0ALT = 1;  // ADC0 = AN45
    //    ADCTRGMODEbits.SH1ALT = 1;  // ADC1 = AN46
        
        // What do these do?? see FRM 22.4.4.2
        ADCTRGMODEbits.STRGEN4 = 1;     // presynchronized triggers
        ADCTRGMODEbits.SSAMPEN4 = 0;    // synchronous sampling for the first sample after being idle or disabled
        
        /* Select ADC input mode */
        ADCIMCON1 = 0; // all unsigned data format & Single ended mode
        ADCIMCON2 = 0;
        ADCIMCON1bits.SIGN2 = 1;    // Signed Data mode
        ADCIMCON1bits.SIGN3 = 1;    // Signed Data mode
    //    ADCIMCON1bits.SIGN4 = 1;    // Signed Data mode
                
        /* Configure ADCGIRQENx */
        ADCGIRQEN1 = 0; // No interrupts are used.
        ADCGIRQEN2 = 0;
    //    ADCGIRQEN1bits.AGIEN0 = 1;  // ADC0 IF -> DMA transfer
    //    ADCGIRQEN1bits.AGIEN4 = 1;  // ADC4 IF -> DMA transfer
        ADCGIRQEN1bits.AGIEN2 = 1;  // ADC2 IF -> DMA transfer
        
        /* Early interrupt */
        ADCEIEN1 = 0; // No early interrupt
        ADCEIEN2 = 0;
        
        /* Configure ADCCSSx ADC COMMON SCAN SELECT REGISTER */
        ADCCSS1 = 0; // Clear all bits  - No scanning is used
        ADCCSS2 = 0; // clear all bits
          
        ADCCSS1bits.CSS5 = 1;
        ADCCSS1bits.CSS6 = 1;
        ADCCSS1bits.CSS7 = 1;
        ADCCSS1bits.CSS8 = 1;
        ADCCSS1bits.CSS9 = 1;
        ADCCSS1bits.CSS10 = 1;
        
        ADCCSS1bits.CSS29 = 1;
        ADCCSS2bits.CSS38 = 1;
        ADCCSS2bits.CSS39 = 1;
        ADCCSS2bits.CSS42 = 1;
        
        /* Configure ADCCMPCONx */
        ADCCMPCON1 = 0; // No digital comparators are used. Setting the ADCCMPCONx
        ADCCMPCON2 = 0; // register to '0' ensures that the comparator is disabled.
        ADCCMPCON3 = 0; // Other registers are ?don't care?.
        ADCCMPCON4 = 0;
        ADCCMPCON5 = 0;
        ADCCMPCON6 = 0;
        
        /* Configure ADCFLTRx */
        ADCFLTR1 = 0; // No oversampling filters are used.
        ADCFLTR2 = 0;
        ADCFLTR3 = 0;
        ADCFLTR4 = 0;
        ADCFLTR5 = 0;
        ADCFLTR6 = 0;

        // Setup Class 1 - TMR3 triggered, AN0-4 only -> DMA -> Mem
        
        
        // Setup Class 2 - trigger sources AN0-11 only:
        ADCTRGSNS = 0;     // Edge trigger

        // ADC0-4
    //    ADCTRG1bits.TRGSRC0 = 6;
    //    ADCTRG1bits.TRGSRC1 = 1;    // Software edge trigger
    //    ADCTRG1bits.TRGSRC2 = 1;
    //    ADCTRG1bits.TRGSRC3 = 1;
        
        // ADC7
        ADCTRG2bits.TRGSRC5 = 1;  
        ADCTRG2bits.TRGSRC6 = 1;
        ADCTRG2bits.TRGSRC7 = 1;
        ADCTRG3bits.TRGSRC8 = 1;
        ADCTRG3bits.TRGSRC9 = 1;
        ADCTRG3bits.TRGSRC10 = 1;
        
        ADCCON1bits.STRGSRC = 1;    // Scan Trigger source = Software edge trigger
        
        // Setup Manual SAMP/CONV: AN0-42
        // not needed. Set SAMP-RQCNVRT in function that does manual convert
        // see FRM22.4.4.4
        
        /* Initialize warm up time register */
        ADCANCON = 0;
        ADCANCONbits.WKUPCLKCNT = 9; // Wakeup exponent = 512 * TADx
        
        /* Turn the ADC on */
        ADCCON1bits.ON = 1;
        UART2_string_Out("ADC ON\n\r");
        
        /* Wait for voltage reference to be stable */
        while(!ADCCON2bits.BGVRRDY);   // Wait until the reference voltage is ready
        while(ADCCON2bits.REFFLT);     // Wait if there is a fault with the reference voltage
        UART2_string_Out("ADC reference voltage is ready\n\r");
        
        
    //    ADCANCONbits.ANEN0 = 1;     // Enable Analog and Bias circuitry
    //    ADCANCONbits.ANEN1 = 1;
        ADCANCONbits.ANEN2 = 1;
        ADCANCONbits.ANEN3 = 1;
    //    ADCANCONbits.ANEN4 = 1;
        ADCANCONbits.ANEN7 = 1;
        UART2_string_Out("Clock ON\n\r");
        

    //    while( !ADCANCONbits.WKRDY0);
    //    while( !ADCANCONbits.WKRDY1);
        while( !ADCANCONbits.WKRDY2);
        while( !ADCANCONbits.WKRDY3);
    //    while( !ADCANCONbits.WKRDY4);
        while( !ADCANCONbits.WKRDY7 );  // Wait until ADC7 is ready
        
        // Enable clock to the module.
    //    ADCCON3bits.DIGEN0 = 1;     // Enable ADC0
    //    ADCCON3bits.DIGEN1 = 1;
        ADCCON3bits.DIGEN2 = 1;
        ADCCON3bits.DIGEN3 = 1;
    //    ADCCON3bits.DIGEN4 = 1;
        ADCCON3bits.DIGEN7 = 1;     // Enable ADC7
        UART2_string_Out("ADC Ready\n\r");
        
        /* Setup pins for ADC input */
     
    //    ANSELBSET = 0x0001;    // AN0 RB0
    //    TRISBSET = 0x0001;
    //    ANSELBSET = 0x0002;    // AN1 RB1
    //    TRISBSET = 0x0002;
    // AN0, AN1 alternet input
        ANSELBSET = 0x0020;    // AN0 -> AN45 RB5
        TRISBSET = 0x0020;
        ANSELBSET = 0x0040;    // AN1 -> AN46 RB6
        TRISBSET = 0x0040;
        ANSELBSET = 0x0004;    // AN2 RB2   -EXT1 ADC+
        TRISBSET = 0x0004;
        ANSELBSET = 0x0008;    // AN3 RB3   -Ext1 SPI_MOSI
        TRISBSET = 0x0008;
        
        ANSELBSET = 0x0400;     // AN5 RB10 -Bus1 AN
        TRISBSET = 0x0400;
        ANSELBSET = 0x0800;     // AN6 RB11 -Bus2 AN
        TRISBSET = 0x0800;
        ANSELBSET = 0x1000;     // AN7 RB12 -Ext1 ADC-
        TRISBSET = 0x1000;
        ANSELBSET = 0x2000;     // AN8 RB13 -Ard A2
        TRISBSET = 0x2000;      
        ANSELBSET = 0x4000;     // AN9 RB14 -Ext1 SPI_CLK
        TRISBSET = 0x4000;
        ANSELBSET = 0x8000;     // AN10 RB15 -Ext1 SPI_SS
        TRISBSET = 0x8000;
         
        ANSELASET = 0x0002;     // AN29, Ard A1, pin RA1
        TRISASET = 0x0002;
        ANSELHSET = 0x0001;     // AN38, Ard A3, pin RH0
        TRISHSET = 0x0001;
        ANSELHSET = 0x0002;     // AN39, Ard A4, pin RH1
        TRISHSET = 0x0002;
        ANSELHSET = 0x0040;     // AN42, Ard A5, pin RH6
        TRISHSET = 0x0040;
        
        ADCDATA0;   // Read ADC data to make sure that data ready bits are clear.
        ADCDATA1;   //
        ADCDATA2;   //
        ADCDATA3;   //
        ADCDATA4;   //
        
        ADCDATA5;   //
        ADCDATA6;   //
        ADCDATA7;   //
        ADCDATA8;   //
        ADCDATA9;   //
        ADCDATA10;  //
        
    //    ADCDATA29;   //
        ADCDATA38;   //
        ADCDATA39;   //
        ADCDATA42;   //
    }

    // Convert all AN's setup for Class 2 - Global software trigger sources AN0-11 only:
    // These convert is sequence, lowest AN number first (highest priority)
    int read_ADC_7( unsigned int* ADCbuf)
    {
        int i = 0;
        ADCCON3bits.GSWTRG = 1;             // Start software trigger

        while(ADCDSTAT1bits.ARDY5 == 0);    // Wait until the measurement run
        ADCbuf[i] = ADCDATA5;               // measured data
        i++;
        while(ADCDSTAT1bits.ARDY6 == 0);
        ADCbuf[i] = ADCDATA6;
        i++;
        while(ADCDSTAT1bits.ARDY7 == 0);
        ADCbuf[i] = ADCDATA7;
        i++;
        while(ADCDSTAT1bits.ARDY8 == 0);
        ADCbuf[i] = ADCDATA8;  
        i++;
        
        while(ADCDSTAT1bits.ARDY9 == 0);
        ADCbuf[i] = ADCDATA9;
        i++;
        while(ADCDSTAT1bits.ARDY10 == 0);
        ADCbuf[i] = ADCDATA10;
        i++;

        while(ADCDSTAT1bits.ARDY29 == 0);    
        ADCbuf[i] = ADCDATA29;               
        i++;
        while(ADCDSTAT2bits.ARDY38 == 0);
        ADCbuf[i] = ADCDATA38;
        i++;
        while(ADCDSTAT2bits.ARDY39 == 0);
        ADCbuf[i] = ADCDATA39;
        i++;
        while(ADCDSTAT2bits.ARDY42 == 0);
        ADCbuf[i] = ADCDATA42;
        i++;
        return i;
    }

     
    I call read_ADC_7() from main and 'print' results through the UART to the PC.
    // Test ADC scan
        n = read_ADC_7(adc_buf);
        for ( i=0; i<n; i++) {
            UART2_dec_out(adc_buf[i]);
            UART2_new_line();
        }
        UART2_new_line();

    Note: ADC AN2 & 3 are setup to trigger DMA for synchronous conversion of external signals.
    I am not using the Class 1 ADCs in the scan.
     
    Maybe you can switch to use only Class 2 & 3 ADCs (11-44) for the scan reserving the Class 1 ADCs for Timing critical sampling.
     
    I would not go with the external ADCs you mentioned. This PIC should work properly to do what you need.
     
    To Test each AN try doing a Manual sample/convert like this:
    unsigned int read_ADC_AN42 (void)
    {
        ADCCON3bits.ADINSEL = 42;       // AN42, Ard A5, pin RH6
        ADCCON3bits.SAMP = 1;           // start sampling pin
        Wait_200ns();
        ADCCON3bits.RQCNVRT = 1;        // start conversion
        ADCCON3bits.SAMP = 0;
        while (ADCCON3bits.RQCNVRT);    // wait for conversion to finish
        return ADCDATA42;
    }

     
    Change the AN number and call this in a loop outputting the value. Then you can change the Voltage into the ADC input to ensure it is working.
     
    Last thing to do before giving up is Open a trouble ticket with Microchip.
     
    #16
    ACPUK
    New Member
    • Total Posts : 6
    • Reward points : 0
    • Joined: 2020/03/31 18:52:16
    • Location: 0
    • Status: offline
    Re: PIC32MZ EF ADC usage methods 2020/04/17 10:00:15 (permalink)
    0
    Hi WaltR, thank you for your reply, when I get back in, I will try your code and compare the results. I don't think this is a fault as I get the same results on two PICs.
     
    #17
    Jump to:
    © 2020 APG vNext Commercial Version 4.5