• AVR Freaks

PIC24FJ128GB204 ADC conversion does not start (or finish)

New Member
  • Total Posts : 2
  • Reward points : 0
  • Joined: 2020/01/07 07:43:22
  • Location: 0
  • Status: offline
2020/01/07 11:58:19 (permalink)

PIC24FJ128GB204 ADC conversion does not start (or finish)

This is my second project using a PIC and second time using C, so I might be missing something obvious.
My problem is with the ADC module of my PIC24FJ128GB204.
I am using AN11 (PORTC1) as input, which is the battery voltage through a resistor divider. Input voltage to the pin is 2.12V during my tests.
The PIC gets Vcc from a 3.3V LDO which I use as reference. I don't really care too much about mV precision, so the LDO output is good enough.
My code (PRAGMA's in main.c):
#pragma config WDTPS = PS512 // Watchdog Timer Postscaler Select->1:512
#pragma config FWPSA = PR128 // WDT Prescaler Ratio Select->1:128
#pragma config WINDIS = OFF // Windowed WDT Disable->Standard Watchdog Timer
#pragma config FWDTEN = SWON // Watchdog Timer controlled by SWDTEN
#pragma config ICS = PGx1 // Emulator Pin Placement Select bits->Emulator functions are shared with PGEC1/PGED1
#pragma config LPCFG = OFF // Low power regulator control->Disabled - regardless of RETEN
#pragma config GWRP = OFF // General Segment Write Protect->Write to program memory allowed
#pragma config GCP = OFF // General Segment Code Protect->Code protection is disabled
#pragma config JTAGEN = OFF // JTAG Port Enable->Disabled
#pragma config POSCMD = NONE // Primary Oscillator Select->Primary Oscillator Disabled
#pragma config WDTCLK = LPRC // WDT Clock Source Select bits->WDT uses LPRC
#pragma config OSCIOFCN = ON // OSCO Pin Configuration->OSCO/CLKO/RA3 functions as port I/O (RA3)
#pragma config FCKSM = CSECMD // Clock Switching and Fail-Safe Clock Monitor Configuration bits->Clock switching is enabled, Fail-Safe Clock Monitor is disabled
#pragma config FNOSC = FRCPLL // Initial Oscillator Select->Fast RC Oscillator with PLL module (FRCPLL)
#pragma config ALTRB6 = APPEND // Alternate RB6 pin function enable bit->Append the RP6/ASCL1/PMPD6 functions of RB6 to RA1 pin functions
#pragma config ALTCMPI = CxINC_RB // Alternate Comparator Input bit->C1INC is on RB13, C2INC is on RB9 and C3INC is on RA0
#pragma config WDTCMX = WDTCLK // WDT Clock Source Select bits->WDT clock source is determined by the WDTCLK Configuration bits
#pragma config IESO = ON // Internal External Switchover->Enabled
#pragma config WPFP = WPFP127 // Write Protection Flash Page Segment Boundary->Page 127 (0x1FC00)
#pragma config SOSCSEL = ON // SOSC Selection bits->SOSC circuit selected
#pragma config WDTWIN = PS25_0 // Window Mode Watchdog Timer Window Width Select->Watch Dog Timer Window Width is 25 percent
#pragma config PLLSS = PLL_FRC // PLL Secondary Selection Configuration bit->PLL is fed by the on-chip Fast RC (FRC) oscillator
#pragma config BOREN = ON // Brown-out Reset Enable->Brown-out Reset Enable
#pragma config WPDIS = WPDIS // Segment Write Protection Disable->Disabled
#pragma config WPCFG = WPCFGDIS // Write Protect Configuration Page Select->Disabled
#pragma config WPEND = WPENDMEM // Segment Write Protection End Page Select->Write Protect from WPFP to the last page of memory
#pragma config DSWDTPS = DSWDTPS1F // Deep Sleep Watchdog Timer Postscale Select bits->1:68719476736 (25.7 Days)
#pragma config DSWDTOSC = LPRC // DSWDT Reference Clock Select->DSWDT uses LPRC as reference clock
#pragma config DSBOREN = ON // Deep Sleep BOR Enable bit->DSBOR Enabled
#pragma config DSWDTEN = ON // Deep Sleep Watchdog Timer Enable->DSWDT Enabled
#pragma config DSSWEN = ON // DSEN Bit Enable->Deep Sleep is controlled by the register bit DSEN
#pragma config PLLDIV = PLL6X // USB 96 MHz PLL Prescaler Select bits->6x PLL selected
#pragma config I2C1SEL = DISABLE // Alternate I2C1 enable bit->I2C1 uses SCL1 and SDA1 pins
#pragma config IOL1WAY = ON // PPS IOLOCK Set Only Once Enable bit->Once set, the IOLOCK bit cannot be cleared
Interrupt trap for ADC (in main.c):
void __attribute__ ( ( interrupt, no_auto_psv ) ) _ADC1Interrupt( void ){

Relevant part of the main loop (in main.c):
(Flag500ms  is an interrupt flag, Uart1SendString is a function that works, I know that I probably shouldn't send an Int as a string, but still need to find how to do this correctly)
if (Flag500ms == true){
            Flag500ms = false;
            Batt_Raw = sampleBatt();

initADC (in hardware.c):
void initAdc (void){
      /* Battery is connected through voltage divider (xxxR to batt, xxxR to GND) to pin RC1/AN11.
        Pin is initialised in initPins function. */
    /* ADC input */
    _ANSC1 = 1;
    _TRISC1 = 1;
    AD1CON1bits.ADON = 0;
    AD1CON1bits.ADSIDL = 0;     //Continues operation in idle mode
    AD1CON1bits.DMABM = 0;      // Not used since not using DMA
    AD1CON1bits.DMAEN = 0;      // No extended features
    AD1CON1bits.MODE12 = 1;     // 12 bit operation
    AD1CON1bits.FORM = 0;       // Absolute decimal, unsigned, right justified
    AD1CON1bits.SSRC = 0;       // Clear SAMP bit to start conversion
    AD1CON1bits.ASAM = 0;       // Sample when SAMP is set manually
    AD1CON1bits.SAMP = 0;       // Don't sample yet
    AD1CON1bits.DONE = 0;       // no conversion yet
    AD1CON2bits.PVCFG = 0;      // Use AVdd as pos volt ref
    AD1CON2bits.NVCFG0 = 0;     // Use AVss as neg voltage ref
    AD1CON2bits.OFFCAL = 0;     // inputs are connected to normal inputs
    AD1CON2bits.BUFREGEN = 0;   // Buffer register is used as FIFO
    AD1CON2bits.CSCNA = 0;      // No scanning
    AD1CON2bits.BUFS = 0;       // Not used since BUFM = 0
    AD1CON2bits.SMPI = 0;       // Interrupt at completion of each sample (no interrupt needed)
    AD1CON2bits.BUFM = 0;       // Start filling buffer at ADC1BUF0
    AD1CON2bits.ALTS = 0;       // Always use Sample A
    AD1CON3bits.ADRC = 0;       // Clock derived from system clock
    AD1CON3bits.PUMPEN = 0;     // Charge pump is disabled
    AD1CON3bits.SAMC = 0;       // Auto sample is 0Tad (not used)
    AD1CON3bits.ADCS = 0b10;    // Tad = 4xTcy
    //AD1CON4 is used to configure DMA
    //AD1CON5 is used for Threshold detect
    AD1CHS = 0xB;                // select AN11/PORTC1 as POS inp, Vss as neg for CHAN A
    AD1CON1bits.ADON = 1;        // turn ADC ON

Function showing the issue (in hardware.c, called from main loop):
unsigned int sampleBatt( void ){
//    #define    FCY    8000000UL    // Instruction cycle frequency, Hz - required for __delayXXX() to work
//    #include <libpic30.h>           // has __delay_ms() function
    unsigned int wait, value = 0;      // for for loop while sampling
    AD1CON1bits.SAMP = 1;               // start sampling
//    __delay_ms(100);    
    for(wait=0; wait < 200; wait++){};    // give time to sample
    AD1CON1bits.SAMP = 0;               // stop sampling, start conversion
//    Uart1SendString("Converting\r");
//    __delay_ms(200);    
    while (!AD1CON1bits.DONE){}      // wait for conversion to be finished
//    for(wait=0; wait < 180000; wait++){};    // give time to sample
//    __delay_ms(200);  
    value = ADC1BUF0;
    Uart1SendString("Conversion finished\r");
    return value;

So the issue is that the loop never gets past the
while (!AD1CON1bits.DONE){}
line. Watching the bit shows that it doesn't get set.
Replacing the line by __delay_ms(200);  to force the function to continue results in a value of 0x00 in ADC1BUF0.
To me it seems like the conversion is not triggered, but I can't seem to find what I do wrong.
post edited by dietervansteenwegen - 2020/01/08 01:44:06

2 Replies Related Threads

    Super Member
    • Total Posts : 25244
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: offline
    Re: PIC24FJ128GB204 ADC conversion does not start (or finish) 2020/01/07 14:30:53 (permalink)
    Why are you coding your own delays, rather than using the library ones?
    If you don't make the loop variable "volatile", the compiler will just optimise the "do nothing" loop away.

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    New Member
    • Total Posts : 2
    • Reward points : 0
    • Joined: 2020/01/07 07:43:22
    • Location: 0
    • Status: offline
    Re: PIC24FJ128GB204 ADC conversion does not start (or finish) 2020/01/08 01:53:00 (permalink)
    As said, this is the second project I do in C and using PICs. I come from a Python/Linux background so quite a lot of changes. The most compact answer to your question probably would be: "not knowing any better and trying things out".
    I suppose you mean the line
    for(wait=0; wait < 200; wait++){};    // give time to sample

    As you can see, I also tried using:
    //    #define    FCY    8000000UL    // Instruction cycle frequency, Hz - required for __delayXXX() to work
    //    #include <libpic30.h>           // has __delay_ms() function
    //    __delay_ms(200);

    It is commented out at the moment, but I can guarantee that I tried using that function for the delay, which resulted in an ADC conversion result of 0x00.
    I tried the included delay, the "self made" delay as well as waiting for AD1CON1bits.DONE to go high.
    I will look up what volatile just does, but if I understand you correctly then the way I coded the delay loop myself will just removed by the compiler? I will look up what volatile means and how that works.
    I had used the self-made delay in other places and it seemed to work, but that could have been a misinterpretation of mine.
    Bottom line is that it didn't work with the __delay_ms(), nor waiting for AD1CON1bits.DONE to go high...
    Jump to:
    © 2020 APG vNext Commercial Version 4.5